Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef P99_TSS_H
00014 #define P99_TSS_H 1
00015
00016 #define _XOPEN_SOURCE 600
00017 #include <unistd.h>
00018 #include <sys/time.h>
00019 #include <time.h>
00020 #include <pthread.h>
00021 #if defined(__GNUC__) || defined(P00_DOXYGEN)
00022 # include "p99_atomic.h"
00023 #endif
00024
00025 #include "p99_compiler.h"
00026
00051 #ifndef PTHREAD_DESTRUCTOR_ITERATIONS
00052 # warning "definition of PTHREAD_DESTRUCTOR_ITERATIONS is missing"
00053
00059 # define TSS_DTOR_ITERATIONS 1
00060 #else
00061 # define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
00062 #endif
00063
00083 P99_ENC_DECLARE(pthread_key_t, tss_t);
00084
00091 typedef void (*tss_dtor_t)(void*);
00092
00105 enum thrd_status {
00109 thrd_timedout = ETIMEDOUT,
00113 thrd_success = 0,
00119 thrd_busy = EBUSY,
00123 thrd_error = INT_MIN,
00128 thrd_nomem = ENOMEM,
00133 thrd_intr = -1
00134 };
00135
00150 p99_inline
00151 int tss_create(tss_t *p00_key, tss_dtor_t dtor) {
00152 return pthread_key_create(&P99_ENCP(p00_key), dtor) ? thrd_error : thrd_success;
00153 }
00154
00158 p99_inline
00159 void tss_delete(tss_t p00_key) {
00160 (void)pthread_key_delete(P99_ENC(p00_key));
00161 }
00162
00169 p99_inline
00170 void *tss_get(tss_t p00_key) {
00171 return pthread_getspecific(P99_ENC(p00_key));
00172 }
00173
00179 p99_inline
00180 int tss_set(tss_t p00_key, void *p00_val) {
00181 return pthread_setspecific(P99_ENC(p00_key), p00_val) ? thrd_error : thrd_success;
00182 }
00183
00209 struct p99_tss {
00210 tss_t p00_val;
00211 tss_dtor_t p00_func;
00212 bool volatile p00_done;
00213 atomic_flag p00_flg;
00214 };
00215
00216 typedef struct p99_tss p99_tss;
00217
00218
00219
00220
00221 p99_inline
00222 void p00_key_once_init(p99_tss * p00_key) {
00223 if (!p00_key->p00_done) {
00224 P99_SPIN_EXCLUDE(&p00_key->p00_flg) {
00225 if (!p00_key->p00_done) {
00226 if (!p00_key->p00_func) p00_key->p00_func = free;
00227 int p00_ret = tss_create(&P99_ENCP(p00_key), p00_key->p00_func);
00228 if (p00_ret) {
00229 errno = p00_ret;
00230 perror("can't create thread specific key");
00231 abort();
00232 }
00233 p00_key->p00_done = true;
00234 }
00235 }
00236 }
00237 }
00238
00239 p99_inline
00240 void* p00_thread_local_get(p99_tss * p00_key, size_t p00_size) {
00241 p00_key_once_init(p00_key);
00242 void * p00_ret = tss_get(P99_ENCP(p00_key));
00243 if (P99_UNLIKELY(!p00_ret)) {
00244 p00_ret = calloc(1, p00_size);
00245 tss_set(P99_ENCP(p00_key), p00_ret);
00246 }
00247 return p00_ret;
00248 }
00249
00250 #if defined(thread_local) && !defined(P99_EMULATE_THREAD_LOCAL) && !defined(P00_DOXYGEN)
00251
00252 #define P99_DECLARE_THREAD_LOCAL(T, NAME) \
00253 P99_WEAK(NAME) \
00254 thread_local T NAME
00255
00256 #define P99_THREAD_LOCAL(NAME) (NAME)
00257
00258 #else
00259
00269 #define P99_DECLARE_THREAD_LOCAL(T, NAME) \
00270 \
00271 P99_WEAK(NAME) \
00272 p99_tss NAME; \
00273 typedef T P99_PASTE3(p00_, NAME, _type)
00274
00284 #define P99_THREAD_LOCAL(NAME) (*(P99_PASTE3(p00_, NAME, _type)*)p00_thread_local_get(&(NAME), sizeof(P99_PASTE3(p00_, NAME, _type))))
00285
00286 #endif
00287
00288
00293 #endif