diff options
author | Douglas Gregor <dgregor@apple.com> | 2013-03-19 00:28:20 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2013-03-19 00:28:20 +0000 |
commit | 677e15ffee2ecc9c1c8f46fd77cab4b5afb59640 (patch) | |
tree | 7d1d3c5c95436eb48920bf6acd83de504828bec6 /include/clang/Serialization/ModuleManager.h | |
parent | aa624954c50a741528752b85d3a3bf11ef9771db (diff) |
<rdar://problem/13363214> Eliminate race condition between module rebuild and the global module index.
The global module index was querying the file manager for each of the
module files it knows about at load time, to prune out any out-of-date
information. The file manager would then cache the results of the
stat() falls used to find that module file.
Later, the same translation unit could end up trying to import one of the
module files that had previously been ignored by the module cache, but
after some other Clang instance rebuilt the module file to bring it
up-to-date. The stale stat() results in the file manager would
trigger a second rebuild of the already-up-to-date module, causing
failures down the line.
The global module index now lazily resolves its module file references
to actual AST reader module files only after the module file has been
loaded, eliminating the stat-caching race. Moreover, the AST reader
can communicate to its caller that a module file is missing (rather
than simply being out-of-date), allowing us to simplify the
module-loading logic and allowing the compiler to recover if a
dependent module file ends up getting deleted.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177367 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang/Serialization/ModuleManager.h')
-rw-r--r-- | include/clang/Serialization/ModuleManager.h | 73 |
1 files changed, 63 insertions, 10 deletions
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h index 60e3b40a7a..9b58b75ebb 100644 --- a/include/clang/Serialization/ModuleManager.h +++ b/include/clang/Serialization/ModuleManager.h @@ -16,17 +16,18 @@ #define LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H #include "clang/Basic/FileManager.h" +#include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/Module.h" #include "llvm/ADT/DenseMap.h" namespace clang { -class GlobalModuleIndex; +class ModuleMap; namespace serialization { /// \brief Manages the set of modules loaded by an AST reader. -class ModuleManager { +class ModuleManager : public ModuleFileNameResolver { /// \brief The chain of AST files. The first entry is the one named by the /// user, the last one is the one that doesn't depend on anything further. SmallVector<ModuleFile *, 2> Chain; @@ -143,6 +144,19 @@ public: /// \brief Number of modules loaded unsigned size() const { return Chain.size(); } + + /// \brief The result of attempting to add a new module. + enum AddModuleResult { + /// \brief The module file had already been loaded. + AlreadyLoaded, + /// \brief The module file was just loaded in response to this call. + NewlyLoaded, + /// \brief The module file is missing. + Missing, + /// \brief The module file is out-of-date. + OutOfDate + }; + /// \brief Attempts to create a new module and add it to the list of known /// modules. /// @@ -157,18 +171,30 @@ public: /// /// \param Generation The generation in which this module was loaded. /// + /// \param ExpectedSize The expected size of the module file, used for + /// validation. This will be zero if unknown. + /// + /// \param ExpectedModTime The expected modification time of the module + /// file, used for validation. This will be zero if unknown. + /// + /// \param Module A pointer to the module file if the module was successfully + /// loaded. + /// /// \param ErrorStr Will be set to a non-empty string if any errors occurred /// while trying to load the module. /// /// \return A pointer to the module that corresponds to this file name, - /// and a boolean indicating whether the module was newly added. - std::pair<ModuleFile *, bool> - addModule(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, - ModuleFile *ImportedBy, unsigned Generation, - std::string &ErrorStr); + /// and a value indicating whether the module was loaded. + AddModuleResult addModule(StringRef FileName, ModuleKind Type, + SourceLocation ImportLoc, + ModuleFile *ImportedBy, unsigned Generation, + off_t ExpectedSize, time_t ExpectedModTime, + ModuleFile *&Module, + std::string &ErrorStr); /// \brief Remove the given set of modules. - void removeModules(ModuleIterator first, ModuleIterator last); + void removeModules(ModuleIterator first, ModuleIterator last, + ModuleMap *modMap); /// \brief Add an in-memory buffer the list of known buffers void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer); @@ -200,7 +226,7 @@ public: /// Any module that is known to both the global module index and the module /// manager that is *not* in this set can be skipped. void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData, - llvm::SmallPtrSet<const FileEntry *, 4> *ModuleFilesHit = 0); + llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit = 0); /// \brief Visit each of the modules with a depth-first traversal. /// @@ -221,7 +247,34 @@ public: void visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder, void *UserData), void *UserData); - + + /// \brief Attempt to resolve the given module file name to a file entry. + /// + /// \param FileName The name of the module file. + /// + /// \param ExpectedSize The size that the module file is expected to have. + /// If the actual size differs, the resolver should return \c true. + /// + /// \param ExpectedModTime The modification time that the module file is + /// expected to have. If the actual modification time differs, the resolver + /// should return \c true. + /// + /// \param File Will be set to the file if there is one, or null + /// otherwise. + /// + /// \returns True if a file exists but does not meet the size/ + /// modification time criteria, false if the file is either available and + /// suitable, or is missing. + bool lookupModuleFile(StringRef FileName, + off_t ExpectedSize, + time_t ExpectedModTime, + const FileEntry *&File); + + virtual bool resolveModuleFileName(StringRef FileName, + off_t ExpectedSize, + time_t ExpectedModTime, + ModuleFile *&File); + /// \brief View the graphviz representation of the module graph. void viewGraph(); }; |