Avoid implicitly destructing thread-locals
Chrome supports Linux versions which don't come with a glibc library
which supports __cxa_thread_atexit_impl. This function is required for
destroying C++11 thread_local objects at thread exit.
The 'jit' and 'unmaterializedVariables' thread-local objects used by
Reactor are only needed between Function<> creation and Routine
acquisition, so replace them by explicitly managed raw pointers.
Bug: chromium:1074222
Bug: b/153803432
Change-Id: I0a92bdd30940048b9ce0c208d3a2c1a952091283
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44428
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 82e5cdc..f09787c 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -65,7 +65,9 @@
namespace {
-thread_local std::unique_ptr<rr::JITBuilder> jit;
+// This has to be a raw pointer because glibc 2.17 doesn't support __cxa_thread_atexit_impl
+// for destructing objects at exit. See crbug.com/1074222
+thread_local rr::JITBuilder *jit = nullptr;
// Default configuration settings. Must be accessed under mutex lock.
std::mutex defaultConfigLock;
@@ -603,12 +605,19 @@
Nucleus::Nucleus()
{
ASSERT(jit == nullptr);
- jit.reset(new JITBuilder(Nucleus::getDefaultConfig()));
+ jit = new JITBuilder(Nucleus::getDefaultConfig());
+
+ ASSERT(Variable::unmaterializedVariables == nullptr);
+ Variable::unmaterializedVariables = new std::unordered_set<Variable *>();
}
Nucleus::~Nucleus()
{
- jit.reset();
+ delete Variable::unmaterializedVariables;
+ Variable::unmaterializedVariables = nullptr;
+
+ delete jit;
+ jit = nullptr;
}
void Nucleus::setDefaultConfig(const Config &cfg)
@@ -634,10 +643,10 @@
{
std::shared_ptr<Routine> routine;
- auto acquire = [&](std::unique_ptr<rr::JITBuilder> jitBuilder) {
+ auto acquire = [&](rr::JITBuilder *jitBuilder) {
// ::jit is thread-local, so when this is executed on a separate thread (see JIT_IN_SEPARATE_THREAD)
// it needs to be assigned the value from the parent thread.
- jit = std::move(jitBuilder);
+ jit = jitBuilder;
auto cfg = cfgEdit.apply(jit->config);
@@ -687,7 +696,8 @@
}
routine = jit->acquireRoutine(&jit->function, 1, cfg);
- jit.reset();
+ delete jit;
+ jit = nullptr;
};
#ifdef JIT_IN_SEPARATE_THREAD
@@ -4288,7 +4298,8 @@
funcs[Nucleus::CoroutineEntryAwait] = jit->coroutine.await;
funcs[Nucleus::CoroutineEntryDestroy] = jit->coroutine.destroy;
auto routine = jit->acquireRoutine(funcs, Nucleus::CoroutineEntryCount, cfg);
- jit.reset();
+ delete jit;
+ jit = nullptr;
return routine;
}
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index 0ffa010..dc8d960 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -64,7 +64,7 @@
}
// Set of variables that do not have a stack location yet.
-thread_local std::unordered_set<Variable *> Variable::unmaterializedVariables;
+thread_local std::unordered_set<Variable *> *Variable::unmaterializedVariables = nullptr;
Variable::Variable(Type *type, int arraySize)
: arraySize(arraySize)
@@ -73,28 +73,28 @@
#if REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION
materialize();
#else
- unmaterializedVariables.emplace(this);
+ unmaterializedVariables->emplace(this);
#endif
}
Variable::~Variable()
{
- unmaterializedVariables.erase(this);
+ unmaterializedVariables->erase(this);
}
void Variable::materializeAll()
{
- for(auto *var : unmaterializedVariables)
+ for(auto *var : *unmaterializedVariables)
{
var->materialize();
}
- unmaterializedVariables.clear();
+ unmaterializedVariables->clear();
}
void Variable::killUnmaterialized()
{
- unmaterializedVariables.clear();
+ unmaterializedVariables->clear();
}
// NOTE: Only 12 bits out of 16 of the |select| value are used.
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 33e8b44..8744189 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -133,7 +133,9 @@
static void materializeAll();
static void killUnmaterialized();
- static thread_local std::unordered_set<Variable *> unmaterializedVariables;
+ // This has to be a raw pointer because glibc 2.17 doesn't support __cxa_thread_atexit_impl
+ // for destructing objects at exit. See crbug.com/1074222
+ static thread_local std::unordered_set<Variable *> *unmaterializedVariables;
Type *const type;
mutable Value *rvalue = nullptr;
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 522b566..1a4a666 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -855,7 +855,7 @@
Nucleus::Nucleus()
{
- ::codegenMutex.lock(); // Reactor is currently not thread safe
+ ::codegenMutex.lock(); // SubzeroReactor is currently not thread safe
Ice::ClFlags &Flags = Ice::ClFlags::Flags;
Ice::ClFlags::getParsedClFlags(Flags);
@@ -901,10 +901,16 @@
::context = new Ice::GlobalContext(&cout, &cout, &cerr, elfMemory);
::routine = elfMemory;
}
+
+ ASSERT(Variable::unmaterializedVariables == nullptr);
+ Variable::unmaterializedVariables = new std::unordered_set<Variable *>();
}
Nucleus::~Nucleus()
{
+ delete Variable::unmaterializedVariables;
+ Variable::unmaterializedVariables = nullptr;
+
delete ::routine;
::routine = nullptr;