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