Add GRecMutexLocker

This is the same as GMutexLocker, just for recursive mutexes.
This commit is contained in:
Kalev Lember 2018-12-12 12:03:13 +01:00
parent 2a64176b83
commit 8c2e71bba0
4 changed files with 118 additions and 0 deletions

View File

@ -733,6 +733,11 @@ g_rec_mutex_lock
g_rec_mutex_trylock
g_rec_mutex_unlock
<SUBSECTION>
GRecMutexLocker
g_rec_mutex_locker_new
g_rec_mutex_locker_free
<SUBSECTION>
GRWLock
g_rw_lock_init

View File

@ -75,6 +75,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GStringChunk, g_string_chunk_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GThread, g_thread_unref)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GMutex, g_mutex_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMutexLocker, g_mutex_locker_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRecMutexLocker, g_rec_mutex_locker_free)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GCond, g_cond_clear)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimer, g_timer_destroy)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimeZone, g_time_zone_unref)

View File

@ -336,6 +336,75 @@ g_mutex_locker_free (GMutexLocker *locker)
g_mutex_unlock ((GMutex *) locker);
}
/**
* GRecMutexLocker:
*
* Opaque type. See g_rec_mutex_locker_new() for details.
* Since: 2.60
*/
typedef void GRecMutexLocker;
/**
* g_rec_mutex_locker_new:
* @rec_mutex: a recursive mutex to lock
*
* Lock @rec_mutex and return a new #GRecMutexLocker. Unlock with
* g_rec_mutex_locker_free(). Using g_rec_mutex_unlock() on @rec_mutex
* while a #GRecMutexLocker exists can lead to undefined behaviour.
*
* This is intended to be used with g_autoptr(). Note that g_autoptr()
* is only available when using GCC or clang, so the following example
* will only work with those compilers:
* |[
* typedef struct
* {
* ...
* GRecMutex rec_mutex;
* ...
* } MyObject;
*
* static void
* my_object_do_stuff (MyObject *self)
* {
* g_autoptr(GRecMutexLocker) locker = g_rec_mutex_locker_new (&self->rec_mutex);
*
* // Code with rec_mutex locked here
*
* if (cond)
* // No need to unlock
* return;
*
* // Optionally early unlock
* g_clear_pointer (&locker, g_rec_mutex_locker_free);
*
* // Code with rec_mutex unlocked here
* }
* ]|
*
* Returns: a #GRecMutexLocker
* Since: 2.60
*/
static inline GRecMutexLocker *
g_rec_mutex_locker_new (GRecMutex *rec_mutex)
{
g_rec_mutex_lock (rec_mutex);
return (GRecMutexLocker *) rec_mutex;
}
/**
* g_rec_mutex_locker_free:
* @locker: a GRecMutexLocker
*
* Unlock @locker's recursive mutex. See g_rec_mutex_locker_new() for details.
*
* Since: 2.60
*/
static inline void
g_rec_mutex_locker_free (GRecMutexLocker *locker)
{
g_rec_mutex_unlock ((GRecMutex *) locker);
}
G_END_DECLS
#endif /* __G_THREAD_H__ */

View File

@ -344,6 +344,48 @@ test_g_mutex_locker (void)
}
}
/* Thread function to check that a recursive mutex given in @data is locked */
static gpointer
rec_mutex_locked_thread (gpointer data)
{
GRecMutex *rec_mutex = (GRecMutex *) data;
g_assert_false (g_rec_mutex_trylock (rec_mutex));
return NULL;
}
/* Thread function to check that a recursive mutex given in @data is unlocked */
static gpointer
rec_mutex_unlocked_thread (gpointer data)
{
GRecMutex *rec_mutex = (GRecMutex *) data;
g_assert_true (g_rec_mutex_trylock (rec_mutex));
return NULL;
}
static void
test_g_rec_mutex_locker (void)
{
GRecMutex rec_mutex;
GThread *thread;
g_rec_mutex_init (&rec_mutex);
if (TRUE)
{
g_autoptr(GRecMutexLocker) val = g_rec_mutex_locker_new (&rec_mutex);
g_assert_nonnull (val);
/* Verify that the mutex is actually locked */
thread = g_thread_new ("rec mutex locked", rec_mutex_locked_thread, &rec_mutex);
g_thread_join (thread);
}
/* Verify that the mutex is unlocked again */
thread = g_thread_new ("rec mutex unlocked", rec_mutex_unlocked_thread, &rec_mutex);
g_thread_join (thread);
}
static void
test_g_cond (void)
{
@ -536,6 +578,7 @@ main (int argc, gchar *argv[])
g_test_add_func ("/autoptr/g_thread", test_g_thread);
g_test_add_func ("/autoptr/g_mutex", test_g_mutex);
g_test_add_func ("/autoptr/g_mutex_locker", test_g_mutex_locker);
g_test_add_func ("/autoptr/g_rec_mutex_locker", test_g_rec_mutex_locker);
g_test_add_func ("/autoptr/g_cond", test_g_cond);
g_test_add_func ("/autoptr/g_timer", test_g_timer);
g_test_add_func ("/autoptr/g_time_zone", test_g_time_zone);