summaryrefslogtreecommitdiff
path: root/gn/tools/gn/input_file_manager.h
blob: 20874d1d9d2d92f26690dffcbe1bfde2aa7bdd8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// 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_