[Mesa-dev] [PATCH 1/2] gallivm: Allow drivers and state trackers to initialize gallivm LLVM targets
Tom Stellard
thomas.stellard at amd.com
Thu Sep 24 09:31:59 PDT 2015
Drivers and state trackers that use LLVM for generating code, must
register the targets they use with LLVM's global TargetRegistry.
The TargetRegistry is not thread-safe, so all targets must be added
to the registry before it can be queried for target information.
When drivers and state trackers initialize their own targets, they need
a way to force gallivm to initialize its targets at the same time.
Otherwise, there can be a race condition in some multi-threaded
applications (e.g. glx-multihreaded-shader-compile in piglit),
when one thread creates a context for a driver that uses LLVM (e.g.
radeonsi) and another thread creates a gallivm context (glxContextCreate
does this).
The race happens when the driver thread initializes its LLVM targets and
then starts using the registry before the gallivm thread has a chance to
register its targets.
This patch allows users to force gallivm to register its targets by
adding two new functions: gallivm_llvm_init_begin() which locks a mutex
guarding the TargetRegistry and initializes the gallivm targets, and
gallivm_llvm_init_end() which unlocks the mutex.
Drivers and state trackers should use this sequence to correctly
initialize the LLVM targets they use:
gallivm_init_llvm_begin();
LLVMInitializeFooTarget();
gallivm_init_llvm_end();
CC: "10.6 11.0" <mesa-stable at lists.freedesktop.org>
---
src/gallium/auxiliary/gallivm/lp_bld_misc.cpp | 68 ++++++++++++++++++++++++---
src/gallium/auxiliary/gallivm/lp_bld_misc.h | 5 ++
2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
index 5e25819..8bf833e 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
+++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
@@ -81,6 +81,7 @@
# pragma pop_macro("DEBUG")
#endif
+#include "os/os_thread.h"
#include "pipe/p_config.h"
#include "util/u_debug.h"
#include "util/u_cpu_detect.h"
@@ -101,6 +102,64 @@ public:
static LLVMEnsureMultithreaded lLVMEnsureMultithreaded;
+struct LLVMRegistryLock {
+private:
+ pipe_mutex mutex;
+
+public:
+ LLVMRegistryLock()
+ {
+ pipe_mutex_init(mutex);
+ }
+
+ void lock()
+ {
+ pipe_mutex_lock(mutex);
+ }
+
+ void unlock()
+ {
+ pipe_mutex_unlock(mutex);
+ }
+};
+
+static LLVMRegistryLock gallivm_llvm_registry_lock;
+
+}
+
+/**
+ * The llvm target registry is not thread-safe, so drivers and state-trackers
+ * that want to initialize targets should use the gallivm_init_llvm_begin() and
+ * gallivm_init_llvm_end() functions to safely initialize targets. For example:
+ *
+ * gallivm_init_llvm_begin();
+ * LLVMInitializeFooTarget();
+ * gallivm_init_llvm_end();
+ *
+ * LLVM targets should be initialized before the driver tries to access the
+ * registry.
+ */
+extern "C" void
+gallivm_init_llvm_begin(void)
+{
+ static int init = 0;
+ gallivm_llvm_registry_lock.lock();
+ if (!init) {
+ // If we have a native target, initialize it to ensure it is linked in and
+ // usable by the JIT.
+ llvm::InitializeNativeTarget();
+
+ llvm::InitializeNativeTargetAsmPrinter();
+
+ llvm::InitializeNativeTargetDisassembler();
+ init = 1;
+ }
+}
+
+extern "C" void
+gallivm_init_llvm_end(void)
+{
+ gallivm_llvm_registry_lock.unlock();
}
extern "C" void
@@ -115,13 +174,8 @@ lp_set_target_options(void)
llvm::DisablePrettyStackTrace = true;
#endif
- // If we have a native target, initialize it to ensure it is linked in and
- // usable by the JIT.
- llvm::InitializeNativeTarget();
-
- llvm::InitializeNativeTargetAsmPrinter();
-
- llvm::InitializeNativeTargetDisassembler();
+ gallivm_init_llvm_begin();
+ gallivm_init_llvm_end();
}
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.h b/src/gallium/auxiliary/gallivm/lp_bld_misc.h
index 36923aa..f87bb24 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_misc.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.h
@@ -41,6 +41,11 @@ extern "C" {
struct lp_generated_code;
+extern void
+gallivm_init_llvm_begin(void);
+
+extern void
+gallivm_init_llvm_end(void);
extern void
lp_set_target_options(void);
--
2.0.4
More information about the mesa-dev
mailing list