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

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

Issue 1957483004: GN: Don't import a file more than once. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: typo Created 4 years, 7 months 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
« no previous file with comments | « tools/gn/import_manager.h ('k') | tools/gn/scheduler.cc » ('j') | 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/import_manager.h" 5 #include "tools/gn/import_manager.h"
6 6
7 #include "tools/gn/err.h"
7 #include "tools/gn/parse_tree.h" 8 #include "tools/gn/parse_tree.h"
8 #include "tools/gn/scheduler.h" 9 #include "tools/gn/scheduler.h"
9 #include "tools/gn/scope_per_file_provider.h" 10 #include "tools/gn/scope_per_file_provider.h"
10 11
11 namespace { 12 namespace {
12 13
13 // Returns a newly-allocated scope on success, null on failure. 14 // Returns a newly-allocated scope on success, null on failure.
14 std::unique_ptr<Scope> UncachedImport(const Settings* settings, 15 std::unique_ptr<Scope> UncachedImport(const Settings* settings,
15 const SourceFile& file, 16 const SourceFile& file,
16 const ParseNode* node_for_err, 17 const ParseNode* node_for_err,
(...skipping 17 matching lines...) Expand all
34 // If there was an error, append the caller location so the error message 35 // If there was an error, append the caller location so the error message
35 // displays a why the file was imported (esp. useful for failed asserts). 36 // displays a why the file was imported (esp. useful for failed asserts).
36 err->AppendSubErr(Err(node_for_err, "whence it was imported.")); 37 err->AppendSubErr(Err(node_for_err, "whence it was imported."));
37 return nullptr; 38 return nullptr;
38 } 39 }
39 scope->ClearProcessingImport(); 40 scope->ClearProcessingImport();
40 41
41 return scope; 42 return scope;
42 } 43 }
43 44
44 } // namesapce 45 } // namespace
46
47 struct ImportManager::ImportInfo {
48 ImportInfo() {}
49 ~ImportInfo() {}
50
51 // This lock protects the unique_ptr. Once the scope is computed,
52 // it is const and can be accessed read-only outside of the lock.
53 base::Lock load_lock;
54
55 std::unique_ptr<const Scope> scope;
56
57 // The result of loading the import. If the load failed, the scope will be
58 // null but this will be set to error. In this case the thread should not
59 // attempt to load the file, even if the scope is null.
60 Err load_result;
61 };
45 62
46 ImportManager::ImportManager() { 63 ImportManager::ImportManager() {
47 } 64 }
48 65
49 ImportManager::~ImportManager() { 66 ImportManager::~ImportManager() {
50 } 67 }
51 68
52 bool ImportManager::DoImport(const SourceFile& file, 69 bool ImportManager::DoImport(const SourceFile& file,
53 const ParseNode* node_for_err, 70 const ParseNode* node_for_err,
54 Scope* scope, 71 Scope* scope,
55 Err* err) { 72 Err* err) {
56 // See if we have a cached import, but be careful to actually do the scope 73 // See if we have a cached import, but be careful to actually do the scope
57 // copying outside of the lock. 74 // copying outside of the lock.
58 const Scope* imported_scope = nullptr; 75 ImportInfo* import_info = nullptr;
59 { 76 {
60 base::AutoLock lock(lock_); 77 base::AutoLock lock(imports_lock_);
61 ImportMap::const_iterator found = imports_.find(file); 78 std::unique_ptr<ImportInfo>& info_ptr = imports_[file];
62 if (found != imports_.end()) 79 if (!info_ptr)
63 imported_scope = found->second.get(); 80 info_ptr.reset(new ImportInfo);
81
82 // Promote the ImportInfo to outside of the imports lock.
83 import_info = info_ptr.get();
64 } 84 }
65 85
66 if (!imported_scope) { 86 // Now use the per-import-file lock to block this thread if another thread
67 // Do a new import of the file. 87 // is already processing the import.
68 std::unique_ptr<Scope> new_imported_scope = 88 const Scope* import_scope = nullptr;
69 UncachedImport(scope->settings(), file, node_for_err, err); 89 {
70 if (!new_imported_scope) 90 base::AutoLock lock(import_info->load_lock);
71 return false;
72 91
73 // We loaded the file outside the lock. This means that there could be a 92 if (!import_info->scope) {
74 // race and the file was already loaded on a background thread. Recover 93 // Only load if the import hasn't already failed.
75 // from this and use the existing one if that happens. 94 if (!import_info->load_result.has_error()) {
76 { 95 import_info->scope = UncachedImport(
77 base::AutoLock lock(lock_); 96 scope->settings(), file, node_for_err, &import_info->load_result);
78 ImportMap::const_iterator found = imports_.find(file); 97 }
79 if (found != imports_.end()) { 98 if (import_info->load_result.has_error()) {
80 imported_scope = found->second.get(); 99 *err = import_info->load_result;
81 } else { 100 return false;
82 imported_scope = new_imported_scope.get();
83 imports_[file] = std::move(new_imported_scope);
84 } 101 }
85 } 102 }
103
104 // Promote the now-read-only scope to outside the load lock.
105 import_scope = import_info->scope.get();
86 } 106 }
87 107
88 Scope::MergeOptions options; 108 Scope::MergeOptions options;
89 options.skip_private_vars = true; 109 options.skip_private_vars = true;
90 options.mark_dest_used = true; // Don't require all imported values be used. 110 options.mark_dest_used = true; // Don't require all imported values be used.
91 return imported_scope->NonRecursiveMergeTo(scope, options, node_for_err, 111 return import_scope->NonRecursiveMergeTo(scope, options, node_for_err,
92 "import", err); 112 "import", err);
93 } 113 }
OLDNEW
« no previous file with comments | « tools/gn/import_manager.h ('k') | tools/gn/scheduler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698