| 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); | |
| 1099 subtle::NoBarrier_Store(&new_entry->activated, | 1089 subtle::NoBarrier_Store(&new_entry->activated, |
| 1100 subtle::NoBarrier_Load(&prev_entry->activated)); | 1090 subtle::NoBarrier_Load(&prev_entry->activated)); |
| 1101 new_entry->pickle_size = pickle.size(); | 1091 new_entry->pickle_size = pickle.size(); |
| 1102 | 1092 |
| 1103 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section | 1093 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section |
| 1104 // in memory, so we can avoid this memcpy. | 1094 // in memory, so we can avoid this memcpy. |
| 1105 char* dst = reinterpret_cast<char*>(new_entry) + | 1095 char* dst = reinterpret_cast<char*>(new_entry) + |
| 1106 sizeof(FieldTrial::FieldTrialEntry); | 1096 sizeof(FieldTrial::FieldTrialEntry); |
| 1107 memcpy(dst, pickle.data(), pickle.size()); | 1097 memcpy(dst, pickle.data(), pickle.size()); |
| 1108 | 1098 |
| 1109 // Update the ref on the field trial and add it to the list to be made | 1099 // Update the ref on the field trial and add it to the list to be made |
| 1110 // iterable. | 1100 // iterable. |
| 1101 FieldTrial::FieldTrialRef new_ref = allocator->GetAsReference(new_entry); |
| 1111 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); | 1102 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); |
| 1112 trial->ref_ = new_ref; | 1103 trial->ref_ = new_ref; |
| 1113 new_refs.push_back(new_ref); | 1104 new_refs.push_back(new_ref); |
| 1114 | 1105 |
| 1115 // Mark the existing entry as unused. | 1106 // Mark the existing entry as unused. |
| 1116 allocator->ChangeType(prev_ref, 0, kFieldTrialType); | 1107 allocator->ChangeType(prev_ref, 0, |
| 1108 FieldTrial::FieldTrialEntry::kPersistentTypeId); |
| 1117 } | 1109 } |
| 1118 | 1110 |
| 1119 for (const auto& ref : new_refs) { | 1111 for (const auto& ref : new_refs) { |
| 1120 allocator->MakeIterable(ref); | 1112 allocator->MakeIterable(ref); |
| 1121 } | 1113 } |
| 1122 } | 1114 } |
| 1123 | 1115 |
| 1124 // static | 1116 // static |
| 1125 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator( | 1117 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator( |
| 1126 PersistentMemoryAllocator* allocator) { | 1118 PersistentMemoryAllocator* allocator) { |
| 1127 if (!global_) | 1119 if (!global_) |
| 1128 return; | 1120 return; |
| 1129 AutoLock auto_lock(global_->lock_); | 1121 AutoLock auto_lock(global_->lock_); |
| 1130 for (const auto& registered : global_->registered_) { | 1122 for (const auto& registered : global_->registered_) { |
| 1131 AddToAllocatorWhileLocked(allocator, registered.second); | 1123 AddToAllocatorWhileLocked(allocator, registered.second); |
| 1132 } | 1124 } |
| 1133 } | 1125 } |
| 1134 | 1126 |
| 1135 // static | 1127 // static |
| 1136 std::vector<const FieldTrial::FieldTrialEntry*> | 1128 std::vector<const FieldTrial::FieldTrialEntry*> |
| 1137 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator( | 1129 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator( |
| 1138 PersistentMemoryAllocator const& allocator) { | 1130 PersistentMemoryAllocator const& allocator) { |
| 1139 std::vector<const FieldTrial::FieldTrialEntry*> entries; | 1131 std::vector<const FieldTrial::FieldTrialEntry*> entries; |
| 1140 FieldTrial::FieldTrialRef ref; | |
| 1141 FieldTrialAllocator::Iterator iter(&allocator); | 1132 FieldTrialAllocator::Iterator iter(&allocator); |
| 1142 while ((ref = iter.GetNextOfType(kFieldTrialType)) != | 1133 const FieldTrial::FieldTrialEntry* entry; |
| 1143 FieldTrialAllocator::kReferenceNull) { | 1134 while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
| 1144 const FieldTrial::FieldTrialEntry* entry = | 1135 nullptr) { |
| 1145 allocator.GetAsObject<const FieldTrial::FieldTrialEntry>( | |
| 1146 ref, kFieldTrialType); | |
| 1147 entries.push_back(entry); | 1136 entries.push_back(entry); |
| 1148 } | 1137 } |
| 1149 return entries; | 1138 return entries; |
| 1150 } | 1139 } |
| 1151 | 1140 |
| 1152 #if defined(OS_WIN) | 1141 #if defined(OS_WIN) |
| 1153 // static | 1142 // static |
| 1154 bool FieldTrialList::CreateTrialsFromHandleSwitch( | 1143 bool FieldTrialList::CreateTrialsFromHandleSwitch( |
| 1155 const std::string& handle_switch) { | 1144 const std::string& handle_switch) { |
| 1156 int field_trial_handle = std::stoi(handle_switch); | 1145 int field_trial_handle = std::stoi(handle_switch); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1175 #endif | 1164 #endif |
| 1176 | 1165 |
| 1177 // static | 1166 // static |
| 1178 bool FieldTrialList::CreateTrialsFromSharedMemory( | 1167 bool FieldTrialList::CreateTrialsFromSharedMemory( |
| 1179 std::unique_ptr<SharedMemory> shm) { | 1168 std::unique_ptr<SharedMemory> shm) { |
| 1180 global_->field_trial_allocator_.reset( | 1169 global_->field_trial_allocator_.reset( |
| 1181 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); | 1170 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); |
| 1182 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); | 1171 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); |
| 1183 FieldTrialAllocator::Iterator mem_iter(shalloc); | 1172 FieldTrialAllocator::Iterator mem_iter(shalloc); |
| 1184 | 1173 |
| 1185 FieldTrial::FieldTrialRef ref; | 1174 const FieldTrial::FieldTrialEntry* entry; |
| 1186 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 1175 while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
| 1187 FieldTrialAllocator::kReferenceNull) { | 1176 nullptr) { |
| 1188 const FieldTrial::FieldTrialEntry* entry = | |
| 1189 shalloc->GetAsObject<const FieldTrial::FieldTrialEntry>( | |
| 1190 ref, kFieldTrialType); | |
| 1191 | |
| 1192 StringPiece trial_name; | 1177 StringPiece trial_name; |
| 1193 StringPiece group_name; | 1178 StringPiece group_name; |
| 1194 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) | 1179 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) |
| 1195 return false; | 1180 return false; |
| 1196 | 1181 |
| 1197 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take | 1182 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take |
| 1198 // StringPieces. | 1183 // StringPieces. |
| 1199 FieldTrial* trial = | 1184 FieldTrial* trial = |
| 1200 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); | 1185 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); |
| 1201 | 1186 |
| 1202 trial->ref_ = ref; | 1187 trial->ref_ = mem_iter.GetAsReference(entry); |
| 1203 if (subtle::NoBarrier_Load(&entry->activated)) { | 1188 if (subtle::NoBarrier_Load(&entry->activated)) { |
| 1204 // Call |group()| to mark the trial as "used" and notify observers, if | 1189 // 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 | 1190 // any. This is useful to ensure that field trials created in child |
| 1206 // processes are properly reported in crash reports. | 1191 // processes are properly reported in crash reports. |
| 1207 trial->group(); | 1192 trial->group(); |
| 1208 } | 1193 } |
| 1209 } | 1194 } |
| 1210 return true; | 1195 return true; |
| 1211 } | 1196 } |
| 1212 | 1197 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1279 if (field_trial->ref_) | 1264 if (field_trial->ref_) |
| 1280 return; | 1265 return; |
| 1281 | 1266 |
| 1282 Pickle pickle; | 1267 Pickle pickle; |
| 1283 if (!PickleFieldTrial(trial_state, &pickle)) { | 1268 if (!PickleFieldTrial(trial_state, &pickle)) { |
| 1284 NOTREACHED(); | 1269 NOTREACHED(); |
| 1285 return; | 1270 return; |
| 1286 } | 1271 } |
| 1287 | 1272 |
| 1288 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); | 1273 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); |
| 1289 FieldTrial::FieldTrialRef ref = | 1274 FieldTrial::FieldTrialRef ref = allocator->Allocate( |
| 1290 allocator->Allocate(total_size, kFieldTrialType); | 1275 total_size, FieldTrial::FieldTrialEntry::kPersistentTypeId); |
| 1291 if (ref == FieldTrialAllocator::kReferenceNull) { | 1276 if (ref == FieldTrialAllocator::kReferenceNull) { |
| 1292 NOTREACHED(); | 1277 NOTREACHED(); |
| 1293 return; | 1278 return; |
| 1294 } | 1279 } |
| 1295 | 1280 |
| 1296 FieldTrial::FieldTrialEntry* entry = | 1281 FieldTrial::FieldTrialEntry* entry = |
| 1297 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, kFieldTrialType); | 1282 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref); |
| 1298 subtle::NoBarrier_Store(&entry->activated, trial_state.activated); | 1283 subtle::NoBarrier_Store(&entry->activated, trial_state.activated); |
| 1299 entry->pickle_size = pickle.size(); | 1284 entry->pickle_size = pickle.size(); |
| 1300 | 1285 |
| 1301 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in | 1286 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in |
| 1302 // memory, so we can avoid this memcpy. | 1287 // memory, so we can avoid this memcpy. |
| 1303 char* dst = | 1288 char* dst = |
| 1304 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry); | 1289 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry); |
| 1305 memcpy(dst, pickle.data(), pickle.size()); | 1290 memcpy(dst, pickle.data(), pickle.size()); |
| 1306 | 1291 |
| 1307 allocator->MakeIterable(ref); | 1292 allocator->MakeIterable(ref); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1321 if (ref == FieldTrialAllocator::kReferenceNull) { | 1306 if (ref == FieldTrialAllocator::kReferenceNull) { |
| 1322 // It's fine to do this even if the allocator hasn't been instantiated | 1307 // It's fine to do this even if the allocator hasn't been instantiated |
| 1323 // yet -- it'll just return early. | 1308 // yet -- it'll just return early. |
| 1324 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(), | 1309 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(), |
| 1325 field_trial); | 1310 field_trial); |
| 1326 } else { | 1311 } else { |
| 1327 // It's also okay to do this even though the callee doesn't have a lock -- | 1312 // 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 | 1313 // the only thing that happens on a stale read here is a slight performance |
| 1329 // hit from the child re-synchronizing activation state. | 1314 // hit from the child re-synchronizing activation state. |
| 1330 FieldTrial::FieldTrialEntry* entry = | 1315 FieldTrial::FieldTrialEntry* entry = |
| 1331 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, | 1316 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref); |
| 1332 kFieldTrialType); | |
| 1333 subtle::NoBarrier_Store(&entry->activated, 1); | 1317 subtle::NoBarrier_Store(&entry->activated, 1); |
| 1334 } | 1318 } |
| 1335 } | 1319 } |
| 1336 | 1320 |
| 1337 // static | 1321 // static |
| 1338 const FieldTrial::EntropyProvider* | 1322 const FieldTrial::EntropyProvider* |
| 1339 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { | 1323 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { |
| 1340 if (!global_) { | 1324 if (!global_) { |
| 1341 used_without_global_ = true; | 1325 used_without_global_ = true; |
| 1342 return NULL; | 1326 return NULL; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1359 return; | 1343 return; |
| 1360 } | 1344 } |
| 1361 AutoLock auto_lock(global_->lock_); | 1345 AutoLock auto_lock(global_->lock_); |
| 1362 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1346 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1363 trial->AddRef(); | 1347 trial->AddRef(); |
| 1364 trial->SetTrialRegistered(); | 1348 trial->SetTrialRegistered(); |
| 1365 global_->registered_[trial->trial_name()] = trial; | 1349 global_->registered_[trial->trial_name()] = trial; |
| 1366 } | 1350 } |
| 1367 | 1351 |
| 1368 } // namespace base | 1352 } // namespace base |
| OLD | NEW |