[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: checkin of glthread/glcond modules
From: |
Bruno Haible |
Subject: |
Re: checkin of glthread/glcond modules |
Date: |
Mon, 18 Aug 2008 02:23:10 +0200 |
User-agent: |
KMail/1.5.4 |
Here is the Win32 implementation of the thread module.
Please review it; it's quite complicated. The complexity comes from
1. the need to have a 'void *' as thread exit value, where Win32 only
manages a 32-bit value,
2. weird thread APIs: In Win32, every thread has an id and multiple handles.
But It's hard to get a handle for the current thread. And in order to
wait for a thread, you need one of its handles...
2008-08-17 Bruno Haible <address@hidden>
* lib/glthread/thread.c: New file, based on code from tests/test-lock.c.
* lib/glthread/thread.h: Provide Win32 specific implementation.
* modules/thread (Files): Add lib/glthread/thread.c.
(Depends-on): Add lock.
(Makefile.am): Add glthread/thread.c to lib_SOURCES.
*** lib/glthread/thread.c.orig 2003-09-23 19:59:22.000000000 +0200
--- lib/glthread/thread.c 2008-08-18 02:17:39.000000000 +0200
***************
*** 0 ****
--- 1,186 ----
+ /* Creating and controlling threads.
+ Copyright (C) 2005-2008 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+ /* Written by Bruno Haible <address@hidden>, 2005.
+ Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
+ gthr-win32.h. */
+
+ #include <config.h>
+
+ #include "glthread/thread.h"
+
+ #include <stdlib.h>
+ #include "glthread/lock.h"
+
+ /* =========================================================================
*/
+
+ #if USE_WIN32_THREADS
+
+ /* -------------------------- 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;
+ 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;
+
+ xarg->id = GetCurrentThreadId ();
+ /* 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->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);
+ return EAGAIN;
+ }
+ x->id = thread_id;
+ x->handle = thread_handle;
+ gl_lock_unlock (running_lock);
+ *threadp = thread_id;
+ return 0;
+ }
+ }
+
+ 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 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_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 **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;
+ free (x);
+ break;
+ }
+ }
+ gl_lock_unlock (running_lock);
+
+ CloseHandle (thread_handle);
+
+ return 0;
+ }
+
+ 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);
+ }
+
+ #endif
+
+ /* =========================================================================
*/
*** lib/glthread/thread.h.orig 2008-08-18 02:17:53.000000000 +0200
--- lib/glthread/thread.h 2008-08-18 02:16:32.000000000 +0200
***************
*** 267,272 ****
--- 267,312 ----
/* =========================================================================
*/
+ #if USE_WIN32_THREADS
+
+ # include <windows.h>
+
+ # ifdef __cplusplus
+ extern "C" {
+ # endif
+
+ /* -------------------------- 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) \
+ /* unsupported */ 0
+ # 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
+ }
+ # endif
+
+ #endif
+
+ /* =========================================================================
*/
+
#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS ||
USE_WIN32_THREADS)
/* Provide dummy implementation if threads are not supported. */
*** modules/thread.orig 2008-08-18 02:17:53.000000000 +0200
--- modules/thread 2008-08-18 00:55:28.000000000 +0200
***************
*** 3,18 ****
Files:
lib/glthread/thread.h
m4/thread.m4
Depends-on:
threadlib
configure.ac:
gl_THREAD
Makefile.am:
! lib_SOURCES += glthread/thread.h
Include:
"glthread/thread.h"
--- 3,20 ----
Files:
lib/glthread/thread.h
+ lib/glthread/thread.c
m4/thread.m4
Depends-on:
threadlib
+ lock
configure.ac:
gl_THREAD
Makefile.am:
! lib_SOURCES += glthread/thread.h glthread/thread.c
Include:
"glthread/thread.h"
- Re: checkin of glthread/glcond modules, (continued)
- Re: checkin of glthread/glcond modules, Yoann Vandoorselaere, 2008/08/13
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/14
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/17
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/17
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/17
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/17
- Re: checkin of glthread/glcond modules,
Bruno Haible <=
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/18
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/17
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/17
- Re: checkin of glthread/glcond modules, Bruno Haible, 2008/08/17