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