(root)/
m4-1.4.19/
tests/
glthread/
thread.h
       1  /* Creating and controlling threads.
       2     Copyright (C) 2005-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, or (at your option)
       7     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     Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h.  */
      19  
      20  /* This file contains primitives for creating and controlling threads.
      21  
      22     Thread data type: gl_thread_t.
      23  
      24     Creating a thread:
      25         thread = gl_thread_create (func, arg);
      26     Or with control of error handling:
      27         err = glthread_create (&thread, func, arg);
      28         extern int glthread_create (gl_thread_t *result,
      29                                     void *(*func) (void *), void *arg);
      30  
      31     Querying and changing the signal mask of a thread (not supported on all
      32     platforms):
      33         gl_thread_sigmask (how, newmask, oldmask);
      34     Or with control of error handling:
      35         err = glthread_sigmask (how, newmask, oldmask);
      36         extern int glthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask);
      37  
      38     Waiting for termination of another thread:
      39         gl_thread_join (thread, &return_value);
      40     Or with control of error handling:
      41         err = glthread_join (thread, &return_value);
      42         extern int glthread_join (gl_thread_t thread, void **return_value_ptr);
      43  
      44     Getting a reference to the current thread:
      45         current = gl_thread_self ();
      46         extern gl_thread_t gl_thread_self (void);
      47  
      48     Getting a reference to the current thread as a pointer, for debugging:
      49         ptr = gl_thread_self_pointer ();
      50         extern void * gl_thread_self_pointer (void);
      51  
      52     Terminating the current thread:
      53         gl_thread_exit (return_value);
      54         extern _Noreturn void gl_thread_exit (void *return_value);
      55  
      56     Requesting custom code to be executed at fork() time (not supported on all
      57     platforms):
      58         gl_thread_atfork (prepare_func, parent_func, child_func);
      59     Or with control of error handling:
      60         err = glthread_atfork (prepare_func, parent_func, child_func);
      61         extern int glthread_atfork (void (*prepare_func) (void),
      62                                     void (*parent_func) (void),
      63                                     void (*child_func) (void));
      64     Note that even on platforms where this is supported, use of fork() and
      65     threads together is problematic, see
      66       <https://lists.gnu.org/r/bug-gnulib/2008-08/msg00062.html>
      67   */
      68  
      69  
      70  #ifndef _GLTHREAD_THREAD_H
      71  #define _GLTHREAD_THREAD_H
      72  
      73  #include <errno.h>
      74  #include <stdlib.h>
      75  
      76  #if !defined c11_threads_in_use
      77  # if HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
      78  #  include <threads.h>
      79  #  pragma weak thrd_exit
      80  #  define c11_threads_in_use() (thrd_exit != NULL)
      81  # else
      82  #  define c11_threads_in_use() 0
      83  # endif
      84  #endif
      85  
      86  #ifndef _GL_INLINE_HEADER_BEGIN
      87   #error "Please include config.h first."
      88  #endif
      89  _GL_INLINE_HEADER_BEGIN
      90  #ifndef _GLTHREAD_THREAD_INLINE
      91  # define _GLTHREAD_THREAD_INLINE _GL_INLINE
      92  #endif
      93  
      94  /* ========================================================================= */
      95  
      96  #if USE_ISOC_THREADS
      97  
      98  /* Use the ISO C threads library.  */
      99  
     100  # include <threads.h>
     101  
     102  # ifdef __cplusplus
     103  extern "C" {
     104  # endif
     105  
     106  /* -------------------------- gl_thread_t datatype -------------------------- */
     107  
     108  typedef struct thrd_with_exitvalue *gl_thread_t;
     109  extern int glthread_create (gl_thread_t *threadp,
     110                              void *(*func) (void *), void *arg);
     111  # define glthread_sigmask(HOW, SET, OSET) \
     112      pthread_sigmask (HOW, SET, OSET)
     113  extern int glthread_join (gl_thread_t thread, void **return_value_ptr);
     114  extern gl_thread_t gl_thread_self (void);
     115  # define gl_thread_self_pointer() \
     116      (void *) gl_thread_self ()
     117  extern _Noreturn void gl_thread_exit (void *return_value);
     118  # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
     119  
     120  # ifdef __cplusplus
     121  }
     122  # endif
     123  
     124  #endif
     125  
     126  /* ========================================================================= */
     127  
     128  #if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
     129  
     130  /* Use the POSIX threads library.  */
     131  
     132  # include <pthread.h>
     133  
     134  /* On IRIX, pthread_atfork is declared in <unistd.h>, not in <pthread.h>.  */
     135  # if defined __sgi
     136  #  include <unistd.h>
     137  # endif
     138  
     139  # if USE_POSIX_THREADS_WEAK
     140  /* Compilers other than GCC need to see the declaration of pthread_sigmask
     141     before the "#pragma weak pthread_sigmask" below.  */
     142  #  include <signal.h>
     143  # endif
     144  
     145  # ifdef __cplusplus
     146  extern "C" {
     147  # endif
     148  
     149  # if PTHREAD_IN_USE_DETECTION_HARD
     150  
     151  /* The pthread_in_use() detection needs to be done at runtime.  */
     152  #  define pthread_in_use() \
     153       glthread_in_use ()
     154  extern int glthread_in_use (void);
     155  
     156  # endif
     157  
     158  # if USE_POSIX_THREADS_WEAK
     159  
     160  /* Use weak references to the POSIX threads library.  */
     161  
     162  /* Weak references avoid dragging in external libraries if the other parts
     163     of the program don't use them.  Here we use them, because we don't want
     164     every program that uses libintl to depend on libpthread.  This assumes
     165     that libpthread would not be loaded after libintl; i.e. if libintl is
     166     loaded first, by an executable that does not depend on libpthread, and
     167     then a module is dynamically loaded that depends on libpthread, libintl
     168     will not be multithread-safe.  */
     169  
     170  /* The way to test at runtime whether libpthread is present is to test
     171     whether a function pointer's value, such as &pthread_mutex_init, is
     172     non-NULL.  However, some versions of GCC have a bug through which, in
     173     PIC mode, &foo != NULL always evaluates to true if there is a direct
     174     call to foo(...) in the same function.  To avoid this, we test the
     175     address of a function in libpthread that we don't use.  */
     176  
     177  #  ifndef pthread_sigmask /* Do not declare rpl_pthread_sigmask weak.  */
     178  #   pragma weak pthread_sigmask
     179  #  endif
     180  
     181  #  pragma weak pthread_join
     182  #  ifndef pthread_self
     183  #   pragma weak pthread_self
     184  #  endif
     185  #  pragma weak pthread_exit
     186  #  if HAVE_PTHREAD_ATFORK
     187  #   pragma weak pthread_atfork
     188  #  endif
     189  
     190  #  if !PTHREAD_IN_USE_DETECTION_HARD
     191  #   pragma weak pthread_mutexattr_gettype
     192  #   define pthread_in_use() \
     193        (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
     194  #  endif
     195  
     196  # else
     197  
     198  #  if !PTHREAD_IN_USE_DETECTION_HARD
     199  #   define pthread_in_use() 1
     200  #  endif
     201  
     202  # endif
     203  
     204  /* -------------------------- gl_thread_t datatype -------------------------- */
     205  
     206  /* This choice of gl_thread_t assumes that
     207       pthread_equal (a, b)  is equivalent to  ((a) == (b)).
     208     This is the case on all platforms in use in 2008.  */
     209  typedef pthread_t gl_thread_t;
     210  # define glthread_create(THREADP, FUNC, ARG) \
     211      (pthread_in_use () ? pthread_create (THREADP, NULL, FUNC, ARG) : ENOSYS)
     212  # define glthread_sigmask(HOW, SET, OSET) \
     213      (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
     214  # define glthread_join(THREAD, RETVALP) \
     215      (pthread_in_use () ? pthread_join (THREAD, RETVALP) : 0)
     216  # ifdef PTW32_VERSION
     217     /* In pthreads-win32, pthread_t is a struct with a pointer field 'p' and
     218        other fields.  */
     219  #  define gl_thread_self() \
     220       (pthread_in_use () ? pthread_self () : gl_null_thread)
     221  #  define gl_thread_self_pointer() \
     222       (pthread_in_use () ? pthread_self ().p : NULL)
     223  extern const gl_thread_t gl_null_thread;
     224  # elif defined __MVS__
     225     /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field.
     226        The first three bytes of this field appear to uniquely identify a
     227        pthread_t, though not necessarily representing a pointer.  */
     228  #  define gl_thread_self() \
     229       (pthread_in_use () ? pthread_self () : gl_null_thread)
     230  #  define gl_thread_self_pointer() \
     231       (pthread_in_use () ? *((void **) pthread_self ().__) : NULL)
     232  extern const gl_thread_t gl_null_thread;
     233  # else
     234  #  define gl_thread_self() \
     235       (pthread_in_use () ? pthread_self () : (pthread_t) 0)
     236  #  define gl_thread_self_pointer() \
     237       (pthread_in_use () ? (void *) pthread_self () : NULL)
     238  # endif
     239  # define gl_thread_exit(RETVAL) \
     240      (void) (pthread_in_use () ? (pthread_exit (RETVAL), 0) : 0)
     241  
     242  # if HAVE_PTHREAD_ATFORK
     243  #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) \
     244       (pthread_in_use () ? pthread_atfork (PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) : 0)
     245  # else
     246  #  define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
     247  # endif
     248  
     249  # ifdef __cplusplus
     250  }
     251  # endif
     252  
     253  #endif
     254  
     255  /* ========================================================================= */
     256  
     257  #if USE_WINDOWS_THREADS
     258  
     259  # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
     260  # include <windows.h>
     261  
     262  # include "windows-thread.h"
     263  
     264  # ifdef __cplusplus
     265  extern "C" {
     266  # endif
     267  
     268  /* -------------------------- gl_thread_t datatype -------------------------- */
     269  
     270  typedef glwthread_thread_t gl_thread_t;
     271  # define glthread_create(THREADP, FUNC, ARG) \
     272      glwthread_thread_create (THREADP, 0, FUNC, ARG)
     273  # define glthread_sigmask(HOW, SET, OSET) \
     274      /* unsupported */ 0
     275  # define glthread_join(THREAD, RETVALP) \
     276      glwthread_thread_join (THREAD, RETVALP)
     277  # define gl_thread_self() \
     278      glwthread_thread_self ()
     279  # define gl_thread_self_pointer() \
     280      gl_thread_self ()
     281  # define gl_thread_exit(RETVAL) \
     282      glwthread_thread_exit (RETVAL)
     283  # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
     284  
     285  # ifdef __cplusplus
     286  }
     287  # endif
     288  
     289  #endif
     290  
     291  /* ========================================================================= */
     292  
     293  #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
     294  
     295  /* Provide dummy implementation if threads are not supported.  */
     296  
     297  typedef int gl_thread_t;
     298  # define glthread_create(THREADP, FUNC, ARG) ENOSYS
     299  # define glthread_sigmask(HOW, SET, OSET) 0
     300  # define glthread_join(THREAD, RETVALP) 0
     301  # define gl_thread_self() 0
     302  # define gl_thread_self_pointer() \
     303      ((void *) gl_thread_self ())
     304  # define gl_thread_exit(RETVAL) (void)0
     305  # define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
     306  
     307  #endif
     308  
     309  /* ========================================================================= */
     310  
     311  /* Macros with built-in error handling.  */
     312  
     313  #ifdef __cplusplus
     314  extern "C" {
     315  #endif
     316  
     317  _GLTHREAD_THREAD_INLINE gl_thread_t
     318  gl_thread_create (void *(*func) (void *arg), void *arg)
     319  {
     320    gl_thread_t thread;
     321    int ret;
     322  
     323    ret = glthread_create (&thread, func, arg);
     324    if (ret != 0)
     325      abort ();
     326    return thread;
     327  }
     328  #define gl_thread_sigmask(HOW, SET, OSET)     \
     329     do                                         \
     330       {                                        \
     331         if (glthread_sigmask (HOW, SET, OSET)) \
     332           abort ();                            \
     333       }                                        \
     334     while (0)
     335  #define gl_thread_join(THREAD, RETVAL)     \
     336     do                                      \
     337       {                                     \
     338         if (glthread_join (THREAD, RETVAL)) \
     339           abort ();                         \
     340       }                                     \
     341     while (0)
     342  #define gl_thread_atfork(PREPARE, PARENT, CHILD)     \
     343     do                                                \
     344       {                                               \
     345         if (glthread_atfork (PREPARE, PARENT, CHILD)) \
     346           abort ();                                   \
     347       }                                               \
     348     while (0)
     349  
     350  #ifdef __cplusplus
     351  }
     352  #endif
     353  
     354  _GL_INLINE_HEADER_END
     355  
     356  #endif /* _GLTHREAD_THREAD_H */