| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/metrics/field_trial.h" | 5 #include "base/metrics/field_trial.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/base_switches.h" | 10 #include "base/base_switches.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 // shared memory segment). See https://codereview.chromium.org/2365273004/ and | 48 // shared memory segment). See https://codereview.chromium.org/2365273004/ and |
| 49 // crbug.com/653874 | 49 // crbug.com/653874 |
| 50 // The browser is the only process that has write access to the shared memory. | 50 // The browser is the only process that has write access to the shared memory. |
| 51 // This is safe from race conditions because MakeIterable is a release operation | 51 // This is safe from race conditions because MakeIterable is a release operation |
| 52 // and GetNextOfType is an acquire operation, so memory writes before | 52 // and GetNextOfType is an acquire operation, so memory writes before |
| 53 // MakeIterable happen before memory reads after GetNextOfType. | 53 // MakeIterable happen before memory reads after GetNextOfType. |
| 54 const bool kUseSharedMemoryForFieldTrials = true; | 54 const bool kUseSharedMemoryForFieldTrials = true; |
| 55 | 55 |
| 56 // Constants for the field trial allocator. | 56 // Constants for the field trial allocator. |
| 57 const char kAllocatorName[] = "FieldTrialAllocator"; | 57 const char kAllocatorName[] = "FieldTrialAllocator"; |
| 58 const uint32_t kFieldTrialType = 0xABA17E13 + 2; // SHA1(FieldTrialEntry) v2 | |
| 59 | 58 |
| 60 // We allocate 128 KiB to hold all the field trial data. This should be enough, | 59 // We allocate 128 KiB to hold all the field trial data. This should be enough, |
| 61 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016). | 60 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016). |
| 62 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped | 61 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped |
| 63 // to physical memory when they are touched. If the size of the allocated field | 62 // to physical memory when they are touched. If the size of the allocated field |
| 64 // trials does get larger than 128 KiB, then we will drop some field trials in | 63 // trials does get larger than 128 KiB, then we will drop some field trials in |
| 65 // child processes, leading to an inconsistent view between browser and child | 64 // child processes, leading to an inconsistent view between browser and child |
| 66 // processes and possibly causing crashes (see crbug.com/661617). | 65 // processes and possibly causing crashes (see crbug.com/661617). |
| 67 #if !defined(OS_NACL) | 66 #if !defined(OS_NACL) |
| 68 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB | 67 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 | 709 |
| 711 if (!global_->field_trial_allocator_) { | 710 if (!global_->field_trial_allocator_) { |
| 712 GetActiveFieldTrialGroupsFromString( | 711 GetActiveFieldTrialGroupsFromString( |
| 713 command_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 712 command_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
| 714 active_groups); | 713 active_groups); |
| 715 return; | 714 return; |
| 716 } | 715 } |
| 717 | 716 |
| 718 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); | 717 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); |
| 719 FieldTrialAllocator::Iterator mem_iter(allocator); | 718 FieldTrialAllocator::Iterator mem_iter(allocator); |
| 720 FieldTrial::FieldTrialRef ref; | 719 const FieldTrial::FieldTrialEntry* entry; |
| 721 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 720 while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
| 722 SharedPersistentMemoryAllocator::kReferenceNull) { | 721 nullptr) { |
| 723 const FieldTrial::FieldTrialEntry* entry = | |
| 724 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>( | |
| 725 ref, kFieldTrialType); | |
| 726 | |
| 727 StringPiece trial_name; | 722 StringPiece trial_name; |
| 728 StringPiece group_name; | 723 StringPiece group_name; |
| 729 if (subtle::NoBarrier_Load(&entry->activated) && | 724 if (subtle::NoBarrier_Load(&entry->activated) && |
| 730 entry->GetTrialAndGroupName(&trial_name, &group_name)) { | 725 entry->GetTrialAndGroupName(&trial_name, &group_name)) { |
| 731 FieldTrial::ActiveGroup group; | 726 FieldTrial::ActiveGroup group; |
| 732 group.trial_name = trial_name.as_string(); | 727 group.trial_name = trial_name.as_string(); |
| 733 group.group_name = group_name.as_string(); | 728 group.group_name = group_name.as_string(); |
| 734 active_groups->push_back(group); | 729 active_groups->push_back(group); |
| 735 } | 730 } |
| 736 } | 731 } |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1035 // you can call it after it's been set up. | 1030 // you can call it after it's been set up. |
| 1036 AutoLock auto_lock(global_->lock_); | 1031 AutoLock auto_lock(global_->lock_); |
| 1037 if (!global_->field_trial_allocator_) | 1032 if (!global_->field_trial_allocator_) |
| 1038 return false; | 1033 return false; |
| 1039 | 1034 |
| 1040 // If ref_ isn't set, then the field trial data can't be in shared memory. | 1035 // If ref_ isn't set, then the field trial data can't be in shared memory. |
| 1041 if (!field_trial->ref_) | 1036 if (!field_trial->ref_) |
| 1042 return false; | 1037 return false; |
| 1043 | 1038 |
| 1044 const FieldTrial::FieldTrialEntry* entry = | 1039 const FieldTrial::FieldTrialEntry* entry = |
| 1045 global_->field_trial_allocator_ | 1040 global_->field_trial_allocator_->GetAsObject<FieldTrial::FieldTrialEntry>( |
| 1046 ->GetAsObject<const FieldTrial::FieldTrialEntry>(field_trial->ref_, | 1041 field_trial->ref_); |
| 1047 kFieldTrialType); | |
| 1048 | 1042 |
| 1049 size_t allocated_size = | 1043 size_t allocated_size = |
| 1050 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_); | 1044 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_); |
| 1051 size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size; | 1045 size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size; |
| 1052 if (allocated_size < actual_size) | 1046 if (allocated_size < actual_size) |
| 1053 return false; | 1047 return false; |
| 1054 | 1048 |
| 1055 return entry->GetParams(params); | 1049 return entry->GetParams(params); |
| 1056 } | 1050 } |
| 1057 | 1051 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1068 // just the trial and group name into a newly-allocated segment and then clear | 1062 // just the trial and group name into a newly-allocated segment and then clear |
| 1069 // the existing item. | 1063 // the existing item. |
| 1070 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); | 1064 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); |
| 1071 FieldTrialAllocator::Iterator mem_iter(allocator); | 1065 FieldTrialAllocator::Iterator mem_iter(allocator); |
| 1072 | 1066 |
| 1073 // List of refs to eventually be made iterable. We can't make it in the loop, | 1067 // List of refs to eventually be made iterable. We can't make it in the loop, |
| 1074 // since it would go on forever. | 1068 // since it would go on forever. |
| 1075 std::vector<FieldTrial::FieldTrialRef> new_refs; | 1069 std::vector<FieldTrial::FieldTrialRef> new_refs; |
| 1076 | 1070 |
| 1077 FieldTrial::FieldTrialRef prev_ref; | 1071 FieldTrial::FieldTrialRef prev_ref; |
| 1078 while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 1072 while ((prev_ref = mem_iter.GetNextOfType<FieldTrial::FieldTrialEntry>()) != |
| 1079 FieldTrialAllocator::kReferenceNull) { | 1073 FieldTrialAllocator::kReferenceNull) { |
| 1080 // Get the existing field trial entry in shared memory. | 1074 // Get the existing field trial entry in shared memory. |
| 1081 const FieldTrial::FieldTrialEntry* prev_entry = | 1075 const FieldTrial::FieldTrialEntry* prev_entry = |
| 1082 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>( | 1076 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(prev_ref); |
| 1083 prev_ref, kFieldTrialType); | |
| 1084 StringPiece trial_name; | 1077 StringPiece trial_name; |
| 1085 StringPiece group_name; | 1078 StringPiece group_name; |
| 1086 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name)) | 1079 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name)) |
| 1087 continue; | 1080 continue; |
| 1088 | 1081 |
| 1089 // Write a new entry, minus the params. | 1082 // Write a new entry, minus the params. |
| 1090 Pickle pickle; | 1083 Pickle pickle; |
| 1091 pickle.WriteString(trial_name); | 1084 pickle.WriteString(trial_name); |
| 1092 pickle.WriteString(group_name); | 1085 pickle.WriteString(group_name); |
| 1093 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); | 1086 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); |
| 1094 FieldTrial::FieldTrialRef new_ref = | |
| 1095 allocator->Allocate(total_size, kFieldTrialType); | |
| 1096 FieldTrial::FieldTrialEntry* new_entry = | 1087 FieldTrial::FieldTrialEntry* new_entry = |
| 1097 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(new_ref, | 1088 allocator->AllocateObject<FieldTrial::FieldTrialEntry>(total_size); |
| 1098 kFieldTrialType); | 1089 new_entry->activated = prev_entry->activated; |
| 1099 subtle::NoBarrier_Store(&new_entry->activated, | |
| 1100 subtle::NoBarrier_Load(&prev_entry->activated)); | |
| 1101 new_entry->pickle_size = pickle.size(); | 1090 new_entry->pickle_size = pickle.size(); |
| 1102 | 1091 |
| 1103 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section | 1092 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section |
| 1104 // in memory, so we can avoid this memcpy. | 1093 // in memory, so we can avoid this memcpy. |
| 1105 char* dst = reinterpret_cast<char*>(new_entry) + | 1094 char* dst = reinterpret_cast<char*>(new_entry) + |
| 1106 sizeof(FieldTrial::FieldTrialEntry); | 1095 sizeof(FieldTrial::FieldTrialEntry); |
| 1107 memcpy(dst, pickle.data(), pickle.size()); | 1096 memcpy(dst, pickle.data(), pickle.size()); |
| 1108 | 1097 |
| 1109 // Update the ref on the field trial and add it to the list to be made | 1098 // Update the ref on the field trial and add it to the list to be made |
| 1110 // iterable. | 1099 // iterable. |
| 1100 FieldTrial::FieldTrialRef new_ref = allocator->GetAsReference(new_entry); |
| 1111 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); | 1101 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); |
| 1112 trial->ref_ = new_ref; | 1102 trial->ref_ = new_ref; |
| 1113 new_refs.push_back(new_ref); | 1103 new_refs.push_back(new_ref); |
| 1114 | 1104 |
| 1115 // Mark the existing entry as unused. | 1105 // Mark the existing entry as unused. |
| 1116 allocator->ChangeType(prev_ref, 0, kFieldTrialType); | 1106 allocator->ChangeType(prev_ref, 0, |
| 1107 FieldTrial::FieldTrialEntry::kPersistentTypeId); |
| 1117 } | 1108 } |
| 1118 | 1109 |
| 1119 for (const auto& ref : new_refs) { | 1110 for (const auto& ref : new_refs) { |
| 1120 allocator->MakeIterable(ref); | 1111 allocator->MakeIterable(ref); |
| 1121 } | 1112 } |
| 1122 } | 1113 } |
| 1123 | 1114 |
| 1124 // static | 1115 // static |
| 1125 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator( | 1116 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator( |
| 1126 PersistentMemoryAllocator* allocator) { | 1117 PersistentMemoryAllocator* allocator) { |
| 1127 if (!global_) | 1118 if (!global_) |
| 1128 return; | 1119 return; |
| 1129 AutoLock auto_lock(global_->lock_); | 1120 AutoLock auto_lock(global_->lock_); |
| 1130 for (const auto& registered : global_->registered_) { | 1121 for (const auto& registered : global_->registered_) { |
| 1131 AddToAllocatorWhileLocked(allocator, registered.second); | 1122 AddToAllocatorWhileLocked(allocator, registered.second); |
| 1132 } | 1123 } |
| 1133 } | 1124 } |
| 1134 | 1125 |
| 1135 // static | 1126 // static |
| 1136 std::vector<const FieldTrial::FieldTrialEntry*> | 1127 std::vector<const FieldTrial::FieldTrialEntry*> |
| 1137 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator( | 1128 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator( |
| 1138 PersistentMemoryAllocator const& allocator) { | 1129 PersistentMemoryAllocator const& allocator) { |
| 1139 std::vector<const FieldTrial::FieldTrialEntry*> entries; | 1130 std::vector<const FieldTrial::FieldTrialEntry*> entries; |
| 1140 FieldTrial::FieldTrialRef ref; | |
| 1141 FieldTrialAllocator::Iterator iter(&allocator); | 1131 FieldTrialAllocator::Iterator iter(&allocator); |
| 1142 while ((ref = iter.GetNextOfType(kFieldTrialType)) != | 1132 const FieldTrial::FieldTrialEntry* entry; |
| 1143 FieldTrialAllocator::kReferenceNull) { | 1133 while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
| 1144 const FieldTrial::FieldTrialEntry* entry = | 1134 nullptr) { |
| 1145 allocator.GetAsObject<const FieldTrial::FieldTrialEntry>( | |
| 1146 ref, kFieldTrialType); | |
| 1147 entries.push_back(entry); | 1135 entries.push_back(entry); |
| 1148 } | 1136 } |
| 1149 return entries; | 1137 return entries; |
| 1150 } | 1138 } |
| 1151 | 1139 |
| 1152 #if defined(OS_WIN) | 1140 #if defined(OS_WIN) |
| 1153 // static | 1141 // static |
| 1154 bool FieldTrialList::CreateTrialsFromHandleSwitch( | 1142 bool FieldTrialList::CreateTrialsFromHandleSwitch( |
| 1155 const std::string& handle_switch) { | 1143 const std::string& handle_switch) { |
| 1156 int field_trial_handle = std::stoi(handle_switch); | 1144 int field_trial_handle = std::stoi(handle_switch); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1175 #endif | 1163 #endif |
| 1176 | 1164 |
| 1177 // static | 1165 // static |
| 1178 bool FieldTrialList::CreateTrialsFromSharedMemory( | 1166 bool FieldTrialList::CreateTrialsFromSharedMemory( |
| 1179 std::unique_ptr<SharedMemory> shm) { | 1167 std::unique_ptr<SharedMemory> shm) { |
| 1180 global_->field_trial_allocator_.reset( | 1168 global_->field_trial_allocator_.reset( |
| 1181 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); | 1169 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); |
| 1182 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); | 1170 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); |
| 1183 FieldTrialAllocator::Iterator mem_iter(shalloc); | 1171 FieldTrialAllocator::Iterator mem_iter(shalloc); |
| 1184 | 1172 |
| 1185 FieldTrial::FieldTrialRef ref; | 1173 const FieldTrial::FieldTrialEntry* entry; |
| 1186 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 1174 while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
| 1187 FieldTrialAllocator::kReferenceNull) { | 1175 nullptr) { |
| 1188 const FieldTrial::FieldTrialEntry* entry = | |
| 1189 shalloc->GetAsObject<const FieldTrial::FieldTrialEntry>( | |
| 1190 ref, kFieldTrialType); | |
| 1191 | |
| 1192 StringPiece trial_name; | 1176 StringPiece trial_name; |
| 1193 StringPiece group_name; | 1177 StringPiece group_name; |
| 1194 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) | 1178 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) |
| 1195 return false; | 1179 return false; |
| 1196 | 1180 |
| 1197 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take | 1181 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take |
| 1198 // StringPieces. | 1182 // StringPieces. |
| 1199 FieldTrial* trial = | 1183 FieldTrial* trial = |
| 1200 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); | 1184 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); |
| 1201 | 1185 |
| 1202 trial->ref_ = ref; | 1186 trial->ref_ = mem_iter.GetAsReference(entry); |
| 1203 if (subtle::NoBarrier_Load(&entry->activated)) { | 1187 if (subtle::NoBarrier_Load(&entry->activated)) { |
| 1204 // Call |group()| to mark the trial as "used" and notify observers, if | 1188 // Call |group()| to mark the trial as "used" and notify observers, if |
| 1205 // any. This is useful to ensure that field trials created in child | 1189 // any. This is useful to ensure that field trials created in child |
| 1206 // processes are properly reported in crash reports. | 1190 // processes are properly reported in crash reports. |
| 1207 trial->group(); | 1191 trial->group(); |
| 1208 } | 1192 } |
| 1209 } | 1193 } |
| 1210 return true; | 1194 return true; |
| 1211 } | 1195 } |
| 1212 | 1196 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1279 if (field_trial->ref_) | 1263 if (field_trial->ref_) |
| 1280 return; | 1264 return; |
| 1281 | 1265 |
| 1282 Pickle pickle; | 1266 Pickle pickle; |
| 1283 if (!PickleFieldTrial(trial_state, &pickle)) { | 1267 if (!PickleFieldTrial(trial_state, &pickle)) { |
| 1284 NOTREACHED(); | 1268 NOTREACHED(); |
| 1285 return; | 1269 return; |
| 1286 } | 1270 } |
| 1287 | 1271 |
| 1288 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); | 1272 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); |
| 1289 FieldTrial::FieldTrialRef ref = | 1273 FieldTrial::FieldTrialRef ref = allocator->Allocate( |
| 1290 allocator->Allocate(total_size, kFieldTrialType); | 1274 total_size, FieldTrial::FieldTrialEntry::kPersistentTypeId); |
| 1291 if (ref == FieldTrialAllocator::kReferenceNull) { | 1275 if (ref == FieldTrialAllocator::kReferenceNull) { |
| 1292 NOTREACHED(); | 1276 NOTREACHED(); |
| 1293 return; | 1277 return; |
| 1294 } | 1278 } |
| 1295 | 1279 |
| 1296 FieldTrial::FieldTrialEntry* entry = | 1280 FieldTrial::FieldTrialEntry* entry = |
| 1297 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, kFieldTrialType); | 1281 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref); |
| 1298 subtle::NoBarrier_Store(&entry->activated, trial_state.activated); | 1282 entry->activated = trial_state.activated; |
| 1299 entry->pickle_size = pickle.size(); | 1283 entry->pickle_size = pickle.size(); |
| 1300 | 1284 |
| 1301 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in | 1285 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in |
| 1302 // memory, so we can avoid this memcpy. | 1286 // memory, so we can avoid this memcpy. |
| 1303 char* dst = | 1287 char* dst = |
| 1304 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry); | 1288 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry); |
| 1305 memcpy(dst, pickle.data(), pickle.size()); | 1289 memcpy(dst, pickle.data(), pickle.size()); |
| 1306 | 1290 |
| 1307 allocator->MakeIterable(ref); | 1291 allocator->MakeIterable(ref); |
| 1308 field_trial->ref_ = ref; | 1292 field_trial->ref_ = ref; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1321 if (ref == FieldTrialAllocator::kReferenceNull) { | 1305 if (ref == FieldTrialAllocator::kReferenceNull) { |
| 1322 // It's fine to do this even if the allocator hasn't been instantiated | 1306 // It's fine to do this even if the allocator hasn't been instantiated |
| 1323 // yet -- it'll just return early. | 1307 // yet -- it'll just return early. |
| 1324 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(), | 1308 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(), |
| 1325 field_trial); | 1309 field_trial); |
| 1326 } else { | 1310 } else { |
| 1327 // It's also okay to do this even though the callee doesn't have a lock -- | 1311 // It's also okay to do this even though the callee doesn't have a lock -- |
| 1328 // the only thing that happens on a stale read here is a slight performance | 1312 // the only thing that happens on a stale read here is a slight performance |
| 1329 // hit from the child re-synchronizing activation state. | 1313 // hit from the child re-synchronizing activation state. |
| 1330 FieldTrial::FieldTrialEntry* entry = | 1314 FieldTrial::FieldTrialEntry* entry = |
| 1331 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, | 1315 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref); |
| 1332 kFieldTrialType); | 1316 entry->activated = true; |
| 1333 subtle::NoBarrier_Store(&entry->activated, 1); | |
| 1334 } | 1317 } |
| 1335 } | 1318 } |
| 1336 | 1319 |
| 1337 // static | 1320 // static |
| 1338 const FieldTrial::EntropyProvider* | 1321 const FieldTrial::EntropyProvider* |
| 1339 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { | 1322 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { |
| 1340 if (!global_) { | 1323 if (!global_) { |
| 1341 used_without_global_ = true; | 1324 used_without_global_ = true; |
| 1342 return NULL; | 1325 return NULL; |
| 1343 } | 1326 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1359 return; | 1342 return; |
| 1360 } | 1343 } |
| 1361 AutoLock auto_lock(global_->lock_); | 1344 AutoLock auto_lock(global_->lock_); |
| 1362 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1345 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1363 trial->AddRef(); | 1346 trial->AddRef(); |
| 1364 trial->SetTrialRegistered(); | 1347 trial->SetTrialRegistered(); |
| 1365 global_->registered_[trial->trial_name()] = trial; | 1348 global_->registered_[trial->trial_name()] = trial; |
| 1366 } | 1349 } |
| 1367 | 1350 |
| 1368 } // namespace base | 1351 } // namespace base |
| OLD | NEW |