diff --git a/glib/glib.symbols b/glib/glib.symbols index 7f798133f..03cbb4465 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -1624,3 +1624,8 @@ g_rw_lock_reader_unlock g_rw_lock_writer_lock g_rw_lock_writer_trylock g_rw_lock_writer_unlock +g_rec_mutex_clear +g_rec_mutex_init +g_rec_mutex_lock +g_rec_mutex_trylock +g_rec_mutex_unlock diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c index c4fd6f2cb..fa13ddae1 100644 --- a/glib/gthread-posix.c +++ b/glib/gthread-posix.c @@ -43,6 +43,7 @@ #include "gthread.h" #include "gthreadprivate.h" +#include "gslice.h" #include #include @@ -197,6 +198,77 @@ g_mutex_trylock (GMutex *mutex) return FALSE; } +/* {{{1 GRecMutex */ + +static pthread_mutex_t * +g_rec_mutex_impl_new (void) +{ + pthread_mutexattr_t attr; + pthread_mutex_t *mutex; + + mutex = g_slice_new (pthread_mutex_t); + pthread_mutexattr_init (&attr); + pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init (mutex, &attr); + pthread_mutexattr_destroy (&attr); + + return mutex; +} + +static void +g_rec_mutex_impl_free (pthread_mutex_t *mutex) +{ + pthread_mutex_destroy (mutex); + g_slice_free (pthread_mutex_t, mutex); +} + +static pthread_mutex_t * +g_rec_mutex_get_impl (GRecMutex *mutex) +{ + pthread_mutex_t *impl = mutex->impl; + + if G_UNLIKELY (mutex->impl == NULL) + { + impl = g_rec_mutex_impl_new (); + if (!g_atomic_pointer_compare_and_exchange (&mutex->impl, NULL, impl)) + 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) +{ + pthread_mutex_lock (g_rec_mutex_get_impl (mutex)); +} + +void +g_rec_mutex_unlock (GRecMutex *mutex) +{ + pthread_mutex_unlock (mutex->impl); +} + +gboolean +g_rec_mutex_trylock (GRecMutex *mutex) +{ + return pthread_mutex_trylock (g_rec_mutex_get_impl (mutex)); +} + /* {{{1 GRWLock */ void diff --git a/glib/gthread-win32.c b/glib/gthread-win32.c index 1213143a6..f1533c796 100644 --- a/glib/gthread-win32.c +++ b/glib/gthread-win32.c @@ -44,6 +44,7 @@ #include "gthread.h" #include "gthreadprivate.h" +#include "gslice.h" #include @@ -154,6 +155,73 @@ g_mutex_unlock (GMutex *mutex) 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 diff --git a/glib/gthread.h b/glib/gthread.h index e713f79cc..9cde985c2 100644 --- a/glib/gthread.h +++ b/glib/gthread.h @@ -53,6 +53,7 @@ typedef gpointer (*GThreadFunc) (gpointer data); typedef struct _GThread GThread; typedef struct _GMutex GMutex; +typedef struct _GRecMutex GRecMutex; typedef struct _GRWLock GRWLock; typedef struct _GCond GCond; typedef struct _GPrivate GPrivate; @@ -101,6 +102,12 @@ struct _GCond #endif +#define G_REC_MUTEX_INIT { NULL } +struct _GRecMutex +{ + gpointer impl; +}; + /* initializes the mutex/cond/private implementation for glib, might * only be called once, and must not be called directly or indirectly * from another glib-function, e.g. as a callback. @@ -314,6 +321,12 @@ void g_rw_lock_reader_lock (GRWLock gboolean g_rw_lock_reader_trylock (GRWLock *lock); void g_rw_lock_reader_unlock (GRWLock *lock); +void g_rec_mutex_init (GRecMutex *rec_mutex); +void g_rec_mutex_clear (GRecMutex *rec_mutex); +void g_rec_mutex_lock (GRecMutex *rec_mutex); +gboolean g_rec_mutex_trylock (GRecMutex *rec_mutex); +void g_rec_mutex_unlock (GRecMutex *rec_mutex); + GCond * g_cond_new (void); void g_cond_free (GCond *cond); void g_cond_init (GCond *cond);