[lld] r231153 - Implement our own future and use that for FileArchive::preload().
Rui Ueyama
ruiu at google.com
Tue Mar 3 14:19:46 PST 2015
Author: ruiu
Date: Tue Mar 3 16:19:46 2015
New Revision: 231153
URL: http://llvm.org/viewvc/llvm-project?rev=231153&view=rev
Log:
Implement our own future and use that for FileArchive::preload().
std::promise and std::future in old version of libstdc++ are buggy.
I think that's the reason why LLD tests were flaky on Ubuntu 13
buildbots until we disabled file preloading.
In this patch, I implemented very simple future and used that in
FileArchive. Compared to std::promise and std::future, it lacks
many features, but should serve our purpose.
http://reviews.llvm.org/D8025
Modified:
lld/trunk/include/lld/Core/Parallel.h
lld/trunk/lib/Core/Resolver.cpp
lld/trunk/lib/ReaderWriter/FileArchive.cpp
Modified: lld/trunk/include/lld/Core/Parallel.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Parallel.h?rev=231153&r1=231152&r2=231153&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Parallel.h (original)
+++ lld/trunk/include/lld/Core/Parallel.h Tue Mar 3 16:19:46 2015
@@ -68,6 +68,41 @@ public:
}
};
+/// \brief An implementation of future. std::future and std::promise in
+/// old libstdc++ have a threading bug; there is a small chance that a
+/// call of future::get throws an exception in the normal use case.
+/// We want to use our own future implementation until we drop support
+/// of old versions of libstdc++.
+/// https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01389.html
+template<typename T> class Future {
+public:
+ Future() : _hasValue(false) {}
+
+ void set(T &&val) {
+ assert(!_hasValue);
+ {
+ std::unique_lock<std::mutex> lock(_mutex);
+ _val = val;
+ _hasValue = true;
+ }
+ _cond.notify_all();
+ }
+
+ T &get() {
+ std::unique_lock<std::mutex> lock(_mutex);
+ if (_hasValue)
+ return _val;
+ _cond.wait(lock, [&] { return _hasValue; });
+ return _val;
+ }
+
+private:
+ T _val;
+ bool _hasValue;
+ std::mutex _mutex;
+ std::condition_variable _cond;
+};
+
/// \brief An abstract class that takes closures and runs them asynchronously.
class Executor {
public:
Modified: lld/trunk/lib/Core/Resolver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Resolver.cpp?rev=231153&r1=231152&r2=231153&view=diff
==============================================================================
--- lld/trunk/lib/Core/Resolver.cpp (original)
+++ lld/trunk/lib/Core/Resolver.cpp Tue Mar 3 16:19:46 2015
@@ -31,9 +31,12 @@ bool Resolver::handleFile(const File &fi
bool undefAdded = false;
for (const DefinedAtom *atom : file.defined())
doDefinedAtom(*atom);
- for (const UndefinedAtom *atom : file.undefined())
- if (doUndefinedAtom(*atom))
+ for (const UndefinedAtom *atom : file.undefined()) {
+ if (doUndefinedAtom(*atom)) {
undefAdded = true;
+ maybePreloadArchiveMember(atom->name());
+ }
+ }
for (const SharedLibraryAtom *atom : file.sharedLibrary())
doSharedLibraryAtom(*atom);
for (const AbsoluteAtom *atom : file.absolute())
@@ -230,6 +233,17 @@ void Resolver::addAtoms(const std::vecto
doDefinedAtom(*newAtom);
}
+// Instantiate an archive file member if there's a file containing a
+// defined symbol for a given symbol name. Instantiation is done in a
+// different worker thread and has no visible side effect.
+void Resolver::maybePreloadArchiveMember(StringRef sym) {
+ auto it = _archiveMap.find(sym);
+ if (it == _archiveMap.end())
+ return;
+ ArchiveLibraryFile *archive = it->second;
+ archive->preload(_ctx.getTaskGroup(), sym);
+}
+
// Returns true if at least one of N previous files has created an
// undefined symbol.
bool Resolver::undefinesAdded(int begin, int end) {
Modified: lld/trunk/lib/ReaderWriter/FileArchive.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/FileArchive.cpp?rev=231153&r1=231152&r2=231153&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/FileArchive.cpp (original)
+++ lld/trunk/lib/ReaderWriter/FileArchive.cpp Tue Mar 3 16:19:46 2015
@@ -10,6 +10,7 @@
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Parallel.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
@@ -17,7 +18,6 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <future>
#include <memory>
#include <mutex>
#include <set>
@@ -63,8 +63,9 @@ public:
std::lock_guard<std::mutex> lock(_mutex);
auto it = _preloaded.find(memberStart);
if (it != _preloaded.end()) {
- std::future<const File *> &future = it->second;
- return future.get();
+ std::unique_ptr<Future<const File *>> &p = it->second;
+ Future<const File *> *future = p.get();
+ return future->get();
}
}
@@ -93,17 +94,13 @@ public:
return;
// Instantiate the member
- auto *promise = new std::promise<const File *>;
- _preloaded[memberStart] = promise->get_future();
- _promises.push_back(std::unique_ptr<std::promise<const File *>>(promise));
+ auto *future = new Future<const File *>();
+ _preloaded[memberStart] = std::unique_ptr<Future<const File *>>(future);
group.spawn([=] {
std::unique_ptr<File> result;
- if (instantiateMember(ci, result)) {
- promise->set_value(nullptr);
- return;
- }
- promise->set_value(result.release());
+ std::error_code ec = instantiateMember(ci, result);
+ future->set(ec ? nullptr : result.release());
});
}
@@ -269,8 +266,7 @@ private:
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
bool _logLoading;
mutable std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
- mutable std::map<const char *, std::future<const File *>> _preloaded;
- mutable std::vector<std::unique_ptr<std::promise<const File *>>> _promises;
+ mutable std::map<const char *, std::unique_ptr<Future<const File *>>> _preloaded;
mutable std::mutex _mutex;
};
More information about the llvm-commits
mailing list