mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-14 00:06:24 +01:00
Merge branch 'wip/kalev/GRWLock-autoptr' into 'master'
Add autoptr support for GRWLock See merge request GNOME/glib!825
This commit is contained in:
commit
314901309f
@ -743,6 +743,16 @@ GRecMutexLocker
|
||||
g_rec_mutex_locker_new
|
||||
g_rec_mutex_locker_free
|
||||
|
||||
<SUBSECTION>
|
||||
GRWLockWriterLocker
|
||||
g_rw_lock_writer_locker_new
|
||||
g_rw_lock_writer_locker_free
|
||||
|
||||
<SUBSECTION>
|
||||
GRWLockReaderLocker
|
||||
g_rw_lock_reader_locker_new
|
||||
g_rw_lock_reader_locker_free
|
||||
|
||||
<SUBSECTION>
|
||||
GRWLock
|
||||
g_rw_lock_init
|
||||
|
@ -76,6 +76,8 @@ 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_AUTOPTR_CLEANUP_FUNC(GRWLockWriterLocker, g_rw_lock_writer_locker_free)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRWLockReaderLocker, g_rw_lock_reader_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)
|
||||
|
146
glib/gthread.h
146
glib/gthread.h
@ -405,6 +405,152 @@ g_rec_mutex_locker_free (GRecMutexLocker *locker)
|
||||
g_rec_mutex_unlock ((GRecMutex *) locker);
|
||||
}
|
||||
|
||||
/**
|
||||
* GRWLockWriterLocker:
|
||||
*
|
||||
* Opaque type. See g_rw_lock_writer_locker_new() for details.
|
||||
* Since: 2.62
|
||||
*/
|
||||
typedef void GRWLockWriterLocker;
|
||||
|
||||
/**
|
||||
* g_rw_lock_writer_locker_new:
|
||||
* @rw_lock: a #GRWLock
|
||||
*
|
||||
* Obtain a write lock on @rw_lock and return a new #GRWLockWriterLocker.
|
||||
* Unlock with g_rw_lock_writer_locker_free(). Using g_rw_lock_writer_unlock()
|
||||
* on @rw_lock while a #GRWLockWriterLocker 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
|
||||
* {
|
||||
* ...
|
||||
* GRWLock rw_lock;
|
||||
* GPtrArray *array;
|
||||
* ...
|
||||
* } MyObject;
|
||||
*
|
||||
* static gchar *
|
||||
* my_object_get_data (MyObject *self, guint index)
|
||||
* {
|
||||
* g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&self->rw_lock);
|
||||
*
|
||||
* // Code with a read lock obtained on rw_lock here
|
||||
*
|
||||
* if (self->array == NULL)
|
||||
* // No need to unlock
|
||||
* return NULL;
|
||||
*
|
||||
* if (index < self->array->len)
|
||||
* // No need to unlock
|
||||
* return g_ptr_array_index (self->array, index);
|
||||
*
|
||||
* // Optionally early unlock
|
||||
* g_clear_pointer (&locker, g_rw_lock_reader_locker_free);
|
||||
*
|
||||
* // Code with rw_lock unlocked here
|
||||
* return NULL;
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* my_object_set_data (MyObject *self, guint index, gpointer data)
|
||||
* {
|
||||
* g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&self->rw_lock);
|
||||
*
|
||||
* // Code with a write lock obtained on rw_lock here
|
||||
*
|
||||
* if (self->array == NULL)
|
||||
* self->array = g_ptr_array_new ();
|
||||
*
|
||||
* if (cond)
|
||||
* // No need to unlock
|
||||
* return;
|
||||
*
|
||||
* if (index >= self->array->len)
|
||||
* g_ptr_array_set_size (self->array, index+1);
|
||||
* g_ptr_array_index (self->array, index) = data;
|
||||
*
|
||||
* // Optionally early unlock
|
||||
* g_clear_pointer (&locker, g_rw_lock_writer_locker_free);
|
||||
*
|
||||
* // Code with rw_lock unlocked here
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Returns: a #GRWLockWriterLocker
|
||||
* Since: 2.62
|
||||
*/
|
||||
static inline GRWLockWriterLocker *
|
||||
g_rw_lock_writer_locker_new (GRWLock *rw_lock)
|
||||
{
|
||||
g_rw_lock_writer_lock (rw_lock);
|
||||
return (GRWLockWriterLocker *) rw_lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_rw_lock_writer_locker_free:
|
||||
* @locker: a GRWLockWriterLocker
|
||||
*
|
||||
* Release a write lock on @locker's read-write lock. See
|
||||
* g_rw_lock_writer_locker_new() for details.
|
||||
*
|
||||
* Since: 2.62
|
||||
*/
|
||||
static inline void
|
||||
g_rw_lock_writer_locker_free (GRWLockWriterLocker *locker)
|
||||
{
|
||||
g_rw_lock_writer_unlock ((GRWLock *) locker);
|
||||
}
|
||||
|
||||
/**
|
||||
* GRWLockReaderLocker:
|
||||
*
|
||||
* Opaque type. See g_rw_lock_reader_locker_new() for details.
|
||||
* Since: 2.62
|
||||
*/
|
||||
typedef void GRWLockReaderLocker;
|
||||
|
||||
/**
|
||||
* g_rw_lock_reader_locker_new:
|
||||
* @rw_lock: a #GRWLock
|
||||
*
|
||||
* Obtain a read lock on @rw_lock and return a new #GRWLockReaderLocker.
|
||||
* Unlock with g_rw_lock_reader_locker_free(). Using g_rw_lock_reader_unlock()
|
||||
* on @rw_lock while a #GRWLockReaderLocker exists can lead to undefined
|
||||
* behaviour.
|
||||
*
|
||||
* This is intended to be used with g_autoptr(). For a code sample, see
|
||||
* g_rw_lock_writer_locker_new().
|
||||
*
|
||||
* Returns: a #GRWLockReaderLocker
|
||||
* Since: 2.62
|
||||
*/
|
||||
static inline GRWLockReaderLocker *
|
||||
g_rw_lock_reader_locker_new (GRWLock *rw_lock)
|
||||
{
|
||||
g_rw_lock_reader_lock (rw_lock);
|
||||
return (GRWLockReaderLocker *) rw_lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_rw_lock_reader_locker_free:
|
||||
* @locker: a GRWLockReaderLocker
|
||||
*
|
||||
* Release a read lock on @locker's read-write lock. See
|
||||
* g_rw_lock_reader_locker_new() for details.
|
||||
*
|
||||
* Since: 2.62
|
||||
*/
|
||||
static inline void
|
||||
g_rw_lock_reader_locker_free (GRWLockReaderLocker *locker)
|
||||
{
|
||||
g_rw_lock_reader_unlock ((GRWLock *) locker);
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_THREAD_H__ */
|
||||
|
@ -414,6 +414,72 @@ test_g_rec_mutex_locker (void)
|
||||
g_thread_join (thread);
|
||||
}
|
||||
|
||||
/* Thread function to check that an rw lock given in @data cannot be writer locked */
|
||||
static gpointer
|
||||
rw_lock_cannot_take_writer_lock_thread (gpointer data)
|
||||
{
|
||||
GRWLock *lock = (GRWLock *) data;
|
||||
g_assert_false (g_rw_lock_writer_trylock (lock));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Thread function to check that an rw lock given in @data can be reader locked */
|
||||
static gpointer
|
||||
rw_lock_can_take_reader_lock_thread (gpointer data)
|
||||
{
|
||||
GRWLock *lock = (GRWLock *) data;
|
||||
g_assert_true (g_rw_lock_reader_trylock (lock));
|
||||
g_rw_lock_reader_unlock (lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
test_g_rw_lock_lockers (void)
|
||||
{
|
||||
GRWLock lock;
|
||||
GThread *thread;
|
||||
|
||||
g_rw_lock_init (&lock);
|
||||
|
||||
if (TRUE)
|
||||
{
|
||||
g_autoptr(GRWLockWriterLocker) val = g_rw_lock_writer_locker_new (&lock);
|
||||
|
||||
g_assert_nonnull (val);
|
||||
|
||||
/* Verify that we cannot take another writer lock as a writer lock is currently held */
|
||||
thread = g_thread_new ("rw lock cannot take writer lock", rw_lock_cannot_take_writer_lock_thread, &lock);
|
||||
g_thread_join (thread);
|
||||
|
||||
/* Verify that we cannot take a reader lock as a writer lock is currently held */
|
||||
g_assert_false (g_rw_lock_reader_trylock (&lock));
|
||||
}
|
||||
|
||||
if (TRUE)
|
||||
{
|
||||
g_autoptr(GRWLockReaderLocker) val = g_rw_lock_reader_locker_new (&lock);
|
||||
|
||||
g_assert_nonnull (val);
|
||||
|
||||
/* Verify that we can take another reader lock from another thread */
|
||||
thread = g_thread_new ("rw lock can take reader lock", rw_lock_can_take_reader_lock_thread, &lock);
|
||||
g_thread_join (thread);
|
||||
|
||||
/* ... and also that recursive reader locking from the same thread works */
|
||||
g_assert_true (g_rw_lock_reader_trylock (&lock));
|
||||
g_rw_lock_reader_unlock (&lock);
|
||||
|
||||
/* Verify that we cannot take a writer lock as a reader lock is currently held */
|
||||
thread = g_thread_new ("rw lock cannot take writer lock", rw_lock_cannot_take_writer_lock_thread, &lock);
|
||||
g_thread_join (thread);
|
||||
}
|
||||
|
||||
/* Verify that we can take a writer lock again: this can only work if all of
|
||||
* the locks taken above have been correctly released. */
|
||||
g_assert_true (g_rw_lock_writer_trylock (&lock));
|
||||
g_rw_lock_writer_unlock (&lock);
|
||||
}
|
||||
|
||||
static void
|
||||
test_g_cond (void)
|
||||
{
|
||||
@ -636,6 +702,7 @@ main (int argc, gchar *argv[])
|
||||
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_rw_lock_lockers", test_g_rw_lock_lockers);
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user