1 /* Creating and controlling threads.
2 Copyright (C) 2005-2008 Free Software Foundation, Inc.
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 2, or (at your option)
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.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
19 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
24 #include "glthread/thread.h"
27 #include "glthread/lock.h"
29 /* ========================================================================= */
33 /* -------------------------- gl_thread_t datatype -------------------------- */
35 /* Use a wrapper function, instead of adding WINAPI through a cast.
36 This struct also holds the thread's exit value. */
39 /* Fields for managing the association between thread id and handle. */
41 HANDLE volatile handle;
42 CRITICAL_SECTION handle_lock;
43 struct thread_extra * volatile next;
44 /* Fields for managing the exit value. */
45 void * volatile result;
46 /* Fields for managing the thread start. */
47 void * (*func) (void *);
51 /* Linked list of thread_extra of running or zombie (not-yet-joined)
53 TODO: Use a hash table indexed by id instead of a linked list. */
54 static struct thread_extra *running_threads /* = NULL */;
56 /* Lock protecting running_threads. */
57 gl_lock_define_initialized(static, running_lock)
60 wrapper_func (void *varg)
62 struct thread_extra *xarg = (struct thread_extra *)varg;
64 EnterCriticalSection (&xarg->handle_lock);
65 xarg->id = GetCurrentThreadId ();
66 /* Create a new handle for the thread only if the parent thread did not yet
67 fill in the handle. */
68 if (xarg->handle == NULL)
71 if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
72 GetCurrentProcess (), &this_thread,
73 0, FALSE, DUPLICATE_SAME_ACCESS))
75 xarg->handle = this_thread;
77 LeaveCriticalSection (&xarg->handle_lock);
78 /* Add xarg to the list of running thread_extra. */
79 gl_lock_lock (running_lock);
80 if (!(xarg->id == GetCurrentThreadId ()))
82 xarg->next = running_threads;
83 running_threads = xarg;
84 gl_lock_unlock (running_lock);
86 /* Run the thread. Store the exit value if the thread was not terminated
88 xarg->result = xarg->func (xarg->arg);
93 glthread_create_func (gl_thread_t *threadp, void * (*func) (void *), void *arg)
95 struct thread_extra *x =
96 (struct thread_extra *) malloc (sizeof (struct thread_extra));
100 InitializeCriticalSection (&x->handle_lock);
101 x->result = NULL; /* just to be deterministic */
106 HANDLE thread_handle;
108 thread_handle = CreateThread (NULL, 100000, wrapper_func, x, 0, &thread_id);
109 if (thread_handle == NULL)
111 DeleteCriticalSection (&x->handle_lock);
115 EnterCriticalSection (&x->handle_lock);
117 if (x->handle == NULL)
118 x->handle = thread_handle;
120 /* x->handle was already set by the thread itself. */
121 CloseHandle (thread_handle);
122 LeaveCriticalSection (&x->handle_lock);
123 *threadp = thread_id;
129 glthread_join_func (gl_thread_t thread, void **retvalp)
131 HANDLE thread_handle;
133 if (thread == gl_thread_self ())
136 /* Find the thread handle that corresponds to the thread id.
137 The thread argument must come from either the parent thread or from the
138 thread itself. So at this point, either glthread_create_func or
139 wrapper_func (whichever was executed first) has filled in x->handle. */
140 thread_handle = NULL;
141 gl_lock_lock (running_lock);
143 struct thread_extra *x;
144 for (x = running_threads; x != NULL; x = x->next)
147 thread_handle = x->handle;
151 gl_lock_unlock (running_lock);
152 if (thread_handle == NULL)
155 if (WaitForSingleObject (thread_handle, INFINITE) == WAIT_FAILED)
158 /* Remove the 'struct thread_extra' from running_threads. */
159 gl_lock_lock (running_lock);
161 struct thread_extra * volatile *xp;
162 for (xp = &running_threads; *xp != NULL; xp = &(*xp)->next)
163 if ((*xp)->id == thread)
165 struct thread_extra *x = *xp;
167 *retvalp = x->result;
168 if (x->handle != thread_handle)
171 DeleteCriticalSection (&x->handle_lock);
176 gl_lock_unlock (running_lock);
178 CloseHandle (thread_handle);
184 gl_thread_exit_func (void *retval)
186 DWORD this_thread = GetCurrentThreadId ();
188 /* Store the exit value in the appropriate element of running_threads. */
189 gl_lock_lock (running_lock);
191 struct thread_extra *x;
192 for (x = running_threads; x != NULL; x = x->next)
193 if (x->id == this_thread)
199 gl_lock_unlock (running_lock);
206 /* ========================================================================= */