[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH]: update tls and lock tests to use newer glthread API
From: |
Bruno Haible |
Subject: |
Re: [PATCH]: update tls and lock tests to use newer glthread API |
Date: |
Wed, 1 Oct 2008 02:29:22 +0200 |
User-agent: |
KMail/1.5.4 |
Yoann Vandoorselaere wrote on 2008-09-15:
> > - Make 'lock-tests' and 'tls-tests' depend on the thread and yield
> > module, use YIELD_LIBS in place of the deprecated LIBSCHED variable, and
> > update 'lock-tests.c' and 'tls-tests.c' to use newer glthread API.
Doing this broke test-lock on mingw. But after reimplementing the 'thread'
module for win32, it works fine. So I'm first committing the corrected
'thread` module.
2008-09-30 Bruno Haible <address@hidden>
Fix the Win32 implementation of the 'thread' module.
* lib/glthread/thread.h [USE_WIN32_THREADS] (gl_thread_t): Change to a
pointer type.
(gl_thread_self): Invoke gl_thread_self_func.
(gl_thread_self_func): New declaration.
* lib/glthread/thread.c [USE_WIN32_THREADS] (self_key): New variable.
(do_init_self_key, init_self_key): New functions.
(struct gl_thread_struct): Renamed from 'struct thread_extra'.
Remove some fields.
(running_threads, running_lock): Remove variables.
(get_current_thread_handle): New function.
(gl_thread_self_func, wrapper_func, glthread_create_func,
glthread_join_func, gl_thread_exit_func): Largely rewritten and
simplified.
*** lib/glthread/thread.h.orig 2008-10-01 02:22:43.000000000 +0200
--- lib/glthread/thread.h 2008-10-01 01:50:19.000000000 +0200
***************
*** 277,289 ****
/* -------------------------- gl_thread_t datatype --------------------------
*/
! /* The gl_thread_t is the thread id, not the thread handle. If it were the
! thread handle, it would be hard to implement gl_thread_self()
! (since GetCurrentThread () returns a pseudo-handle,
! DuplicateHandle (GetCurrentThread ()) returns a handle that must be closed
! afterwards, and there is no function for quickly retrieving a thread handle
! from its id). */
! typedef DWORD gl_thread_t;
# define glthread_create(THREADP, FUNC, ARG) \
glthread_create_func (THREADP, FUNC, ARG)
# define glthread_sigmask(HOW, SET, OSET) \
--- 277,292 ----
/* -------------------------- gl_thread_t datatype --------------------------
*/
! /* The gl_thread_t is a pointer to a structure in memory.
! Why not the thread handle? If it were the thread handle, it would be hard
! to implement gl_thread_self() (since GetCurrentThread () returns a pseudo-
! handle, DuplicateHandle (GetCurrentThread ()) returns a handle that must be
! closed afterwards, and there is no function for quickly retrieving a thread
! handle from its id).
! Why not the thread id? I tried it. It did not work: Sometimes ids
appeared
! that did not belong to running threads, and glthread_join failed with
ESRCH.
! */
! typedef struct gl_thread_struct *gl_thread_t;
# define glthread_create(THREADP, FUNC, ARG) \
glthread_create_func (THREADP, FUNC, ARG)
# define glthread_sigmask(HOW, SET, OSET) \
***************
*** 291,302 ****
# define glthread_join(THREAD, RETVALP) \
glthread_join_func (THREAD, RETVALP)
# define gl_thread_self() \
! GetCurrentThreadId ()
# define gl_thread_exit(RETVAL) \
gl_thread_exit_func (RETVAL)
# define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
extern int glthread_create_func (gl_thread_t *threadp, void * (*func) (void
*), void *arg);
extern int glthread_join_func (gl_thread_t thread, void **retvalp);
extern int gl_thread_exit_func (void *retval);
# ifdef __cplusplus
--- 294,306 ----
# define glthread_join(THREAD, RETVALP) \
glthread_join_func (THREAD, RETVALP)
# define gl_thread_self() \
! gl_thread_self_func ()
# define gl_thread_exit(RETVAL) \
gl_thread_exit_func (RETVAL)
# define glthread_atfork(PREPARE_FUNC, PARENT_FUNC, CHILD_FUNC) 0
extern int glthread_create_func (gl_thread_t *threadp, void * (*func) (void
*), void *arg);
extern int glthread_join_func (gl_thread_t thread, void **retvalp);
+ extern gl_thread_t gl_thread_self_func (void);
extern int gl_thread_exit_func (void *retval);
# ifdef __cplusplus
*** lib/glthread/thread.c.orig 2008-10-01 02:22:43.000000000 +0200
--- lib/glthread/thread.c 2008-10-01 02:21:31.000000000 +0200
***************
*** 21,26 ****
--- 21,27 ----
#include <config.h>
+ /* Specification. */
#include "glthread/thread.h"
#include <stdlib.h>
***************
*** 32,126 ****
/* -------------------------- gl_thread_t datatype --------------------------
*/
! /* Use a wrapper function, instead of adding WINAPI through a cast.
! This struct also holds the thread's exit value. */
! struct thread_extra
! {
! /* 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;
! /* Fields for managing the thread start. */
! void * (*func) (void *);
! void *arg;
! };
!
! /* Linked list of thread_extra of running or zombie (not-yet-joined)
! threads.
! TODO: Use a hash table indexed by id instead of a linked list. */
! static struct thread_extra *running_threads /* = NULL */;
! /* Lock protecting running_threads. */
! gl_lock_define_initialized(static, running_lock)
static DWORD WINAPI
wrapper_func (void *varg)
{
! 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 ()))
! abort ();
! xarg->next = running_threads;
! running_threads = xarg;
! gl_lock_unlock (running_lock);
/* Run the thread. Store the exit value if the thread was not terminated
otherwise. */
! xarg->result = xarg->func (xarg->arg);
return 0;
}
int
glthread_create_func (gl_thread_t *threadp, void * (*func) (void *), void
*arg)
{
! struct thread_extra *x =
! (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;
! thread_handle = CreateThread (NULL, 100000, wrapper_func, x, 0,
&thread_id);
if (thread_handle == NULL)
{
! DeleteCriticalSection (&x->handle_lock);
! free (x);
return EAGAIN;
}
! EnterCriticalSection (&x->handle_lock);
! x->id = thread_id;
! 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;
}
}
--- 33,180 ----
/* -------------------------- gl_thread_t datatype --------------------------
*/
! /* The Thread-Local Storage (TLS) key that allows to access each thread's
! 'struct gl_thread_struct *' pointer. */
! static DWORD self_key = (DWORD)-1;
!
! /* Initializes self_key. This function must only be called once. */
! static void
! do_init_self_key (void)
! {
! self_key = TlsAlloc ();
! /* If this fails, we're hosed. */
! if (self_key == (DWORD)-1)
! abort ();
! }
!
! /* Initializes self_key. */
! static void
! init_self_key (void)
! {
! gl_once_define(static, once)
! gl_once (once, do_init_self_key);
! }
!
! /* This structure contains information about a thread.
! It is stored in TLS under key self_key. */
! struct gl_thread_struct
! {
! /* Fields for managing the handle. */
! HANDLE volatile handle;
! CRITICAL_SECTION handle_lock;
! /* Fields for managing the exit value. */
! void * volatile result;
! /* Fields for managing the thread start. */
! void * (*func) (void *);
! void *arg;
! };
!
! /* Return a real HANDLE object for the current thread. */
! static inline HANDLE
! get_current_thread_handle (void)
! {
! HANDLE this_handle;
!
! /* GetCurrentThread() returns a pseudo-handle, i.e. only a symbolic
! identifier, not a real handle. */
! if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
! GetCurrentProcess (), &this_handle,
! 0, FALSE, DUPLICATE_SAME_ACCESS))
! abort ();
! return this_handle;
! }
! gl_thread_t
! gl_thread_self_func (void)
! {
! gl_thread_t thread;
+ if (self_key == (DWORD)-1)
+ init_self_key ();
+ thread = TlsGetValue (self_key);
+ if (thread == NULL)
+ {
+ /* This happens only in threads that have not been created through
+ glthread_create(), such as the main thread. */
+ for (;;)
+ {
+ thread =
+ (struct gl_thread_struct *)
+ malloc (sizeof (struct gl_thread_struct));
+ if (thread != NULL)
+ break;
+ /* Memory allocation failed. There is not much we can do. Have to
+ busy-loop, waiting for the availability of memory. */
+ Sleep (1);
+ }
+
+ thread->handle = get_current_thread_handle ();
+ InitializeCriticalSection (&thread->handle_lock);
+ thread->result = NULL; /* just to be deterministic */
+ TlsSetValue (self_key, thread);
+ }
+ return thread;
+ }
+
+ /* The main function of a freshly creating thread. It's a wrapper around
+ the FUNC and ARG arguments passed to glthread_create_func. */
static DWORD WINAPI
wrapper_func (void *varg)
{
! struct gl_thread_struct *thread = (struct gl_thread_struct *)varg;
! EnterCriticalSection (&thread->handle_lock);
/* Create a new handle for the thread only if the parent thread did not yet
fill in the handle. */
! if (thread->handle == NULL)
! thread->handle = get_current_thread_handle ();
! LeaveCriticalSection (&thread->handle_lock);
!
! if (self_key == (DWORD)-1)
! init_self_key ();
! TlsSetValue (self_key, thread);
/* Run the thread. Store the exit value if the thread was not terminated
otherwise. */
! thread->result = thread->func (thread->arg);
return 0;
}
int
glthread_create_func (gl_thread_t *threadp, void * (*func) (void *), void
*arg)
{
! struct gl_thread_struct *thread =
! (struct gl_thread_struct *) malloc (sizeof (struct gl_thread_struct));
! if (thread == NULL)
return ENOMEM;
! thread->handle = NULL;
! InitializeCriticalSection (&thread->handle_lock);
! thread->result = NULL; /* just to be deterministic */
! thread->func = func;
! thread->arg = arg;
!
{
DWORD thread_id;
HANDLE thread_handle;
! thread_handle =
! CreateThread (NULL, 100000, wrapper_func, thread, 0, &thread_id);
if (thread_handle == NULL)
{
! DeleteCriticalSection (&thread->handle_lock);
! free (thread);
return EAGAIN;
}
!
! EnterCriticalSection (&thread->handle_lock);
! if (thread->handle == NULL)
! thread->handle = thread_handle;
else
! /* thread->handle was already set by the thread itself. */
CloseHandle (thread_handle);
! LeaveCriticalSection (&thread->handle_lock);
!
! *threadp = thread;
return 0;
}
}
***************
*** 128,181 ****
int
glthread_join_func (gl_thread_t thread, void **retvalp)
{
! HANDLE thread_handle;
if (thread == gl_thread_self ())
return EDEADLK;
! /* 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 or
! wrapper_func (whichever was executed first) has filled in x->handle. */
! thread_handle = NULL;
! gl_lock_lock (running_lock);
! {
! struct thread_extra *x;
! for (x = running_threads; x != NULL; x = x->next)
! if (x->id == thread)
! {
! thread_handle = x->handle;
! break;
! }
! }
! gl_lock_unlock (running_lock);
! if (thread_handle == NULL)
! return ESRCH;
!
! if (WaitForSingleObject (thread_handle, INFINITE) == WAIT_FAILED)
return EINVAL;
! /* Remove the 'struct thread_extra' from running_threads. */
! gl_lock_lock (running_lock);
! {
! struct thread_extra * volatile *xp;
! for (xp = &running_threads; *xp != NULL; xp = &(*xp)->next)
! if ((*xp)->id == thread)
! {
! struct thread_extra *x = *xp;
! if (retvalp != NULL)
! *retvalp = x->result;
! if (x->handle != thread_handle)
! abort ();
! *xp = x->next;
! DeleteCriticalSection (&x->handle_lock);
! free (x);
! break;
! }
! }
! gl_lock_unlock (running_lock);
! CloseHandle (thread_handle);
return 0;
}
--- 182,202 ----
int
glthread_join_func (gl_thread_t thread, void **retvalp)
{
! if (thread == NULL)
! return EINVAL;
if (thread == gl_thread_self ())
return EDEADLK;
! if (WaitForSingleObject (thread->handle, INFINITE) == WAIT_FAILED)
return EINVAL;
! if (retvalp != NULL)
! *retvalp = thread->result;
! DeleteCriticalSection (&thread->handle_lock);
! CloseHandle (thread->handle);
! free (thread);
return 0;
}
***************
*** 183,203 ****
int
gl_thread_exit_func (void *retval)
{
! DWORD this_thread = GetCurrentThreadId ();
!
! /* Store the exit value in the appropriate element of running_threads. */
! gl_lock_lock (running_lock);
! {
! struct thread_extra *x;
! for (x = running_threads; x != NULL; x = x->next)
! if (x->id == this_thread)
! {
! x->result = retval;
! break;
! }
! }
! gl_lock_unlock (running_lock);
!
ExitThread (0);
}
--- 204,211 ----
int
gl_thread_exit_func (void *retval)
{
! gl_thread_t thread = gl_thread_self ();
! thread->result = retval;
ExitThread (0);
}
- [PATCH]: update tls and lock tests to use newer glthread API, Yoann Vandoorselaere, 2008/09/14
- Re: [PATCH]: update tls and lock tests to use newer glthread API, Yoann Vandoorselaere, 2008/09/15
- Re: [PATCH]: update tls and lock tests, gl_cond_t WIN32 implementation, Yoann Vandoorselaere, 2008/09/18
- Re: [PATCH]: update tls and lock tests to use newer glthread API,
Bruno Haible <=
- Re: [PATCH]: update tls and lock tests to use newer glthread API, Bruno Haible, 2008/09/30
- Re: [PATCH]: update tls and lock tests to use newer glthread API, Bruno Haible, 2008/09/30
- Re: [PATCH]: update tls and lock tests to use newer glthread API, Bruno Haible, 2008/09/30