#ifndef _U_THREAD_H_
#define _U_THREAD_H_
+#include <stdio.h>
+#include <stdlib.h>
#include "u_compiler.h"
-#if defined(PTHREADS) || defined(WIN32)
+#if defined(HAVE_PTHREAD)
+#include <pthread.h> /* POSIX threads headers */
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#if defined(HAVE_PTHREAD) || defined(_WIN32)
#ifndef THREADS
#define THREADS
#endif
#endif
+/*
+ * Error messages
+ */
+#define INIT_TSD_ERROR "_glthread_: failed to allocate key for thread specific data"
+#define GET_TSD_ERROR "_glthread_: failed to get thread specific data"
+#define SET_TSD_ERROR "_glthread_: thread failed to set thread specific data"
+
+
+/*
+ * Magic number to determine if a TSD object has been initialized.
+ * Kind of a hack but there doesn't appear to be a better cross-platform
+ * solution.
+ */
+#define INIT_MAGIC 0xff8adc98
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
/*
* POSIX threads. This should be your choice in the Unix world
* whenever possible. When building with POSIX threads, be sure
* compiler flag. On Solaris with gcc, use -D_REENTRANT to enable
* proper compiling for MT-safe libc etc.
*/
-#if defined(PTHREADS)
-#include <pthread.h> /* POSIX threads headers */
+#if defined(HAVE_PTHREAD)
struct u_tsd {
pthread_key_t key;
- int initMagic;
+ unsigned initMagic;
};
typedef pthread_mutex_t u_mutex;
#define u_mutex_lock(name) (void) pthread_mutex_lock(&(name))
#define u_mutex_unlock(name) (void) pthread_mutex_unlock(&(name))
-#endif /* PTHREADS */
+static INLINE unsigned long
+u_thread_self(void)
+{
+ return (unsigned long) pthread_self();
+}
+
+
+static INLINE void
+u_tsd_init(struct u_tsd *tsd)
+{
+ if (pthread_key_create(&tsd->key, NULL/*free*/) != 0) {
+ perror(INIT_TSD_ERROR);
+ exit(-1);
+ }
+ tsd->initMagic = INIT_MAGIC;
+}
+
+
+static INLINE void *
+u_tsd_get(struct u_tsd *tsd)
+{
+ if (tsd->initMagic != INIT_MAGIC) {
+ u_tsd_init(tsd);
+ }
+ return pthread_getspecific(tsd->key);
+}
+
+
+static INLINE void
+u_tsd_set(struct u_tsd *tsd, void *ptr)
+{
+ if (tsd->initMagic != INIT_MAGIC) {
+ u_tsd_init(tsd);
+ }
+ if (pthread_setspecific(tsd->key, ptr) != 0) {
+ perror(SET_TSD_ERROR);
+ exit(-1);
+ }
+}
+
+#endif /* HAVE_PTHREAD */
/*
* IMPORTANT: Link with multithreaded runtime library when THREADS are
* used!
*/
-#ifdef WIN32
-#include <windows.h>
+#ifdef _WIN32
struct u_tsd {
DWORD key;
- int initMagic;
+ unsigned initMagic;
};
typedef CRITICAL_SECTION u_mutex;
#define u_mutex_lock(name) EnterCriticalSection(&name)
#define u_mutex_unlock(name) LeaveCriticalSection(&name)
-#endif /* WIN32 */
+static INLINE unsigned long
+u_thread_self(void)
+{
+ return GetCurrentThreadId();
+}
+
+
+static INLINE void
+u_tsd_init(struct u_tsd *tsd)
+{
+ tsd->key = TlsAlloc();
+ if (tsd->key == TLS_OUT_OF_INDEXES) {
+ perror(INIT_TSD_ERROR);
+ exit(-1);
+ }
+ tsd->initMagic = INIT_MAGIC;
+}
+
+
+static INLINE void
+u_tsd_destroy(struct u_tsd *tsd)
+{
+ if (tsd->initMagic != INIT_MAGIC) {
+ return;
+ }
+ TlsFree(tsd->key);
+ tsd->initMagic = 0x0;
+}
+
+
+static INLINE void *
+u_tsd_get(struct u_tsd *tsd)
+{
+ if (tsd->initMagic != INIT_MAGIC) {
+ u_tsd_init(tsd);
+ }
+ return TlsGetValue(tsd->key);
+}
+
+
+static INLINE void
+u_tsd_set(struct u_tsd *tsd, void *ptr)
+{
+ /* the following code assumes that the struct u_tsd has been initialized
+ to zero at creation */
+ if (tsd->initMagic != INIT_MAGIC) {
+ u_tsd_init(tsd);
+ }
+ if (TlsSetValue(tsd->key, ptr) == 0) {
+ perror(SET_TSD_ERROR);
+ exit(-1);
+ }
+}
+
+#endif /* _WIN32 */
/*
#ifndef THREADS
struct u_tsd {
- int initMagic;
+ unsigned initMagic;
};
typedef unsigned u_mutex;
#define u_mutex_lock(name) (void) name
#define u_mutex_unlock(name) (void) name
-#endif /* THREADS */
+/*
+ * no-op functions
+ */
+
+static INLINE unsigned long
+u_thread_self(void)
+{
+ return 0;
+}
+
+static INLINE void
+u_tsd_init(struct u_tsd *tsd)
+{
+ (void) tsd;
+}
-unsigned long
-u_thread_self(void);
-void
-u_tsd_init(struct u_tsd *tsd);
+static INLINE void *
+u_tsd_get(struct u_tsd *tsd)
+{
+ (void) tsd;
+ return NULL;
+}
-void
-u_tsd_destroy(struct u_tsd *tsd); /* WIN32 only */
-void *
-u_tsd_get(struct u_tsd *tsd);
+static INLINE void
+u_tsd_set(struct u_tsd *tsd, void *ptr)
+{
+ (void) tsd;
+ (void) ptr;
+}
+#endif /* THREADS */
+
-void
-u_tsd_set(struct u_tsd *tsd, void *ptr);
+#ifdef __cplusplus
+}
+#endif
#endif /* _U_THREAD_H_ */