Blame gnulib/lib/glthread/tls.h

Packit eba2e2
/* Thread-local storage in multithreaded situations.
Packit eba2e2
   Copyright (C) 2005, 2007-2014 Free Software Foundation, Inc.
Packit eba2e2
Packit eba2e2
   This program is free software: you can redistribute it and/or modify
Packit eba2e2
   it under the terms of the GNU General Public License as published by
Packit eba2e2
   the Free Software Foundation; either version 3 of the License, or
Packit eba2e2
   (at your option) any later version.
Packit eba2e2
Packit eba2e2
   This program is distributed in the hope that it will be useful,
Packit eba2e2
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit eba2e2
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit eba2e2
   GNU General Public License for more details.
Packit eba2e2
Packit eba2e2
   You should have received a copy of the GNU General Public License
Packit eba2e2
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit eba2e2
Packit eba2e2
/* Written by Bruno Haible <bruno@clisp.org>, 2005.  */
Packit eba2e2
Packit eba2e2
/* This file contains thread-local storage primitives for use with a given
Packit eba2e2
   thread library.  It does not contain primitives for creating threads or
Packit eba2e2
   for other multithreading primitives.
Packit eba2e2
Packit eba2e2
     Type:                      gl_tls_key_t
Packit eba2e2
     Initialization:            gl_tls_key_init (name, destructor);
Packit eba2e2
     Getting per-thread value:  gl_tls_get (name)
Packit eba2e2
     Setting per-thread value:  gl_tls_set (name, pointer);
Packit eba2e2
     De-initialization:         gl_tls_key_destroy (name);
Packit eba2e2
   Equivalent functions with control of error handling:
Packit eba2e2
     Initialization:            err = glthread_tls_key_init (&name, destructor);
Packit eba2e2
     Setting per-thread value:  err = glthread_tls_set (&name, pointer);
Packit eba2e2
     De-initialization:         err = glthread_tls_key_destroy (&name);
Packit eba2e2
Packit eba2e2
   A per-thread value is of type 'void *'.
Packit eba2e2
Packit eba2e2
   A destructor is a function pointer of type 'void (*) (void *)', called
Packit eba2e2
   when a thread exits, and taking the last per-thread value as argument.  It
Packit eba2e2
   is unspecified whether the destructor function is called when the last
Packit eba2e2
   per-thread value is NULL.  On some platforms, the destructor function is
Packit eba2e2
   not called at all.
Packit eba2e2
*/
Packit eba2e2
Packit eba2e2
Packit eba2e2
#ifndef _TLS_H
Packit eba2e2
#define _TLS_H
Packit eba2e2
Packit eba2e2
#include <errno.h>
Packit eba2e2
#include <stdlib.h>
Packit eba2e2
Packit eba2e2
/* ========================================================================= */
Packit eba2e2
Packit eba2e2
#if USE_POSIX_THREADS
Packit eba2e2
Packit eba2e2
/* Use the POSIX threads library.  */
Packit eba2e2
Packit eba2e2
# include <pthread.h>
Packit eba2e2
Packit eba2e2
# if PTHREAD_IN_USE_DETECTION_HARD
Packit eba2e2
Packit eba2e2
/* The pthread_in_use() detection needs to be done at runtime.  */
Packit eba2e2
#  define pthread_in_use() \
Packit eba2e2
     glthread_in_use ()
Packit eba2e2
extern int glthread_in_use (void);
Packit eba2e2
Packit eba2e2
# endif
Packit eba2e2
Packit eba2e2
# if USE_POSIX_THREADS_WEAK
Packit eba2e2
Packit eba2e2
/* Use weak references to the POSIX threads library.  */
Packit eba2e2
Packit eba2e2
#  pragma weak pthread_key_create
Packit eba2e2
#  pragma weak pthread_getspecific
Packit eba2e2
#  pragma weak pthread_setspecific
Packit eba2e2
#  pragma weak pthread_key_delete
Packit eba2e2
#  ifndef pthread_self
Packit eba2e2
#   pragma weak pthread_self
Packit eba2e2
#  endif
Packit eba2e2
Packit eba2e2
#  if !PTHREAD_IN_USE_DETECTION_HARD
Packit eba2e2
#   pragma weak pthread_cancel
Packit eba2e2
#   define pthread_in_use() (pthread_cancel != NULL)
Packit eba2e2
#  endif
Packit eba2e2
Packit eba2e2
# else
Packit eba2e2
Packit eba2e2
#  if !PTHREAD_IN_USE_DETECTION_HARD
Packit eba2e2
#   define pthread_in_use() 1
Packit eba2e2
#  endif
Packit eba2e2
Packit eba2e2
# endif
Packit eba2e2
Packit eba2e2
/* ------------------------- gl_tls_key_t datatype ------------------------- */
Packit eba2e2
Packit eba2e2
typedef union
Packit eba2e2
        {
Packit eba2e2
          void *singlethread_value;
Packit eba2e2
          pthread_key_t key;
Packit eba2e2
        }
Packit eba2e2
        gl_tls_key_t;
