root/maint/gnulib/lib/windows-thread.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. do_init_self_key
  2. init_self_key
  3. get_current_thread_handle
  4. glwthread_thread_self
  5. wrapper_func
  6. glwthread_thread_create
  7. glwthread_thread_join
  8. glwthread_thread_detach
  9. glwthread_thread_exit

   1 /* Creating and controlling threads (native Windows implementation).
   2    Copyright (C) 2005-2021 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    Based on GCC's gthr-win32.h.  */
  19 
  20 #include <config.h>
  21 
  22 /* Specification.  */
  23 #include "windows-thread.h"
  24 
  25 #include <errno.h>
  26 #include <process.h>
  27 #include <stdlib.h>
  28 
  29 #include "windows-once.h"
  30 #include "windows-tls.h"
  31 
  32 /* The Thread-Local Storage (TLS) key that allows to access each thread's
  33    'struct glwthread_thread_struct *' pointer.  */
  34 static DWORD self_key = (DWORD)-1;
  35 
  36 /* Initializes self_key.  This function must only be called once.  */
  37 static void
  38 do_init_self_key (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40   self_key = TlsAlloc ();
  41   /* If this fails, we're hosed.  */
  42   if (self_key == (DWORD)-1)
  43     abort ();
  44 }
  45 
  46 /* Initializes self_key.  */
  47 static void
  48 init_self_key (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50   static glwthread_once_t once = GLWTHREAD_ONCE_INIT;
  51   glwthread_once (&once, do_init_self_key);
  52 }
  53 
  54 /* This structure contains information about a thread.
  55    It is stored in TLS under key self_key.  */
  56 struct glwthread_thread_struct
  57 {
  58   /* Fields for managing the handle.  */
  59   HANDLE volatile handle;
  60   CRITICAL_SECTION handle_lock;
  61   /* Fields for managing the exit value.  */
  62   BOOL volatile detached;
  63   void * volatile result;
  64   /* Fields for managing the thread start.  */
  65   void * (*func) (void *);
  66   void *arg;
  67 };
  68 
  69 /* Return a real HANDLE object for the current thread.  */
  70 static HANDLE
  71 get_current_thread_handle (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73   HANDLE this_handle;
  74 
  75   /* GetCurrentThread() returns a pseudo-handle, i.e. only a symbolic
  76      identifier, not a real handle.  */
  77   if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
  78                         GetCurrentProcess (), &this_handle,
  79                         0, FALSE, DUPLICATE_SAME_ACCESS))
  80     abort ();
  81   return this_handle;
  82 }
  83 
  84 glwthread_thread_t
  85 glwthread_thread_self (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87   glwthread_thread_t thread;
  88 
  89   if (self_key == (DWORD)-1)
  90     init_self_key ();
  91   thread = TlsGetValue (self_key);
  92   if (thread == NULL)
  93     {
  94       /* This happens only in threads that have not been created through
  95          glthread_create(), such as the main thread.  */
  96       for (;;)
  97         {
  98           thread =
  99             (struct glwthread_thread_struct *)
 100             malloc (sizeof (struct glwthread_thread_struct));
 101           if (thread != NULL)
 102             break;
 103           /* Memory allocation failed.  There is not much we can do.  Have to
 104              busy-loop, waiting for the availability of memory.  */
 105           Sleep (1);
 106         }
 107 
 108       thread->handle = get_current_thread_handle ();
 109       InitializeCriticalSection (&thread->handle_lock);
 110       thread->detached = FALSE; /* This can lead to a memory leak.  */
 111       thread->result = NULL; /* just to be deterministic */
 112       TlsSetValue (self_key, thread);
 113     }
 114   return thread;
 115 }
 116 
 117 /* The main function of a freshly creating thread.  It's a wrapper around
 118    the FUNC and ARG arguments passed to glthread_create_func.  */
 119 static unsigned int WINAPI
 120 wrapper_func (void *varg)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122   struct glwthread_thread_struct *thread =
 123     (struct glwthread_thread_struct *) varg;
 124 
 125   EnterCriticalSection (&thread->handle_lock);
 126   /* Create a new handle for the thread only if the parent thread did not yet
 127      fill in the handle.  */
 128   if (thread->handle == NULL)
 129     thread->handle = get_current_thread_handle ();
 130   LeaveCriticalSection (&thread->handle_lock);
 131 
 132   if (self_key == (DWORD)-1)
 133     init_self_key ();
 134   TlsSetValue (self_key, thread);
 135 
 136   /* Run the thread.  Store the exit value if the thread was not terminated
 137      otherwise.  */
 138   thread->result = thread->func (thread->arg);
 139 
 140   /* Process the TLS destructors.  */
 141   glwthread_tls_process_destructors ();
 142 
 143   if (thread->detached)
 144     {
 145       /* Clean up the thread, like thrd_join would do.  */
 146       DeleteCriticalSection (&thread->handle_lock);
 147       CloseHandle (thread->handle);
 148       free (thread);
 149     }
 150 
 151   return 0;
 152 }
 153 
 154 int
 155 glwthread_thread_create (glwthread_thread_t *threadp, unsigned int attr,
     /* [previous][next][first][last][top][bottom][index][help] */
 156                          void * (*func) (void *), void *arg)
 157 {
 158   struct glwthread_thread_struct *thread =
 159     (struct glwthread_thread_struct *)
 160     malloc (sizeof (struct glwthread_thread_struct));
 161   if (thread == NULL)
 162     return ENOMEM;
 163   thread->handle = NULL;
 164   InitializeCriticalSection (&thread->handle_lock);
 165   thread->detached = (attr & GLWTHREAD_ATTR_DETACHED ? TRUE : FALSE);
 166   thread->result = NULL; /* just to be deterministic */
 167   thread->func = func;
 168   thread->arg = arg;
 169 
 170   {
 171     unsigned int thread_id;
 172     HANDLE thread_handle;
 173 
 174     thread_handle = (HANDLE)
 175       _beginthreadex (NULL, 100000, wrapper_func, thread, 0, &thread_id);
 176       /* calls CreateThread with the same arguments */
 177     if (thread_handle == NULL)
 178       {
 179         DeleteCriticalSection (&thread->handle_lock);
 180         free (thread);
 181         return EAGAIN;
 182       }
 183 
 184     EnterCriticalSection (&thread->handle_lock);
 185     if (thread->handle == NULL)
 186       thread->handle = thread_handle;
 187     else
 188       /* thread->handle was already set by the thread itself.  */
 189       CloseHandle (thread_handle);
 190     LeaveCriticalSection (&thread->handle_lock);
 191 
 192     *threadp = thread;
 193     return 0;
 194   }
 195 }
 196 
 197 int
 198 glwthread_thread_join (glwthread_thread_t thread, void **retvalp)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200   if (thread == NULL)
 201     return EINVAL;
 202 
 203   if (thread == glwthread_thread_self ())
 204     return EDEADLK;
 205 
 206   if (thread->detached)
 207     return EINVAL;
 208 
 209   if (WaitForSingleObject (thread->handle, INFINITE) == WAIT_FAILED)
 210     return EINVAL;
 211 
 212   if (retvalp != NULL)
 213     *retvalp = thread->result;
 214 
 215   DeleteCriticalSection (&thread->handle_lock);
 216   CloseHandle (thread->handle);
 217   free (thread);
 218 
 219   return 0;
 220 }
 221 
 222 int
 223 glwthread_thread_detach (glwthread_thread_t thread)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225   if (thread == NULL)
 226     return EINVAL;
 227 
 228   if (thread->detached)
 229     return EINVAL;
 230 
 231   thread->detached = TRUE;
 232   return 0;
 233 }
 234 
 235 void
 236 glwthread_thread_exit (void *retval)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238   glwthread_thread_t thread = glwthread_thread_self ();
 239   thread->result = retval;
 240   glwthread_tls_process_destructors ();
 241   _endthreadex (0); /* calls ExitThread (0) */
 242   abort ();
 243 }

/* [previous][next][first][last][top][bottom][index][help] */