#include "config.h"
#include "gthread.h"
+#include "gthreadprivate.h"
-#define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
#include <windows.h>
#include <process.h>
*/
typedef struct
{
- void (* CallThisOnThreadExit) (void); /* fake */
-
- void (* InitializeSRWLock) (gpointer lock);
- void (* DeleteSRWLock) (gpointer lock); /* fake */
- void (* AcquireSRWLockExclusive) (gpointer lock);
- BOOLEAN (* TryAcquireSRWLockExclusive) (gpointer lock);
- void (* ReleaseSRWLockExclusive) (gpointer lock);
-
- void (* InitializeConditionVariable) (gpointer cond);
- void (* DeleteConditionVariable) (gpointer cond); /* fake */
- BOOL (* SleepConditionVariableSRW) (gpointer cond,
- gpointer lock,
- DWORD timeout,
- ULONG flags);
- void (* WakeAllConditionVariable) (gpointer cond);
- void (* WakeConditionVariable) (gpointer cond);
+ void (__stdcall * CallThisOnThreadExit) (void); /* fake */
+
+ void (__stdcall * InitializeSRWLock) (gpointer lock);
+ void (__stdcall * DeleteSRWLock) (gpointer lock); /* fake */
+ void (__stdcall * AcquireSRWLockExclusive) (gpointer lock);
+ BOOLEAN (__stdcall * TryAcquireSRWLockExclusive) (gpointer lock);
+ void (__stdcall * ReleaseSRWLockExclusive) (gpointer lock);
+
+ void (__stdcall * InitializeConditionVariable) (gpointer cond);
+ void (__stdcall * DeleteConditionVariable) (gpointer cond); /* fake */
+ BOOL (__stdcall * SleepConditionVariableSRW) (gpointer cond,
+ gpointer lock,
+ DWORD timeout,
+ ULONG flags);
+ void (__stdcall * WakeAllConditionVariable) (gpointer cond);
+ void (__stdcall * WakeConditionVariable) (gpointer cond);
} GThreadImplVtable;
static GThreadImplVtable g_thread_impl_vtable;
/* {{{1 GPrivate */
+typedef struct _GPrivateDestructor GPrivateDestructor;
+
+struct _GPrivateDestructor
+{
+ DWORD index;
+ GDestroyNotify notify;
+ GPrivateDestructor *next;
+};
+
+static GPrivateDestructor * volatile g_private_destructors;
+
+void
+g_private_init (GPrivate *key,
+ GDestroyNotify notify)
+{
+ GPrivateDestructor *destructor;
+
+ key->index = TlsAlloc ();
+
+ destructor = malloc (sizeof (GPrivateDestructor));
+ if G_UNLIKELY (destructor == NULL)
+ g_thread_abort (errno, "malloc");
+ destructor->index = key->index;
+ destructor->notify = notify;
+
+ do
+ destructor->next = g_private_destructors;
+ while (InterlockedCompareExchangePointer (&g_private_destructors, destructor->next, destructor) != destructor->next);
+
+ key->ready = TRUE;
+}
+
+gpointer
+g_private_get (GPrivate *key)
+{
+ if (!key->ready)
+ return key->single_value;
+
+ return TlsGetValue (key->index);
+}
+
+void
+g_private_set (GPrivate *key,
+ gpointer value)
+{
+ if (!key->ready)
+ {
+ key->single_value = value;
+ return;
+ }
+
+ TlsSetValue (key->index, value);
+}
+
+/* {{{1 GThread */
+
#include "glib.h"
#include "gthreadprivate.h"
static DWORD g_thread_self_tls;
static DWORD g_private_tls;
-static CRITICAL_SECTION g_thread_global_spinlock;
typedef BOOL (__stdcall *GTryEnterCriticalSectionFunc) (CRITICAL_SECTION *);
-/* 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 100
-
-static GDestroyNotify g_private_destructors[G_PRIVATE_MAX];
-
-static guint g_private_next = 0;
-
typedef struct _GThreadData GThreadData;
struct _GThreadData
{
gboolean joinable;
};
-static GPrivate *
-g_private_new_win32_impl (GDestroyNotify destructor)
-{
- GPrivate *result;
- EnterCriticalSection (&g_thread_global_spinlock);
- if (g_private_next >= G_PRIVATE_MAX)
- {
- char buf[100];
- sprintf (buf,
- "Too many GPrivate allocated. Their number is limited to %d.",
- G_PRIVATE_MAX);
- MessageBox (NULL, buf, NULL, MB_ICONERROR|MB_SETFOREGROUND);
- if (IsDebuggerPresent ())
- G_BREAKPOINT ();
- abort ();
- }
- 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];
-}
-
-/* {{{1 GThread */
static void
g_thread_set_priority_win32_impl (gpointer thread, GThreadPriority priority)
*(GThreadData **)thread = self;
}
-static void
-g_thread_exit_win32_impl (void)
+void
+g_system_thread_exit (void)
{
GThreadData *self = TlsGetValue (g_thread_self_tls);
- guint i, private_max;
- gpointer *array = TlsGetValue (g_private_tls);
-
- EnterCriticalSection (&g_thread_global_spinlock);
- private_max = g_private_next;
- LeaveCriticalSection (&g_thread_global_spinlock);
+ gboolean dtors_called;
- if (array)
+ do
{
- gboolean some_data_non_null;
-
- do {
- some_data_non_null = FALSE;
- for (i = 0; i < private_max; i++)
- {
- GDestroyNotify destructor = g_private_destructors[i];
- GDestroyNotify data = array[i];
-
- if (data)
- some_data_non_null = TRUE;
-
- array[i] = NULL;
-
- if (destructor && data)
- destructor (data);
- }
- } while (some_data_non_null);
-
- free (array);
-
- win32_check_for_error (TlsSetValue (g_private_tls, NULL));
+ GPrivateDestructor *dtor;
+
+ /* We go by the POSIX book on this one.
+ *
+ * If we call a destructor then there is a chance that some new
+ * TLS variables got set by code called in that destructor.
+ *
+ * Loop until nothing is left.
+ */
+ dtors_called = FALSE;
+
+ for (dtor = g_private_destructors; dtor; dtor = dtor->next)
+ {
+ gpointer value;
+
+ value = TlsGetValue (dtor->index);
+ if (value != NULL && dtor->notify != NULL)
+ {
+ /* POSIX says to clear this before the call */
+ TlsSetValue (dtor->index, NULL);
+ dtor->notify (value);
+ dtors_called = TRUE;
+ }
+ }
}
+ while (dtors_called);
if (self)
{
self->func (self->data);
- g_thread_exit_win32_impl ();
+ g_system_thread_exit ();
g_assert_not_reached ();
g_thread_set_priority_win32_impl (thread, priority);
}
-static void
-g_thread_yield_win32_impl (void)
+void
+g_thread_yield (void)
{
Sleep(0);
}
g_free (target);
}
+gboolean
+g_system_thread_equal (gpointer thread1,
+ gpointer thread2)
+{
+ return ((GSystemThread*)thread1)->dummy_pointer == ((GSystemThread*)thread2)->dummy_pointer;
+}
+
/* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */
-static DWORD g_thread_xp_waiter_tls;
static CRITICAL_SECTION g_thread_xp_lock;
+static DWORD g_thread_xp_waiter_tls;
/* {{{2 GThreadWaiter utility class for CONDITION_VARIABLE emulation */
typedef struct _GThreadXpWaiter GThreadXpWaiter;
return waiter;
}
-static void
+static void __stdcall
g_thread_xp_CallThisOnThreadExit (void)
{
GThreadXpWaiter *waiter;
CRITICAL_SECTION critical_section;
} GThreadSRWLock;
-static void
+static void __stdcall
g_thread_xp_InitializeSRWLock (gpointer mutex)
{
*(GThreadSRWLock * volatile *) mutex = NULL;
}
-static void
+static void __stdcall
g_thread_xp_DeleteSRWLock (gpointer mutex)
{
GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
}
}
-static GThreadSRWLock *
+static GThreadSRWLock * __stdcall
g_thread_xp_get_srwlock (GThreadSRWLock * volatile *lock)
{
GThreadSRWLock *result;
return result;
}
-static void
+static void __stdcall
g_thread_xp_AcquireSRWLockExclusive (gpointer mutex)
{
GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
EnterCriticalSection (&lock->critical_section);
}
-static BOOLEAN
+static BOOLEAN __stdcall
g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex)
{
GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
return TryEnterCriticalSection (&lock->critical_section);
}
-static void
+static void __stdcall
g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex)
{
GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
volatile GThreadXpWaiter **last_ptr;
} GThreadXpCONDITION_VARIABLE;
-static void
+static void __stdcall
g_thread_xp_InitializeConditionVariable (gpointer cond)
{
*(GThreadXpCONDITION_VARIABLE * volatile *) cond = NULL;
}
-static void
+static void __stdcall
g_thread_xp_DeleteConditionVariable (gpointer cond)
{
GThreadXpCONDITION_VARIABLE *cv = *(GThreadXpCONDITION_VARIABLE * volatile *) cond;
free (cv);
}
-static GThreadXpCONDITION_VARIABLE *
+static GThreadXpCONDITION_VARIABLE * __stdcall
g_thread_xp_get_condition_variable (GThreadXpCONDITION_VARIABLE * volatile *cond)
{
GThreadXpCONDITION_VARIABLE *result;
return result;
}
-static BOOL
+static BOOL __stdcall
g_thread_xp_SleepConditionVariableSRW (gpointer cond,
gpointer mutex,
DWORD timeout,
return status == WAIT_OBJECT_0;
}
-static void
+static void __stdcall
g_thread_xp_WakeConditionVariable (gpointer cond)
{
GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
SetEvent (waiter->event);
}
-static void
+static void __stdcall
g_thread_xp_WakeAllConditionVariable (gpointer cond)
{
GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
g_cond_wait,
g_cond_timed_wait,
g_cond_free,
- g_private_new_win32_impl, /* private thread data */
- g_private_get_win32_impl,
- g_private_set_win32_impl,
+ g_private_new, /* private thread data */
+ g_private_get,
+ g_private_set,
g_thread_create_win32_impl, /* thread */
- g_thread_yield_win32_impl,
+ g_thread_yield,
g_thread_join_win32_impl,
- g_thread_exit_win32_impl,
+ g_system_thread_exit,
g_thread_set_priority_win32_impl,
g_thread_self_win32_impl,
- NULL /* no equal function necessary */
+ g_system_thread_equal
};
void
(g_thread_self_tls = TlsAlloc ()));
win32_check_for_error (TLS_OUT_OF_INDEXES !=
(g_private_tls = TlsAlloc ()));
- InitializeCriticalSection (&g_thread_global_spinlock);
}
static gboolean
G_GNUC_INTERNAL void
g_thread_DllMain (void)
{
- /* XXX This is broken right now for some unknown reason...
-
if (g_thread_lookup_native_funcs ())
fprintf (stderr, "(debug) GThread using native mode\n");
else
-*/
{
fprintf (stderr, "(debug) GThread using Windows XP mode\n");
g_thread_xp_init ();