1d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// found in the LICENSE file. 4d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 5d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/input_file_manager.h" 6d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 7d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/bind.h" 8d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/stl_util.h" 9d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/filesystem_utils.h" 10d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/parser.h" 11d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/scheduler.h" 12d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/scope_per_file_provider.h" 13d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/tokenizer.h" 1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/trace.h" 15d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 16d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochnamespace { 17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 18d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid InvokeFileLoadCallback(const InputFileManager::FileLoadCallback& cb, 19d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const ParseNode* node) { 20d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch cb.Run(node); 21d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 22d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 23d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} // namespace 24d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 25d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochInputFileManager::InputFileData::InputFileData(const SourceFile& file_name) 26d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch : file(file_name), 27d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch loaded(false), 28d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch sync_invocation(false) { 29d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 30d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 31d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochInputFileManager::InputFileData::~InputFileData() { 32d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 33d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 34d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochInputFileManager::InputFileManager() { 35d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 36d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 37d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochInputFileManager::~InputFileManager() { 38d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Should be single-threaded by now. 39d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch STLDeleteContainerPairSecondPointers(input_files_.begin(), 40d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch input_files_.end()); 41d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 42d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 43d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool InputFileManager::AsyncLoadFile(const LocationRange& origin, 44d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const BuildSettings* build_settings, 45d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const SourceFile& file_name, 46d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const FileLoadCallback& callback, 47d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch Err* err) { 48d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Try not to schedule callbacks while holding the lock. All cases that don't 49d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // want to schedule should return early. Otherwise, this will be scheduled 50d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // after we leave the lock. 51d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::Closure schedule_this; 52d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch { 53d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::AutoLock lock(lock_); 54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFileMap::const_iterator found = input_files_.find(file_name); 56d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (found == input_files_.end()) { 57d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // New file, schedule load. 58d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFileData* data = new InputFileData(file_name); 59d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->scheduled_callbacks.push_back(callback); 60d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch input_files_[file_name] = data; 61d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 62d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch schedule_this = base::Bind(&InputFileManager::BackgroundLoadFile, 63d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch this, 64d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch origin, 65d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch build_settings, 66d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch file_name, 67d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch &data->file); 68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } else { 69d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFileData* data = found->second; 70d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 71d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Prevent mixing async and sync loads. See SyncLoadFile for discussion. 72d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (data->sync_invocation) { 73d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch g_scheduler->FailWithError(Err( 74d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch origin, "Load type mismatch.", 75d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "The file \"" + file_name.value() + "\" was previously loaded\n" 76d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "synchronously (via an import) and now you're trying to load it " 77d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "asynchronously\n(via a deps rule). This is a class 2 misdemeanor: " 78d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "a single input file must\nbe loaded the same way each time to " 79d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "avoid blowing my tiny, tiny mind.")); 80d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return false; 81d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 82d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 83d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (data->loaded) { 84d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Can just directly issue the callback on the background thread. 85d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch schedule_this = base::Bind(&InvokeFileLoadCallback, callback, 86d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->parsed_root.get()); 87d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } else { 88d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Load is pending on this file, schedule the invoke. 89d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->scheduled_callbacks.push_back(callback); 90d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return true; 91d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 92d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 93d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 94d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch g_scheduler->pool()->PostWorkerTaskWithShutdownBehavior( 95d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch FROM_HERE, schedule_this, 96d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::SequencedWorkerPool::BLOCK_SHUTDOWN); 97d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return true; 98d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 99d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 100d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochconst ParseNode* InputFileManager::SyncLoadFile( 101d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const LocationRange& origin, 102d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const BuildSettings* build_settings, 103d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const SourceFile& file_name, 104d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch Err* err) { 105d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::AutoLock lock(lock_); 106d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 107d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFileData* data = NULL; 108d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFileMap::iterator found = input_files_.find(file_name); 109d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (found == input_files_.end()) { 110d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Haven't seen this file yet, start loading right now. 111d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data = new InputFileData(file_name); 112d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->sync_invocation = true; 113d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch input_files_[file_name] = data; 114d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::AutoUnlock unlock(lock_); 116d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!LoadFile(origin, build_settings, file_name, &data->file, err)) 117d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return NULL; 118d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } else { 119d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // This file has either been loaded or is pending loading. 120d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data = found->second; 121d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 122d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!data->sync_invocation) { 123d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Don't allow mixing of sync and async loads. If an async load is 124d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // scheduled and then a bunch of threads need to load it synchronously 125d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // and block on it loading, it could deadlock or at least cause a lot 126d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // of wasted CPU while those threads wait for the load to complete (which 127d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // may be far back in the input queue). 128d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // 129d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // We could work around this by promoting the load to a sync load. This 130d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // requires a bunch of extra code to either check flags and likely do 131d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // extra locking (bad) or to just do both types of load on the file and 132d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // deal with the race condition. 133d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // 134d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // I have no practical way to test this, and generally we should have 135d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // all include files processed synchronously and all build files 136d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // processed asynchronously, so it doesn't happen in practice. 137d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch *err = Err( 138d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch origin, "Load type mismatch.", 139d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "The file \"" + file_name.value() + "\" was previously loaded\n" 140d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "asynchronously (via a deps rule) and now you're trying to load it " 141d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "synchronously.\nThis is a class 2 misdemeanor: a single input file " 142d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "must be loaded the same way\neach time to avoid blowing my tiny, " 143d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "tiny mind."); 144d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return NULL; 145d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 146d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 147d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!data->loaded) { 148d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Wait for the already-pending sync load to complete. 149d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!data->completion_event) 150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->completion_event.reset(new base::WaitableEvent(false, false)); 151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch { 152d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::AutoUnlock unlock(lock_); 153d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->completion_event->Wait(); 154d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If there were multiple waiters on the same event, we now need to wake 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // up the next one. 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) data->completion_event->Signal(); 158d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 159d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 160d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 161d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // The other load could have failed. In this case that error will be printed 162d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // to the console, but we need to return something here, so make up a 163d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // dummy error. 164d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!data->parsed_root) 165d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch *err = Err(origin, "File parse failed"); 166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return data->parsed_root.get(); 167d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 168d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 169d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochint InputFileManager::GetInputFileCount() const { 170d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::AutoLock lock(lock_); 1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return static_cast<int>(input_files_.size()); 172d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 1743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid InputFileManager::GetAllPhysicalInputFileNames( 1753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch std::vector<base::FilePath>* result) const { 176d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::AutoLock lock(lock_); 177d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch result->reserve(input_files_.size()); 178d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch for (InputFileMap::const_iterator i = input_files_.begin(); 179d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch i != input_files_.end(); ++i) { 1803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (!i->second->file.physical_name().empty()) 1813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch result->push_back(i->second->file.physical_name()); 182d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 183d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 184d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 185d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid InputFileManager::BackgroundLoadFile(const LocationRange& origin, 186d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const BuildSettings* build_settings, 187d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const SourceFile& name, 188d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFile* file) { 189d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch Err err; 190d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!LoadFile(origin, build_settings, name, file, &err)) 191d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch g_scheduler->FailWithError(err); 192d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 193d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 194d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool InputFileManager::LoadFile(const LocationRange& origin, 195d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const BuildSettings* build_settings, 196d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch const SourceFile& name, 197d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFile* file, 198d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch Err* err) { 199d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Do all of this stuff outside the lock. We should not give out file 200d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // pointers until the read is complete. 201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (g_scheduler->verbose_logging()) { 202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) std::string logmsg = name.value(); 203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (origin.begin().file()) 204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) logmsg += " (referenced from " + origin.begin().Describe(false) + ")"; 205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) g_scheduler->Log("Loading", logmsg); 206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 207d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 208d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Read. 209d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::FilePath primary_path = build_settings->GetFullPath(name); 21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ScopedTrace load_trace(TraceItem::TRACE_FILE_LOAD, name.value()); 211d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!file->Load(primary_path)) { 212d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!build_settings->secondary_source_path().empty()) { 213d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Fall back to secondary source tree. 214d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::FilePath secondary_path = 215d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch build_settings->GetFullPathSecondary(name); 216d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (!file->Load(secondary_path)) { 217d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch *err = Err(origin, "Can't load input file.", 218d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "Unable to load either \n" + 219d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch FilePathToUTF8(primary_path) + " or \n" + 220d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch FilePathToUTF8(secondary_path)); 221d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return false; 222d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 223d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } else { 224d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch *err = Err(origin, 225d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch "Unable to load \"" + FilePathToUTF8(primary_path) + "\"."); 226d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return false; 227d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 228d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 22968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) load_trace.Done(); 23068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 23168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ScopedTrace exec_trace(TraceItem::TRACE_FILE_PARSE, name.value()); 232d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 233d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Tokenize. 234d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch std::vector<Token> tokens = Tokenizer::Tokenize(file, err); 235d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (err->has_error()) 236d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return false; 237d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 238d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Parse. 239d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch scoped_ptr<ParseNode> root = Parser::Parse(tokens, err); 240d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch if (err->has_error()) 241d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return false; 242d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch ParseNode* unowned_root = root.get(); 243d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 24468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) exec_trace.Done(); 24568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 246d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch std::vector<FileLoadCallback> callbacks; 247d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch { 248d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch base::AutoLock lock(lock_); 249d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch DCHECK(input_files_.find(name) != input_files_.end()); 250d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 251d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch InputFileData* data = input_files_[name]; 252d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->loaded = true; 253d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->tokens.swap(tokens); 254d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch data->parsed_root = root.Pass(); 255d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Unblock waiters on this event. 257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // 258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // It's somewhat bad to signal this inside the lock. When it's used, it's 259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // lazily created inside the lock. So we need to do the check and signal 260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // inside the lock to avoid race conditions on the lazy creation of the 261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // lock. 262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // 263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // We could avoid this by creating the lock every time, but the lock is 264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // very seldom used and will generally be NULL, so my current theory is that 265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // several signals of a completion event inside a lock is better than 266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // creating about 1000 extra locks (one for each file). 267d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (data->completion_event) 268d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) data->completion_event->Signal(); 269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 270d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch callbacks.swap(data->scheduled_callbacks); 271d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 272d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 273d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // Run pending invocations. Theoretically we could schedule each of these 274d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // separately to get some parallelism. But normally there will only be one 275d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // item in the list, so that's extra overhead and complexity for no gain. 276d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch for (size_t i = 0; i < callbacks.size(); i++) 277d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch callbacks[i].Run(unowned_root); 278d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return true; 279d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch} 280