From d6ed8e36e78373329315d743743c7480724e87ef Mon Sep 17 00:00:00 2001 From: Sebastian Wilhelmi Date: Tue, 22 May 2001 12:28:06 +0000 Subject: [PATCH] Removed POSIX_*. Defined G_THREAD_SOURCE to "gthread-win32.c". 2001-05-22 Sebastian Wilhelmi * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to "gthread-win32.c". * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't know about MSC. Define G_THREADS_IMPL_WIN32 instead of G_THREADS_IMPL_POSIX and define the right static mutex macros and types. * build/win32/make.mingw (CXX): Removed PTHREAD defs. Added -O2 -Wall to compile flags. * gthread/gthread-impl.c (g_thread_init): Move the thread implementation initialization to before assigning GThreadFuncs, which now is just struct assigned and not memcpy'ed. Completed check for zero members of GThreadFuncs. * gthread/makefile.mingw: Don't link to pthread anymore. * gthread/gthread-win32.c: New file for native thread support for win32. Thanks to Hans Breuer to got me kickstarted. * gthread/Makefile.am: Also distribute gthread-win32.c. --- ChangeLog | 8 + ChangeLog.pre-2-0 | 8 + ChangeLog.pre-2-10 | 8 + ChangeLog.pre-2-12 | 8 + ChangeLog.pre-2-2 | 8 + ChangeLog.pre-2-4 | 8 + ChangeLog.pre-2-6 | 8 + ChangeLog.pre-2-8 | 8 + config.h.win32.in | 6 +- glibconfig.h.win32.in | 42 +--- gthread/ChangeLog | 15 ++ gthread/Makefile.am | 1 + gthread/gthread-impl.c | 33 +-- gthread/gthread-win32.c | 567 ++++++++++++++++++++++++++++++++++++++++++++++ gthread/makefile.mingw.in | 3 +- 15 files changed, 671 insertions(+), 60 deletions(-) create mode 100644 gthread/gthread-win32.c diff --git a/ChangeLog b/ChangeLog index 8244509..cd6afb2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 8244509..cd6afb2 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 8244509..cd6afb2 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 8244509..cd6afb2 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 8244509..cd6afb2 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 8244509..cd6afb2 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 8244509..cd6afb2 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 8244509..cd6afb2 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,5 +1,13 @@ 2001-05-22 Sebastian Wilhelmi + * config.h.win32.in: Removed POSIX_*. Defined G_THREAD_SOURCE to + "gthread-win32.c". + + * glibconfig.h.win32.in: Define G_HAVE_ISO_VARARGS for gcc, don't + know about MSC. Define G_THREADS_IMPL_WIN32 instead of + G_THREADS_IMPL_POSIX and define the right static mutex macros and + types. + * glib.def: g_thread_create renamed to g_thread_create_full. * gthread.c: memcpy is not necessary here. We can simply use diff --git a/config.h.win32.in b/config.h.win32.in index 6e8f1a8..e98a9cd 100644 --- a/config.h.win32.in +++ b/config.h.win32.in @@ -66,11 +66,7 @@ #define GLIB_SIZEOF_PTRDIFF_T 4 #define GLIB_SIZEOF_INTMAX_T 4 -#define POSIX_MIN_PRIORITY -2 -#define POSIX_MAX_PRIORITY 2 -#define POSIX_YIELD_FUNC Sleep(0) - -#define G_THREAD_SOURCE "gthread-posix.c" +#define G_THREAD_SOURCE "gthread-win32.c" /* The number of bytes in a char. */ #define SIZEOF_CHAR 1 diff --git a/glibconfig.h.win32.in b/glibconfig.h.win32.in index e870068..4cdea83 100644 --- a/glibconfig.h.win32.in +++ b/glibconfig.h.win32.in @@ -74,6 +74,7 @@ typedef unsigned __int64 guint64; typedef long long gint64; typedef unsigned long long guint64; #define G_GINT64_CONSTANT(val) (val##LL) +#define G_HAVE_ISO_VARARGS 1 #endif /* These depend on the C library. Using this file means the we @@ -112,43 +113,10 @@ typedef guint32 gsize; #endif #define G_THREADS_ENABLED -/* - * The following program can be used to determine the magic values below: - * #include - * #include - * main(int argc, char **argv) - * { - * int i; - * pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; - * printf ("sizeof (pthread_mutex_t) = %d\n", sizeof (pthread_mutex_t)); - * printf ("sizeof (pthread_t) = %d\n", sizeof (pthread_t)); - * printf ("PTHREAD_MUTEX_INITIALIZER = "); - * for (i = 0; i < sizeof (pthread_mutex_t); i++) - * printf ("%u, ", ((unsigned char *) &m)[i]); - * printf ("\n"); - * exit(0); - * } - */ - -#define G_THREADS_IMPL_POSIX -typedef struct _GStaticMutex GStaticMutex; -struct _GStaticMutex -{ - struct _GMutex *runtime_mutex; - union { - /* The size of the pad array should be sizeof (pthread_mutex_t) */ - /* This value corresponds to the 1999-05-30 version of pthreads-win32 */ - char pad[4]; - double dummy_double; - void *dummy_pointer; - long dummy_long; - } static_mutex; -}; -/* This should be NULL followed by the bytes in PTHREAD_MUTEX_INITIALIZER */ -#define G_STATIC_MUTEX_INIT { NULL, { { 255, 255, 255, 255 } } } -#define g_static_mutex_get_mutex(mutex) \ - (g_thread_use_default_impl ? ((GMutex*) &((mutex)->static_mutex)) : \ - g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex))) +#define G_THREADS_IMPL_WIN32 +typedef struct _GMutex* GStaticMutex; +#define G_STATIC_MUTEX_INIT NULL +#define g_static_mutex_get_mutex(mutex) (g_static_mutex_get_mutex_impl (mutex)) /* This represents a system thread as used by the implementation. An * alien implementaion, as loaded by g_thread_init can only count on * "sizeof (gpointer)" bytes to store their info. We however need more diff --git a/gthread/ChangeLog b/gthread/ChangeLog index adfc286..b40f8c9 100644 --- a/gthread/ChangeLog +++ b/gthread/ChangeLog @@ -1,3 +1,18 @@ +2001-05-22 Sebastian Wilhelmi + + * gthread-impl.c (g_thread_init): Move the thread implementation + initialization to before assigning GThreadFuncs, which now is just + struct assigned and not memcpy'ed. Completed check for zero + members of GThreadFuncs. + + * makefile.mingw: Don't link to pthread anymore. + + * gthread-win32.c: New file for native thread support for + win32. Thanks to Hans Breuer to got me + kickstarted. + + * Makefile.am: Also distribute gthread-win32.c. + Fri May 4 04:14:45 2001 Tim Janik * gthread-posix.c (g_cond_timed_wait_posix_impl): don't g_assert() diff --git a/gthread/Makefile.am b/gthread/Makefile.am index 4780748..9950690 100644 --- a/gthread/Makefile.am +++ b/gthread/Makefile.am @@ -9,6 +9,7 @@ EXTRA_DIST = \ makefile.msc.in \ gthread-posix.c \ gthread-solaris.c \ + gthread-win32.c \ gthread-none.c \ gthread.def \ gthread.rc.in diff --git a/gthread/gthread-impl.c b/gthread/gthread-impl.c index a00012c..03c710c 100644 --- a/gthread/gthread-impl.c +++ b/gthread/gthread-impl.c @@ -314,19 +314,23 @@ g_thread_init (GThreadFunctions* init) thread_system_already_initialized = TRUE; if (init == NULL) - init = &g_thread_functions_for_glib_use_default; + { +#ifdef HAVE_G_THREAD_IMPL_INIT + /* now do any initialization stuff required by the + * implementation, but only if called with a NULL argument, of + * course. Otherwise it's up to the user to do so. */ + g_thread_impl_init(); +#endif /* HAVE_G_THREAD_IMPL_INIT */ + init = &g_thread_functions_for_glib_use_default; + } else g_thread_use_default_impl = FALSE; -#if defined (G_PLATFORM_WIN32) && defined (__GNUC__) - memcpy(&g_thread_functions_for_glib_use, init, sizeof (*init)); -#else g_thread_functions_for_glib_use = *init; -#endif + /* It is important, that g_threads_got_initialized is not set before the * thread initialization functions of the different modules are called */ - supported = (init->mutex_new && init->mutex_lock && init->mutex_trylock && @@ -340,7 +344,13 @@ g_thread_init (GThreadFunctions* init) init->cond_free && init->private_new && init->private_get && - init->private_get); + init->private_get && + init->thread_create && + init->thread_yield && + init->thread_join && + init->thread_exit && + init->thread_set_priority && + init->thread_self); /* if somebody is calling g_thread_init (), it means that he wants to * have thread support, so check this @@ -353,15 +363,6 @@ g_thread_init (GThreadFunctions* init) g_error ("The supplied thread function vector is invalid."); } - /* now do any initialization stuff required by the implementation, - * but only if called with a NULL argument, of course. Otherwise - * it's up to the user to do so. */ - -#ifdef HAVE_G_THREAD_IMPL_INIT - if (g_thread_use_default_impl) - g_thread_impl_init(); -#endif - g_thread_priority_map [G_THREAD_PRIORITY_LOW] = PRIORITY_LOW_VALUE; g_thread_priority_map [G_THREAD_PRIORITY_NORMAL] = PRIORITY_NORMAL_VALUE; g_thread_priority_map [G_THREAD_PRIORITY_HIGH] = PRIORITY_HIGH_VALUE; diff --git a/gthread/gthread-win32.c b/gthread/gthread-win32.c new file mode 100644 index 0000000..17b9eea --- /dev/null +++ b/gthread/gthread-win32.c @@ -0,0 +1,567 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gthread.c: solaris thread system implementation + * Copyright 1998-2001 Sebastian Wilhelmi; University of Karlsruhe + * Copyright 2001 Hans Breuer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * MT safe + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#define STRICT +#include +#undef STRICT + +#include +#include + +#define win32_check_for_error(what) G_STMT_START{ \ + if (!(what)) \ + g_error ("file %s: line %d (%s): error %ld during %s", \ + __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \ + GetLastError (), #what); \ + }G_STMT_END + +#define G_MUTEX_SIZE (sizeof (HANDLE)) + +#define PRIORITY_LOW_VALUE THREAD_PRIORITY_BELOW_NORMAL +#define PRIORITY_NORMAL_VALUE THREAD_PRIORITY_NORMAL +#define PRIORITY_HIGH_VALUE THREAD_PRIORITY_ABOVE_NORMAL +#define PRIORITY_URGENT_VALUE THREAD_PRIORITY_HIGHEST + +static DWORD g_thread_self_tls; +static DWORD g_private_tls; +static DWORD g_cond_event_tls; +static CRITICAL_SECTION g_thread_global_spinlock; + +typedef BOOL (__stdcall *GTryEnterCriticalSectionFunc) (CRITICAL_SECTION *); + +static GTryEnterCriticalSectionFunc try_enter_critical_section = NULL; + +/* As noted in the docs, GPrivate is a limited resource, here we take + * a rather low maximum to save memory, use GStaticPrivate instead. */ +#define G_PRIVATE_MAX 16 + +static GDestroyNotify g_private_destructors[G_PRIVATE_MAX]; + +static guint g_private_next = 0; + +typedef struct _GThreadData GThreadData; +struct _GThreadData +{ + GThreadFunc func; + gpointer data; + HANDLE thread; + gboolean joinable; +}; + +struct _GCond +{ + GPtrArray *array; + CRITICAL_SECTION lock; +}; + +static GMutex * +g_mutex_new_win32_cs_impl (void) +{ + CRITICAL_SECTION *retval = g_new (CRITICAL_SECTION, 1); + InitializeCriticalSection (retval); + return (GMutex *) retval; +} + +static void +g_mutex_free_win32_cs_impl (GMutex *mutex) +{ + g_free (mutex); +} + +/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use + functions from gmem.c and gmessages.c; */ + +static void +g_mutex_lock_win32_cs_impl (GMutex *mutex) +{ + EnterCriticalSection ((CRITICAL_SECTION *)mutex); +} + +static gboolean +g_mutex_trylock_win32_cs_impl (GMutex * mutex) +{ + return try_enter_critical_section ((CRITICAL_SECTION *)mutex); +} + +static void +g_mutex_unlock_win32_cs_impl (GMutex *mutex) +{ + LeaveCriticalSection ((CRITICAL_SECTION *)mutex); +} + +static GMutex * +g_mutex_new_win32_impl (void) +{ + HANDLE handle; + win32_check_for_error (handle = CreateMutex (NULL, FALSE, NULL)); + return (GMutex *) handle; +} + +static void +g_mutex_free_win32_impl (GMutex *mutex) +{ + win32_check_for_error (CloseHandle ((HANDLE) mutex)); +} + +/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use + functions from gmem.c and gmessages.c; */ + +static void +g_mutex_lock_win32_impl (GMutex *mutex) +{ + WaitForSingleObject ((HANDLE) mutex, INFINITE); +} + +static gboolean +g_mutex_trylock_win32_impl (GMutex * mutex) +{ + DWORD result; + win32_check_for_error (WAIT_FAILED != + (result = WaitForSingleObject ((HANDLE)mutex, 0))); + return result != WAIT_TIMEOUT; +} + +static void +g_mutex_unlock_win32_impl (GMutex *mutex) +{ + ReleaseMutex ((HANDLE) mutex); +} + +static GCond * +g_cond_new_win32_impl (void) +{ + GCond *retval = g_new (GCond, 1); + + retval->array = g_ptr_array_new (); + InitializeCriticalSection (&retval->lock); + + return retval; +} + +static void +g_cond_signal_win32_impl (GCond * cond) +{ + EnterCriticalSection (&cond->lock); + + if (cond->array->len > 0) + { + SetEvent (g_ptr_array_index (cond->array, 0)); + g_ptr_array_remove_index (cond->array, 0); + } + + LeaveCriticalSection (&cond->lock); +} + +static void +g_cond_broadcast_win32_impl (GCond * cond) +{ + guint i; + EnterCriticalSection (&cond->lock); + + for (i = 0; i < cond->array->len; i++) + SetEvent (g_ptr_array_index (cond->array, i)); + + g_ptr_array_set_size (cond->array, 0); + LeaveCriticalSection (&cond->lock); +} + +static gboolean +g_cond_wait_internal (GCond *cond, + GMutex *entered_mutex, + gulong milliseconds) +{ + gulong retval; + HANDLE event = TlsGetValue (g_cond_event_tls); + + if (!event) + { + win32_check_for_error (event = CreateEvent (0, FALSE, FALSE, NULL)); + TlsSetValue (g_cond_event_tls, event); + } + + EnterCriticalSection (&cond->lock); + + /* The event must not be signaled. Check this */ + g_assert (WaitForSingleObject (event, 0) == WAIT_TIMEOUT); + + g_ptr_array_add (cond->array, event); + LeaveCriticalSection (&cond->lock); + + g_mutex_unlock (entered_mutex); + + win32_check_for_error (WAIT_FAILED != + (retval = WaitForSingleObject (event, milliseconds))); + + g_mutex_lock (entered_mutex); + + if (retval == WAIT_TIMEOUT) + { + EnterCriticalSection (&cond->lock); + g_ptr_array_remove (cond->array, event); + + /* In the meantime we could have been signaled, so we must again + * wait for the signal, this time with no timeout, to reset it */ + win32_check_for_error (WAIT_FAILED != WaitForSingleObject (event, 0)); + + LeaveCriticalSection (&cond->lock); + } + +#ifndef G_DISABLE_ASSERT + EnterCriticalSection (&cond->lock); + + /* Now event must not be inside the array, check this */ + g_assert (g_ptr_array_remove (cond->array, event) == FALSE); + + LeaveCriticalSection (&cond->lock); +#endif /* !G_DISABLE_ASSERT */ + + return retval != WAIT_TIMEOUT; +} + +static void +g_cond_wait_win32_impl (GCond *cond, + GMutex *entered_mutex) +{ + g_return_if_fail (cond != NULL); + g_return_if_fail (entered_mutex != NULL); + + g_cond_wait_internal (cond, entered_mutex, INFINITE); +} + +static gboolean +g_cond_timed_wait_win32_impl (GCond *cond, + GMutex *entered_mutex, + GTimeVal *abs_time) +{ + GTimeVal current_time; + gulong to_wait; + + g_return_val_if_fail (cond != NULL, FALSE); + g_return_val_if_fail (entered_mutex != NULL, FALSE); + + g_get_current_time (¤t_time); + to_wait = (abs_time->tv_sec - current_time.tv_sec) * 1000 + + (abs_time->tv_usec - current_time.tv_usec) / 1000; + + return g_cond_wait_internal (cond, entered_mutex, to_wait); +} + +static void +g_cond_free_win32_impl (GCond * cond) +{ + g_ptr_array_free (cond->array, TRUE); + g_free (cond); +} + +static GPrivate * +g_private_new_win32_impl (GDestroyNotify destructor) +{ + GPrivate *result; + EnterCriticalSection (&g_thread_global_spinlock); + if (g_private_next >= G_PRIVATE_MAX) + g_error ("Too many GPrivate allocated. Their number is limited to %d.\n" + "Use GStaticPrivate instead.\n", G_PRIVATE_MAX); + g_private_destructors[g_private_next] = destructor; + result = GUINT_TO_POINTER (g_private_next); + g_private_next++; + LeaveCriticalSection (&g_thread_global_spinlock); + + return result; +} + +/* NOTE: the functions g_private_get and g_private_set may not use + functions from gmem.c and gmessages.c */ + +static void +g_private_set_win32_impl (GPrivate * private_key, gpointer value) +{ + gpointer* array = TlsGetValue (g_private_tls); + guint index = GPOINTER_TO_UINT (private_key); + + if (index >= G_PRIVATE_MAX) + return; + + if (!array) + { + array = (gpointer*) calloc (G_PRIVATE_MAX, sizeof (gpointer)); + TlsSetValue (g_private_tls, array); + } + + array[index] = value; +} + +static gpointer +g_private_get_win32_impl (GPrivate * private_key) +{ + gpointer* array = TlsGetValue (g_private_tls); + guint index = GPOINTER_TO_UINT (private_key); + + if (index >= G_PRIVATE_MAX || !array) + return NULL; + + return array[index]; +} + +static void +g_thread_set_priority_win32_impl (gpointer thread, GThreadPriority priority) +{ + GThreadData *target = *(GThreadData **)thread; + + g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW); + g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT); + + win32_check_for_error (SetThreadPriority (target->thread, + g_thread_priority_map [priority])); +} + +static void +g_thread_self_win32_impl (gpointer thread) +{ + GThreadData *self = TlsGetValue (g_thread_self_tls); + + if (!self) + { + /* This should only happen for the main thread! */ + HANDLE handle = GetCurrentThread (); + HANDLE process = GetCurrentProcess (); + self = g_new (GThreadData, 1); + win32_check_for_error (DuplicateHandle (process, handle, process, + &self->thread, 0, FALSE, + DUPLICATE_SAME_ACCESS)); + win32_check_for_error (TlsSetValue (g_thread_self_tls, self)); + self->func = NULL; + self->data = NULL; + self->joinable = FALSE; + } + + *(GThreadData **)thread = self; +} + +static void +g_thread_exit_win32_impl (void) +{ + GThreadData *self = TlsGetValue (g_thread_self_tls); + guint i, private_max; + gpointer *array = TlsGetValue (g_private_tls); + HANDLE event = TlsGetValue (g_cond_event_tls); + + EnterCriticalSection (&g_thread_global_spinlock); + private_max = g_private_next; + LeaveCriticalSection (&g_thread_global_spinlock); + + if (array) + { + for (i = 0; i < private_max; i++) + { + GDestroyNotify destructor = g_private_destructors[i]; + GDestroyNotify data = array[i]; + if (destructor && data) + destructor (data); + } + + g_free (array); + + win32_check_for_error (TlsSetValue (g_private_tls, NULL)); + } + + if (self) + { + if (!self->joinable) + { + win32_check_for_error (CloseHandle (self->thread)); + g_free (self); + } + win32_check_for_error (TlsSetValue (g_thread_self_tls, NULL)); + } + + if (event) + { + CloseHandle (event); + win32_check_for_error (TlsSetValue (g_cond_event_tls, NULL)); + } + + _endthreadex (0); +} + +static guint __stdcall +g_thread_proxy (gpointer data) +{ + GThreadData *self = (GThreadData*) data; + + win32_check_for_error (TlsSetValue (g_thread_self_tls, self)); + + self->func (self->data); + + g_thread_exit_win32_impl (); + + g_assert_not_reached (); + + return 0; +} + +static void +g_thread_create_win32_impl (GThreadFunc func, + gpointer data, + gulong stack_size, + gboolean joinable, + gboolean bound, + GThreadPriority priority, + gpointer thread, + GError **error) +{ + guint ignore; + GThreadData *retval; + + g_return_if_fail (func); + g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW); + g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT); + + retval = g_new(GThreadData, 1); + retval->func = func; + retval->data = data; + + retval->joinable = joinable; + + retval->thread = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_proxy, + retval, 0, &ignore); + + if (retval->thread == NULL) + { + g_free (retval); + g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN, + "Error creating thread: %ld", GetLastError()); + return; + } + + *(GThreadData **)thread = retval; + + g_thread_set_priority_win32_impl (thread, priority); +} + +static void +g_thread_yield_win32_impl (void) +{ + Sleep(0); +} + +static void +g_thread_join_win32_impl (gpointer thread) +{ + GThreadData *target = *(GThreadData **)thread; + + g_return_if_fail (target->joinable); + + win32_check_for_error (WAIT_FAILED != + WaitForSingleObject (target->thread, INFINITE)); + + win32_check_for_error (CloseHandle (target->thread)); + g_free (target); +} + +static GThreadFunctions g_thread_functions_for_glib_use_default = +{ + g_mutex_new_win32_impl, /* mutex */ + g_mutex_lock_win32_impl, + g_mutex_trylock_win32_impl, + g_mutex_unlock_win32_impl, + g_mutex_free_win32_impl, + g_cond_new_win32_impl, /* condition */ + g_cond_signal_win32_impl, + g_cond_broadcast_win32_impl, + g_cond_wait_win32_impl, + g_cond_timed_wait_win32_impl, + g_cond_free_win32_impl, + g_private_new_win32_impl, /* private thread data */ + g_private_get_win32_impl, + g_private_set_win32_impl, + g_thread_create_win32_impl, /* thread */ + g_thread_yield_win32_impl, + g_thread_join_win32_impl, + g_thread_exit_win32_impl, + g_thread_set_priority_win32_impl, + g_thread_self_win32_impl +}; + +#define HAVE_G_THREAD_IMPL_INIT +static void +g_thread_impl_init () +{ + HMODULE kernel32; + + win32_check_for_error (TLS_OUT_OF_INDEXES != + (g_thread_self_tls = TlsAlloc ())); + win32_check_for_error (TLS_OUT_OF_INDEXES != + (g_private_tls = TlsAlloc ())); + win32_check_for_error (TLS_OUT_OF_INDEXES != + (g_cond_event_tls = TlsAlloc ())); + InitializeCriticalSection (&g_thread_global_spinlock); + + /* Here we are looking for TryEnterCriticalSection in KERNEL32.DLL, + * if it is found, we can use the faster critical sections instead + * of mutexes. Note however that + * http://www2.awl.com/cseng/titles/0-201-63465-1/csmutx.htm indicates, + * that critical sections might not be ideal after all on SMP machines */ + kernel32 = GetModuleHandle ("KERNEL32.DLL"); + if (kernel32) + { + try_enter_critical_section = (GTryEnterCriticalSectionFunc) + GetProcAddress(kernel32, "TryEnterCriticalSection"); + + /* Even if TryEnterCriticalSection is found, it is not + * necessarily working..., we have to check it */ + if (try_enter_critical_section && + try_enter_critical_section (&g_thread_global_spinlock)) + { + LeaveCriticalSection (&g_thread_global_spinlock); + + g_thread_functions_for_glib_use_default.mutex_new = + g_mutex_new_win32_cs_impl; + g_thread_functions_for_glib_use_default.mutex_lock = + g_mutex_lock_win32_cs_impl; + g_thread_functions_for_glib_use_default.mutex_trylock = + g_mutex_trylock_win32_cs_impl; + g_thread_functions_for_glib_use_default.mutex_unlock = + g_mutex_unlock_win32_cs_impl; + g_thread_functions_for_glib_use_default.mutex_free = + g_mutex_free_win32_cs_impl; + } + } +} + diff --git a/gthread/makefile.mingw.in b/gthread/makefile.mingw.in index c3757bb..d1adee3 100644 --- a/gthread/makefile.mingw.in +++ b/gthread/makefile.mingw.in @@ -16,7 +16,6 @@ GLIB_VER = @GLIB_MAJOR_VERSION@.@GLIB_MINOR_VERSION@ INCLUDES = -I .. -I . DEFINES = -DHAVE_CONFIG_H -DG_LOG_DOMAIN=\"GThread\" -DG_ENABLE_DEBUG -DEPCFLAGS = $(PTHREAD_CFLAGS) BUILD_DLL = ../build-dll @@ -33,4 +32,4 @@ gthread_OBJECTS = \ gthread-impl.o gthread-$(GLIB_VER).dll : $(gthread_OBJECTS) gthread.def - $(BUILD_DLL) gthread $(GLIB_VER) gthread.def $(gthread_OBJECTS) -L .. -lglib-$(GLIB_VER) $(PTHREAD_LIBS) + $(BUILD_DLL) gthread $(GLIB_VER) gthread.def $(gthread_OBJECTS) -L .. -lglib-$(GLIB_VER) -- 2.7.4