P99
p99_tss.h
Go to the documentation of this file.
1 /* This may look like nonsense, but it really is -*- mode: C; coding: utf-8 -*- */
2 /* */
3 /* Except for parts copied from previous work and as explicitly stated below, */
4 /* the authors and copyright holders for this work are as follows: */
5 /* (C) copyright 2012-2014 Jens Gustedt, INRIA, France */
6 /* (C) copyright 2012 William Morris */
7 /* */
8 /* This file is free software; it is part of the P99 project. */
9 /* */
10 /* Licensed under the Apache License, Version 2.0 (the "License"); */
11 /* you may not use this file except in compliance with the License. */
12 /* You may obtain a copy of the License at */
13 /* */
14 /* http://www.apache.org/licenses/LICENSE-2.0 */
15 /* */
16 /* Unless required by applicable law or agreed to in writing, software */
17 /* distributed under the License is distributed on an "AS IS" BASIS, */
18 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
19 /* See the License for the specific language governing permissions and */
20 /* limitations under the License. */
21 /* */
22 #ifndef P99_TSS_H
23 #define P99_TSS_H 1
24 
25 #include <unistd.h>
26 #include <sys/time.h>
27 #include <pthread.h>
28 
29 #include "p99_defarg.h"
30 #include "p99_atomic.h"
31 
32 #if !p99_has_feature(threads_h)
33 
58 #ifndef PTHREAD_DESTRUCTOR_ITERATIONS
59 # warning "definition of PTHREAD_DESTRUCTOR_ITERATIONS is missing"
60 
66 # define TSS_DTOR_ITERATIONS 1
67 #else
68 # define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
69 #endif
70 
90 P99_ENC_DECLARE(pthread_key_t, tss_t);
91 
98 typedef void (*tss_dtor_t)(void*);
99 
112 enum thrd_status {
116  thrd_timedout = ETIMEDOUT,
120  thrd_success = 0,
126  thrd_busy = EBUSY,
130  thrd_error = INT_MIN,
135  thrd_nomem = ENOMEM,
140  thrd_intr = -1
141 };
142 
159 int tss_create(tss_t *p00_key, tss_dtor_t dtor) {
160  return pthread_key_create(&P99_ENCP(p00_key), dtor) ? thrd_error : thrd_success;
161 }
162 
167 void tss_delete(tss_t p00_key) {
168  (void)pthread_key_delete(P99_ENC(p00_key));
169 }
170 
178 void *tss_get(tss_t p00_key) {
179  return pthread_getspecific(P99_ENC(p00_key));
180 }
181 
189 int tss_set(tss_t p00_key, void *p00_val) {
190  return pthread_setspecific(P99_ENC(p00_key), p00_val) ? thrd_error : thrd_success;
191 }
192 
193 
194 #endif
195 
232 struct p99_tss {
233  tss_t p00_val;
239  bool volatile p00_done;
240  atomic_flag p00_flg;
241 };
242 
243 typedef struct p99_tss p99_tss;
244 
246 p99_tss* p99_tss_init(p99_tss* p00_el, tss_dtor_t p00_f) {
247  if (p00_el) {
248  *p00_el = (p99_tss) { .p99_dtor = p00_f, };
249  atomic_flag_clear_explicit(&p00_el->p00_flg, memory_order_release);
250  }
251  return p00_el;
252 }
253 
254 /* This is an implementation to bootstrap the thread specific
255  code. Once initialization functionalities that are better suited
256  for application code are defined elsewhere. */
258 void p00_tss_init(p99_tss * p00_key) {
259  if (P99_UNLIKELY(!p00_key->p00_done)) {
260  P99_SPIN_EXCLUDE(&p00_key->p00_flg) {
261  if (!p00_key->p00_done) {
262  int p00_ret = tss_create(&P99_ENCP(p00_key), p00_key->p99_dtor);
263  if (p00_ret) {
264  errno = p00_ret;
265  perror("can't create thread specific key");
266  abort();
267  }
268  p00_key->p00_done = true;
269  }
270  }
271  }
272 }
273 
280 void p99_tss_delete(p99_tss * p00_key) {
281  p00_tss_init(p00_key);
282  tss_delete(P99_ENCP(p00_key));
283  memcpy(p00_key, &P99_LVAL(p99_tss const, .p00_done = false), sizeof *p00_key);
284 }
285 
292 void* p99_tss_get(p99_tss * p00_key) {
293  p00_tss_init(p00_key);
294  return tss_get(P99_ENCP(p00_key));
295 }
296 
312 P99_DEFARG_DOCU(p99_tss_set)
315 int p99_tss_set(p99_tss * p00_key, void *p00_val) {
316  int p00_ret = thrd_success;
317  void * p00_vol = p99_tss_get(p00_key);
318  if (p00_val != p00_vol) {
319  p00_ret = tss_set(P99_ENCP(p00_key), p00_val);
320  if (p00_ret == thrd_success && p00_vol && p00_key->p99_dtor) {
321  p00_key->p99_dtor(p00_vol);
322  }
323  }
324  return p00_ret;
325 }
326 
327 #ifndef P00_DOXYGEN
328 inline
329 P99_PROTOTYPE(int, p99_tss_set, p99_tss*, void *);
330 #define p99_tss_set(...) P99_CALL_DEFARG(p99_tss_set, 2, __VA_ARGS__)
331 #endif
332 
333 #define p99_tss_set_defarg_1() (0)
334 
335 
371 P00_DOCUMENT_IDENTIFIER_ARGUMENT(P99_TSS_DECLARE_LOCAL, 1)
372 #ifdef P00_DOXYGEN
373 # define P99_TSS_DECLARE_LOCAL(T, NAME, DTOR) \
374  \
375 p99_tss NAME
376 #else
377 # define P99_TSS_DECLARE_LOCAL(...) \
378 P99_IF_LT(P99_NARG(__VA_ARGS__), 3) \
379 (P00_TSS_DECLARE_LOCAL(__VA_ARGS__, (free))) \
380 (P00_TSS_DECLARE_LOCAL(__VA_ARGS__))
381 
382 #define P00_TSS_DECLARE_LOCAL(T, NAME, DTOR) \
383 P99_WEAK(NAME) \
384 P00_TSS_DECLARE_LOCAL3(NAME, T, DTOR); \
385 P00_TSS_DEFINE_LOCAL3(NAME, T, DTOR)
386 
387 # define P99_TSS_DECLARE_LOCAL_EXTERN(...) \
388 P99_IF_LT(P99_NARG(__VA_ARGS__), 3) \
389 (P00_TSS_DECLARE_LOCAL_EXTERN(__VA_ARGS__, (free))) \
390 (P00_TSS_DECLARE_LOCAL_EXTERN(__VA_ARGS__))
391 
392 #define P00_TSS_DECLARE_LOCAL_EXTERN(T, NAME, DTOR) \
393 extern \
394 P00_TSS_DECLARE_LOCAL3(NAME, T, DTOR)
395 
396 # define P99_TSS_DEFINE_LOCAL(...) \
397 P99_IF_LT(P99_NARG(__VA_ARGS__), 3) \
398 (P00_TSS_DEFINE_LOCAL(__VA_ARGS__, (free))) \
399 (P00_TSS_DEFINE_LOCAL(__VA_ARGS__))
400 
401 #define P00_TSS_DEFINE_LOCAL(T, NAME, DTOR) \
402 P00_TSS_DEFINE_LOCAL3(NAME, T, DTOR)
403 
404 
405 #endif
406 
407 
408 #define P00_TSS_DECLARE_LOCAL3(NAME, T, DTOR) \
409  \
410 p99_tss NAME; \
411 typedef T P99_PASTE3(p00_, NAME, _type)
412 
413 #define P00_TSS_DEFINE_LOCAL3(NAME, T, DTOR) \
414 p99_tss NAME = { .p99_dtor = (DTOR), }
415 
416 
427 #define P99_TSS_LOCAL(NAME) (*(P99_PASTE3(p00_, NAME, _type)*)p99_tss_get_alloc(&(NAME), sizeof(P99_PASTE3(p00_, NAME, _type))))
428 
429 
442 void* p99_tss_get_alloc(p99_tss * p00_key, size_t p00_size) {
443  void * p00_ret = p99_tss_get(p00_key);
444  if (P99_UNLIKELY(!p00_ret))
445  if (p00_size) {
446  p00_ret = calloc(1, p00_size);
447  if (p99_tss_set(p00_key, p00_ret) != thrd_success) {
448  free(p00_ret);
449  p00_ret = 0;
450  }
451  }
452  return p00_ret;
453 }
454 
455 #if defined(thread_local) && !defined(P99_EMULATE_THREAD_LOCAL) && !defined(P00_DOXYGEN)
456 
457 #define P99_DECLARE_THREAD_LOCAL(T, NAME) \
458 P99_WEAK(NAME) \
459 thread_local T NAME
460 
461 #define P99_DECLARE_THREAD_LOCAL_EXTERN(T, NAME) \
462 extern \
463 thread_local T NAME
464 
465 #define P99_DEFINE_THREAD_LOCAL(T, NAME) \
466 thread_local T NAME
467 
468 
469 #define P99_THREAD_LOCAL(NAME) (NAME)
470 
471 #else
472 
485 #define P99_DECLARE_THREAD_LOCAL P99_TSS_DECLARE_LOCAL
486 
487 #define P99_DECLARE_THREAD_LOCAL_EXTERN P99_TSS_DECLARE_LOCAL_EXTERN
488 
489 #define P99_DEFINE_THREAD_LOCAL P99_TSS_DEFINE_LOCAL
490 
499 #define P99_THREAD_LOCAL P99_TSS_LOCAL
500 #endif
501 
502 
507 #endif
void
void void
Definition: p99_bitset.h:84
thrd_timedout
@ thrd_timedout
returned by a timed wait function to indicate that the time specified in the call was reached without...
Definition: p99_tss.h:114
p99_defarg.h
Macros for default arguments to functions.
thrd_busy
@ thrd_busy
returned by a function to indicate that the requested operation failed because a resource requested b...
Definition: p99_tss.h:124
P99_TSS_DECLARE_LOCAL
#define P99_TSS_DECLARE_LOCAL(T, NAME, DTOR)
P99_WARN_UNUSED_RESULT
#define P99_WARN_UNUSED_RESULT
On architectures that support this, warn if the result of a function is not used.
Definition: p99_compiler.h:602
calloc
#define calloc(...)
Default arguments for C99 function calloc
Definition: p99_c99_default.h:44
p99_tss
struct p99_tss p99_tss
Definition: p99_tss.h:241
P99_SPIN_EXCLUDE
#define P99_SPIN_EXCLUDE(FLAGP)
Protect the following block or statement as a critical section of the program by using FLAGP as a spi...
Definition: p99_atomic_flag.h:90
P99_ENC
#define P99_ENC(OBJ)
Access an encapsulated object.
Definition: p99_type.h:190
thrd_success
@ thrd_success
returned by a function to indicate that the requested operation succeeded
Definition: p99_tss.h:118
p99_inline
#define p99_inline
Try to force a function always to be inlined.
Definition: p99_compiler.h:496
P99_PROTOTYPE
#define P99_PROTOTYPE(...)
Define the prototype of function NAME.
Definition: p99_defarg.h:197
P99_DEFARG_DOCU
#define P99_DEFARG_DOCU(NAME)
Provide a documentation section to a function defined with P99_CALL_DEFARG.
Definition: p99_defarg.h:318
thrd_nomem
@ thrd_nomem
returned by a function to indicate that the requested operation failed because it was unable to alloc...
Definition: p99_tss.h:133
P99_LVAL
#define P99_LVAL(...)
Define an lvalue of type T, where T is the first parameter in the variable parameter list.
Definition: p99_int.h:1084
tss_dtor_t
void(* tss_dtor_t)(void *)
which is the function pointer type void (*)(void*), used for a destructor for a thread-specific stora...
Definition: p99_tss.h:96
p99_atomic.h
P99_ENC_DECLARE
#define P99_ENC_DECLARE(T, NAME)
Encapsulate an object of type T in a new type called NAME.
Definition: p99_type.h:178
p99_tss::p99_dtor
tss_dtor_t p99_dtor
Destructor function that is automatically called at the termination of a thread.
Definition: p99_tss.h:236
pthread_key_create
#define pthread_key_create(...)
Default arguments for POSIX function pthread_key_create.
Definition: p99_posix_default.h:76
thrd_intr
@ thrd_intr
(extension) returned by ::thrd_sleep to indicate that the corresponding request has been interrupted ...
Definition: p99_tss.h:138
thrd_error
@ thrd_error
returned by a function to indicate that the requested operation failed
Definition: p99_tss.h:128
P99_ENCP
#define P99_ENCP(OBJP)
Access an encapsulated object through a pointer.
Definition: p99_type.h:196
tss_t
typedef **addtogroup threads C11 thread emulation on top of POSIX threads ****This is a relatively straightforward implementation of the C11 **thread model on top of POSIX threads The main difficulty this presents **is that the thread entry function signature differs between the **two C11 thread returns an< code > int</code > whereas POSIX returns **a< code > void *</code > ****You can find the thread management interfaces through the **documentation of the type ::thrd_t ****remark In addition to POSIX threads this implementation needs **some C11 atomic operations for initialization via ::call_once and **status communication ****struct tss_t tss_t
Definition: p99_tss.h:88
P99_UNLIKELY
#define P99_UNLIKELY(...)
Mark the conditional expression as being unlikely.
Definition: p99_compiler.h:994
p99_tss_init
p99_tss * p99_tss_init(p99_tss *p00_el, tss_dtor_t p00_f)
Definition: p99_tss.h:244
errno
errno
Definition: p99_constraint.h:199
thrd_status
thrd_status
C11 thread function return values.
Definition: p99_tss.h:110
p99_tss
A stub structure to hold a thread local variable if thread_local is not available.
Definition: p99_tss.h:230