(root)/
gettext-0.22.4/
gettext-tools/
libgettextpo/
glthread/
tls.h
       1  /* Thread-local storage in multithreaded situations.
       2     Copyright (C) 2005, 2007-2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file 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 Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser 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  /* This file uses HAVE_THREADS_H.  */
      47  #if !_GL_CONFIG_H_INCLUDED
      48   #error "Please include config.h first."
      49  #endif
      50  
      51  #include <errno.h>
      52  #include <stdlib.h>
      53  
      54  #if !defined c11_threads_in_use
      55  # if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
      56  #  define c11_threads_in_use() 1
      57  # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
      58  #  include <threads.h>
      59  #  pragma weak thrd_exit
      60  #  define c11_threads_in_use() (thrd_exit != NULL)
      61  # else
      62  #  define c11_threads_in_use() 0
      63  # endif
      64  #endif
      65  
      66  /* ========================================================================= */
      67  
      68  #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
      69  
      70  /* Use the ISO C threads library.  */
      71  
      72  # include <threads.h>
      73  
      74  /* ------------------------- gl_tls_key_t datatype ------------------------- */
      75  
      76  typedef tss_t gl_tls_key_t;
      77  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
      78      (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0)
      79  # define gl_tls_get(NAME) \
      80      tss_get (NAME)
      81  # define glthread_tls_set(KEY, POINTER) \
      82      (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0)
      83  # define glthread_tls_key_destroy(KEY) \
      84      (tss_delete (*(KEY)), 0)
      85  
      86  #endif
      87  
      88  /* ========================================================================= */
      89  
      90  #if USE_POSIX_THREADS
      91  
      92  /* Use the POSIX threads library.  */
      93  
      94  # include <pthread.h>
      95  
      96  # if PTHREAD_IN_USE_DETECTION_HARD
      97  
      98  /* The pthread_in_use() detection needs to be done at runtime.  */
      99  #  define pthread_in_use() \
     100       glthread_in_use ()
     101  extern int glthread_in_use (void);
     102  
     103  # endif
     104  
     105  # if USE_POSIX_THREADS_WEAK
     106  
     107  /* Use weak references to the POSIX threads library.  */
     108  
     109  #  pragma weak pthread_key_create
     110  #  pragma weak pthread_getspecific
     111  #  pragma weak pthread_setspecific
     112  #  pragma weak pthread_key_delete
     113  #  ifndef pthread_self
     114  #   pragma weak pthread_self
     115  #  endif
     116  
     117  #  if !PTHREAD_IN_USE_DETECTION_HARD
     118  #   pragma weak pthread_mutexattr_gettype
     119  #   define pthread_in_use() \
     120        (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
     121  #  endif
     122  
     123  # else
     124  
     125  #  if !PTHREAD_IN_USE_DETECTION_HARD
     126  #   define pthread_in_use() 1
     127  #  endif
     128  
     129  # endif
     130  
     131  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     132  
     133  typedef union
     134          {
     135            void *singlethread_value;
     136            pthread_key_t key;
     137          }
     138          gl_tls_key_t;
     139  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
     140      (pthread_in_use ()                              \
     141       ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \
     142       : ((KEY)->singlethread_value = NULL, 0))
     143  # define gl_tls_get(NAME) \
     144      (pthread_in_use ()                  \
     145       ? pthread_getspecific ((NAME).key) \
     146       : (NAME).singlethread_value)
     147  # define glthread_tls_set(KEY, POINTER) \
     148      (pthread_in_use ()                             \
     149       ? pthread_setspecific ((KEY)->key, (POINTER)) \
     150       : ((KEY)->singlethread_value = (POINTER), 0))
     151  # define glthread_tls_key_destroy(KEY) \
     152      (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0)
     153  
     154  #endif
     155  
     156  /* ========================================================================= */
     157  
     158  #if USE_WINDOWS_THREADS
     159  
     160  # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
     161  # include <windows.h>
     162  
     163  # include "windows-tls.h"
     164  
     165  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     166  
     167  typedef glwthread_tls_key_t gl_tls_key_t;
     168  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
     169      glwthread_tls_key_create (KEY, DESTRUCTOR)
     170  # define gl_tls_get(NAME) \
     171      TlsGetValue (NAME)
     172  # define glthread_tls_set(KEY, POINTER) \
     173      (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0)
     174  # define glthread_tls_key_destroy(KEY) \
     175      glwthread_tls_key_delete (*(KEY))
     176  
     177  #endif
     178  
     179  /* ========================================================================= */
     180  
     181  #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
     182  
     183  /* Provide dummy implementation if threads are not supported.  */
     184  
     185  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     186  
     187  typedef struct
     188          {
     189            void *singlethread_value;
     190          }
     191          gl_tls_key_t;
     192  # define glthread_tls_key_init(KEY, DESTRUCTOR) \
     193      ((KEY)->singlethread_value = NULL, \
     194       (void) (DESTRUCTOR),              \
     195       0)
     196  # define gl_tls_get(NAME) \
     197      (NAME).singlethread_value
     198  # define glthread_tls_set(KEY, POINTER) \
     199      ((KEY)->singlethread_value = (POINTER), 0)
     200  # define glthread_tls_key_destroy(KEY) \
     201      0
     202  
     203  #endif
     204  
     205  /* ========================================================================= */
     206  
     207  /* Macros with built-in error handling.  */
     208  
     209  /* ------------------------- gl_tls_key_t datatype ------------------------- */
     210  
     211  #define gl_tls_key_init(NAME, DESTRUCTOR) \
     212     do                                                 \
     213       {                                                \
     214         if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \
     215           abort ();                                    \
     216       }                                                \
     217     while (0)
     218  #define gl_tls_set(NAME, POINTER) \
     219     do                                         \
     220       {                                        \
     221         if (glthread_tls_set (&NAME, POINTER)) \
     222           abort ();                            \
     223       }                                        \
     224     while (0)
     225  #define gl_tls_key_destroy(NAME) \
     226     do                                        \
     227       {                                       \
     228         if (glthread_tls_key_destroy (&NAME)) \
     229           abort ();                           \
     230       }                                       \
     231     while (0)
     232  
     233  /* ========================================================================= */
     234  
     235  #endif /* _TLS_H */