(root)/
m4-1.4.19/
lib/
glthread/
tls.h
       1  /* Thread-local storage in multithreaded situations.
       2     Copyright (C) 2005, 2007-2021 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Bruno Haible <bruno@clisp.org>, 2005.  */
      18  
      19  /* This file contains thread-local storage primitives for use with a given
      20     thread library.  It does not contain primitives for creating threads or
      21     for other multithreading primitives.
      22  
      23       Type:                      gl_tls_key_t
      24       Initialization:            gl_tls_key_init (name, destructor);
      25       Getting per-thread value:  gl_tls_get (name)
      26       Setting per-thread value:  gl_tls_set (name, pointer);
      27       De-initialization:         gl_tls_key_destroy (name);
      28     Equivalent functions with control of error handling:
      29       Initialization:            err = glthread_tls_key_init (&name, destructor);
      30       Setting per-thread value:  err = glthread_tls_set (&name, pointer);
      31       De-initialization:         err = glthread_tls_key_destroy (&name);
      32  
      33     A per-thread value is of type 'void *'.
      34  
      35     A destructor is a function pointer of type 'void (*) (void *)', called
      36     when a thread exits, and taking the last per-thread value as argument.  It
      37     is unspecified whether the destructor function is called when the last
      38     per-thread value is NULL.  On some platforms, the destructor function is
      39     not called at all.
      40  */
      41  
      42  
      43  #ifndef _TLS_H
      44  #define _TLS_H
      45  
      46  #include <errno.h>
      47  #include <stdlib.h>
      48  
      49  #if !defined c11_threads_in_use
      50  # if HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
      51  #  include <threads.h>
      52  #  pragma weak thrd_exit
      53  #  define c11_threads_in_use() (thrd_exit != NULL)
      54  # else
      55  #  define c11_threads_in_use() 0
      56  # endif
      57  #endif
      58  
      59  /* ========================================================================= */
      60  
      61  #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
      62  
      63  /* Use the ISO C threads library.  */
      64  
      65  # include <threads.h>
      66  
      67  /* ------------------------- gl_tls_key_t datatype ------------------------- */
      68  
      69  typedef tss_t gl_tls_key_t;
      70  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
      71      (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0)
      72  # define gl_tls_get(NAME) \
      73      tss_get (NAME)
      74  # define glthread_tls_set(KEY, POINTER) \
      75      (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0)
      76  # define glthread_tls_key_destroy(KEY) \
      77      (tss_delete (*(KEY)), 0)
      78  
      79  #endif
      80  
      81  /* ========================================================================= */
      82  
      83  #if USE_POSIX_THREADS
      84  
      85  /* Use the POSIX threads library.  */
      86  
      87  # include <pthread.h>
      88  
      89  # if PTHREAD_IN_USE_DETECTION_HARD
      90  
      91  /* The pthread_in_use() detection needs to be done at runtime.  */
      92  #  define pthread_in_use() \
      93       glthread_in_use ()
      94  extern int glthread_in_use (void);
      95  
      96  # endif
      97  
      98  # if USE_POSIX_THREADS_WEAK
      99  
     100  /* Use weak references to the POSIX threads library.  */
     101  
     102  #  pragma weak pthread_key_create
     103  #  pragma weak pthread_getspecific
     104  #  pragma weak pthread_setspecific
     105  #  pragma weak pthread_key_delete
     106  #  ifndef pthread_self
     107  #   pragma weak pthread_self
     108  #  endif
     109  
     110  #  if !PTHREAD_IN_USE_DETECTION_HARD
     111  #   pragma weak pthread_mutexattr_gettype
     112  #   define pthread_in_use() \
     113        (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
     114  #  endif
     115  
     116  # else
     117  
     118  #  if !PTHREAD_IN_USE_DETECTION_HARD
     119  #   define pthread_in_use() 1
     120  #  endif
     121  
     122  # endif
     123  
     124  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     125  
     126  typedef union
     127          {
     128            void *singlethread_value;
     129            pthread_key_t key;
     130          }
     131          gl_tls_key_t;
     132  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
     133      (pthread_in_use ()                              \
     134       ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \
     135       : ((KEY)->singlethread_value = NULL, 0))
     136  # define gl_tls_get(NAME) \
     137      (pthread_in_use ()                  \
     138       ? pthread_getspecific ((NAME).key) \
     139       : (NAME).singlethread_value)
     140  # define glthread_tls_set(KEY, POINTER) \
     141      (pthread_in_use ()                             \
     142       ? pthread_setspecific ((KEY)->key, (POINTER)) \
     143       : ((KEY)->singlethread_value = (POINTER), 0))
     144  # define glthread_tls_key_destroy(KEY) \
     145      (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0)
     146  
     147  #endif
     148  
     149  /* ========================================================================= */
     150  
     151  #if USE_WINDOWS_THREADS
     152  
     153  # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
     154  # include <windows.h>
     155  
     156  # include "windows-tls.h"
     157  
     158  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     159  
     160  typedef glwthread_tls_key_t gl_tls_key_t;
     161  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
     162      glwthread_tls_key_create (KEY, DESTRUCTOR)
     163  # define gl_tls_get(NAME) \
     164      TlsGetValue (NAME)
     165  # define glthread_tls_set(KEY, POINTER) \
     166      (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0)
     167  # define glthread_tls_key_destroy(KEY) \
     168      glwthread_tls_key_delete (*(KEY))
     169  
     170  #endif
     171  
     172  /* ========================================================================= */
     173  
     174  #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
     175  
     176  /* Provide dummy implementation if threads are not supported.  */
     177  
     178  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     179  
     180  typedef struct
     181          {
     182            void *singlethread_value;
     183          }
     184          gl_tls_key_t;
     185  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
     186      ((KEY)->singlethread_value = NULL, \
     187       (void) (DESTRUCTOR),              \
     188       0)
     189  # define gl_tls_get(NAME) \
     190      (NAME).singlethread_value
     191  # define glthread_tls_set(KEY, POINTER) \
     192      ((KEY)->singlethread_value = (POINTER), 0)
     193  # define glthread_tls_key_destroy(KEY) \
     194      0
     195  
     196  #endif
     197  
     198  /* ========================================================================= */
     199  
     200  /* Macros with built-in error handling.  */
     201  
     202  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     203  
     204  #define gl_tls_key_init(NAME, DESTRUCTOR) \
     205     do                                                 \
     206       {                                                \
     207         if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \
     208           abort ();                                    \
     209       }                                                \
     210     while (0)
     211  #define gl_tls_set(NAME, POINTER) \
     212     do                                         \
     213       {                                        \
     214         if (glthread_tls_set (&NAME, POINTER)) \
     215           abort ();                            \
     216       }                                        \
     217     while (0)
     218  #define gl_tls_key_destroy(NAME) \
     219     do                                        \
     220       {                                       \
     221         if (glthread_tls_key_destroy (&NAME)) \
     222           abort ();                           \
     223       }                                       \
     224     while (0)
     225  
     226  /* ========================================================================= */
     227  
     228  #endif /* _TLS_H */