gallivm: Allow drivers and state trackers to initialize gallivm LLVM targets v2
authorTom Stellard <thomas.stellard@amd.com>
Thu, 24 Sep 2015 15:57:02 +0000 (15:57 +0000)
committerTom Stellard <thomas.stellard@amd.com>
Fri, 2 Oct 2015 23:41:26 +0000 (23:41 +0000)
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
calling the gallivm_init_llvm_targets() function.

v2:
  - Use call_once and remove mutexes and static initializations.
  - Replace gallivm_init_llvm_{begin,end}() with
    gallivm_init_llvm_targets().

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
CC: "10.6 11.0" <mesa-stable@lists.freedesktop.org>
src/gallium/auxiliary/gallivm/lp_bld_misc.cpp
src/gallium/auxiliary/gallivm/lp_bld_misc.h
src/gallium/targets/opencl/Makefile.am

index 5e25819ac5578fa1bd06b3400b161fa14f001796..72fab8ccf060375438129f7a95b809ba81a89c18 100644 (file)
@@ -81,6 +81,8 @@
 #  pragma pop_macro("DEBUG")
 #endif
 
+#include "c11/threads.h"
+#include "os/os_thread.h"
 #include "pipe/p_config.h"
 #include "util/u_debug.h"
 #include "util/u_cpu_detect.h"
@@ -103,6 +105,33 @@ static LLVMEnsureMultithreaded lLVMEnsureMultithreaded;
 
 }
 
+static once_flag init_native_targets_once_flag;
+
+static void init_native_targets()
+{
+   // 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();
+}
+
+/**
+ * The llvm target registry is not thread-safe, so drivers and state-trackers
+ * that want to initialize targets should use the gallivm_init_llvm_targets()
+ * function to safely initialize targets.
+ *
+ * LLVM targets should be initialized before the driver or state-tracker tries
+ * to access the registry.
+ */
+extern "C" void
+gallivm_init_llvm_targets(void)
+{
+   call_once(&init_native_targets_once_flag, init_native_targets);
+}
+
 extern "C" void
 lp_set_target_options(void)
 {
@@ -115,13 +144,7 @@ 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_targets();
 }
 
 
index 36923aa423f579ebcfba6057013b9bd47ba6f9ee..86d2f86ac45a1f32ff5fcf1b5a34ccb5bfbe50f0 100644 (file)
@@ -41,6 +41,8 @@ extern "C" {
 
 struct lp_generated_code;
 
+extern void
+gallivm_init_llvm_targets(void);
 
 extern void
 lp_set_target_options(void);
index 4ab706ef2acf425885de81aadbdf0ce4aca77c8d..c78b26832ff0bc2535e12cef1004e62d50193f4d 100644 (file)
@@ -35,7 +35,8 @@ lib@OPENCL_LIBNAME@_la_LIBADD = \
        -lclangEdit \
        -lclangLex \
        -lclangBasic \
-       $(LLVM_LIBS)
+       $(LLVM_LIBS) \
+       $(PTHREAD_LIBS)
 
 nodist_EXTRA_lib@OPENCL_LIBNAME@_la_SOURCES = dummy.cpp
 lib@OPENCL_LIBNAME@_la_SOURCES =