Index: tools/gn/input_file_manager.cc |
diff --git a/tools/gn/input_file_manager.cc b/tools/gn/input_file_manager.cc |
index 04578b60643b977c02304ba5a6f6e7fb0dac6284..097474ae061c0b99953accf3341e668cbba9bbe7 100644 |
--- a/tools/gn/input_file_manager.cc |
+++ b/tools/gn/input_file_manager.cc |
@@ -20,6 +20,61 @@ void InvokeFileLoadCallback(const InputFileManager::FileLoadCallback& cb, |
cb.Run(node); |
} |
+bool DoLoadFile(const LocationRange& origin, |
+ const BuildSettings* build_settings, |
+ const SourceFile& name, |
+ InputFile* file, |
+ std::vector<Token>* tokens, |
+ scoped_ptr<ParseNode>* root, |
+ Err* err) { |
+ // Do all of this stuff outside the lock. We should not give out file |
+ // pointers until the read is complete. |
+ if (g_scheduler->verbose_logging()) { |
+ std::string logmsg = name.value(); |
+ if (origin.begin().file()) |
+ logmsg += " (referenced from " + origin.begin().Describe(false) + ")"; |
+ g_scheduler->Log("Loading", logmsg); |
+ } |
+ |
+ // Read. |
+ base::FilePath primary_path = build_settings->GetFullPath(name); |
+ ScopedTrace load_trace(TraceItem::TRACE_FILE_LOAD, name.value()); |
+ if (!file->Load(primary_path)) { |
+ if (!build_settings->secondary_source_path().empty()) { |
+ // Fall back to secondary source tree. |
+ base::FilePath secondary_path = |
+ build_settings->GetFullPathSecondary(name); |
+ if (!file->Load(secondary_path)) { |
+ *err = Err(origin, "Can't load input file.", |
+ "Unable to load either \n" + |
+ FilePathToUTF8(primary_path) + " or \n" + |
+ FilePathToUTF8(secondary_path)); |
+ return false; |
+ } |
+ } else { |
+ *err = Err(origin, |
+ "Unable to load \"" + FilePathToUTF8(primary_path) + "\"."); |
+ return false; |
+ } |
+ } |
+ load_trace.Done(); |
+ |
+ ScopedTrace exec_trace(TraceItem::TRACE_FILE_PARSE, name.value()); |
+ |
+ // Tokenize. |
+ *tokens = Tokenizer::Tokenize(file, err); |
+ if (err->has_error()) |
+ return false; |
+ |
+ // Parse. |
+ *root = Parser::Parse(*tokens, err); |
+ if (err->has_error()) |
+ return false; |
+ |
+ exec_trace.Done(); |
+ return true; |
+} |
+ |
} // namespace |
InputFileManager::InputFileData::InputFileData(const SourceFile& file_name) |
@@ -211,53 +266,17 @@ bool InputFileManager::LoadFile(const LocationRange& origin, |
const SourceFile& name, |
InputFile* file, |
Err* err) { |
- // Do all of this stuff outside the lock. We should not give out file |
- // pointers until the read is complete. |
- if (g_scheduler->verbose_logging()) { |
- std::string logmsg = name.value(); |
- if (origin.begin().file()) |
- logmsg += " (referenced from " + origin.begin().Describe(false) + ")"; |
- g_scheduler->Log("Loading", logmsg); |
- } |
- |
- // Read. |
- base::FilePath primary_path = build_settings->GetFullPath(name); |
- ScopedTrace load_trace(TraceItem::TRACE_FILE_LOAD, name.value()); |
- if (!file->Load(primary_path)) { |
- if (!build_settings->secondary_source_path().empty()) { |
- // Fall back to secondary source tree. |
- base::FilePath secondary_path = |
- build_settings->GetFullPathSecondary(name); |
- if (!file->Load(secondary_path)) { |
- *err = Err(origin, "Can't load input file.", |
- "Unable to load either \n" + |
- FilePathToUTF8(primary_path) + " or \n" + |
- FilePathToUTF8(secondary_path)); |
- return false; |
- } |
- } else { |
- *err = Err(origin, |
- "Unable to load \"" + FilePathToUTF8(primary_path) + "\"."); |
- return false; |
- } |
- } |
- load_trace.Done(); |
- |
- ScopedTrace exec_trace(TraceItem::TRACE_FILE_PARSE, name.value()); |
- |
- // Tokenize. |
- std::vector<Token> tokens = Tokenizer::Tokenize(file, err); |
- if (err->has_error()) |
- return false; |
- |
- // Parse. |
- scoped_ptr<ParseNode> root = Parser::Parse(tokens, err); |
- if (err->has_error()) |
- return false; |
+ std::vector<Token> tokens; |
+ scoped_ptr<ParseNode> root; |
+ bool success = DoLoadFile(origin, build_settings, name, file, |
+ &tokens, &root, err); |
+ // Can't return early. We have to ensure that the completion event is |
+ // signaled in all cases bacause another thread could be blocked on this one. |
+ |
+ // Save this pointer for running the callbacks below, which happens after the |
+ // scoped ptr ownership is taken away inside the lock. |
ParseNode* unowned_root = root.get(); |
- exec_trace.Done(); |
- |
std::vector<FileLoadCallback> callbacks; |
{ |
base::AutoLock lock(lock_); |
@@ -265,8 +284,10 @@ bool InputFileManager::LoadFile(const LocationRange& origin, |
InputFileData* data = input_files_[name]; |
data->loaded = true; |
- data->tokens.swap(tokens); |
- data->parsed_root = root.Pass(); |
+ if (success) { |
+ data->tokens.swap(tokens); |
+ data->parsed_root = root.Pass(); |
+ } |
// Unblock waiters on this event. |
// |
@@ -288,7 +309,9 @@ bool InputFileManager::LoadFile(const LocationRange& origin, |
// Run pending invocations. Theoretically we could schedule each of these |
// separately to get some parallelism. But normally there will only be one |
// item in the list, so that's extra overhead and complexity for no gain. |
- for (size_t i = 0; i < callbacks.size(); i++) |
- callbacks[i].Run(unowned_root); |
- return true; |
+ if (success) { |
+ for (size_t i = 0; i < callbacks.size(); i++) |
+ callbacks[i].Run(unowned_root); |
+ } |
+ return success; |
} |