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; |
Alexei Svitkine (slow)
2017/01/10 18:01:04
Preserve the NoBarrier_Store() here?
bcwhite
2017/01/10 18:30:17
Done.
| |
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; |
Alexei Svitkine (slow)
2017/01/10 18:01:03
Preserve the NoBarrier_Store() here?
bcwhite
2017/01/10 18:30:17
Done.
| |
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 |