Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(391)

Side by Side Diff: tools/gn/toolchain_manager.cc

Issue 51693002: GN: toolchain threading cleanup (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/toolchain.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "tools/gn/toolchain_manager.h" 5 #include "tools/gn/toolchain_manager.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "build/build_config.h" 10 #include "build/build_config.h"
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 return SourceFile(dir.value() + "BUILD.gn"); 71 return SourceFile(dir.value() + "BUILD.gn");
72 } 72 }
73 73
74 } // namespace 74 } // namespace
75 75
76 struct ToolchainManager::Info { 76 struct ToolchainManager::Info {
77 Info(const BuildSettings* build_settings, 77 Info(const BuildSettings* build_settings,
78 const Label& toolchain_name, 78 const Label& toolchain_name,
79 const std::string& output_subdir_name) 79 const std::string& output_subdir_name)
80 : state(TOOLCHAIN_NOT_LOADED), 80 : state(TOOLCHAIN_NOT_LOADED),
81 toolchain(toolchain_name), 81 settings(build_settings, output_subdir_name),
82 toolchain(new Toolchain(&settings, toolchain_name)),
82 toolchain_set(false), 83 toolchain_set(false),
83 settings(build_settings, &toolchain, output_subdir_name),
84 toolchain_file_loaded(false), 84 toolchain_file_loaded(false),
85 item_node(NULL) { 85 item_node(NULL) {
86 settings.set_toolchain_label(toolchain_name);
87 }
88
89 ~Info() {
90 if (!item_node) // See toolchain definition for more.
91 delete toolchain;
86 } 92 }
87 93
88 // Makes sure that an ItemNode is created for the toolchain, which lets 94 // Makes sure that an ItemNode is created for the toolchain, which lets
89 // targets depend on the (potentially future) loading of the toolchain. 95 // targets depend on the (potentially future) loading of the toolchain.
90 // 96 //
91 // We can't always do this at the beginning since when doing the default 97 // We can't always do this at the beginning since when doing the default
92 // build config, we don't know the toolchain name yet. We also need to go 98 // build config, we don't know the toolchain name yet. We also need to go
93 // through some effort to avoid doing this inside the toolchain manager's 99 // through some effort to avoid doing this inside the toolchain manager's
94 // lock (to avoid holding two locks at once). 100 // lock (to avoid holding two locks at once).
95 void EnsureItemNode() { 101 void EnsureItemNode() {
96 if (!item_node) { 102 if (!item_node) {
97 ItemTree& tree = settings.build_settings()->item_tree(); 103 ItemTree& tree = settings.build_settings()->item_tree();
98 item_node = new ItemNode(&toolchain); 104 item_node = new ItemNode(toolchain);
99 tree.AddNodeLocked(item_node); 105 tree.AddNodeLocked(item_node);
100 } 106 }
101 } 107 }
102 108
103 ToolchainState state; 109 ToolchainState state;
104 110
105 Toolchain toolchain;
106 bool toolchain_set;
107 LocationRange toolchain_definition_location;
108
109 // The first place in the build that we saw a reference for this toolchain. 111 // The first place in the build that we saw a reference for this toolchain.
110 // This allows us to report errors if it can't be loaded and blame some 112 // This allows us to report errors if it can't be loaded and blame some
111 // reasonable place of the code. This will be empty for the default toolchain. 113 // reasonable place of the code. This will be empty for the default toolchain.
112 LocationRange specified_from; 114 LocationRange specified_from;
113 115
114 // When the state is TOOLCHAIN_SETTINGS_LOADED, the settings should be 116 // When the state is TOOLCHAIN_SETTINGS_LOADED, the settings should be
115 // considered read-only and can be read without locking. Otherwise, they 117 // considered read-only and can be read without locking. Otherwise, they
116 // should not be accessed at all except to load them (which can therefore 118 // should not be accessed at all except to load them (which can therefore
117 // also be done outside of the lock). This works as long as the state flag 119 // also be done outside of the lock). This works as long as the state flag
118 // is only ever read or written inside the lock. 120 // is only ever read or written inside the lock.
119 Settings settings; 121 Settings settings;
120 122
123 // When we create an item node, this pointer will be owned by that node
124 // so it's lifetime is managed by the dependency graph. Before we've created
125 // the ItemNode, this class has to takre responsibility for this pointer.
126 Toolchain* toolchain;
127 bool toolchain_set;
128 LocationRange toolchain_definition_location;
129
121 // Set when the file corresponding to the toolchain definition is loaded. 130 // Set when the file corresponding to the toolchain definition is loaded.
122 // This will normally be set right after "toolchain_set". However, if the 131 // This will normally be set right after "toolchain_set". However, if the
123 // toolchain definition is missing, the file might be marked loaded but the 132 // toolchain definition is missing, the file might be marked loaded but the
124 // toolchain definition could still be unset. 133 // toolchain definition could still be unset.
125 bool toolchain_file_loaded; 134 bool toolchain_file_loaded;
126 135
127 // While state == TOOLCHAIN_SETTINGS_LOADING || TOOLCHAIN_DEFINITION_LOADING, 136 // While state == TOOLCHAIN_SETTINGS_LOADING || TOOLCHAIN_DEFINITION_LOADING,
128 // this will collect all scheduled invocations using this toolchain. They'll 137 // this will collect all scheduled invocations using this toolchain. They'll
129 // be issued once the settings file has been interpreted. 138 // be issued once the settings file has been interpreted.
130 // 139 //
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 const Toolchain* ToolchainManager::GetToolchainDefinitionUnlocked( 204 const Toolchain* ToolchainManager::GetToolchainDefinitionUnlocked(
196 const Label& toolchain_name) { 205 const Label& toolchain_name) {
197 base::AutoLock lock(GetLock()); 206 base::AutoLock lock(GetLock());
198 ToolchainMap::iterator found = toolchains_.find(toolchain_name); 207 ToolchainMap::iterator found = toolchains_.find(toolchain_name);
199 if (found == toolchains_.end() || !found->second->toolchain_set) 208 if (found == toolchains_.end() || !found->second->toolchain_set)
200 return NULL; 209 return NULL;
201 210
202 // Since we don't allow defining a toolchain more than once, we know that 211 // Since we don't allow defining a toolchain more than once, we know that
203 // once it's set it won't be mutated, so we can safely return this pointer 212 // once it's set it won't be mutated, so we can safely return this pointer
204 // for reading outside the lock. 213 // for reading outside the lock.
205 return &found->second->toolchain; 214 return found->second->toolchain;
206 } 215 }
207 216
208 bool ToolchainManager::SetDefaultToolchainUnlocked( 217 bool ToolchainManager::SetDefaultToolchainUnlocked(
209 const Label& default_toolchain, 218 const Label& default_toolchain,
210 const LocationRange& defined_here, 219 const LocationRange& defined_here,
211 Err* err) { 220 Err* err) {
212 base::AutoLock lock(GetLock()); 221 base::AutoLock lock(GetLock());
213 if (!default_toolchain_.is_null()) { 222 if (!default_toolchain_.is_null()) {
214 *err = Err(defined_here, "Default toolchain already set."); 223 *err = Err(defined_here, "Default toolchain already set.");
215 err->AppendSubErr(Err(default_toolchain_defined_here_, 224 err->AppendSubErr(Err(default_toolchain_defined_here_,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 info = LoadNewToolchainLocked(defined_from, tc.label(), err); 263 info = LoadNewToolchainLocked(defined_from, tc.label(), err);
255 if (!info) 264 if (!info)
256 return false; 265 return false;
257 } else { 266 } else {
258 // It's important to preserve the exact Toolchain object in our tree since 267 // It's important to preserve the exact Toolchain object in our tree since
259 // it will be in the ItemTree and targets may have dependencies on it. 268 // it will be in the ItemTree and targets may have dependencies on it.
260 info = found->second; 269 info = found->second;
261 } 270 }
262 271
263 // The labels should match or else we're setting the wrong one! 272 // The labels should match or else we're setting the wrong one!
264 CHECK(info->toolchain.label() == tc.label()); 273 CHECK(info->toolchain->label() == tc.label());
265 274
266 // Save the toolchain. We can just overwrite our definition, but we need to 275 // Save the toolchain. We can just overwrite our definition.
267 // be careful to preserve the is_default flag. 276 *info->toolchain = tc;
268 bool is_default = info->toolchain.is_default();
269 info->toolchain = tc;
270 info->toolchain.set_is_default(is_default);
271 277
272 if (info->toolchain_set) { 278 if (info->toolchain_set) {
273 *err = Err(defined_from, "Duplicate toolchain definition."); 279 *err = Err(defined_from, "Duplicate toolchain definition.");
274 err->AppendSubErr(Err( 280 err->AppendSubErr(Err(
275 info->toolchain_definition_location, 281 info->toolchain_definition_location,
276 "Previously defined here.", 282 "Previously defined here.",
277 "A toolchain can only be defined once. One tricky way that this could\n" 283 "A toolchain can only be defined once. One tricky way that this could\n"
278 "happen is if your definition is itself in a file that's interpreted\n" 284 "happen is if your definition is itself in a file that's interpreted\n"
279 "under different toolchains, which would result in multiple\n" 285 "under different toolchains, which would result in multiple\n"
280 "definitions as the file is loaded multiple times. So be sure your\n" 286 "definitions as the file is loaded multiple times. So be sure your\n"
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 toolchains_[default_toolchain_] = info; 422 toolchains_[default_toolchain_] = info;
417 toolchains_.erase(old_default); 423 toolchains_.erase(old_default);
418 424
419 // Toolchain should not have been loaded in the build config file. 425 // Toolchain should not have been loaded in the build config file.
420 CHECK(!info->toolchain_set); 426 CHECK(!info->toolchain_set);
421 427
422 // We need to set the toolchain label now that we know it. There's no way 428 // We need to set the toolchain label now that we know it. There's no way
423 // to set the label, but we can assign the toolchain to a new one. Loading 429 // to set the label, but we can assign the toolchain to a new one. Loading
424 // the build config can not change the toolchain, so we won't be overwriting 430 // the build config can not change the toolchain, so we won't be overwriting
425 // anything useful. 431 // anything useful.
426 info->toolchain = Toolchain(default_toolchain_); 432 *info->toolchain = Toolchain(&info->settings, default_toolchain_);
427 info->toolchain.set_is_default(true); 433 info->settings.set_is_default(true);
434 info->settings.set_toolchain_label(default_toolchain_);
428 info->EnsureItemNode(); 435 info->EnsureItemNode();
429 436
430 // The default toolchain is loaded in greedy mode so all targets we 437 // The default toolchain is loaded in greedy mode so all targets we
431 // encounter are generated. Non-default toolchain settings stay in non-greedy 438 // encounter are generated. Non-default toolchain settings stay in non-greedy
432 // so we only generate the minimally required set. 439 // so we only generate the minimally required set.
433 info->settings.set_greedy_target_generation(true); 440 info->settings.set_greedy_target_generation(true);
434 441
435 // Schedule a load of the toolchain build file. 442 // Schedule a load of the toolchain build file.
436 Err err; 443 Err err;
437 ScheduleInvocationLocked(LocationRange(), default_toolchain_, 444 ScheduleInvocationLocked(LocationRange(), default_toolchain_,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 void ToolchainManager::BackgroundLoadBuildConfig(Info* info, 486 void ToolchainManager::BackgroundLoadBuildConfig(Info* info,
480 bool is_default, 487 bool is_default,
481 const ParseNode* root) { 488 const ParseNode* root) {
482 // Danger: No early returns without decrementing the work count. 489 // Danger: No early returns without decrementing the work count.
483 if (root && !g_scheduler->is_failed()) { 490 if (root && !g_scheduler->is_failed()) {
484 // Nobody should be accessing settings at this point other than us since we 491 // Nobody should be accessing settings at this point other than us since we
485 // haven't marked it loaded, so we can do it outside the lock. 492 // haven't marked it loaded, so we can do it outside the lock.
486 Scope* base_config = info->settings.base_config(); 493 Scope* base_config = info->settings.base_config();
487 base_config->set_source_dir(SourceDir("//")); 494 base_config->set_source_dir(SourceDir("//"));
488 495
489 info->settings.build_settings()->build_args().SetupRootScope(base_config, 496 info->settings.build_settings()->build_args().SetupRootScope(
490 info->settings.toolchain()->args()); 497 base_config, info->toolchain->args());
491 498
492 base_config->SetProcessingBuildConfig(); 499 base_config->SetProcessingBuildConfig();
493 if (is_default) 500 if (is_default)
494 base_config->SetProcessingDefaultBuildConfig(); 501 base_config->SetProcessingDefaultBuildConfig();
495 502
496 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, 503 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE,
497 info->settings.build_settings()->build_config_file().value()); 504 info->settings.build_settings()->build_config_file().value());
498 trace.SetToolchain(info->settings.toolchain()->label()); 505 trace.SetToolchain(info->settings.toolchain_label());
499 506
500 const BlockNode* root_block = root->AsBlock(); 507 const BlockNode* root_block = root->AsBlock();
501 Err err; 508 Err err;
502 root_block->ExecuteBlockInScope(base_config, &err); 509 root_block->ExecuteBlockInScope(base_config, &err);
503 510
504 trace.Done(); 511 trace.Done();
505 512
506 base_config->ClearProcessingBuildConfig(); 513 base_config->ClearProcessingBuildConfig();
507 if (is_default) 514 if (is_default)
508 base_config->ClearProcessingDefaultBuildConfig(); 515 base_config->ClearProcessingDefaultBuildConfig();
(...skipping 24 matching lines...) Expand all
533 } 540 }
534 g_scheduler->DecrementWorkCount(); 541 g_scheduler->DecrementWorkCount();
535 } 542 }
536 543
537 void ToolchainManager::BackgroundInvoke(const Info* info, 544 void ToolchainManager::BackgroundInvoke(const Info* info,
538 const SourceFile& file_name, 545 const SourceFile& file_name,
539 const ParseNode* root) { 546 const ParseNode* root) {
540 if (root && !g_scheduler->is_failed()) { 547 if (root && !g_scheduler->is_failed()) {
541 if (g_scheduler->verbose_logging()) { 548 if (g_scheduler->verbose_logging()) {
542 g_scheduler->Log("Running", file_name.value() + " with toolchain " + 549 g_scheduler->Log("Running", file_name.value() + " with toolchain " +
543 info->toolchain.label().GetUserVisibleName(false)); 550 info->toolchain->label().GetUserVisibleName(false));
544 } 551 }
545 552
546 Scope our_scope(info->settings.base_config()); 553 Scope our_scope(info->settings.base_config());
547 ScopePerFileProvider per_file_provider(&our_scope); 554 ScopePerFileProvider per_file_provider(&our_scope);
548 our_scope.set_source_dir(file_name.GetDir()); 555 our_scope.set_source_dir(file_name.GetDir());
549 556
550 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, file_name.value()); 557 ScopedTrace trace(TraceItem::TRACE_FILE_EXECUTE, file_name.value());
551 trace.SetToolchain(info->settings.toolchain()->label()); 558 trace.SetToolchain(info->settings.toolchain_label());
552 559
553 Err err; 560 Err err;
554 root->Execute(&our_scope, &err); 561 root->Execute(&our_scope, &err);
555 if (err.has_error()) 562 if (err.has_error())
556 g_scheduler->FailWithError(err); 563 g_scheduler->FailWithError(err);
557 564
558 trace.Done(); 565 trace.Done();
559 566
560 { 567 {
561 // Check to see if any build config invocations depend on this file and 568 // Check to see if any build config invocations depend on this file and
(...skipping 15 matching lines...) Expand all
577 } 584 }
578 } 585 }
579 } 586 }
580 587
581 g_scheduler->DecrementWorkCount(); 588 g_scheduler->DecrementWorkCount();
582 } 589 }
583 590
584 base::Lock& ToolchainManager::GetLock() const { 591 base::Lock& ToolchainManager::GetLock() const {
585 return build_settings_->item_tree().lock(); 592 return build_settings_->item_tree().lock();
586 } 593 }
OLDNEW
« no previous file with comments | « tools/gn/toolchain.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698