diff --git a/glib/Makefile.am b/glib/Makefile.am index 5d005f5f3..74bf0606e 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -114,7 +114,8 @@ uninstall-ms-lib: deprecated_sources = \ deprecated/gallocator.c \ deprecated/gcompletion.c \ - deprecated/grel.c + deprecated/grel.c \ + deprecated/gthread-deprecated.c libglib_2_0_la_SOURCES = \ $(deprecated_sources) \ diff --git a/glib/deprecated/gthread-deprecated.c b/glib/deprecated/gthread-deprecated.c new file mode 100644 index 000000000..fa6a3bb3d --- /dev/null +++ b/glib/deprecated/gthread-deprecated.c @@ -0,0 +1,977 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gthread.c: MT safety related functions + * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe + * Owen Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "gmessages.h" +#include "gmain.h" +#include "gthread.h" +#include "gthreadprivate.h" +#include "deprecated/gthread.h" + +/* {{{1 Documentation */ + +/** + * GThreadPriority: + * @G_THREAD_PRIORITY_LOW: a priority lower than normal + * @G_THREAD_PRIORITY_NORMAL: the default priority + * @G_THREAD_PRIORITY_HIGH: a priority higher than normal + * @G_THREAD_PRIORITY_URGENT: the highest priority + * + * Deprecated:2.32: thread priorities no longer have any effect. + */ + +/** + * GThreadFunctions: + * @mutex_new: virtual function pointer for g_mutex_new() + * @mutex_lock: virtual function pointer for g_mutex_lock() + * @mutex_trylock: virtual function pointer for g_mutex_trylock() + * @mutex_unlock: virtual function pointer for g_mutex_unlock() + * @mutex_free: virtual function pointer for g_mutex_free() + * @cond_new: virtual function pointer for g_cond_new() + * @cond_signal: virtual function pointer for g_cond_signal() + * @cond_broadcast: virtual function pointer for g_cond_broadcast() + * @cond_wait: virtual function pointer for g_cond_wait() + * @cond_timed_wait: virtual function pointer for g_cond_timed_wait() + * @cond_free: virtual function pointer for g_cond_free() + * @private_new: virtual function pointer for g_private_new() + * @private_get: virtual function pointer for g_private_get() + * @private_set: virtual function pointer for g_private_set() + * @thread_create: virtual function pointer for g_thread_create() + * @thread_yield: virtual function pointer for g_thread_yield() + * @thread_join: virtual function pointer for g_thread_join() + * @thread_exit: virtual function pointer for g_thread_exit() + * @thread_set_priority: virtual function pointer for + * g_thread_set_priority() + * @thread_self: virtual function pointer for g_thread_self() + * @thread_equal: used internally by recursive mutex locks and by some + * assertion checks + * + * This function table is no longer used by g_thread_init() + * to initialize the thread system. + */ + +/* {{{1 Exported Variables */ + +gboolean g_thread_use_default_impl = TRUE; + +GThreadFunctions g_thread_functions_for_glib_use = +{ + g_mutex_new, + g_mutex_lock, + g_mutex_trylock, + g_mutex_unlock, + g_mutex_free, + g_cond_new, + g_cond_signal, + g_cond_broadcast, + g_cond_wait, + g_cond_timed_wait, + g_cond_free, + g_private_new, + g_private_get, + g_private_set, + NULL, + g_thread_yield, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static guint64 +gettime (void) +{ + return g_get_monotonic_time () * 1000; +} + +guint64 (*g_thread_gettime) (void) = gettime; + +/* Misc. GThread functions {{{1 */ + +/** + * g_thread_set_priority: + * @thread: a #GThread. + * @priority: ignored + * + * This function does nothing. + * + * Deprecated:2.32: Thread priorities no longer have any effect. + */ +void +g_thread_set_priority (GThread *thread, + GThreadPriority priority) +{ +} + +/** + * g_thread_create_full: + * @func: a function to execute in the new thread. + * @data: an argument to supply to the new thread. + * @stack_size: a stack size for the new thread. + * @joinable: should this thread be joinable? + * @bound: ignored + * @priority: ignored + * @error: return location for error. + * @Returns: the new #GThread on success. + * + * This function creates a new thread. + * + * Deprecated:2.32: The @bound and @priority arguments are now ignored. + * Use g_thread_create() or g_thread_create_with_stack_size() instead. + */ +GThread * +g_thread_create_full (GThreadFunc func, + gpointer data, + gulong stack_size, + gboolean joinable, + gboolean bound, + GThreadPriority priority, + GError **error) +{ + return g_thread_create_with_stack_size (func, data, joinable, stack_size, error); +} + +/* GStaticMutex {{{1 ------------------------------------------------------ */ + +/** + * GStaticMutex: + * + * A #GStaticMutex works like a #GMutex. + * + * Prior to GLib 2.32, GStaticMutex had the significant advantage + * that it doesn't need to be created at run-time, but can be defined + * at compile-time. Since 2.32, #GMutex can be statically allocated + * as well, and GStaticMutex has been deprecated. + * + * Here is a version of our give_me_next_number() example using + * a GStaticMutex. + * + * + * + * Using <structname>GStaticMutex</structname> + * to simplify thread-safe programming + * + * + * int + * give_me_next_number (void) + * { + * static int current_number = 0; + * int ret_val; + * static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + * + * g_static_mutex_lock (&mutex); + * ret_val = current_number = calc_next_number (current_number); + * g_static_mutex_unlock (&mutex); + * + * return ret_val; + * } + * + * + * + * Sometimes you would like to dynamically create a mutex. If you don't + * want to require prior calling to g_thread_init(), because your code + * should also be usable in non-threaded programs, you are not able to + * use g_mutex_new() and thus #GMutex, as that requires a prior call to + * g_thread_init(). In theses cases you can also use a #GStaticMutex. + * It must be initialized with g_static_mutex_init() before using it + * and freed with with g_static_mutex_free() when not needed anymore to + * free up any allocated resources. + * + * Even though #GStaticMutex is not opaque, it should only be used with + * the following functions, as it is defined differently on different + * platforms. + * + * All of the g_static_mutex_* functions apart + * from g_static_mutex_get_mutex can also be used + * even if g_thread_init() has not yet been called. Then they do + * nothing, apart from g_static_mutex_trylock, + * which does nothing but returning %TRUE. + * + * All of the g_static_mutex_* + * functions are actually macros. Apart from taking their addresses, you + * can however use them as if they were functions. + **/ + +/** + * G_STATIC_MUTEX_INIT: + * + * A #GStaticMutex must be initialized with this macro, before it can + * be used. This macro can used be to initialize a variable, but it + * cannot be assigned to a variable. In that case you have to use + * g_static_mutex_init(). + * + * |[ + * GStaticMutex my_mutex = G_STATIC_MUTEX_INIT; + * ]| + **/ + +/** + * g_static_mutex_init: + * @mutex: a #GStaticMutex to be initialized. + * + * Initializes @mutex. + * Alternatively you can initialize it with #G_STATIC_MUTEX_INIT. + * + * Deprecated: 2.32: Use g_mutex_init() + */ +void +g_static_mutex_init (GStaticMutex *mutex) +{ + static const GStaticMutex init_mutex = G_STATIC_MUTEX_INIT; + + g_return_if_fail (mutex); + + *mutex = init_mutex; +} + +/* IMPLEMENTATION NOTE: + * + * On some platforms a GStaticMutex is actually a normal GMutex stored + * inside of a structure instead of being allocated dynamically. We can + * only do this for platforms on which we know, in advance, how to + * allocate (size) and initialise (value) that memory. + * + * On other platforms, a GStaticMutex is nothing more than a pointer to + * a GMutex. In that case, the first access we make to the static mutex + * must first allocate the normal GMutex and store it into the pointer. + * + * configure.ac writes macros into glibconfig.h to determine if + * g_static_mutex_get_mutex() accesses the structure in memory directly + * (on platforms where we are able to do that) or if it ends up here, + * where we may have to allocate the GMutex before returning it. + */ + +/** + * g_static_mutex_get_mutex: + * @mutex: a #GStaticMutex. + * @Returns: the #GMutex corresponding to @mutex. + * + * For some operations (like g_cond_wait()) you must have a #GMutex + * instead of a #GStaticMutex. This function will return the + * corresponding #GMutex for @mutex. + * + * Deprecated: 2.32: Just use a #GMutex + */ +GMutex * +g_static_mutex_get_mutex_impl (GMutex** mutex) +{ + GMutex *result; + + if (!g_thread_supported ()) + return NULL; + + result = g_atomic_pointer_get (mutex); + + if (!result) + { + g_mutex_lock (&g_once_mutex); + + result = *mutex; + if (!result) + { + result = g_mutex_new (); + g_atomic_pointer_set (mutex, result); + } + + g_mutex_unlock (&g_once_mutex); + } + + return result; +} + +/* IMPLEMENTATION NOTE: + * + * g_static_mutex_lock(), g_static_mutex_trylock() and + * g_static_mutex_unlock() are all preprocessor macros that wrap the + * corresponding g_mutex_*() function around a call to + * g_static_mutex_get_mutex(). + */ + +/** + * g_static_mutex_lock: + * @mutex: a #GStaticMutex. + * + * Works like g_mutex_lock(), but for a #GStaticMutex. + * + * Deprecated: 2.32: Use g_mutex_lock() + */ + +/** + * g_static_mutex_trylock: + * @mutex: a #GStaticMutex. + * @Returns: %TRUE, if the #GStaticMutex could be locked. + * + * Works like g_mutex_trylock(), but for a #GStaticMutex. + * + * Deprecated: 2.32: Use g_mutex_trylock() + */ + +/** + * g_static_mutex_unlock: + * @mutex: a #GStaticMutex. + * + * Works like g_mutex_unlock(), but for a #GStaticMutex. + * + * Deprecated: 2.32: Use g_mutex_unlock() + */ + +/** + * g_static_mutex_free: + * @mutex: a #GStaticMutex to be freed. + * + * Releases all resources allocated to @mutex. + * + * You don't have to call this functions for a #GStaticMutex with an + * unbounded lifetime, i.e. objects declared 'static', but if you have + * a #GStaticMutex as a member of a structure and the structure is + * freed, you should also free the #GStaticMutex. + * + * Calling g_static_mutex_free() on a locked mutex may + * result in undefined behaviour. + * + * Deprecated: 2.32: Use g_mutex_free() + */ +void +g_static_mutex_free (GStaticMutex* mutex) +{ + GMutex **runtime_mutex; + + g_return_if_fail (mutex); + + /* The runtime_mutex is the first (or only) member of GStaticMutex, + * see both versions (of glibconfig.h) in configure.ac. Note, that + * this variable is NULL, if g_thread_init() hasn't been called or + * if we're using the default thread implementation and it provides + * static mutexes. */ + runtime_mutex = ((GMutex**)mutex); + + if (*runtime_mutex) + g_mutex_free (*runtime_mutex); + + *runtime_mutex = NULL; +} + +/* {{{1 GStaticRecMutex */ + +/** + * GStaticRecMutex: + * + * A #GStaticRecMutex works like a #GStaticMutex, but it can be locked + * multiple times by one thread. If you enter it n times, you have to + * unlock it n times again to let other threads lock it. An exception + * is the function g_static_rec_mutex_unlock_full(): that allows you to + * unlock a #GStaticRecMutex completely returning the depth, (i.e. the + * number of times this mutex was locked). The depth can later be used + * to restore the state of the #GStaticRecMutex by calling + * g_static_rec_mutex_lock_full(). In GLib 2.32, #GStaticRecMutex has + * been deprecated in favor of #GRecMutex. + * + * Even though #GStaticRecMutex is not opaque, it should only be used + * with the following functions. + * + * All of the g_static_rec_mutex_* functions can + * be used even if g_thread_init() has not been called. Then they do + * nothing, apart from g_static_rec_mutex_trylock, + * which does nothing but returning %TRUE. + **/ + +/** + * G_STATIC_REC_MUTEX_INIT: + * + * A #GStaticRecMutex must be initialized with this macro before it can + * be used. This macro can used be to initialize a variable, but it + * cannot be assigned to a variable. In that case you have to use + * g_static_rec_mutex_init(). + * + * |[ + * GStaticRecMutex my_mutex = G_STATIC_REC_MUTEX_INIT; + * ]| + */ + +/** + * g_static_rec_mutex_init: + * @mutex: a #GStaticRecMutex to be initialized. + * + * A #GStaticRecMutex must be initialized with this function before it + * can be used. Alternatively you can initialize it with + * #G_STATIC_REC_MUTEX_INIT. + * + * Deprecated: 2.32: Use g_rec_mutex_init() + */ +void +g_static_rec_mutex_init (GStaticRecMutex *mutex) +{ + static const GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT; + + g_return_if_fail (mutex); + + *mutex = init_mutex; +} + +/** + * g_static_rec_mutex_lock: + * @mutex: a #GStaticRecMutex to lock. + * + * Locks @mutex. If @mutex is already locked by another thread, the + * current thread will block until @mutex is unlocked by the other + * thread. If @mutex is already locked by the calling thread, this + * functions increases the depth of @mutex and returns immediately. + * + * Deprecated: 2.32: Use g_rec_mutex_lock() + */ +void +g_static_rec_mutex_lock (GStaticRecMutex* mutex) +{ + GSystemThread self; + + g_return_if_fail (mutex); + + if (!g_thread_supported ()) + return; + + g_system_thread_self (&self); + + if (g_system_thread_equal (&self, &mutex->owner)) + { + mutex->depth++; + return; + } + g_static_mutex_lock (&mutex->mutex); + g_system_thread_assign (mutex->owner, self); + mutex->depth = 1; +} + +/** + * g_static_rec_mutex_trylock: + * @mutex: a #GStaticRecMutex to lock. + * @Returns: %TRUE, if @mutex could be locked. + * + * Tries to lock @mutex. If @mutex is already locked by another thread, + * it immediately returns %FALSE. Otherwise it locks @mutex and returns + * %TRUE. If @mutex is already locked by the calling thread, this + * functions increases the depth of @mutex and immediately returns + * %TRUE. + * + * Deprecated: 2.32: Use g_rec_mutex_trylock() + */ +gboolean +g_static_rec_mutex_trylock (GStaticRecMutex* mutex) +{ + GSystemThread self; + + g_return_val_if_fail (mutex, FALSE); + + if (!g_thread_supported ()) + return TRUE; + + g_system_thread_self (&self); + + if (g_system_thread_equal (&self, &mutex->owner)) + { + mutex->depth++; + return TRUE; + } + + if (!g_static_mutex_trylock (&mutex->mutex)) + return FALSE; + + g_system_thread_assign (mutex->owner, self); + mutex->depth = 1; + return TRUE; +} + +/** + * g_static_rec_mutex_unlock: + * @mutex: a #GStaticRecMutex to unlock. + * + * Unlocks @mutex. Another thread will be allowed to lock @mutex only + * when it has been unlocked as many times as it had been locked + * before. If @mutex is completely unlocked and another thread is + * blocked in a g_static_rec_mutex_lock() call for @mutex, it will be + * woken and can lock @mutex itself. + * + * Deprecated: 2.32: Use g_rec_mutex_unlock() + */ +void +g_static_rec_mutex_unlock (GStaticRecMutex* mutex) +{ + g_return_if_fail (mutex); + + if (!g_thread_supported ()) + return; + + if (mutex->depth > 1) + { + mutex->depth--; + return; + } + g_system_thread_assign (mutex->owner, zero_thread); + g_static_mutex_unlock (&mutex->mutex); +} + +/** + * g_static_rec_mutex_lock_full: + * @mutex: a #GStaticRecMutex to lock. + * @depth: number of times this mutex has to be unlocked to be + * completely unlocked. + * + * Works like calling g_static_rec_mutex_lock() for @mutex @depth times. + * + * Deprecated: 2.32: Use g_rec_mutex_lock() + */ +void +g_static_rec_mutex_lock_full (GStaticRecMutex *mutex, + guint depth) +{ + GSystemThread self; + g_return_if_fail (mutex); + + if (!g_thread_supported ()) + return; + + if (depth == 0) + return; + + g_system_thread_self (&self); + + if (g_system_thread_equal (&self, &mutex->owner)) + { + mutex->depth += depth; + return; + } + g_static_mutex_lock (&mutex->mutex); + g_system_thread_assign (mutex->owner, self); + mutex->depth = depth; +} + +/** + * g_static_rec_mutex_unlock_full: + * @mutex: a #GStaticRecMutex to completely unlock. + * @Returns: number of times @mutex has been locked by the current + * thread. + * + * Completely unlocks @mutex. If another thread is blocked in a + * g_static_rec_mutex_lock() call for @mutex, it will be woken and can + * lock @mutex itself. This function returns the number of times that + * @mutex has been locked by the current thread. To restore the state + * before the call to g_static_rec_mutex_unlock_full() you can call + * g_static_rec_mutex_lock_full() with the depth returned by this + * function. + * + * Deprecated: 2.32: Use g_rec_mutex_unlock() + */ +guint +g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex) +{ + guint depth; + + g_return_val_if_fail (mutex, 0); + + if (!g_thread_supported ()) + return 1; + + depth = mutex->depth; + + g_system_thread_assign (mutex->owner, zero_thread); + mutex->depth = 0; + g_static_mutex_unlock (&mutex->mutex); + + return depth; +} + +/** + * g_static_rec_mutex_free: + * @mutex: a #GStaticRecMutex to be freed. + * + * Releases all resources allocated to a #GStaticRecMutex. + * + * You don't have to call this functions for a #GStaticRecMutex with an + * unbounded lifetime, i.e. objects declared 'static', but if you have + * a #GStaticRecMutex as a member of a structure and the structure is + * freed, you should also free the #GStaticRecMutex. + * + * Deprecated: 2.32: Use g_rec_mutex_clear() + */ +void +g_static_rec_mutex_free (GStaticRecMutex *mutex) +{ + g_return_if_fail (mutex); + + g_static_mutex_free (&mutex->mutex); +} + +/* GStaticRWLock {{{1 ----------------------------------------------------- */ + +/** + * GStaticRWLock: + * + * The #GStaticRWLock struct represents a read-write lock. A read-write + * lock can be used for protecting data that some portions of code only + * read from, while others also write. In such situations it is + * desirable that several readers can read at once, whereas of course + * only one writer may write at a time. Take a look at the following + * example: + * + * + * An array with access functions + * + * GStaticRWLock rwlock = G_STATIC_RW_LOCK_INIT; + * GPtrArray *array; + * + * gpointer + * my_array_get (guint index) + * { + * gpointer retval = NULL; + * + * if (!array) + * return NULL; + * + * g_static_rw_lock_reader_lock (&rwlock); + * if (index < array->len) + * retval = g_ptr_array_index (array, index); + * g_static_rw_lock_reader_unlock (&rwlock); + * + * return retval; + * } + * + * void + * my_array_set (guint index, gpointer data) + * { + * g_static_rw_lock_writer_lock (&rwlock); + * + * if (!array) + * array = g_ptr_array_new (); + * + * if (index >= array->len) + * g_ptr_array_set_size (array, index+1); + * g_ptr_array_index (array, index) = data; + * + * g_static_rw_lock_writer_unlock (&rwlock); + * } + * + * + * + * This example shows an array which can be accessed by many readers + * (the my_array_get() function) simultaneously, + * whereas the writers (the my_array_set() + * function) will only be allowed once at a time and only if no readers + * currently access the array. This is because of the potentially + * dangerous resizing of the array. Using these functions is fully + * multi-thread safe now. + * + * Most of the time, writers should have precedence over readers. That + * means, for this implementation, that as soon as a writer wants to + * lock the data, no other reader is allowed to lock the data, whereas, + * of course, the readers that already have locked the data are allowed + * to finish their operation. As soon as the last reader unlocks the + * data, the writer will lock it. + * + * Even though #GStaticRWLock is not opaque, it should only be used + * with the following functions. + * + * All of the g_static_rw_lock_* functions can be + * used even if g_thread_init() has not been called. Then they do + * nothing, apart from g_static_rw_lock_*_trylock, + * which does nothing but returning %TRUE. + * + * A read-write lock has a higher overhead than a mutex. For + * example, both g_static_rw_lock_reader_lock() and + * g_static_rw_lock_reader_unlock() have to lock and unlock a + * #GStaticMutex, so it takes at least twice the time to lock and unlock + * a #GStaticRWLock that it does to lock and unlock a #GStaticMutex. So + * only data structures that are accessed by multiple readers, and which + * keep the lock for a considerable time justify a #GStaticRWLock. The + * above example most probably would fare better with a + * #GStaticMutex. + * + * Deprecated: 2.32: Use a #GRWLock instead + **/ + +/** + * G_STATIC_RW_LOCK_INIT: + * + * A #GStaticRWLock must be initialized with this macro before it can + * be used. This macro can used be to initialize a variable, but it + * cannot be assigned to a variable. In that case you have to use + * g_static_rw_lock_init(). + * + * |[ + * GStaticRWLock my_lock = G_STATIC_RW_LOCK_INIT; + * ]| + */ + +/** + * g_static_rw_lock_init: + * @lock: a #GStaticRWLock to be initialized. + * + * A #GStaticRWLock must be initialized with this function before it + * can be used. Alternatively you can initialize it with + * #G_STATIC_RW_LOCK_INIT. + * + * Deprecated: 2.32: Use g_rw_lock_init() instead + */ +void +g_static_rw_lock_init (GStaticRWLock* lock) +{ + static const GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT; + + g_return_if_fail (lock); + + *lock = init_lock; +} + +inline static void +g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex) +{ + if (!*cond) + *cond = g_cond_new (); + g_cond_wait (*cond, g_static_mutex_get_mutex (mutex)); +} + +inline static void +g_static_rw_lock_signal (GStaticRWLock* lock) +{ + if (lock->want_to_write && lock->write_cond) + g_cond_signal (lock->write_cond); + else if (lock->want_to_read && lock->read_cond) + g_cond_broadcast (lock->read_cond); +} + +/** + * g_static_rw_lock_reader_lock: + * @lock: a #GStaticRWLock to lock for reading. + * + * Locks @lock for reading. There may be unlimited concurrent locks for + * reading of a #GStaticRWLock at the same time. If @lock is already + * locked for writing by another thread or if another thread is already + * waiting to lock @lock for writing, this function will block until + * @lock is unlocked by the other writing thread and no other writing + * threads want to lock @lock. This lock has to be unlocked by + * g_static_rw_lock_reader_unlock(). + * + * #GStaticRWLock is not recursive. It might seem to be possible to + * recursively lock for reading, but that can result in a deadlock, due + * to writer preference. + * + * Deprecated: 2.32: Use g_rw_lock_reader_lock() instead + */ +void +g_static_rw_lock_reader_lock (GStaticRWLock* lock) +{ + g_return_if_fail (lock); + + if (!g_threads_got_initialized) + return; + + g_static_mutex_lock (&lock->mutex); + lock->want_to_read++; + while (lock->have_writer || lock->want_to_write) + g_static_rw_lock_wait (&lock->read_cond, &lock->mutex); + lock->want_to_read--; + lock->read_counter++; + g_static_mutex_unlock (&lock->mutex); +} + +/** + * g_static_rw_lock_reader_trylock: + * @lock: a #GStaticRWLock to lock for reading. + * @Returns: %TRUE, if @lock could be locked for reading. + * + * Tries to lock @lock for reading. If @lock is already locked for + * writing by another thread or if another thread is already waiting to + * lock @lock for writing, immediately returns %FALSE. Otherwise locks + * @lock for reading and returns %TRUE. This lock has to be unlocked by + * g_static_rw_lock_reader_unlock(). + * + * Deprectated: 2.32: Use g_rw_lock_reader_trylock() instead + */ +gboolean +g_static_rw_lock_reader_trylock (GStaticRWLock* lock) +{ + gboolean ret_val = FALSE; + + g_return_val_if_fail (lock, FALSE); + + if (!g_threads_got_initialized) + return TRUE; + + g_static_mutex_lock (&lock->mutex); + if (!lock->have_writer && !lock->want_to_write) + { + lock->read_counter++; + ret_val = TRUE; + } + g_static_mutex_unlock (&lock->mutex); + return ret_val; +} + +/** + * g_static_rw_lock_reader_unlock: + * @lock: a #GStaticRWLock to unlock after reading. + * + * Unlocks @lock. If a thread waits to lock @lock for writing and all + * locks for reading have been unlocked, the waiting thread is woken up + * and can lock @lock for writing. + * + * Deprectated: 2.32: Use g_rw_lock_reader_unlock() instead + */ +void +g_static_rw_lock_reader_unlock (GStaticRWLock* lock) +{ + g_return_if_fail (lock); + + if (!g_threads_got_initialized) + return; + + g_static_mutex_lock (&lock->mutex); + lock->read_counter--; + if (lock->read_counter == 0) + g_static_rw_lock_signal (lock); + g_static_mutex_unlock (&lock->mutex); +} + +/** + * g_static_rw_lock_writer_lock: + * @lock: a #GStaticRWLock to lock for writing. + * + * Locks @lock for writing. If @lock is already locked for writing or + * reading by other threads, this function will block until @lock is + * completely unlocked and then lock @lock for writing. While this + * functions waits to lock @lock, no other thread can lock @lock for + * reading. When @lock is locked for writing, no other thread can lock + * @lock (neither for reading nor writing). This lock has to be + * unlocked by g_static_rw_lock_writer_unlock(). + * + * Deprectated: 2.32: Use g_rw_lock_writer_lock() instead + */ +void +g_static_rw_lock_writer_lock (GStaticRWLock* lock) +{ + g_return_if_fail (lock); + + if (!g_threads_got_initialized) + return; + + g_static_mutex_lock (&lock->mutex); + lock->want_to_write++; + while (lock->have_writer || lock->read_counter) + g_static_rw_lock_wait (&lock->write_cond, &lock->mutex); + lock->want_to_write--; + lock->have_writer = TRUE; + g_static_mutex_unlock (&lock->mutex); +} + +/** + * g_static_rw_lock_writer_trylock: + * @lock: a #GStaticRWLock to lock for writing. + * @Returns: %TRUE, if @lock could be locked for writing. + * + * Tries to lock @lock for writing. If @lock is already locked (for + * either reading or writing) by another thread, it immediately returns + * %FALSE. Otherwise it locks @lock for writing and returns %TRUE. This + * lock has to be unlocked by g_static_rw_lock_writer_unlock(). + * + * Deprectated: 2.32: Use g_rw_lock_writer_trylock() instead + */ +gboolean +g_static_rw_lock_writer_trylock (GStaticRWLock* lock) +{ + gboolean ret_val = FALSE; + + g_return_val_if_fail (lock, FALSE); + + if (!g_threads_got_initialized) + return TRUE; + + g_static_mutex_lock (&lock->mutex); + if (!lock->have_writer && !lock->read_counter) + { + lock->have_writer = TRUE; + ret_val = TRUE; + } + g_static_mutex_unlock (&lock->mutex); + return ret_val; +} + +/** + * g_static_rw_lock_writer_unlock: + * @lock: a #GStaticRWLock to unlock after writing. + * + * Unlocks @lock. If a thread is waiting to lock @lock for writing and + * all locks for reading have been unlocked, the waiting thread is + * woken up and can lock @lock for writing. If no thread is waiting to + * lock @lock for writing, and some thread or threads are waiting to + * lock @lock for reading, the waiting threads are woken up and can + * lock @lock for reading. + * + * Deprectated: 2.32: Use g_rw_lock_writer_unlock() instead + */ +void +g_static_rw_lock_writer_unlock (GStaticRWLock* lock) +{ + g_return_if_fail (lock); + + if (!g_threads_got_initialized) + return; + + g_static_mutex_lock (&lock->mutex); + lock->have_writer = FALSE; + g_static_rw_lock_signal (lock); + g_static_mutex_unlock (&lock->mutex); +} + +/** + * g_static_rw_lock_free: + * @lock: a #GStaticRWLock to be freed. + * + * Releases all resources allocated to @lock. + * + * You don't have to call this functions for a #GStaticRWLock with an + * unbounded lifetime, i.e. objects declared 'static', but if you have + * a #GStaticRWLock as a member of a structure, and the structure is + * freed, you should also free the #GStaticRWLock. + * + * Deprecated: 2.32: Use a #GRWLock instead + */ +void +g_static_rw_lock_free (GStaticRWLock* lock) +{ + g_return_if_fail (lock); + + if (lock->read_cond) + { + g_cond_free (lock->read_cond); + lock->read_cond = NULL; + } + if (lock->write_cond) + { + g_cond_free (lock->write_cond); + lock->write_cond = NULL; + } + g_static_mutex_free (&lock->mutex); +} + +/* vim: set foldmethod=marker: */ + diff --git a/glib/gthread.c b/glib/gthread.c index 99c7d0262..81d643232 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -228,118 +228,8 @@ * #G_LOCK_DEFINE. **/ -/* GThreadError {{{1 ------------------------------------------------------- */ -/** - * GThreadError: - * @G_THREAD_ERROR_AGAIN: a thread couldn't be created due to resource - * shortage. Try again later. - * - * Possible errors of thread related functions. - **/ -/** - * G_THREAD_ERROR: - * - * The error domain of the GLib thread subsystem. - **/ -GQuark -g_thread_error_quark (void) -{ - return g_quark_from_static_string ("g_thread_error"); -} - -/* Miscellaneous Structures {{{1 ------------------------------------------ */ -typedef struct _GRealThread GRealThread; -struct _GRealThread -{ - GThread thread; - /* Bit 0 protects private_data. To avoid deadlocks, do not block while - * holding this (particularly on the g_thread lock). */ - volatile gint private_data_lock; - GArray *private_data; - GRealThread *next; - gpointer retval; - GSystemThread system_thread; -}; - -#define LOCK_PRIVATE_DATA(self) g_bit_lock (&(self)->private_data_lock, 0) -#define UNLOCK_PRIVATE_DATA(self) g_bit_unlock (&(self)->private_data_lock, 0) - -typedef struct _GStaticPrivateNode GStaticPrivateNode; -struct _GStaticPrivateNode -{ - gpointer data; - GDestroyNotify destroy; -}; - -static void g_thread_cleanup (gpointer data); -static guint64 gettime (void); - -guint64 (*g_thread_gettime) (void) = gettime; - -/* Global Variables {{{1 -------------------------------------------------- */ - -static GSystemThread zero_thread; /* This is initialized to all zero */ -gboolean g_thread_use_default_impl = TRUE; - -/** - * g_thread_supported: - * @Returns: %TRUE, if the thread system is initialized. - * - * This function returns %TRUE if the thread system is initialized, and - * %FALSE if it is not. - * - * This function is actually a macro. Apart from taking the - * address of it you can however use it as if it was a - * function. - **/ - -/* IMPLEMENTATION NOTE: - * - * g_thread_supported() is just returns g_threads_got_initialized - */ -gboolean g_threads_got_initialized = FALSE; - - -/* Thread Implementation Virtual Function Table {{{1 ---------------------- */ -/* Virtual Function Table Documentation {{{2 ------------------------------ */ -/** - * GThreadFunctions: - * @mutex_new: virtual function pointer for g_mutex_new() - * @mutex_lock: virtual function pointer for g_mutex_lock() - * @mutex_trylock: virtual function pointer for g_mutex_trylock() - * @mutex_unlock: virtual function pointer for g_mutex_unlock() - * @mutex_free: virtual function pointer for g_mutex_free() - * @cond_new: virtual function pointer for g_cond_new() - * @cond_signal: virtual function pointer for g_cond_signal() - * @cond_broadcast: virtual function pointer for g_cond_broadcast() - * @cond_wait: virtual function pointer for g_cond_wait() - * @cond_timed_wait: virtual function pointer for g_cond_timed_wait() - * @cond_free: virtual function pointer for g_cond_free() - * @private_new: virtual function pointer for g_private_new() - * @private_get: virtual function pointer for g_private_get() - * @private_set: virtual function pointer for g_private_set() - * @thread_create: virtual function pointer for g_thread_create() - * @thread_yield: virtual function pointer for g_thread_yield() - * @thread_join: virtual function pointer for g_thread_join() - * @thread_exit: virtual function pointer for g_thread_exit() - * @thread_set_priority: virtual function pointer for - * g_thread_set_priority() - * @thread_self: virtual function pointer for g_thread_self() - * @thread_equal: used internally by recursive mutex locks and by some - * assertion checks - * - * This function table is used by g_thread_init() to initialize the - * thread system. The functions in the table are directly used by their - * g_* prepended counterparts (described in this document). For - * example, if you call g_mutex_new() then mutex_new() from the table - * provided to g_thread_init() will be called. - * - * Do not use this struct unless you know what you are - * doing. - **/ - -/* GMutex Virtual Functions {{{2 ------------------------------------------ */ +/* GMutex Documentation {{{1 ------------------------------------------ */ /** * GMutex: @@ -453,8 +343,8 @@ gboolean g_threads_got_initialized = FALSE; * A #GMutex should only be accessed via g_mutex_ * functions. **/ - -/* GCond Virtual Functions {{{2 ------------------------------------------ */ + +/* GCond Documentation {{{1 ------------------------------------------ */ /** * GCond: @@ -516,7 +406,7 @@ gboolean g_threads_got_initialized = FALSE; * A #GCond should only be accessed via the following functions. */ -/* GPrivate Virtual Functions {{{2 --------------------------------------- */ +/* GPrivate Documentation {{{1 --------------------------------------- */ /** * GPrivate: @@ -572,7 +462,7 @@ gboolean g_threads_got_initialized = FALSE; * use them as if they were functions. **/ -/* GThread Virtual Functions {{{2 ---------------------------------------- */ +/* GThread Documentation {{{1 ---------------------------------------- */ /** * GThread: * @@ -594,19 +484,63 @@ gboolean g_threads_got_initialized = FALSE; * g_thread_create() or g_thread_create_full(). **/ +/* GThreadError {{{1 ------------------------------------------------------- */ /** - * GThreadPriority: - * @G_THREAD_PRIORITY_LOW: a priority lower than normal - * @G_THREAD_PRIORITY_NORMAL: the default priority - * @G_THREAD_PRIORITY_HIGH: a priority higher than normal - * @G_THREAD_PRIORITY_URGENT: the highest priority + * GThreadError: + * @G_THREAD_ERROR_AGAIN: a thread couldn't be created due to resource + * shortage. Try again later. * - * Deprecated:2.32: thread priorities no longer have any effect. + * Possible errors of thread related functions. **/ +/** + * G_THREAD_ERROR: + * + * The error domain of the GLib thread subsystem. + **/ +GQuark +g_thread_error_quark (void) +{ + return g_quark_from_static_string ("g_thread_error"); +} + +/* Miscellaneous Structures {{{1 ------------------------------------------ */ + +typedef struct _GRealThread GRealThread; +struct _GRealThread +{ + GThread thread; + /* Bit 0 protects private_data. To avoid deadlocks, do not block while + * holding this (particularly on the g_thread lock). */ + volatile gint private_data_lock; + GArray *private_data; + GRealThread *next; + gpointer retval; + GSystemThread system_thread; +}; + +#define LOCK_PRIVATE_DATA(self) g_bit_lock (&(self)->private_data_lock, 0) +#define UNLOCK_PRIVATE_DATA(self) g_bit_unlock (&(self)->private_data_lock, 0) + +static void g_thread_cleanup (gpointer data); + +/** + * g_thread_supported: + * @Returns: %TRUE, if the thread system is initialized. + * + * This function returns %TRUE if the thread system is initialized, and + * %FALSE if it is not. + * + * This function is actually a macro. Apart from taking the + * address of it you can however use it as if it was a + * function. + **/ /* Local Data {{{1 -------------------------------------------------------- */ -static GMutex g_once_mutex = G_MUTEX_INIT; +gboolean g_threads_got_initialized = FALSE; +GSystemThread zero_thread; /* This is initialized to all zero */ +GMutex g_once_mutex = G_MUTEX_INIT; + static GCond g_once_cond = G_COND_INIT; static GPrivate g_thread_specific_private; static GRealThread *g_thread_all_threads = NULL; @@ -669,10 +603,6 @@ g_thread_init_glib (void) _g_messages_thread_init_nomessage (); } -/* The following sections implement: GOnce, GStaticMutex, GStaticRecMutex, - * GStaticPrivate, - **/ - /* GOnce {{{1 ------------------------------------------------------------- */ /** @@ -862,477 +792,15 @@ g_once_init_leave (volatile gsize *value_location, g_mutex_unlock (&g_once_mutex); } -/* GStaticMutex {{{1 ------------------------------------------------------ */ - -/** - * GStaticMutex: - * - * A #GStaticMutex works like a #GMutex. - * - * Prior to GLib 2.32, GStaticMutex had the significant advantage - * that it doesn't need to be created at run-time, but can be defined - * at compile-time. Since 2.32, #GMutex can be statically allocated - * as well, and GStaticMutex has been deprecated. - * - * Here is a version of our give_me_next_number() example using - * a GStaticMutex. - * - * - * - * Using <structname>GStaticMutex</structname> - * to simplify thread-safe programming - * - * - * int - * give_me_next_number (void) - * { - * static int current_number = 0; - * int ret_val; - * static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - * - * g_static_mutex_lock (&mutex); - * ret_val = current_number = calc_next_number (current_number); - * g_static_mutex_unlock (&mutex); - * - * return ret_val; - * } - * - * - * - * Sometimes you would like to dynamically create a mutex. If you don't - * want to require prior calling to g_thread_init(), because your code - * should also be usable in non-threaded programs, you are not able to - * use g_mutex_new() and thus #GMutex, as that requires a prior call to - * g_thread_init(). In theses cases you can also use a #GStaticMutex. - * It must be initialized with g_static_mutex_init() before using it - * and freed with with g_static_mutex_free() when not needed anymore to - * free up any allocated resources. - * - * Even though #GStaticMutex is not opaque, it should only be used with - * the following functions, as it is defined differently on different - * platforms. - * - * All of the g_static_mutex_* functions apart - * from g_static_mutex_get_mutex can also be used - * even if g_thread_init() has not yet been called. Then they do - * nothing, apart from g_static_mutex_trylock, - * which does nothing but returning %TRUE. - * - * All of the g_static_mutex_* - * functions are actually macros. Apart from taking their addresses, you - * can however use them as if they were functions. - **/ - -/** - * G_STATIC_MUTEX_INIT: - * - * A #GStaticMutex must be initialized with this macro, before it can - * be used. This macro can used be to initialize a variable, but it - * cannot be assigned to a variable. In that case you have to use - * g_static_mutex_init(). - * - * |[ - * GStaticMutex my_mutex = G_STATIC_MUTEX_INIT; - * ]| - **/ - -/** - * g_static_mutex_init: - * @mutex: a #GStaticMutex to be initialized. - * - * Initializes @mutex. - * Alternatively you can initialize it with #G_STATIC_MUTEX_INIT. - * - * Deprecated: 2.32: Use g_mutex_init() - */ -void -g_static_mutex_init (GStaticMutex *mutex) -{ - static const GStaticMutex init_mutex = G_STATIC_MUTEX_INIT; - - g_return_if_fail (mutex); - - *mutex = init_mutex; -} - -/* IMPLEMENTATION NOTE: - * - * On some platforms a GStaticMutex is actually a normal GMutex stored - * inside of a structure instead of being allocated dynamically. We can - * only do this for platforms on which we know, in advance, how to - * allocate (size) and initialise (value) that memory. - * - * On other platforms, a GStaticMutex is nothing more than a pointer to - * a GMutex. In that case, the first access we make to the static mutex - * must first allocate the normal GMutex and store it into the pointer. - * - * configure.ac writes macros into glibconfig.h to determine if - * g_static_mutex_get_mutex() accesses the structure in memory directly - * (on platforms where we are able to do that) or if it ends up here, - * where we may have to allocate the GMutex before returning it. - */ - -/** - * g_static_mutex_get_mutex: - * @mutex: a #GStaticMutex. - * @Returns: the #GMutex corresponding to @mutex. - * - * For some operations (like g_cond_wait()) you must have a #GMutex - * instead of a #GStaticMutex. This function will return the - * corresponding #GMutex for @mutex. - * - * Deprecated: 2.32: Just use a #GMutex - */ -GMutex * -g_static_mutex_get_mutex_impl (GMutex** mutex) -{ - GMutex *result; - - if (!g_thread_supported ()) - return NULL; - - result = g_atomic_pointer_get (mutex); - - if (!result) - { - g_mutex_lock (&g_once_mutex); - - result = *mutex; - if (!result) - { - result = g_mutex_new (); - g_atomic_pointer_set (mutex, result); - } - - g_mutex_unlock (&g_once_mutex); - } - - return result; -} - -/* IMPLEMENTATION NOTE: - * - * g_static_mutex_lock(), g_static_mutex_trylock() and - * g_static_mutex_unlock() are all preprocessor macros that wrap the - * corresponding g_mutex_*() function around a call to - * g_static_mutex_get_mutex(). - */ - -/** - * g_static_mutex_lock: - * @mutex: a #GStaticMutex. - * - * Works like g_mutex_lock(), but for a #GStaticMutex. - * - * Deprecated: 2.32: Use g_mutex_lock() - */ - -/** - * g_static_mutex_trylock: - * @mutex: a #GStaticMutex. - * @Returns: %TRUE, if the #GStaticMutex could be locked. - * - * Works like g_mutex_trylock(), but for a #GStaticMutex. - * - * Deprecated: 2.32: Use g_mutex_trylock() - */ - -/** - * g_static_mutex_unlock: - * @mutex: a #GStaticMutex. - * - * Works like g_mutex_unlock(), but for a #GStaticMutex. - * - * Deprecated: 2.32: Use g_mutex_unlock() - */ - -/** - * g_static_mutex_free: - * @mutex: a #GStaticMutex to be freed. - * - * Releases all resources allocated to @mutex. - * - * You don't have to call this functions for a #GStaticMutex with an - * unbounded lifetime, i.e. objects declared 'static', but if you have - * a #GStaticMutex as a member of a structure and the structure is - * freed, you should also free the #GStaticMutex. - * - * Calling g_static_mutex_free() on a locked mutex may - * result in undefined behaviour. - * - * Deprecated: 2.32: Use g_mutex_free() - */ -void -g_static_mutex_free (GStaticMutex* mutex) -{ - GMutex **runtime_mutex; - - g_return_if_fail (mutex); - - /* The runtime_mutex is the first (or only) member of GStaticMutex, - * see both versions (of glibconfig.h) in configure.ac. Note, that - * this variable is NULL, if g_thread_init() hasn't been called or - * if we're using the default thread implementation and it provides - * static mutexes. */ - runtime_mutex = ((GMutex**)mutex); - - if (*runtime_mutex) - g_mutex_free (*runtime_mutex); - - *runtime_mutex = NULL; -} - -/* ------------------------------------------------------------------------ */ - -/** - * GStaticRecMutex: - * - * A #GStaticRecMutex works like a #GStaticMutex, but it can be locked - * multiple times by one thread. If you enter it n times, you have to - * unlock it n times again to let other threads lock it. An exception - * is the function g_static_rec_mutex_unlock_full(): that allows you to - * unlock a #GStaticRecMutex completely returning the depth, (i.e. the - * number of times this mutex was locked). The depth can later be used - * to restore the state of the #GStaticRecMutex by calling - * g_static_rec_mutex_lock_full(). In GLib 2.32, #GStaticRecMutex has - * been deprecated in favor of #GRecMutex. - * - * Even though #GStaticRecMutex is not opaque, it should only be used - * with the following functions. - * - * All of the g_static_rec_mutex_* functions can - * be used even if g_thread_init() has not been called. Then they do - * nothing, apart from g_static_rec_mutex_trylock, - * which does nothing but returning %TRUE. - **/ - -/** - * G_STATIC_REC_MUTEX_INIT: - * - * A #GStaticRecMutex must be initialized with this macro before it can - * be used. This macro can used be to initialize a variable, but it - * cannot be assigned to a variable. In that case you have to use - * g_static_rec_mutex_init(). - * - * |[ - * GStaticRecMutex my_mutex = G_STATIC_REC_MUTEX_INIT; - * ]| - */ - -/** - * g_static_rec_mutex_init: - * @mutex: a #GStaticRecMutex to be initialized. - * - * A #GStaticRecMutex must be initialized with this function before it - * can be used. Alternatively you can initialize it with - * #G_STATIC_REC_MUTEX_INIT. - * - * Deprecated: 2.32: Use g_rec_mutex_init() - */ -void -g_static_rec_mutex_init (GStaticRecMutex *mutex) -{ - static const GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT; - - g_return_if_fail (mutex); - - *mutex = init_mutex; -} - -/** - * g_static_rec_mutex_lock: - * @mutex: a #GStaticRecMutex to lock. - * - * Locks @mutex. If @mutex is already locked by another thread, the - * current thread will block until @mutex is unlocked by the other - * thread. If @mutex is already locked by the calling thread, this - * functions increases the depth of @mutex and returns immediately. - * - * Deprecated: 2.32: Use g_rec_mutex_lock() - */ -void -g_static_rec_mutex_lock (GStaticRecMutex* mutex) -{ - GSystemThread self; - - g_return_if_fail (mutex); - - if (!g_thread_supported ()) - return; - - g_system_thread_self (&self); - - if (g_system_thread_equal (&self, &mutex->owner)) - { - mutex->depth++; - return; - } - g_static_mutex_lock (&mutex->mutex); - g_system_thread_assign (mutex->owner, self); - mutex->depth = 1; -} - -/** - * g_static_rec_mutex_trylock: - * @mutex: a #GStaticRecMutex to lock. - * @Returns: %TRUE, if @mutex could be locked. - * - * Tries to lock @mutex. If @mutex is already locked by another thread, - * it immediately returns %FALSE. Otherwise it locks @mutex and returns - * %TRUE. If @mutex is already locked by the calling thread, this - * functions increases the depth of @mutex and immediately returns - * %TRUE. - * - * Deprecated: 2.32: Use g_rec_mutex_trylock() - */ -gboolean -g_static_rec_mutex_trylock (GStaticRecMutex* mutex) -{ - GSystemThread self; - - g_return_val_if_fail (mutex, FALSE); - - if (!g_thread_supported ()) - return TRUE; - - g_system_thread_self (&self); - - if (g_system_thread_equal (&self, &mutex->owner)) - { - mutex->depth++; - return TRUE; - } - - if (!g_static_mutex_trylock (&mutex->mutex)) - return FALSE; - - g_system_thread_assign (mutex->owner, self); - mutex->depth = 1; - return TRUE; -} - -/** - * g_static_rec_mutex_unlock: - * @mutex: a #GStaticRecMutex to unlock. - * - * Unlocks @mutex. Another thread will be allowed to lock @mutex only - * when it has been unlocked as many times as it had been locked - * before. If @mutex is completely unlocked and another thread is - * blocked in a g_static_rec_mutex_lock() call for @mutex, it will be - * woken and can lock @mutex itself. - * - * Deprecated: 2.32: Use g_rec_mutex_unlock() - */ -void -g_static_rec_mutex_unlock (GStaticRecMutex* mutex) -{ - g_return_if_fail (mutex); - - if (!g_thread_supported ()) - return; - - if (mutex->depth > 1) - { - mutex->depth--; - return; - } - g_system_thread_assign (mutex->owner, zero_thread); - g_static_mutex_unlock (&mutex->mutex); -} - -/** - * g_static_rec_mutex_lock_full: - * @mutex: a #GStaticRecMutex to lock. - * @depth: number of times this mutex has to be unlocked to be - * completely unlocked. - * - * Works like calling g_static_rec_mutex_lock() for @mutex @depth times. - * - * Deprecated: 2.32: Use g_rec_mutex_lock() - */ -void -g_static_rec_mutex_lock_full (GStaticRecMutex *mutex, - guint depth) -{ - GSystemThread self; - g_return_if_fail (mutex); - - if (!g_thread_supported ()) - return; - - if (depth == 0) - return; - - g_system_thread_self (&self); - - if (g_system_thread_equal (&self, &mutex->owner)) - { - mutex->depth += depth; - return; - } - g_static_mutex_lock (&mutex->mutex); - g_system_thread_assign (mutex->owner, self); - mutex->depth = depth; -} - -/** - * g_static_rec_mutex_unlock_full: - * @mutex: a #GStaticRecMutex to completely unlock. - * @Returns: number of times @mutex has been locked by the current - * thread. - * - * Completely unlocks @mutex. If another thread is blocked in a - * g_static_rec_mutex_lock() call for @mutex, it will be woken and can - * lock @mutex itself. This function returns the number of times that - * @mutex has been locked by the current thread. To restore the state - * before the call to g_static_rec_mutex_unlock_full() you can call - * g_static_rec_mutex_lock_full() with the depth returned by this - * function. - * - * Deprecated: 2.32: Use g_rec_mutex_unlock() - */ -guint -g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex) -{ - guint depth; - - g_return_val_if_fail (mutex, 0); - - if (!g_thread_supported ()) - return 1; - - depth = mutex->depth; - - g_system_thread_assign (mutex->owner, zero_thread); - mutex->depth = 0; - g_static_mutex_unlock (&mutex->mutex); - - return depth; -} - -/** - * g_static_rec_mutex_free: - * @mutex: a #GStaticRecMutex to be freed. - * - * Releases all resources allocated to a #GStaticRecMutex. - * - * You don't have to call this functions for a #GStaticRecMutex with an - * unbounded lifetime, i.e. objects declared 'static', but if you have - * a #GStaticRecMutex as a member of a structure and the structure is - * freed, you should also free the #GStaticRecMutex. - * - * Deprecated: 2.32: Use g_rec_mutex_clear() - */ -void -g_static_rec_mutex_free (GStaticRecMutex *mutex) -{ - g_return_if_fail (mutex); - - g_static_mutex_free (&mutex->mutex); -} - /* GStaticPrivate {{{1 ---------------------------------------------------- */ +typedef struct _GStaticPrivateNode GStaticPrivateNode; +struct _GStaticPrivateNode +{ + gpointer data; + GDestroyNotify destroy; +}; + /** * GStaticPrivate: * @@ -1640,14 +1108,6 @@ g_thread_cleanup (gpointer data) } } -#define G_NSEC_PER_SEC 1000000000 - -static guint64 -gettime (void) -{ - return g_get_monotonic_time () * 1000; -} - static gpointer g_thread_create_proxy (gpointer data) { @@ -1767,34 +1227,6 @@ g_thread_create_with_stack_size (GThreadFunc func, return (GThread*) result; } -/** - * g_thread_create_full: - * @func: a function to execute in the new thread. - * @data: an argument to supply to the new thread. - * @stack_size: a stack size for the new thread. - * @joinable: should this thread be joinable? - * @bound: ignored - * @priority: ignored - * @error: return location for error. - * @Returns: the new #GThread on success. - * - * This function creates a new thread. - * - * Deprecated:2.32: The @bound and @priority arguments are now ignored. - * Use g_thread_create() or g_thread_create_with_stack_size() instead. - */ -GThread * -g_thread_create_full (GThreadFunc func, - gpointer data, - gulong stack_size, - gboolean joinable, - gboolean bound, - GThreadPriority priority, - GError **error) -{ - return g_thread_create_with_stack_size (func, data, joinable, stack_size, error); -} - /** * g_thread_exit: * @retval: the return value of this thread. @@ -1871,29 +1303,14 @@ g_thread_join (GThread* thread) g_system_thread_assign (real->system_thread, zero_thread); /* the thread structure for non-joinable threads is freed upon - thread end. We free the memory here. This will leave a loose end, - if a joinable thread is not joined. */ - + * thread end. We free the memory here. This will leave a loose end, + * if a joinable thread is not joined. + */ g_free (thread); return retval; } -/** - * g_thread_set_priority: - * @thread: a #GThread. - * @priority: ignored - * - * This function does nothing. - * - * Deprecated:2.32: Thread priorities no longer have any effect. - */ -void -g_thread_set_priority (GThread *thread, - GThreadPriority priority) -{ -} - /** * g_thread_self: * @Returns: the current thread. @@ -1930,357 +1347,6 @@ g_thread_self (void) return (GThread*)thread; } -/* GStaticRWLock {{{1 ----------------------------------------------------- */ - -/** - * GStaticRWLock: - * - * The #GStaticRWLock struct represents a read-write lock. A read-write - * lock can be used for protecting data that some portions of code only - * read from, while others also write. In such situations it is - * desirable that several readers can read at once, whereas of course - * only one writer may write at a time. Take a look at the following - * example: - * - * - * An array with access functions - * - * GStaticRWLock rwlock = G_STATIC_RW_LOCK_INIT; - * GPtrArray *array; - * - * gpointer - * my_array_get (guint index) - * { - * gpointer retval = NULL; - * - * if (!array) - * return NULL; - * - * g_static_rw_lock_reader_lock (&rwlock); - * if (index < array->len) - * retval = g_ptr_array_index (array, index); - * g_static_rw_lock_reader_unlock (&rwlock); - * - * return retval; - * } - * - * void - * my_array_set (guint index, gpointer data) - * { - * g_static_rw_lock_writer_lock (&rwlock); - * - * if (!array) - * array = g_ptr_array_new (); - * - * if (index >= array->len) - * g_ptr_array_set_size (array, index+1); - * g_ptr_array_index (array, index) = data; - * - * g_static_rw_lock_writer_unlock (&rwlock); - * } - * - * - * - * This example shows an array which can be accessed by many readers - * (the my_array_get() function) simultaneously, - * whereas the writers (the my_array_set() - * function) will only be allowed once at a time and only if no readers - * currently access the array. This is because of the potentially - * dangerous resizing of the array. Using these functions is fully - * multi-thread safe now. - * - * Most of the time, writers should have precedence over readers. That - * means, for this implementation, that as soon as a writer wants to - * lock the data, no other reader is allowed to lock the data, whereas, - * of course, the readers that already have locked the data are allowed - * to finish their operation. As soon as the last reader unlocks the - * data, the writer will lock it. - * - * Even though #GStaticRWLock is not opaque, it should only be used - * with the following functions. - * - * All of the g_static_rw_lock_* functions can be - * used even if g_thread_init() has not been called. Then they do - * nothing, apart from g_static_rw_lock_*_trylock, - * which does nothing but returning %TRUE. - * - * A read-write lock has a higher overhead than a mutex. For - * example, both g_static_rw_lock_reader_lock() and - * g_static_rw_lock_reader_unlock() have to lock and unlock a - * #GStaticMutex, so it takes at least twice the time to lock and unlock - * a #GStaticRWLock that it does to lock and unlock a #GStaticMutex. So - * only data structures that are accessed by multiple readers, and which - * keep the lock for a considerable time justify a #GStaticRWLock. The - * above example most probably would fare better with a - * #GStaticMutex. - * - * Deprecated: 2.32: Use a #GRWLock instead - **/ - -/** - * G_STATIC_RW_LOCK_INIT: - * - * A #GStaticRWLock must be initialized with this macro before it can - * be used. This macro can used be to initialize a variable, but it - * cannot be assigned to a variable. In that case you have to use - * g_static_rw_lock_init(). - * - * |[ - * GStaticRWLock my_lock = G_STATIC_RW_LOCK_INIT; - * ]| - */ - -/** - * g_static_rw_lock_init: - * @lock: a #GStaticRWLock to be initialized. - * - * A #GStaticRWLock must be initialized with this function before it - * can be used. Alternatively you can initialize it with - * #G_STATIC_RW_LOCK_INIT. - * - * Deprecated: 2.32: Use g_rw_lock_init() instead - */ -void -g_static_rw_lock_init (GStaticRWLock* lock) -{ - static const GStaticRWLock init_lock = G_STATIC_RW_LOCK_INIT; - - g_return_if_fail (lock); - - *lock = init_lock; -} - -inline static void -g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex) -{ - if (!*cond) - *cond = g_cond_new (); - g_cond_wait (*cond, g_static_mutex_get_mutex (mutex)); -} - -inline static void -g_static_rw_lock_signal (GStaticRWLock* lock) -{ - if (lock->want_to_write && lock->write_cond) - g_cond_signal (lock->write_cond); - else if (lock->want_to_read && lock->read_cond) - g_cond_broadcast (lock->read_cond); -} - -/** - * g_static_rw_lock_reader_lock: - * @lock: a #GStaticRWLock to lock for reading. - * - * Locks @lock for reading. There may be unlimited concurrent locks for - * reading of a #GStaticRWLock at the same time. If @lock is already - * locked for writing by another thread or if another thread is already - * waiting to lock @lock for writing, this function will block until - * @lock is unlocked by the other writing thread and no other writing - * threads want to lock @lock. This lock has to be unlocked by - * g_static_rw_lock_reader_unlock(). - * - * #GStaticRWLock is not recursive. It might seem to be possible to - * recursively lock for reading, but that can result in a deadlock, due - * to writer preference. - * - * Deprecated: 2.32: Use g_rw_lock_reader_lock() instead - */ -void -g_static_rw_lock_reader_lock (GStaticRWLock* lock) -{ - g_return_if_fail (lock); - - if (!g_threads_got_initialized) - return; - - g_static_mutex_lock (&lock->mutex); - lock->want_to_read++; - while (lock->have_writer || lock->want_to_write) - g_static_rw_lock_wait (&lock->read_cond, &lock->mutex); - lock->want_to_read--; - lock->read_counter++; - g_static_mutex_unlock (&lock->mutex); -} - -/** - * g_static_rw_lock_reader_trylock: - * @lock: a #GStaticRWLock to lock for reading. - * @Returns: %TRUE, if @lock could be locked for reading. - * - * Tries to lock @lock for reading. If @lock is already locked for - * writing by another thread or if another thread is already waiting to - * lock @lock for writing, immediately returns %FALSE. Otherwise locks - * @lock for reading and returns %TRUE. This lock has to be unlocked by - * g_static_rw_lock_reader_unlock(). - * - * Deprectated: 2.32: Use g_rw_lock_reader_trylock() instead - */ -gboolean -g_static_rw_lock_reader_trylock (GStaticRWLock* lock) -{ - gboolean ret_val = FALSE; - - g_return_val_if_fail (lock, FALSE); - - if (!g_threads_got_initialized) - return TRUE; - - g_static_mutex_lock (&lock->mutex); - if (!lock->have_writer && !lock->want_to_write) - { - lock->read_counter++; - ret_val = TRUE; - } - g_static_mutex_unlock (&lock->mutex); - return ret_val; -} - -/** - * g_static_rw_lock_reader_unlock: - * @lock: a #GStaticRWLock to unlock after reading. - * - * Unlocks @lock. If a thread waits to lock @lock for writing and all - * locks for reading have been unlocked, the waiting thread is woken up - * and can lock @lock for writing. - * - * Deprectated: 2.32: Use g_rw_lock_reader_unlock() instead - */ -void -g_static_rw_lock_reader_unlock (GStaticRWLock* lock) -{ - g_return_if_fail (lock); - - if (!g_threads_got_initialized) - return; - - g_static_mutex_lock (&lock->mutex); - lock->read_counter--; - if (lock->read_counter == 0) - g_static_rw_lock_signal (lock); - g_static_mutex_unlock (&lock->mutex); -} - -/** - * g_static_rw_lock_writer_lock: - * @lock: a #GStaticRWLock to lock for writing. - * - * Locks @lock for writing. If @lock is already locked for writing or - * reading by other threads, this function will block until @lock is - * completely unlocked and then lock @lock for writing. While this - * functions waits to lock @lock, no other thread can lock @lock for - * reading. When @lock is locked for writing, no other thread can lock - * @lock (neither for reading nor writing). This lock has to be - * unlocked by g_static_rw_lock_writer_unlock(). - * - * Deprectated: 2.32: Use g_rw_lock_writer_lock() instead - */ -void -g_static_rw_lock_writer_lock (GStaticRWLock* lock) -{ - g_return_if_fail (lock); - - if (!g_threads_got_initialized) - return; - - g_static_mutex_lock (&lock->mutex); - lock->want_to_write++; - while (lock->have_writer || lock->read_counter) - g_static_rw_lock_wait (&lock->write_cond, &lock->mutex); - lock->want_to_write--; - lock->have_writer = TRUE; - g_static_mutex_unlock (&lock->mutex); -} - -/** - * g_static_rw_lock_writer_trylock: - * @lock: a #GStaticRWLock to lock for writing. - * @Returns: %TRUE, if @lock could be locked for writing. - * - * Tries to lock @lock for writing. If @lock is already locked (for - * either reading or writing) by another thread, it immediately returns - * %FALSE. Otherwise it locks @lock for writing and returns %TRUE. This - * lock has to be unlocked by g_static_rw_lock_writer_unlock(). - * - * Deprectated: 2.32: Use g_rw_lock_writer_trylock() instead - */ -gboolean -g_static_rw_lock_writer_trylock (GStaticRWLock* lock) -{ - gboolean ret_val = FALSE; - - g_return_val_if_fail (lock, FALSE); - - if (!g_threads_got_initialized) - return TRUE; - - g_static_mutex_lock (&lock->mutex); - if (!lock->have_writer && !lock->read_counter) - { - lock->have_writer = TRUE; - ret_val = TRUE; - } - g_static_mutex_unlock (&lock->mutex); - return ret_val; -} - -/** - * g_static_rw_lock_writer_unlock: - * @lock: a #GStaticRWLock to unlock after writing. - * - * Unlocks @lock. If a thread is waiting to lock @lock for writing and - * all locks for reading have been unlocked, the waiting thread is - * woken up and can lock @lock for writing. If no thread is waiting to - * lock @lock for writing, and some thread or threads are waiting to - * lock @lock for reading, the waiting threads are woken up and can - * lock @lock for reading. - * - * Deprectated: 2.32: Use g_rw_lock_writer_unlock() instead - */ -void -g_static_rw_lock_writer_unlock (GStaticRWLock* lock) -{ - g_return_if_fail (lock); - - if (!g_threads_got_initialized) - return; - - g_static_mutex_lock (&lock->mutex); - lock->have_writer = FALSE; - g_static_rw_lock_signal (lock); - g_static_mutex_unlock (&lock->mutex); -} - -/** - * g_static_rw_lock_free: - * @lock: a #GStaticRWLock to be freed. - * - * Releases all resources allocated to @lock. - * - * You don't have to call this functions for a #GStaticRWLock with an - * unbounded lifetime, i.e. objects declared 'static', but if you have - * a #GStaticRWLock as a member of a structure, and the structure is - * freed, you should also free the #GStaticRWLock. - * - * Deprecated: 2.32: Use a #GRWLock instead - */ -void -g_static_rw_lock_free (GStaticRWLock* lock) -{ - g_return_if_fail (lock); - - if (lock->read_cond) - { - g_cond_free (lock->read_cond); - lock->read_cond = NULL; - } - if (lock->write_cond) - { - g_cond_free (lock->write_cond); - lock->write_cond = NULL; - } - g_static_mutex_free (&lock->mutex); -} - /* Unsorted {{{1 ---------------------------------------------------------- */ /** @@ -2446,29 +1512,4 @@ g_private_new (GDestroyNotify notify) return key; } -GThreadFunctions g_thread_functions_for_glib_use = -{ - g_mutex_new, - g_mutex_lock, - g_mutex_trylock, - g_mutex_unlock, - g_mutex_free, - g_cond_new, - g_cond_signal, - g_cond_broadcast, - g_cond_wait, - g_cond_timed_wait, - g_cond_free, - g_private_new, - g_private_get, - g_private_set, - NULL, - g_thread_yield, - NULL, - NULL, - NULL, - NULL, - NULL, -}; - /* vim: set foldmethod=marker: */ diff --git a/glib/gthreadprivate.h b/glib/gthreadprivate.h index e98647e2a..c924efa57 100644 --- a/glib/gthreadprivate.h +++ b/glib/gthreadprivate.h @@ -47,6 +47,9 @@ G_GNUC_INTERNAL gboolean g_system_thread_equal (gpointer thread1, G_GNUC_INTERNAL void g_system_thread_exit (void); +G_GNUC_INTERNAL GSystemThread zero_thread; +G_GNUC_INTERNAL GMutex g_once_mutex; + /* Is called from gthread/gthread-impl.c */ void g_thread_init_glib (void);