Packit eba2e2
# define glthread_tls_key_init(KEY, DESTRUCTOR) \
Packit eba2e2
    (pthread_in_use ()                              \
Packit eba2e2
     ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \
Packit eba2e2
     : ((KEY)->singlethread_value = NULL, 0))
Packit eba2e2
# define gl_tls_get(NAME) \
Packit eba2e2
    (pthread_in_use ()                  \
Packit eba2e2
     ? pthread_getspecific ((NAME).key) \
Packit eba2e2
     : (NAME).singlethread_value)
Packit eba2e2
# define glthread_tls_set(KEY, POINTER) \
Packit eba2e2
    (pthread_in_use ()                             \
Packit eba2e2
     ? pthread_setspecific ((KEY)->key, (POINTER)) \
Packit eba2e2
     : ((KEY)->singlethread_value = (POINTER), 0))
Packit eba2e2
# define glthread_tls_key_destroy(KEY) \
Packit eba2e2
    (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0)
Packit eba2e2
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
/* ========================================================================= */
Packit eba2e2
Packit eba2e2
#if USE_PTH_THREADS
Packit eba2e2
Packit eba2e2
/* Use the GNU Pth threads library.  */
Packit eba2e2
Packit eba2e2
# include <pth.h>
Packit eba2e2
Packit eba2e2
# if USE_PTH_THREADS_WEAK
Packit eba2e2
Packit eba2e2
/* Use weak references to the GNU Pth threads library.  */
Packit eba2e2
Packit eba2e2
#  pragma weak pth_key_create
Packit eba2e2
#  pragma weak pth_key_getdata
Packit eba2e2
#  pragma weak pth_key_setdata
Packit eba2e2
#  pragma weak pth_key_delete
Packit eba2e2
Packit eba2e2
#  pragma weak pth_cancel
Packit eba2e2
#  define pth_in_use() (pth_cancel != NULL)
Packit eba2e2
Packit eba2e2
# else
Packit eba2e2
Packit eba2e2
#  define pth_in_use() 1
Packit eba2e2
Packit eba2e2
# endif
Packit eba2e2
Packit eba2e2
/* ------------------------- gl_tls_key_t datatype ------------------------- */
Packit eba2e2
Packit eba2e2
typedef union
Packit eba2e2
        {
Packit eba2e2
          void *singlethread_value;
Packit eba2e2
          pth_key_t key;
Packit eba2e2
        }
Packit eba2e2
        gl_tls_key_t;
Packit eba2e2
# define glthread_tls_key_init(KEY, DESTRUCTOR) \
Packit eba2e2
    (pth_in_use ()                                             \
Packit eba2e2
     ? (!pth_key_create (&(KEY)->key, DESTRUCTOR) ? errno : 0) \
Packit eba2e2
     : ((KEY)->singlethread_value = NULL, 0))
Packit eba2e2
# define gl_tls_get(NAME) \
Packit eba2e2
    (pth_in_use ()                  \
Packit eba2e2
     ? pth_key_getdata ((NAME).key) \
Packit eba2e2
     : (NAME).singlethread_value)
Packit eba2e2
# define glthread_tls_set(KEY, POINTER) \
Packit eba2e2
    (pth_in_use ()                                            \
Packit eba2e2
     ? (!pth_key_setdata ((KEY)->key, (POINTER)) ? errno : 0) \
Packit eba2e2
     : ((KEY)->singlethread_value = (POINTER), 0))
Packit eba2e2
# define glthread_tls_key_destroy(KEY) \
Packit eba2e2
    (pth_in_use ()                                \
Packit eba2e2
     ? (!pth_key_delete ((KEY)->key) ? errno : 0) \
Packit eba2e2
     : 0)
Packit eba2e2
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
/* ========================================================================= */
Packit eba2e2
Packit eba2e2
#if USE_SOLARIS_THREADS
Packit eba2e2
Packit eba2e2
/* Use the old Solaris threads library.  */
Packit eba2e2
Packit eba2e2
# include <thread.h>
Packit eba2e2
Packit eba2e2
# if USE_SOLARIS_THREADS_WEAK
Packit eba2e2
Packit eba2e2
/* Use weak references to the old Solaris threads library.  */
Packit eba2e2
Packit eba2e2
#  pragma weak thr_keycreate
Packit eba2e2
#  pragma weak thr_getspecific
Packit eba2e2
#  pragma weak thr_setspecific
Packit eba2e2
Packit eba2e2
#  pragma weak thr_suspend
Packit eba2e2
#  define thread_in_use() (thr_suspend != NULL)
Packit eba2e2
Packit eba2e2
# else
Packit eba2e2
Packit eba2e2
#  define thread_in_use() 1
Packit eba2e2
Packit eba2e2
# endif
Packit eba2e2
Packit eba2e2
/* ------------------------- gl_tls_key_t datatype ------------------------- */
Packit eba2e2
Packit eba2e2
typedef union
Packit eba2e2
        {
Packit eba2e2
          void *singlethread_value;
Packit eba2e2
          thread_key_t key;
Packit eba2e2
        }
Packit eba2e2
        gl_tls_key_t;
