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 3 // found in the LICENSE file. 4 5 #ifndef TOOLS_GN_INPUT_FILE_MANAGER_H_ 6 #define TOOLS_GN_INPUT_FILE_MANAGER_H_ 7 8 #include <functional> 9 #include <mutex> 10 #include <set> 11 #include <unordered_map> 12 #include <utility> 13 #include <vector> 14 15 #include "base/files/file_path.h" 16 #include "base/memory/ref_counted.h" 17 #include "gn/input_file.h" 18 #include "gn/parse_tree.h" 19 #include "gn/settings.h" 20 #include "gn/vector_utils.h" 21 #include "util/auto_reset_event.h" 22 23 class BuildSettings; 24 class Err; 25 class LocationRange; 26 class ParseNode; 27 class Token; 28 29 // Manages loading and parsing files from disk. This doesn't actually have 30 // any context for executing the results, so potentially multiple configs 31 // could use the same input file (saving parsing). 32 // 33 // This class is threadsafe. 34 // 35 // InputFile objects must never be deleted while the program is running since 36 // various state points into them. 37 class InputFileManager : public base::RefCountedThreadSafe<InputFileManager> { 38 public: 39 // Callback issued when a file is loaded. On auccess, the parse node will 40 // refer to the root block of the file. On failure, this will be NULL. 41 using FileLoadCallback = std::function<void(const ParseNode*)>; 42 43 // Callback to emulate SyncLoadFile in tests. 44 using SyncLoadFileCallback = 45 std::function<bool(const SourceFile& file_name, InputFile* file)>; 46 47 InputFileManager(); 48 49 // Loads the given file and executes the callback on the worker pool. 50 // 51 // There are two types of errors. For errors known synchronously, the error 52 // will be set, it will return false, and no work will be scheduled. 53 // 54 // For parse errors and such that happen in the future, the error will be 55 // logged to the scheduler and the callback will be invoked with a null 56 // ParseNode pointer. The given |origin| will be blamed for the invocation. 57 bool AsyncLoadFile(const LocationRange& origin, 58 const BuildSettings* build_settings, 59 const SourceFile& file_name, 60 const FileLoadCallback& callback, 61 Err* err); 62 63 // Loads and parses the given file synchronously, returning the root block 64 // corresponding to the parsed result. On error, return NULL and the given 65 // Err is set. 66 const ParseNode* SyncLoadFile(const LocationRange& origin, 67 const BuildSettings* build_settings, 68 const SourceFile& file_name, 69 Err* err); 70 71 // Creates an entry to manage the memory associated with keeping a parsed 72 // set of code in memory. 73 // 74 // The values pointed to by the parameters will be filled with pointers to 75 // the file, tokens, and parse node that this class created. The calling 76 // code is responsible for populating these values and maintaining 77 // threadsafety. This class' only job is to hold onto the memory and delete 78 // it when the program exits. 79 // 80 // This solves the problem that sometimes we need to execute something 81 // dynamic and save the result, but the values all have references to the 82 // nodes and file that created it. Either we need to reset the origin of 83 // the values and lose context for error reporting, or somehow keep the 84 // associated parse nodes, tokens, and file data in memory. This function 85 // allows the latter. 86 void AddDynamicInput(const SourceFile& name, 87 InputFile** file, 88 std::vector<Token>** tokens, 89 std::unique_ptr<ParseNode>** parse_root); 90 91 // Does not count dynamic input. 92 int GetInputFileCount() const; 93 94 // Add all physical input files to a VectorSetSorter instance. 95 // This allows fast merging and sorting with other file paths sets. 96 // 97 // This is more memory efficient than returning a vector of base::FilePath 98 // instance, especially with projects with a very large number of input files, 99 // but note that the VectorSetSorter only holds pointers to the 100 // items recorded in this InputFileManager instance, and it is up to the 101 // caller to ensure these will not change until the sorter is destroyed. 102 void AddAllPhysicalInputFileNamesToVectorSetSorter( 103 VectorSetSorter<base::FilePath>* sorter) const; 104 set_load_file_callback(SyncLoadFileCallback load_file_callback)105 void set_load_file_callback(SyncLoadFileCallback load_file_callback) { 106 load_file_callback_ = load_file_callback; 107 } 108 109 private: 110 friend class base::RefCountedThreadSafe<InputFileManager>; 111 112 struct InputFileData { 113 explicit InputFileData(const SourceFile& file_name); 114 ~InputFileData(); 115 116 // Don't touch this outside the lock until it's marked loaded. 117 InputFile file; 118 119 bool loaded; 120 121 bool sync_invocation; 122 123 // Lists all invocations that need to be executed when the file completes 124 // loading. 125 std::vector<FileLoadCallback> scheduled_callbacks; 126 127 // Event to signal when the load is complete (or fails). This is lazily 128 // created only when a thread is synchronously waiting for this load (which 129 // only happens for imports). 130 std::unique_ptr<AutoResetEvent> completion_event; 131 132 std::vector<Token> tokens; 133 134 // Null before the file is loaded or if loading failed. 135 std::unique_ptr<ParseNode> parsed_root; 136 Err parse_error; 137 }; 138 139 virtual ~InputFileManager(); 140 141 void BackgroundLoadFile(const LocationRange& origin, 142 const BuildSettings* build_settings, 143 const SourceFile& name, 144 InputFile* file); 145 146 // Loads the given file. On error, sets the Err and return false. 147 bool LoadFile(const LocationRange& origin, 148 const BuildSettings* build_settings, 149 const SourceFile& name, 150 InputFile* file, 151 Err* err); 152 153 mutable std::mutex lock_; 154 155 // Maps repo-relative filenames to the corresponding owned pointer. 156 using InputFileMap = 157 std::unordered_map<SourceFile, std::unique_ptr<InputFileData>>; 158 InputFileMap input_files_; 159 160 // Tracks all dynamic inputs. The data are holders for memory management 161 // purposes and should not be read or modified by this class. The values 162 // will be vended out to the code creating the dynamic input, who is in 163 // charge of the threadsafety requirements. 164 // 165 // See AddDynamicInput(). 166 std::vector<std::unique_ptr<InputFileData>> dynamic_inputs_; 167 168 // Used by unit tests to mock out SyncLoadFile(). 169 SyncLoadFileCallback load_file_callback_; 170 171 InputFileManager(const InputFileManager&) = delete; 172 InputFileManager& operator=(const InputFileManager&) = delete; 173 }; 174 175 #endif // TOOLS_GN_INPUT_FILE_MANAGER_H_ 176