#include "gthread.h"
#include "gthreadprivate.h"
+#include "gslice.h"
#include <windows.h>
void (__stdcall * AcquireSRWLockExclusive) (gpointer lock);
BOOLEAN (__stdcall * TryAcquireSRWLockExclusive) (gpointer lock);
void (__stdcall * ReleaseSRWLockExclusive) (gpointer lock);
+ void (__stdcall * AcquireSRWLockShared) (gpointer lock);
+ BOOLEAN (__stdcall * TryAcquireSRWLockShared) (gpointer lock);
+ void (__stdcall * ReleaseSRWLockShared) (gpointer lock);
void (__stdcall * InitializeConditionVariable) (gpointer cond);
void (__stdcall * DeleteConditionVariable) (gpointer cond); /* fake */
g_thread_impl_vtable.ReleaseSRWLockExclusive (mutex);
}
+/* {{{1 GRecMutex */
+
+static CRITICAL_SECTION *
+g_rec_mutex_impl_new (void)
+{
+ CRITICAL_SECTION *cs;
+
+ cs = g_slice_new (CRITICAL_SECTION);
+ InitializeCriticalSection (cs);
+
+ return cs;
+}
+
+static void
+g_rec_mutex_impl_free (CRITICAL_SECTION *cs)
+{
+ DeleteCriticalSection (cs);
+ g_slice_free (CRITICAL_SECTION, cs);
+}
+
+static CRITICAL_SECTION *
+g_rec_mutex_get_impl (GRecMutex *mutex)
+{
+ CRITICAL_SECTION *impl = mutex->impl;
+
+ if G_UNLIKELY (mutex->impl == NULL)
+ {
+ impl = g_rec_mutex_impl_new ();
+ if (InterlockedCompareExchangePointer (&mutex->impl, impl, NULL) != NULL)
+ g_rec_mutex_impl_free (impl);
+ impl = mutex->impl;
+ }
+
+ return impl;
+}
+
+void
+g_rec_mutex_init (GRecMutex *mutex)
+{
+ mutex->impl = g_rec_mutex_impl_new ();
+}
+
+void
+g_rec_mutex_clear (GRecMutex *mutex)
+{
+ if (mutex->impl)
+ g_rec_mutex_impl_free (mutex->impl);
+}
+
+void
+g_rec_mutex_lock (GRecMutex *mutex)
+{
+ EnterCriticalSection (g_rec_mutex_get_impl (mutex));
+}
+
+void
+g_rec_mutex_unlock (GRecMutex *mutex)
+{
+ LeaveCriticalSection (mutex->impl);
+}
+
+gboolean
+g_rec_mutex_trylock (GRecMutex *mutex)
+{
+ return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex));
+}
+
+/* {{{1 GRWLock */
+
+void
+g_rw_lock_init (GRWLock *lock)
+{
+ g_thread_impl_vtable.InitializeSRWLock (lock);
+}
+
+void
+g_rw_lock_clear (GRWLock *lock)
+{
+ if (g_thread_impl_vtable.DeleteSRWLock != NULL)
+ g_thread_impl_vtable.DeleteSRWLock (lock);
+}
+
+void
+g_rw_lock_writer_lock (GRWLock *lock)
+{
+ g_thread_impl_vtable.AcquireSRWLockExclusive (lock);
+}
+
+gboolean
+g_rw_lock_writer_trylock (GRWLock *lock)
+{
+ return g_thread_impl_vtable.TryAcquireSRWLockExclusive (lock);
+}
+
+void
+g_rw_lock_writer_unlock (GRWLock *lock)
+{
+ g_thread_impl_vtable.ReleaseSRWLockExclusive (lock);
+}
+
+void
+g_rw_lock_reader_lock (GRWLock *lock)
+{
+ g_thread_impl_vtable.AcquireSRWLockShared (lock);
+}
+
+gboolean
+g_rw_lock_reader_trylock (GRWLock *lock)
+{
+ return g_thread_impl_vtable.TryAcquireSRWLockShared (lock);
+}
+
+void
+g_rw_lock_reader_unlock (GRWLock *lock)
+{
+ g_thread_impl_vtable.ReleaseSRWLockShared (lock);
+}
+
/* {{{1 GCond */
void
g_cond_init (GCond *cond)
gboolean joinable;
};
-
-static void
-g_thread_set_priority_win32_impl (gpointer thread, GThreadPriority priority)
-{
- GThreadData *target = *(GThreadData **)thread;
- gint native_prio;
-
- switch (priority)
- {
- case G_THREAD_PRIORITY_LOW:
- native_prio = THREAD_PRIORITY_BELOW_NORMAL;
- break;
-
- case G_THREAD_PRIORITY_NORMAL:
- native_prio = THREAD_PRIORITY_NORMAL;
- break;
-
- case G_THREAD_PRIORITY_HIGH:
- native_prio = THREAD_PRIORITY_ABOVE_NORMAL;
- break;
-
- case G_THREAD_PRIORITY_URGENT:
- native_prio = THREAD_PRIORITY_HIGHEST;
- break;
-
- default:
- g_return_if_reached ();
- }
-
- win32_check_for_error (SetThreadPriority (target->thread, native_prio));
-}
-
-static void
-g_thread_self_win32_impl (gpointer thread)
+void
+g_system_thread_self (gpointer thread)
{
GThreadData *self = TlsGetValue (g_thread_self_tls);
*(GThreadData **)thread = self;
}
-static void
-g_thread_exit_win32_impl (void)
+void
+g_system_thread_exit (void)
{
GThreadData *self = TlsGetValue (g_thread_self_tls);
gboolean dtors_called;
self->func (self->data);
- g_thread_exit_win32_impl ();
+ g_system_thread_exit ();
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)
+void
+g_system_thread_create (GThreadFunc func,
+ gpointer data,
+ gulong stack_size,
+ gboolean joinable,
+ 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;
}
*(GThreadData **)thread = retval;
-
- g_thread_set_priority_win32_impl (thread, priority);
}
void
Sleep(0);
}
-static void
-g_thread_join_win32_impl (gpointer thread)
+void
+g_system_thread_join (gpointer thread)
{
GThreadData *target = *(GThreadData **)thread;
/* {{{2 SRWLock emulation */
typedef struct
{
- CRITICAL_SECTION critical_section;
+ CRITICAL_SECTION writer_lock;
+ gboolean ever_shared; /* protected by writer_lock */
+
+ /* below is only ever touched if ever_shared becomes true */
+ CRITICAL_SECTION atomicity;
+ GThreadXpWaiter *queued_writer; /* protected by atomicity lock */
+ gint num_readers; /* protected by atomicity lock */
} GThreadSRWLock;
static void __stdcall
if (lock)
{
- DeleteCriticalSection (&lock->critical_section);
+ if (lock->ever_shared)
+ DeleteCriticalSection (&lock->atomicity);
+
+ DeleteCriticalSection (&lock->writer_lock);
free (lock);
}
}
if (result == NULL)
g_thread_abort (errno, "malloc");
- InitializeCriticalSection (&result->critical_section);
+ InitializeCriticalSection (&result->writer_lock);
+ result->ever_shared = FALSE;
*lock = result;
LeaveCriticalSection (&g_thread_xp_lock);
{
GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
- EnterCriticalSection (&lock->critical_section);
+ EnterCriticalSection (&lock->writer_lock);
+
+ if (lock->ever_shared)
+ {
+ GThreadXpWaiter *waiter = NULL;
+
+ EnterCriticalSection (&lock->atomicity);
+ if (lock->num_readers > 0)
+ lock->queued_writer = waiter = g_thread_xp_waiter_get ();
+ LeaveCriticalSection (&lock->atomicity);
+
+ if (waiter != NULL)
+ WaitForSingleObject (waiter->event, INFINITE);
+
+ lock->queued_writer = NULL;
+ }
}
static BOOLEAN __stdcall
{
GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
- return TryEnterCriticalSection (&lock->critical_section);
+ if (!TryEnterCriticalSection (&lock->writer_lock))
+ return FALSE;
+
+ if (lock->ever_shared)
+ {
+ gboolean available;
+
+ EnterCriticalSection (&lock->atomicity);
+ available = lock->num_readers == 0;
+ LeaveCriticalSection (&lock->atomicity);
+
+ if (!available)
+ {
+ LeaveCriticalSection (&lock->writer_lock);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
}
static void __stdcall
* unlock freshly-allocated mutexes.
*/
if (lock != NULL)
- LeaveCriticalSection (&lock->critical_section);
+ LeaveCriticalSection (&lock->writer_lock);
+}
+
+static void
+g_thread_xp_srwlock_become_reader (GThreadSRWLock *lock)
+{
+ if G_UNLIKELY (!lock->ever_shared)
+ {
+ InitializeCriticalSection (&lock->atomicity);
+ lock->queued_writer = NULL;
+ lock->num_readers = 0;
+
+ lock->ever_shared = TRUE;
+ }
+
+ EnterCriticalSection (&lock->atomicity);
+ lock->num_readers++;
+ LeaveCriticalSection (&lock->atomicity);
+}
+
+static void __stdcall
+g_thread_xp_AcquireSRWLockShared (gpointer mutex)
+{
+ GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
+
+ EnterCriticalSection (&lock->writer_lock);
+
+ g_thread_xp_srwlock_become_reader (lock);
+
+ LeaveCriticalSection (&lock->writer_lock);
+}
+
+static BOOLEAN __stdcall
+g_thread_xp_TryAcquireSRWLockShared (gpointer mutex)
+{
+ GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
+
+ if (!TryEnterCriticalSection (&lock->writer_lock))
+ return FALSE;
+
+ g_thread_xp_srwlock_become_reader (lock);
+
+ LeaveCriticalSection (&lock->writer_lock);
+
+ return TRUE;
+}
+
+static void __stdcall
+g_thread_xp_ReleaseSRWLockShared (gpointer mutex)
+{
+ GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
+
+ EnterCriticalSection (&lock->atomicity);
+
+ lock->num_readers--;
+
+ if (lock->num_readers == 0 && lock->queued_writer)
+ SetEvent (lock->queued_writer->event);
+
+ LeaveCriticalSection (&lock->atomicity);
}
/* {{{2 CONDITION_VARIABLE emulation */
g_thread_xp_AcquireSRWLockExclusive,
g_thread_xp_TryAcquireSRWLockExclusive,
g_thread_xp_ReleaseSRWLockExclusive,
+ g_thread_xp_AcquireSRWLockShared,
+ g_thread_xp_TryAcquireSRWLockShared,
+ g_thread_xp_ReleaseSRWLockShared,
g_thread_xp_InitializeConditionVariable,
g_thread_xp_DeleteConditionVariable,
g_thread_xp_SleepConditionVariableSRW,
/* {{{1 Epilogue */
-GThreadFunctions g_thread_functions_for_glib_use =
-{
- g_mutex_new, /* mutex */
- g_mutex_lock,
- g_mutex_trylock,
- g_mutex_unlock,
- g_mutex_free,
- g_cond_new, /* condition */
- g_cond_signal,
- g_cond_broadcast,
- g_cond_wait,
- g_cond_timed_wait,
- g_cond_free,
- g_private_new, /* private thread data */
- g_private_get,
- g_private_set,
- g_thread_create_win32_impl, /* thread */
- g_thread_yield,
- g_thread_join_win32_impl,
- g_thread_exit_win32_impl,
- g_thread_set_priority_win32_impl,
- g_thread_self_win32_impl,
- NULL /* no equal function necessary */
-};
-
-void
-_g_thread_impl_init (void)
-{
- static gboolean beenhere = FALSE;
-
- if (beenhere)
- return;
-
- beenhere = TRUE;
-
- printf ("thread init\n");
- 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 ()));
-}
-
static gboolean
g_thread_lookup_native_funcs (void)
{
GET_FUNC(AcquireSRWLockExclusive);
GET_FUNC(TryAcquireSRWLockExclusive);
GET_FUNC(ReleaseSRWLockExclusive);
+ GET_FUNC(AcquireSRWLockShared);
+ GET_FUNC(TryAcquireSRWLockShared);
+ GET_FUNC(ReleaseSRWLockShared);
GET_FUNC(InitializeConditionVariable);
GET_FUNC(SleepConditionVariableSRW);
fprintf (stderr, "(debug) GThread using Windows XP mode\n");
g_thread_xp_init ();
}
+
+ 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 ()));
}
/* vim:set foldmethod=marker: */