Permalink
Browse files

Enable pthread_getspecific() tls for LLVM compiler

LLVM does not support the __thread attribute for thread
local storage and may generate incorrect code for global
register variables. We want to allow building the runtime with
LLVM-based compilers such as llvm-gcc and clang,
particularly for MacOS.

This patch changes the gct variable used by the garbage
collector to use pthread_getspecific() for thread local
storage when an llvm based compiler is used to build the
runtime.
  • Loading branch information...
1 parent 29a97fd commit dba7254566b121408e7167200d0223a531b66e8b @dmpots committed Jun 28, 2011
Showing with 51 additions and 9 deletions.
  1. +4 −1 includes/Stg.h
  2. +12 −2 rts/StgCRun.c
  3. +12 −1 rts/Task.c
  4. +9 −2 rts/Task.h
  5. +1 −1 rts/sm/GC.c
  6. +13 −2 rts/sm/GCTDecl.h
View
@@ -49,7 +49,10 @@
# define _BSD_SOURCE
#endif
-#if IN_STG_CODE == 0
+#if IN_STG_CODE == 0 || defined(llvm_CC_FLAVOR)
+// C compilers that use an LLVM back end (clang or llvm-gcc) do not
+// correctly support global register variables so we make sure that
+// we do not declare them for these compilers.
# define NO_GLOBAL_REG_DECLS /* don't define fixed registers */
#endif
View
@@ -62,13 +62,23 @@ register double fake_f9 __asm__("$f9");
#endif
#endif
+// yeuch
+#define IN_STGCRUN 1
+#ifdef sparc_HOST_ARCH
/* include Stg.h first because we want real machine regs in here: we
* have to get the value of R1 back from Stg land to C land intact.
*/
-// yeuch
-#define IN_STGCRUN 1
#include "Stg.h"
#include "Rts.h"
+#else
+/* The other architectures do not require the actual register macro
+ * definitons here because they use hand written assembly to implement
+ * the StgRun function. The sparc code could be changed so that it does
+ * not require the register macro definitions.
+ */
+#include "Rts.h"
+#include "Stg.h"
+#endif
#include "StgRun.h"
#include "Capability.h"
View
@@ -49,6 +49,9 @@ __thread Task *my_task;
# else
ThreadLocalKey currentTaskKey;
# endif
+#ifdef llvm_CC_FLAVOR
+ThreadLocalKey gctKey;
+#endif
#else
Task *my_task;
#endif
@@ -66,6 +69,9 @@ initTaskManager (void)
#if defined(THREADED_RTS)
#if !defined(MYTASK_USE_TLV)
newThreadLocalKey(&currentTaskKey);
+#endif
+#if defined(llvm_CC_FLAVOR)
+ newThreadLocalKey(&gctKey);
#endif
initMutex(&all_tasks_mutex);
#endif
@@ -96,9 +102,14 @@ freeTaskManager (void)
RELEASE_LOCK(&all_tasks_mutex);
-#if defined(THREADED_RTS) && !defined(MYTASK_USE_TLV)
+#if defined(THREADED_RTS)
closeMutex(&all_tasks_mutex);
+#if !defined(MYTASK_USE_TLV)
freeThreadLocalKey(&currentTaskKey);
+#endif
+#if defined(llvm_CC_FLAVOR)
+ freeThreadLocalKey(&gctKey);
+#endif
#endif
tasksInitialized = 0;
View
@@ -241,14 +241,21 @@ void interruptWorkerTask (Task *task);
// A thread-local-storage key that we can use to get access to the
// current thread's Task structure.
#if defined(THREADED_RTS)
-#if (defined(linux_HOST_OS) && \
+#if ((defined(linux_HOST_OS) && \
(defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH))) || \
- (defined(mingw32_HOST_OS) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4)
+ (defined(mingw32_HOST_OS) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4)) && \
+ (!defined(llvm_CC_FLAVOR))
#define MYTASK_USE_TLV
extern __thread Task *my_task;
#else
extern ThreadLocalKey currentTaskKey;
#endif
+// LLVM-based compilers do not upport the __thread attribute, so we need
+// to store the gct variable as a pthread local storage. We declare the
+// key here to keep thread local storage initialization in the same place.
+#if defined(llvm_CC_FLAVOR)
+extern ThreadLocalKey gctKey;
+#endif
#else
extern Task *my_task;
#endif
View
@@ -1026,7 +1026,7 @@ gcWorkerThread (Capability *cap)
// necessary if we stole a callee-saves register for gct:
saved_gct = gct;
- gct = gc_threads[cap->no];
+ SET_GCT(gc_threads[cap->no]);
gct->id = osThreadId();
stat_gcWorkerThreadStart(gct);
View
@@ -26,7 +26,11 @@
#define GLOBAL_REG_DECL(type,name,reg) register type name REG(reg);
+#ifdef llvm_CC_FLAVOR
+#define SET_GCT(to) (pthread_setspecific(gctKey, to))
+#else
#define SET_GCT(to) gct = (to)
+#endif
@@ -36,12 +40,19 @@
// about 5% in GC performance, but of course that might change as gcc
// improves. -- SDM 2009/04/03
//
-// We ought to do the same on MacOS X, but __thread is not
-// supported there yet (gcc 4.0.1).
+// For MacOSX, we can use an llvm-based C compiler which will store the gct
+// in a thread local variable using pthreads.
extern __thread gc_thread* gct;
#define DECLARE_GCT __thread gc_thread* gct;
+#elif defined(llvm_CC_FLAVOR)
+// LLVM does not support the __thread extension and will generate
+// incorrect code for global register variables. If we are compiling
+// with a C compiler that uses an LLVM back end (clang or llvm-gcc) then we
+// use pthread_getspecific() to handle the thread local storage for gct.
+#define gct ((gc_thread *)(pthread_getspecific(gctKey)))
+#define DECLARE_GCT /* nothing */
#elif defined(sparc_HOST_ARCH)
// On SPARC we can't pin gct to a register. Names like %l1 are just offsets

0 comments on commit dba7254

Please sign in to comment.