/* Fields for managing the association between thread id and handle. */
DWORD volatile id;
HANDLE volatile handle;
+ CRITICAL_SECTION handle_lock;
struct thread_extra * volatile next;
/* Fields for managing the exit value. */
void * volatile result;
{
struct thread_extra *xarg = (struct thread_extra *)varg;
+ EnterCriticalSection (&xarg->handle_lock);
xarg->id = GetCurrentThreadId ();
+ /* Create a new handle for the thread only if the parent thread did not yet
+ fill in the handle. */
+ if (xarg->handle == NULL)
+ {
+ HANDLE this_thread;
+ if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+ GetCurrentProcess (), &this_thread,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ abort ();
+ xarg->handle = this_thread;
+ }
+ LeaveCriticalSection (&xarg->handle_lock);
/* Add xarg to the list of running thread_extra. */
gl_lock_lock (running_lock);
if (!(xarg->id == GetCurrentThreadId ()))
(struct thread_extra *) malloc (sizeof (struct thread_extra));
if (x == NULL)
return ENOMEM;
+ x->handle = NULL;
+ InitializeCriticalSection (&x->handle_lock);
x->result = NULL; /* just to be deterministic */
x->func = func;
x->arg = arg;
DWORD thread_id;
HANDLE thread_handle;
- gl_lock_lock (running_lock);
thread_handle = CreateThread (NULL, 100000, wrapper_func, x, 0, &thread_id);
if (thread_handle == NULL)
{
- gl_lock_unlock (running_lock);
+ DeleteCriticalSection (&x->handle_lock);
+ free (x);
return EAGAIN;
}
+ EnterCriticalSection (&x->handle_lock);
x->id = thread_id;
- x->handle = thread_handle;
- gl_lock_unlock (running_lock);
+ if (x->handle == NULL)
+ x->handle = thread_handle;
+ else
+ /* x->handle was already set by the thread itself. */
+ CloseHandle (thread_handle);
+ LeaveCriticalSection (&x->handle_lock);
*threadp = thread_id;
return 0;
}
/* Find the thread handle that corresponds to the thread id.
The thread argument must come from either the parent thread or from the
- thread itself. So at this point, either glthread_create_func was
- completed (and x->handle set), or x->func was invoked (and that can
- only be after the running_lock was acquired, hence after
- glthread_create_func released it, hence x->handle is set as well). */
+ thread itself. So at this point, either glthread_create_func or
+ wrapper_func (whichever was executed first) has filled in x->handle. */
thread_handle = NULL;
gl_lock_lock (running_lock);
{
/* Remove the 'struct thread_extra' from running_threads. */
gl_lock_lock (running_lock);
{
- struct thread_extra **xp;
+ struct thread_extra * volatile *xp;
for (xp = &running_threads; *xp != NULL; xp = &(*xp)->next)
if ((*xp)->id == thread)
{
if (x->handle != thread_handle)
abort ();
*xp = x->next;
+ DeleteCriticalSection (&x->handle_lock);
free (x);
break;
}