Packit eba2e2
# define glthread_tls_key_init(KEY, DESTRUCTOR) \
Packit eba2e2
    (thread_in_use ()                          \
Packit eba2e2
     ? thr_keycreate (&(KEY)->key, DESTRUCTOR) \
Packit eba2e2
     : ((KEY)->singlethread_value = NULL, 0))
Packit eba2e2
# define gl_tls_get(NAME) \
Packit eba2e2
    (thread_in_use ()                \
Packit eba2e2
     ? glthread_tls_get_multithreaded ((NAME).key) \
Packit eba2e2
     : (NAME).singlethread_value)
Packit eba2e2
extern void *glthread_tls_get_multithreaded (thread_key_t key);
Packit eba2e2
# define glthread_tls_set(KEY, POINTER) \
Packit eba2e2
    (thread_in_use ()                              \
Packit eba2e2
     ? thr_setspecific ((KEY)->key, (POINTER))     \
Packit eba2e2
     : ((KEY)->singlethread_value = (POINTER), 0))
Packit eba2e2
# define glthread_tls_key_destroy(KEY) \
Packit eba2e2
    /* Unsupported.  */ \
Packit eba2e2
    0
Packit eba2e2
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
/* ========================================================================= */
Packit eba2e2
Packit eba2e2
#if USE_WINDOWS_THREADS
Packit eba2e2
Packit eba2e2
# define WIN32_LEAN_AND_MEAN  /* avoid including junk */
Packit eba2e2
# include <windows.h>
Packit eba2e2
Packit eba2e2
/* ------------------------- gl_tls_key_t datatype ------------------------- */
Packit eba2e2
Packit eba2e2
typedef DWORD gl_tls_key_t;
Packit eba2e2
# define glthread_tls_key_init(KEY, DESTRUCTOR) \
Packit eba2e2
    /* The destructor is unsupported.  */    \
Packit eba2e2
    ((*(KEY) = TlsAlloc ()) == (DWORD)-1 ? EAGAIN : ((void) (DESTRUCTOR), 0))
Packit eba2e2
# define gl_tls_get(NAME) \
Packit eba2e2
    TlsGetValue (NAME)
Packit eba2e2
# define glthread_tls_set(KEY, POINTER) \
Packit eba2e2
    (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0)
Packit eba2e2
# define glthread_tls_key_destroy(KEY) \
Packit eba2e2
    (!TlsFree (*(KEY)) ? EINVAL : 0)
Packit eba2e2
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
/* ========================================================================= */
Packit eba2e2
Packit eba2e2
#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
Packit eba2e2
Packit eba2e2
/* Provide dummy implementation if threads are not supported.  */
Packit eba2e2
Packit eba2e2
/* ------------------------- gl_tls_key_t datatype ------------------------- */
Packit eba2e2
Packit eba2e2
typedef struct
Packit eba2e2
        {
Packit eba2e2
          void *singlethread_value;
Packit eba2e2
        }
Packit eba2e2
        gl_tls_key_t;
Packit eba2e2
# define glthread_tls_key_init(KEY, DESTRUCTOR) \
Packit eba2e2
    ((KEY)->singlethread_value = NULL, \
Packit eba2e2
     (void) (DESTRUCTOR),              \
Packit eba2e2
     0)
Packit eba2e2
# define gl_tls_get(NAME) \
Packit eba2e2
    (NAME).singlethread_value
Packit eba2e2
# define glthread_tls_set(KEY, POINTER) \
Packit eba2e2
    ((KEY)->singlethread_value = (POINTER), 0)
Packit eba2e2
# define glthread_tls_key_destroy(KEY) \
Packit eba2e2
    0
Packit eba2e2
Packit eba2e2
#endif
Packit eba2e2
Packit eba2e2
/* ========================================================================= */
Packit eba2e2
Packit eba2e2
/* Macros with built-in error handling.  */
Packit eba2e2
Packit eba2e2
/* ------------------------- gl_tls_key_t datatype ------------------------- */
Packit eba2e2
Packit eba2e2
#define gl_tls_key_init(NAME, DESTRUCTOR) \
Packit eba2e2
   do                                                 \
Packit eba2e2
     {                                                \
Packit eba2e2
       if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \
Packit eba2e2
         abort ();                                    \
Packit eba2e2
     }                                                \
Packit eba2e2
   while (0)
Packit eba2e2
#define gl_tls_set(NAME, POINTER) \
Packit eba2e2
   do                                         \
Packit eba2e2
     {                                        \
Packit eba2e2
       if (glthread_tls_set (&NAME, POINTER)) \
Packit eba2e2
         abort ();                            \
Packit eba2e2
     }                                        \
Packit eba2e2
   while (0)
Packit eba2e2
#define gl_tls_key_destroy(NAME) \
Packit eba2e2
   do                                        \
Packit eba2e2
     {                                       \
Packit eba2e2
       if (glthread_tls_key_destroy (&NAME)) \
Packit eba2e2
         abort ();                           \
Packit eba2e2
     }                                       \
Packit eba2e2
   while (0)
Packit eba2e2
Packit eba2e2
/* ========================================================================= */
Packit eba2e2
Packit eba2e2
#endif /* _TLS_H */