|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef TOOLS_GN_INPUT_FILE_MANAGER_H_ | 
|  | #define TOOLS_GN_INPUT_FILE_MANAGER_H_ | 
|  |  | 
|  | #include <mutex> | 
|  | #include <set> | 
|  | #include <unordered_map> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/callback.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "tools/gn/build_settings.h" | 
|  | #include "tools/gn/input_file.h" | 
|  | #include "tools/gn/parse_tree.h" | 
|  | #include "tools/gn/settings.h" | 
|  | #include "util/auto_reset_event.h" | 
|  |  | 
|  | class Err; | 
|  | class LocationRange; | 
|  | class ParseNode; | 
|  | class Token; | 
|  |  | 
|  | // Manages loading and parsing files from disk. This doesn't actually have | 
|  | // any context for executing the results, so potentially multiple configs | 
|  | // could use the same input file (saving parsing). | 
|  | // | 
|  | // This class is threadsafe. | 
|  | // | 
|  | // InputFile objects must never be deleted while the program is running since | 
|  | // various state points into them. | 
|  | class InputFileManager : public base::RefCountedThreadSafe<InputFileManager> { | 
|  | public: | 
|  | // Callback issued when a file is laoded. On auccess, the parse node will | 
|  | // refer to the root block of the file. On failure, this will be NULL. | 
|  | typedef base::Callback<void(const ParseNode*)> FileLoadCallback; | 
|  |  | 
|  | InputFileManager(); | 
|  |  | 
|  | // Loads the given file and executes the callback on the worker pool. | 
|  | // | 
|  | // There are two types of errors. For errors known synchronously, the error | 
|  | // will be set, it will return false, and no work will be scheduled. | 
|  | // | 
|  | // For parse errors and such that happen in the future, the error will be | 
|  | // logged to the scheduler and the callback will be invoked with a null | 
|  | // ParseNode pointer. The given |origin| will be blamed for the invocation. | 
|  | bool AsyncLoadFile(const LocationRange& origin, | 
|  | const BuildSettings* build_settings, | 
|  | const SourceFile& file_name, | 
|  | const FileLoadCallback& callback, | 
|  | Err* err); | 
|  |  | 
|  | // Loads and parses the given file synchronously, returning the root block | 
|  | // corresponding to the parsed result. On error, return NULL and the given | 
|  | // Err is set. | 
|  | const ParseNode* SyncLoadFile(const LocationRange& origin, | 
|  | const BuildSettings* build_settings, | 
|  | const SourceFile& file_name, | 
|  | Err* err); | 
|  |  | 
|  | // Creates an entry to manage the memory associated with keeping a parsed | 
|  | // set of code in memory. | 
|  | // | 
|  | // The values pointed to by the parameters will be filled with pointers to | 
|  | // the file, tokens, and parse node that this class created. The calling | 
|  | // code is responsible for populating these values and maintaining | 
|  | // threadsafety. This class' only job is to hold onto the memory and delete | 
|  | // it when the program exits. | 
|  | // | 
|  | // This solves the problem that sometimes we need to execute something | 
|  | // dynamic and save the result, but the values all have references to the | 
|  | // nodes and file that created it. Either we need to reset the origin of | 
|  | // the values and lose context for error reporting, or somehow keep the | 
|  | // associated parse nodes, tokens, and file data in memory. This function | 
|  | // allows the latter. | 
|  | void AddDynamicInput(const SourceFile& name, | 
|  | InputFile** file, | 
|  | std::vector<Token>** tokens, | 
|  | std::unique_ptr<ParseNode>** parse_root); | 
|  |  | 
|  | // Does not count dynamic input. | 
|  | int GetInputFileCount() const; | 
|  |  | 
|  | // Fills the vector with all input files. | 
|  | void GetAllPhysicalInputFileNames(std::vector<base::FilePath>* result) const; | 
|  |  | 
|  | private: | 
|  | friend class base::RefCountedThreadSafe<InputFileManager>; | 
|  |  | 
|  | struct InputFileData { | 
|  | explicit InputFileData(const SourceFile& file_name); | 
|  | ~InputFileData(); | 
|  |  | 
|  | // Don't touch this outside the lock until it's marked loaded. | 
|  | InputFile file; | 
|  |  | 
|  | bool loaded; | 
|  |  | 
|  | bool sync_invocation; | 
|  |  | 
|  | // Lists all invocations that need to be executed when the file completes | 
|  | // loading. | 
|  | std::vector<FileLoadCallback> scheduled_callbacks; | 
|  |  | 
|  | // Event to signal when the load is complete (or fails). This is lazily | 
|  | // created only when a thread is synchronously waiting for this load (which | 
|  | // only happens for imports). | 
|  | std::unique_ptr<AutoResetEvent> completion_event; | 
|  |  | 
|  | std::vector<Token> tokens; | 
|  |  | 
|  | // Null before the file is loaded or if loading failed. | 
|  | std::unique_ptr<ParseNode> parsed_root; | 
|  | Err parse_error; | 
|  | }; | 
|  |  | 
|  | virtual ~InputFileManager(); | 
|  |  | 
|  | void BackgroundLoadFile(const LocationRange& origin, | 
|  | const BuildSettings* build_settings, | 
|  | const SourceFile& name, | 
|  | InputFile* file); | 
|  |  | 
|  | // Loads the given file. On error, sets the Err and return false. | 
|  | bool LoadFile(const LocationRange& origin, | 
|  | const BuildSettings* build_settings, | 
|  | const SourceFile& name, | 
|  | InputFile* file, | 
|  | Err* err); | 
|  |  | 
|  | mutable std::mutex lock_; | 
|  |  | 
|  | // Maps repo-relative filenames to the corresponding owned pointer. | 
|  | typedef std::unordered_map<SourceFile, std::unique_ptr<InputFileData>> | 
|  | InputFileMap; | 
|  | InputFileMap input_files_; | 
|  |  | 
|  | // Tracks all dynamic inputs. The data are holders for memory management | 
|  | // purposes and should not be read or modified by this class. The values | 
|  | // will be vended out to the code creating the dynamic input, who is in | 
|  | // charge of the threadsafety requirements. | 
|  | // | 
|  | // See AddDynamicInput(). | 
|  | std::vector<std::unique_ptr<InputFileData>> dynamic_inputs_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(InputFileManager); | 
|  | }; | 
|  |  | 
|  | #endif  // TOOLS_GN_INPUT_FILE_MANAGER_H_ |