diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c index beb637d88..ee13d113e 100644 --- a/glib/gthread-posix.c +++ b/glib/gthread-posix.c @@ -146,78 +146,20 @@ g_mutex_get_impl (GMutex *mutex) } -/** - * g_mutex_init: - * @mutex: an uninitialized #GMutex - * - * Initializes a #GMutex so that it can be used. - * - * This function is useful to initialize a mutex that has been - * allocated on the stack, or as part of a larger structure. - * It is not necessary to initialize a mutex that has been - * statically allocated. - * - * |[ - * typedef struct { - * GMutex m; - * ... - * } Blob; - * - * Blob *b; - * - * b = g_new (Blob, 1); - * g_mutex_init (&b->m); - * ]| - * - * To undo the effect of g_mutex_init() when a mutex is no longer - * needed, use g_mutex_clear(). - * - * Calling g_mutex_init() on an already initialized #GMutex leads - * to undefined behaviour. - * - * Since: 2.32 - */ void -g_mutex_init (GMutex *mutex) +g_mutex_init_impl (GMutex *mutex) { mutex->p = g_mutex_impl_new (); } -/** - * g_mutex_clear: - * @mutex: an initialized #GMutex - * - * Frees the resources allocated to a mutex with g_mutex_init(). - * - * This function should not be used with a #GMutex that has been - * statically allocated. - * - * Calling g_mutex_clear() on a locked mutex leads to undefined - * behaviour. - * - * Since: 2.32 - */ void -g_mutex_clear (GMutex *mutex) +g_mutex_clear_impl (GMutex *mutex) { g_mutex_impl_free (mutex->p); } -/** - * g_mutex_lock: - * @mutex: a #GMutex - * - * Locks @mutex. If @mutex is already locked by another thread, the - * current thread will block until @mutex is unlocked by the other - * thread. - * - * #GMutex is neither guaranteed to be recursive nor to be - * non-recursive. As such, calling g_mutex_lock() on a #GMutex that has - * already been locked by the same thread results in undefined behaviour - * (including but not limited to deadlocks). - */ void -g_mutex_lock (GMutex *mutex) +g_mutex_lock_impl (GMutex *mutex) { gint status; @@ -225,18 +167,8 @@ g_mutex_lock (GMutex *mutex) g_thread_abort (status, "pthread_mutex_lock"); } -/** - * g_mutex_unlock: - * @mutex: a #GMutex - * - * Unlocks @mutex. If another thread is blocked in a g_mutex_lock() - * call for @mutex, it will become unblocked and can lock @mutex itself. - * - * Calling g_mutex_unlock() on a mutex that is not locked by the - * current thread leads to undefined behaviour. - */ void -g_mutex_unlock (GMutex *mutex) +g_mutex_unlock_impl (GMutex *mutex) { gint status; @@ -244,23 +176,8 @@ g_mutex_unlock (GMutex *mutex) g_thread_abort (status, "pthread_mutex_unlock"); } -/** - * g_mutex_trylock: - * @mutex: a #GMutex - * - * Tries to lock @mutex. If @mutex is already locked by another thread, - * it immediately returns %FALSE. Otherwise it locks @mutex and returns - * %TRUE. - * - * #GMutex is neither guaranteed to be recursive nor to be - * non-recursive. As such, calling g_mutex_lock() on a #GMutex that has - * already been locked by the same thread results in undefined behaviour - * (including but not limited to deadlocks or arbitrary return values). - * - * Returns: %TRUE if @mutex could be locked - */ gboolean -g_mutex_trylock (GMutex *mutex) +g_mutex_trylock_impl (GMutex *mutex) { gint status; @@ -318,118 +235,32 @@ g_rec_mutex_get_impl (GRecMutex *rec_mutex) return impl; } -/** - * g_rec_mutex_init: - * @rec_mutex: an uninitialized #GRecMutex - * - * Initializes a #GRecMutex so that it can be used. - * - * This function is useful to initialize a recursive mutex - * that has been allocated on the stack, or as part of a larger - * structure. - * - * It is not necessary to initialise a recursive mutex that has been - * statically allocated. - * - * |[ - * typedef struct { - * GRecMutex m; - * ... - * } Blob; - * - * Blob *b; - * - * b = g_new (Blob, 1); - * g_rec_mutex_init (&b->m); - * ]| - * - * Calling g_rec_mutex_init() on an already initialized #GRecMutex - * leads to undefined behaviour. - * - * To undo the effect of g_rec_mutex_init() when a recursive mutex - * is no longer needed, use g_rec_mutex_clear(). - * - * Since: 2.32 - */ void -g_rec_mutex_init (GRecMutex *rec_mutex) +g_rec_mutex_init_impl (GRecMutex *rec_mutex) { rec_mutex->p = g_rec_mutex_impl_new (); } -/** - * g_rec_mutex_clear: - * @rec_mutex: an initialized #GRecMutex - * - * Frees the resources allocated to a recursive mutex with - * g_rec_mutex_init(). - * - * This function should not be used with a #GRecMutex that has been - * statically allocated. - * - * Calling g_rec_mutex_clear() on a locked recursive mutex leads - * to undefined behaviour. - * - * Since: 2.32 - */ void -g_rec_mutex_clear (GRecMutex *rec_mutex) +g_rec_mutex_clear_impl (GRecMutex *rec_mutex) { g_rec_mutex_impl_free (rec_mutex->p); } -/** - * g_rec_mutex_lock: - * @rec_mutex: a #GRecMutex - * - * Locks @rec_mutex. If @rec_mutex is already locked by another - * thread, the current thread will block until @rec_mutex is - * unlocked by the other thread. If @rec_mutex is already locked - * by the current thread, the 'lock count' of @rec_mutex is increased. - * The mutex will only become available again when it is unlocked - * as many times as it has been locked. - * - * Since: 2.32 - */ void -g_rec_mutex_lock (GRecMutex *mutex) +g_rec_mutex_lock_impl (GRecMutex *mutex) { pthread_mutex_lock (g_rec_mutex_get_impl (mutex)); } -/** - * g_rec_mutex_unlock: - * @rec_mutex: a #GRecMutex - * - * Unlocks @rec_mutex. If another thread is blocked in a - * g_rec_mutex_lock() call for @rec_mutex, it will become unblocked - * and can lock @rec_mutex itself. - * - * Calling g_rec_mutex_unlock() on a recursive mutex that is not - * locked by the current thread leads to undefined behaviour. - * - * Since: 2.32 - */ void -g_rec_mutex_unlock (GRecMutex *rec_mutex) +g_rec_mutex_unlock_impl (GRecMutex *rec_mutex) { pthread_mutex_unlock (rec_mutex->p); } -/** - * g_rec_mutex_trylock: - * @rec_mutex: a #GRecMutex - * - * Tries to lock @rec_mutex. If @rec_mutex is already locked - * by another thread, it immediately returns %FALSE. Otherwise - * it locks @rec_mutex and returns %TRUE. - * - * Returns: %TRUE if @rec_mutex could be locked - * - * Since: 2.32 - */ gboolean -g_rec_mutex_trylock (GRecMutex *rec_mutex) +g_rec_mutex_trylock_impl (GRecMutex *rec_mutex) { if (pthread_mutex_trylock (g_rec_mutex_get_impl (rec_mutex)) != 0) return FALSE; @@ -478,78 +309,20 @@ g_rw_lock_get_impl (GRWLock *lock) return impl; } -/** - * g_rw_lock_init: - * @rw_lock: an uninitialized #GRWLock - * - * Initializes a #GRWLock so that it can be used. - * - * This function is useful to initialize a lock that has been - * allocated on the stack, or as part of a larger structure. It is not - * necessary to initialise a reader-writer lock that has been statically - * allocated. - * - * |[ - * typedef struct { - * GRWLock l; - * ... - * } Blob; - * - * Blob *b; - * - * b = g_new (Blob, 1); - * g_rw_lock_init (&b->l); - * ]| - * - * To undo the effect of g_rw_lock_init() when a lock is no longer - * needed, use g_rw_lock_clear(). - * - * Calling g_rw_lock_init() on an already initialized #GRWLock leads - * to undefined behaviour. - * - * Since: 2.32 - */ void -g_rw_lock_init (GRWLock *rw_lock) +g_rw_lock_init_impl (GRWLock *rw_lock) { rw_lock->p = g_rw_lock_impl_new (); } -/** - * g_rw_lock_clear: - * @rw_lock: an initialized #GRWLock - * - * Frees the resources allocated to a lock with g_rw_lock_init(). - * - * This function should not be used with a #GRWLock that has been - * statically allocated. - * - * Calling g_rw_lock_clear() when any thread holds the lock - * leads to undefined behaviour. - * - * Since: 2.32 - */ void -g_rw_lock_clear (GRWLock *rw_lock) +g_rw_lock_clear_impl (GRWLock *rw_lock) { g_rw_lock_impl_free (rw_lock->p); } -/** - * g_rw_lock_writer_lock: - * @rw_lock: a #GRWLock - * - * Obtain a write lock on @rw_lock. If another thread currently holds - * a read or write lock on @rw_lock, the current thread will block - * until all other threads have dropped their locks on @rw_lock. - * - * Calling g_rw_lock_writer_lock() while the current thread already - * owns a read or write lock on @rw_lock leads to undefined behaviour. - * - * Since: 2.32 - */ void -g_rw_lock_writer_lock (GRWLock *rw_lock) +g_rw_lock_writer_lock_impl (GRWLock *rw_lock) { int retval = pthread_rwlock_wrlock (g_rw_lock_get_impl (rw_lock)); @@ -557,21 +330,8 @@ g_rw_lock_writer_lock (GRWLock *rw_lock) g_critical ("Failed to get RW lock %p: %s", rw_lock, g_strerror (retval)); } -/** - * g_rw_lock_writer_trylock: - * @rw_lock: a #GRWLock - * - * Tries to obtain a write lock on @rw_lock. If another thread - * currently holds a read or write lock on @rw_lock, it immediately - * returns %FALSE. - * Otherwise it locks @rw_lock and returns %TRUE. - * - * Returns: %TRUE if @rw_lock could be locked - * - * Since: 2.32 - */ gboolean -g_rw_lock_writer_trylock (GRWLock *rw_lock) +g_rw_lock_writer_trylock_impl (GRWLock *rw_lock) { if (pthread_rwlock_trywrlock (g_rw_lock_get_impl (rw_lock)) != 0) return FALSE; @@ -579,47 +339,14 @@ g_rw_lock_writer_trylock (GRWLock *rw_lock) return TRUE; } -/** - * g_rw_lock_writer_unlock: - * @rw_lock: a #GRWLock - * - * Release a write lock on @rw_lock. - * - * Calling g_rw_lock_writer_unlock() on a lock that is not held - * by the current thread leads to undefined behaviour. - * - * Since: 2.32 - */ void -g_rw_lock_writer_unlock (GRWLock *rw_lock) +g_rw_lock_writer_unlock_impl (GRWLock *rw_lock) { pthread_rwlock_unlock (g_rw_lock_get_impl (rw_lock)); } -/** - * g_rw_lock_reader_lock: - * @rw_lock: a #GRWLock - * - * Obtain a read lock on @rw_lock. If another thread currently holds - * the write lock on @rw_lock, the current thread will block until the - * write lock was (held and) released. If another thread does not hold - * the write lock, but is waiting for it, it is implementation defined - * whether the reader or writer will block. Read locks can be taken - * recursively. - * - * Calling g_rw_lock_reader_lock() while the current thread already - * owns a write lock leads to undefined behaviour. Read locks however - * can be taken recursively, in which case you need to make sure to - * call g_rw_lock_reader_unlock() the same amount of times. - * - * It is implementation-defined how many read locks are allowed to be - * held on the same lock simultaneously. If the limit is hit, - * or if a deadlock is detected, a critical warning will be emitted. - * - * Since: 2.32 - */ void -g_rw_lock_reader_lock (GRWLock *rw_lock) +g_rw_lock_reader_lock_impl (GRWLock *rw_lock) { int retval = pthread_rwlock_rdlock (g_rw_lock_get_impl (rw_lock)); @@ -627,20 +354,8 @@ g_rw_lock_reader_lock (GRWLock *rw_lock) g_critical ("Failed to get RW lock %p: %s", rw_lock, g_strerror (retval)); } -/** - * g_rw_lock_reader_trylock: - * @rw_lock: a #GRWLock - * - * Tries to obtain a read lock on @rw_lock and returns %TRUE if - * the read lock was successfully obtained. Otherwise it - * returns %FALSE. - * - * Returns: %TRUE if @rw_lock could be locked - * - * Since: 2.32 - */ gboolean -g_rw_lock_reader_trylock (GRWLock *rw_lock) +g_rw_lock_reader_trylock_impl (GRWLock *rw_lock) { if (pthread_rwlock_tryrdlock (g_rw_lock_get_impl (rw_lock)) != 0) return FALSE; @@ -648,19 +363,8 @@ g_rw_lock_reader_trylock (GRWLock *rw_lock) return TRUE; } -/** - * g_rw_lock_reader_unlock: - * @rw_lock: a #GRWLock - * - * Release a read lock on @rw_lock. - * - * Calling g_rw_lock_reader_unlock() on a lock that is not held - * by the current thread leads to undefined behaviour. - * - * Since: 2.32 - */ void -g_rw_lock_reader_unlock (GRWLock *rw_lock) +g_rw_lock_reader_unlock_impl (GRWLock *rw_lock) { pthread_rwlock_unlock (g_rw_lock_get_impl (rw_lock)); } @@ -721,73 +425,21 @@ g_cond_get_impl (GCond *cond) return impl; } -/** - * g_cond_init: - * @cond: an uninitialized #GCond - * - * Initialises a #GCond so that it can be used. - * - * This function is useful to initialise a #GCond that has been - * allocated as part of a larger structure. It is not necessary to - * initialise a #GCond that has been statically allocated. - * - * To undo the effect of g_cond_init() when a #GCond is no longer - * needed, use g_cond_clear(). - * - * Calling g_cond_init() on an already-initialised #GCond leads - * to undefined behaviour. - * - * Since: 2.32 - */ void -g_cond_init (GCond *cond) +g_cond_init_impl (GCond *cond) { cond->p = g_cond_impl_new (); } -/** - * g_cond_clear: - * @cond: an initialised #GCond - * - * Frees the resources allocated to a #GCond with g_cond_init(). - * - * This function should not be used with a #GCond that has been - * statically allocated. - * - * Calling g_cond_clear() for a #GCond on which threads are - * blocking leads to undefined behaviour. - * - * Since: 2.32 - */ void -g_cond_clear (GCond *cond) +g_cond_clear_impl (GCond *cond) { g_cond_impl_free (cond->p); } -/** - * g_cond_wait: - * @cond: a #GCond - * @mutex: a #GMutex that is currently locked - * - * Atomically releases @mutex and waits until @cond is signalled. - * When this function returns, @mutex is locked again and owned by the - * calling thread. - * - * When using condition variables, it is possible that a spurious wakeup - * may occur (ie: g_cond_wait() returns even though g_cond_signal() was - * not called). It's also possible that a stolen wakeup may occur. - * This is when g_cond_signal() is called, but another thread acquires - * @mutex before this thread and modifies the state of the program in - * such a way that when g_cond_wait() is able to return, the expected - * condition is no longer met. - * - * For this reason, g_cond_wait() must always be used in a loop. See - * the documentation for #GCond for a complete example. - **/ void -g_cond_wait (GCond *cond, - GMutex *mutex) +g_cond_wait_impl (GCond *cond, + GMutex *mutex) { gint status; @@ -795,17 +447,8 @@ g_cond_wait (GCond *cond, g_thread_abort (status, "pthread_cond_wait"); } -/** - * g_cond_signal: - * @cond: a #GCond - * - * If threads are waiting for @cond, at least one of them is unblocked. - * If no threads are waiting for @cond, this function has no effect. - * It is good practice to hold the same lock as the waiting thread - * while calling this function, though not required. - */ void -g_cond_signal (GCond *cond) +g_cond_signal_impl (GCond *cond) { gint status; @@ -813,17 +456,8 @@ g_cond_signal (GCond *cond) g_thread_abort (status, "pthread_cond_signal"); } -/** - * g_cond_broadcast: - * @cond: a #GCond - * - * If threads are waiting for @cond, all of them are unblocked. - * If no threads are waiting for @cond, this function has no effect. - * It is good practice to lock the same mutex as the waiting threads - * while calling this function, though not required. - */ void -g_cond_broadcast (GCond *cond) +g_cond_broadcast_impl (GCond *cond) { gint status; @@ -831,68 +465,10 @@ g_cond_broadcast (GCond *cond) g_thread_abort (status, "pthread_cond_broadcast"); } -/** - * g_cond_wait_until: - * @cond: a #GCond - * @mutex: a #GMutex that is currently locked - * @end_time: the monotonic time to wait until - * - * Waits until either @cond is signalled or @end_time has passed. - * - * As with g_cond_wait() it is possible that a spurious or stolen wakeup - * could occur. For that reason, waiting on a condition variable should - * always be in a loop, based on an explicitly-checked predicate. - * - * %TRUE is returned if the condition variable was signalled (or in the - * case of a spurious wakeup). %FALSE is returned if @end_time has - * passed. - * - * The following code shows how to correctly perform a timed wait on a - * condition variable (extending the example presented in the - * documentation for #GCond): - * - * |[ - * gpointer - * pop_data_timed (void) - * { - * gint64 end_time; - * gpointer data; - * - * g_mutex_lock (&data_mutex); - * - * end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND; - * while (!current_data) - * if (!g_cond_wait_until (&data_cond, &data_mutex, end_time)) - * { - * // timeout has passed. - * g_mutex_unlock (&data_mutex); - * return NULL; - * } - * - * // there is data for us - * data = current_data; - * current_data = NULL; - * - * g_mutex_unlock (&data_mutex); - * - * return data; - * } - * ]| - * - * Notice that the end time is calculated once, before entering the - * loop and reused. This is the motivation behind the use of absolute - * time on this API -- if a relative time of 5 seconds were passed - * directly to the call and a spurious wakeup occurred, the program would - * have to start over waiting again (which would lead to a total wait - * time of more than 5 seconds). - * - * Returns: %TRUE on a signal, %FALSE on a timeout - * Since: 2.32 - **/ gboolean -g_cond_wait_until (GCond *cond, - GMutex *mutex, - gint64 end_time) +g_cond_wait_until_impl (GCond *cond, + GMutex *mutex, + gint64 end_time) { struct timespec ts; gint status; @@ -944,82 +520,6 @@ g_cond_wait_until (GCond *cond, /* {{{1 GPrivate */ -/** - * GPrivate: - * - * The #GPrivate struct is an opaque data structure to represent a - * thread-local data key. It is approximately equivalent to the - * pthread_setspecific()/pthread_getspecific() APIs on POSIX and to - * TlsSetValue()/TlsGetValue() on Windows. - * - * If you don't already know why you might want this functionality, - * then you probably don't need it. - * - * #GPrivate is a very limited resource (as far as 128 per program, - * shared between all libraries). It is also not possible to destroy a - * #GPrivate after it has been used. As such, it is only ever acceptable - * to use #GPrivate in static scope, and even then sparingly so. - * - * See G_PRIVATE_INIT() for a couple of examples. - * - * The #GPrivate structure should be considered opaque. It should only - * be accessed via the g_private_ functions. - */ - -/** - * G_PRIVATE_INIT: - * @notify: a #GDestroyNotify - * - * A macro to assist with the static initialisation of a #GPrivate. - * - * This macro is useful for the case that a #GDestroyNotify function - * should be associated with the key. This is needed when the key will be - * used to point at memory that should be deallocated when the thread - * exits. - * - * Additionally, the #GDestroyNotify will also be called on the previous - * value stored in the key when g_private_replace() is used. - * - * If no #GDestroyNotify is needed, then use of this macro is not - * required -- if the #GPrivate is declared in static scope then it will - * be properly initialised by default (ie: to all zeros). See the - * examples below. - * - * |[ - * static GPrivate name_key = G_PRIVATE_INIT (g_free); - * - * // return value should not be freed - * const gchar * - * get_local_name (void) - * { - * return g_private_get (&name_key); - * } - * - * void - * set_local_name (const gchar *name) - * { - * g_private_replace (&name_key, g_strdup (name)); - * } - * - * - * static GPrivate count_key; // no free function - * - * gint - * get_local_count (void) - * { - * return GPOINTER_TO_INT (g_private_get (&count_key)); - * } - * - * void - * set_local_count (gint count) - * { - * g_private_set (&count_key, GINT_TO_POINTER (count)); - * } - * ]| - * - * Since: 2.32 - **/ - static pthread_key_t * g_private_impl_new (GDestroyNotify notify) { @@ -1103,7 +603,7 @@ g_private_impl_free_direct (gpointer impl) } static inline pthread_key_t -g_private_get_impl (GPrivate *key) +_g_private_get_impl (GPrivate *key) { if (sizeof (pthread_key_t) > sizeof (gpointer)) { @@ -1142,65 +642,28 @@ g_private_get_impl (GPrivate *key) } } -/** - * g_private_get: - * @key: a #GPrivate - * - * Returns the current value of the thread local variable @key. - * - * If the value has not yet been set in this thread, %NULL is returned. - * Values are never copied between threads (when a new thread is - * created, for example). - * - * Returns: the thread-local value - */ gpointer -g_private_get (GPrivate *key) +g_private_get_impl (GPrivate *key) { /* quote POSIX: No errors are returned from pthread_getspecific(). */ - return pthread_getspecific (g_private_get_impl (key)); + return pthread_getspecific (_g_private_get_impl (key)); } -/** - * g_private_set: - * @key: a #GPrivate - * @value: the new value - * - * Sets the thread local variable @key to have the value @value in the - * current thread. - * - * This function differs from g_private_replace() in the following way: - * the #GDestroyNotify for @key is not called on the old value. - */ void -g_private_set (GPrivate *key, - gpointer value) +g_private_set_impl (GPrivate *key, + gpointer value) { gint status; - if G_UNLIKELY ((status = pthread_setspecific (g_private_get_impl (key), value)) != 0) + if G_UNLIKELY ((status = pthread_setspecific (_g_private_get_impl (key), value)) != 0) g_thread_abort (status, "pthread_setspecific"); } -/** - * g_private_replace: - * @key: a #GPrivate - * @value: the new value - * - * Sets the thread local variable @key to have the value @value in the - * current thread. - * - * This function differs from g_private_set() in the following way: if - * the previous value was non-%NULL then the #GDestroyNotify handler for - * @key is run on it. - * - * Since: 2.32 - **/ void -g_private_replace (GPrivate *key, - gpointer value) +g_private_replace_impl (GPrivate *key, + gpointer value) { - pthread_key_t impl = g_private_get_impl (key); + pthread_key_t impl = _g_private_get_impl (key); gpointer old; gint status; @@ -1315,16 +778,8 @@ g_system_thread_new (GThreadFunc proxy, return (GRealThread *) thread; } -/** - * g_thread_yield: - * - * Causes the calling thread to voluntarily relinquish the CPU, so - * that other threads can run. - * - * This function is often used as a method to make busy wait less evil. - */ void -g_thread_yield (void) +g_thread_yield_impl (void) { sched_yield (); } @@ -1436,13 +891,13 @@ typedef enum { */ void -g_mutex_init (GMutex *mutex) +g_mutex_init_impl (GMutex *mutex) { mutex->i[0] = G_MUTEX_STATE_EMPTY; } void -g_mutex_clear (GMutex *mutex) +g_mutex_clear_impl (GMutex *mutex) { if G_UNLIKELY (mutex->i[0] != G_MUTEX_STATE_EMPTY) { @@ -1485,7 +940,7 @@ g_mutex_unlock_slowpath (GMutex *mutex, } void -g_mutex_lock (GMutex *mutex) +g_mutex_lock_impl (GMutex *mutex) { /* empty -> owned and we're done. Anything else, and we need to wait... */ if G_UNLIKELY (!g_atomic_int_compare_and_exchange (&mutex->i[0], @@ -1495,7 +950,7 @@ g_mutex_lock (GMutex *mutex) } void -g_mutex_unlock (GMutex *mutex) +g_mutex_unlock_impl (GMutex *mutex) { guint prev; @@ -1507,7 +962,7 @@ g_mutex_unlock (GMutex *mutex) } gboolean -g_mutex_trylock (GMutex *mutex) +g_mutex_trylock_impl (GMutex *mutex) { GMutexState empty = G_MUTEX_STATE_EMPTY; @@ -1532,19 +987,19 @@ g_mutex_trylock (GMutex *mutex) */ void -g_cond_init (GCond *cond) +g_cond_init_impl (GCond *cond) { cond->i[0] = 0; } void -g_cond_clear (GCond *cond) +g_cond_clear_impl (GCond *cond) { } void -g_cond_wait (GCond *cond, - GMutex *mutex) +g_cond_wait_impl (GCond *cond, + GMutex *mutex) { guint sampled = (guint) g_atomic_int_get (&cond->i[0]); @@ -1554,7 +1009,7 @@ g_cond_wait (GCond *cond, } void -g_cond_signal (GCond *cond) +g_cond_signal_impl (GCond *cond) { g_atomic_int_inc (&cond->i[0]); @@ -1562,7 +1017,7 @@ g_cond_signal (GCond *cond) } void -g_cond_broadcast (GCond *cond) +g_cond_broadcast_impl (GCond *cond) { g_atomic_int_inc (&cond->i[0]); @@ -1570,9 +1025,9 @@ g_cond_broadcast (GCond *cond) } gboolean -g_cond_wait_until (GCond *cond, - GMutex *mutex, - gint64 end_time) +g_cond_wait_until_impl (GCond *cond, + GMutex *mutex, + gint64 end_time) { struct timespec now; struct timespec span; diff --git a/glib/gthread-win32.c b/glib/gthread-win32.c index fc5697dfb..519e9b628 100644 --- a/glib/gthread-win32.c +++ b/glib/gthread-win32.c @@ -79,30 +79,30 @@ g_thread_abort (gint status, /* {{{1 GMutex */ void -g_mutex_init (GMutex *mutex) +g_mutex_init_impl (GMutex *mutex) { InitializeSRWLock ((gpointer) mutex); } void -g_mutex_clear (GMutex *mutex) +g_mutex_clear_impl (GMutex *mutex) { } void -g_mutex_lock (GMutex *mutex) +g_mutex_lock_impl (GMutex *mutex) { AcquireSRWLockExclusive ((gpointer) mutex); } gboolean -g_mutex_trylock (GMutex *mutex) +g_mutex_trylock_impl (GMutex *mutex) { return TryAcquireSRWLockExclusive ((gpointer) mutex); } void -g_mutex_unlock (GMutex *mutex) +g_mutex_unlock_impl (GMutex *mutex) { ReleaseSRWLockExclusive ((gpointer) mutex); } @@ -144,31 +144,31 @@ g_rec_mutex_get_impl (GRecMutex *mutex) } void -g_rec_mutex_init (GRecMutex *mutex) +g_rec_mutex_init_impl (GRecMutex *mutex) { mutex->p = g_rec_mutex_impl_new (); } void -g_rec_mutex_clear (GRecMutex *mutex) +g_rec_mutex_clear_impl (GRecMutex *mutex) { g_rec_mutex_impl_free (mutex->p); } void -g_rec_mutex_lock (GRecMutex *mutex) +g_rec_mutex_lock_impl (GRecMutex *mutex) { EnterCriticalSection (g_rec_mutex_get_impl (mutex)); } void -g_rec_mutex_unlock (GRecMutex *mutex) +g_rec_mutex_unlock_impl (GRecMutex *mutex) { LeaveCriticalSection (mutex->p); } gboolean -g_rec_mutex_trylock (GRecMutex *mutex) +g_rec_mutex_trylock_impl (GRecMutex *mutex) { return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex)); } @@ -176,87 +176,87 @@ g_rec_mutex_trylock (GRecMutex *mutex) /* {{{1 GRWLock */ void -g_rw_lock_init (GRWLock *lock) +g_rw_lock_init_impl (GRWLock *lock) { InitializeSRWLock ((gpointer) lock); } void -g_rw_lock_clear (GRWLock *lock) +g_rw_lock_clear_impl (GRWLock *lock) { } void -g_rw_lock_writer_lock (GRWLock *lock) +g_rw_lock_writer_lock_impl (GRWLock *lock) { AcquireSRWLockExclusive ((gpointer) lock); } gboolean -g_rw_lock_writer_trylock (GRWLock *lock) +g_rw_lock_writer_trylock_impl (GRWLock *lock) { return TryAcquireSRWLockExclusive ((gpointer) lock); } void -g_rw_lock_writer_unlock (GRWLock *lock) +g_rw_lock_writer_unlock_impl (GRWLock *lock) { ReleaseSRWLockExclusive ((gpointer) lock); } void -g_rw_lock_reader_lock (GRWLock *lock) +g_rw_lock_reader_lock_impl (GRWLock *lock) { AcquireSRWLockShared ((gpointer) lock); } gboolean -g_rw_lock_reader_trylock (GRWLock *lock) +g_rw_lock_reader_trylock_impl (GRWLock *lock) { return TryAcquireSRWLockShared ((gpointer) lock); } void -g_rw_lock_reader_unlock (GRWLock *lock) +g_rw_lock_reader_unlock_impl (GRWLock *lock) { ReleaseSRWLockShared ((gpointer) lock); } /* {{{1 GCond */ void -g_cond_init (GCond *cond) +g_cond_init_impl (GCond *cond) { InitializeConditionVariable ((gpointer) cond); } void -g_cond_clear (GCond *cond) +g_cond_clear_impl (GCond *cond) { } void -g_cond_signal (GCond *cond) +g_cond_signal_impl (GCond *cond) { WakeConditionVariable ((gpointer) cond); } void -g_cond_broadcast (GCond *cond) +g_cond_broadcast_impl (GCond *cond) { WakeAllConditionVariable ((gpointer) cond); } void -g_cond_wait (GCond *cond, - GMutex *entered_mutex) +g_cond_wait_impl (GCond *cond, + GMutex *entered_mutex) { SleepConditionVariableSRW ((gpointer) cond, (gpointer) entered_mutex, INFINITE, 0); } gboolean -g_cond_wait_until (GCond *cond, - GMutex *entered_mutex, - gint64 end_time) +g_cond_wait_until_impl (GCond *cond, + GMutex *entered_mutex, + gint64 end_time) { gint64 span, start_time; DWORD span_millis; @@ -307,7 +307,7 @@ static GPrivateDestructor *g_private_destructors; /* (atomic) prepend-only */ static CRITICAL_SECTION g_private_lock; static DWORD -g_private_get_impl (GPrivate *key) +_g_private_get_impl (GPrivate *key) { DWORD impl = (DWORD) GPOINTER_TO_UINT(key->p); @@ -366,23 +366,23 @@ g_private_get_impl (GPrivate *key) } gpointer -g_private_get (GPrivate *key) +g_private_get_impl (GPrivate *key) { - return TlsGetValue (g_private_get_impl (key)); + return TlsGetValue (_g_private_get_impl (key)); } void -g_private_set (GPrivate *key, - gpointer value) +g_private_set_impl (GPrivate *key, + gpointer value) { - TlsSetValue (g_private_get_impl (key), value); + TlsSetValue (_g_private_get_impl (key), value); } void -g_private_replace (GPrivate *key, - gpointer value) +g_private_replace_impl (GPrivate *key, + gpointer value) { - DWORD impl = g_private_get_impl (key); + DWORD impl = _g_private_get_impl (key); gpointer old; old = TlsGetValue (impl); @@ -522,7 +522,7 @@ error: } void -g_thread_yield (void) +g_thread_yield_impl (void) { Sleep(0); } diff --git a/glib/gthread.c b/glib/gthread.c index a264353ec..568672aae 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -1129,5 +1129,731 @@ g_get_num_processors (void) return 1; /* Fallback */ } +/** + * g_mutex_init: + * @mutex: an uninitialized #GMutex + * + * Initializes a #GMutex so that it can be used. + * + * This function is useful to initialize a mutex that has been + * allocated on the stack, or as part of a larger structure. + * It is not necessary to initialize a mutex that has been + * statically allocated. + * + * |[ + * typedef struct { + * GMutex m; + * ... + * } Blob; + * + * Blob *b; + * + * b = g_new (Blob, 1); + * g_mutex_init (&b->m); + * ]| + * + * To undo the effect of g_mutex_init() when a mutex is no longer + * needed, use g_mutex_clear(). + * + * Calling g_mutex_init() on an already initialized #GMutex leads + * to undefined behaviour. + * + * Since: 2.32 + */ +void +g_mutex_init (GMutex *mutex) +{ + g_mutex_init_impl (mutex); +} + +/** + * g_mutex_clear: + * @mutex: an initialized #GMutex + * + * Frees the resources allocated to a mutex with g_mutex_init(). + * + * This function should not be used with a #GMutex that has been + * statically allocated. + * + * Calling g_mutex_clear() on a locked mutex leads to undefined + * behaviour. + * + * Since: 2.32 + */ +void +g_mutex_clear (GMutex *mutex) +{ + g_mutex_clear_impl (mutex); +} + +/** + * g_mutex_lock: + * @mutex: a #GMutex + * + * Locks @mutex. If @mutex is already locked by another thread, the + * current thread will block until @mutex is unlocked by the other + * thread. + * + * #GMutex is neither guaranteed to be recursive nor to be + * non-recursive. As such, calling g_mutex_lock() on a #GMutex that has + * already been locked by the same thread results in undefined behaviour + * (including but not limited to deadlocks). + */ +void +g_mutex_lock (GMutex *mutex) +{ + g_mutex_lock_impl (mutex); +} + +/** + * g_mutex_unlock: + * @mutex: a #GMutex + * + * Unlocks @mutex. If another thread is blocked in a g_mutex_lock() + * call for @mutex, it will become unblocked and can lock @mutex itself. + * + * Calling g_mutex_unlock() on a mutex that is not locked by the + * current thread leads to undefined behaviour. + */ +void +g_mutex_unlock (GMutex *mutex) +{ + g_mutex_unlock_impl (mutex); +} + +/** + * g_mutex_trylock: + * @mutex: a #GMutex + * + * Tries to lock @mutex. If @mutex is already locked by another thread, + * it immediately returns %FALSE. Otherwise it locks @mutex and returns + * %TRUE. + * + * #GMutex is neither guaranteed to be recursive nor to be + * non-recursive. As such, calling g_mutex_lock() on a #GMutex that has + * already been locked by the same thread results in undefined behaviour + * (including but not limited to deadlocks or arbitrary return values). + * + * Returns: %TRUE if @mutex could be locked + */ +gboolean +g_mutex_trylock (GMutex *mutex) +{ + return g_mutex_trylock_impl (mutex); +} + +/** + * g_rec_mutex_init: + * @rec_mutex: an uninitialized #GRecMutex + * + * Initializes a #GRecMutex so that it can be used. + * + * This function is useful to initialize a recursive mutex + * that has been allocated on the stack, or as part of a larger + * structure. + * + * It is not necessary to initialise a recursive mutex that has been + * statically allocated. + * + * |[ + * typedef struct { + * GRecMutex m; + * ... + * } Blob; + * + * Blob *b; + * + * b = g_new (Blob, 1); + * g_rec_mutex_init (&b->m); + * ]| + * + * Calling g_rec_mutex_init() on an already initialized #GRecMutex + * leads to undefined behaviour. + * + * To undo the effect of g_rec_mutex_init() when a recursive mutex + * is no longer needed, use g_rec_mutex_clear(). + * + * Since: 2.32 + */ +void +g_rec_mutex_init (GRecMutex *rec_mutex) +{ + g_rec_mutex_init_impl (rec_mutex); +} + +/** + * g_rec_mutex_clear: + * @rec_mutex: an initialized #GRecMutex + * + * Frees the resources allocated to a recursive mutex with + * g_rec_mutex_init(). + * + * This function should not be used with a #GRecMutex that has been + * statically allocated. + * + * Calling g_rec_mutex_clear() on a locked recursive mutex leads + * to undefined behaviour. + * + * Since: 2.32 + */ +void +g_rec_mutex_clear (GRecMutex *rec_mutex) +{ + g_rec_mutex_clear_impl (rec_mutex); +} + +/** + * g_rec_mutex_lock: + * @rec_mutex: a #GRecMutex + * + * Locks @rec_mutex. If @rec_mutex is already locked by another + * thread, the current thread will block until @rec_mutex is + * unlocked by the other thread. If @rec_mutex is already locked + * by the current thread, the 'lock count' of @rec_mutex is increased. + * The mutex will only become available again when it is unlocked + * as many times as it has been locked. + * + * Since: 2.32 + */ +void +g_rec_mutex_lock (GRecMutex *mutex) +{ + g_rec_mutex_lock_impl (mutex); +} + +/** + * g_rec_mutex_unlock: + * @rec_mutex: a #GRecMutex + * + * Unlocks @rec_mutex. If another thread is blocked in a + * g_rec_mutex_lock() call for @rec_mutex, it will become unblocked + * and can lock @rec_mutex itself. + * + * Calling g_rec_mutex_unlock() on a recursive mutex that is not + * locked by the current thread leads to undefined behaviour. + * + * Since: 2.32 + */ +void +g_rec_mutex_unlock (GRecMutex *rec_mutex) +{ + g_rec_mutex_unlock_impl (rec_mutex); +} + +/** + * g_rec_mutex_trylock: + * @rec_mutex: a #GRecMutex + * + * Tries to lock @rec_mutex. If @rec_mutex is already locked + * by another thread, it immediately returns %FALSE. Otherwise + * it locks @rec_mutex and returns %TRUE. + * + * Returns: %TRUE if @rec_mutex could be locked + * + * Since: 2.32 + */ +gboolean +g_rec_mutex_trylock (GRecMutex *rec_mutex) +{ + return g_rec_mutex_trylock_impl (rec_mutex); +} + +/* {{{1 GRWLock */ + +/** + * g_rw_lock_init: + * @rw_lock: an uninitialized #GRWLock + * + * Initializes a #GRWLock so that it can be used. + * + * This function is useful to initialize a lock that has been + * allocated on the stack, or as part of a larger structure. It is not + * necessary to initialise a reader-writer lock that has been statically + * allocated. + * + * |[ + * typedef struct { + * GRWLock l; + * ... + * } Blob; + * + * Blob *b; + * + * b = g_new (Blob, 1); + * g_rw_lock_init (&b->l); + * ]| + * + * To undo the effect of g_rw_lock_init() when a lock is no longer + * needed, use g_rw_lock_clear(). + * + * Calling g_rw_lock_init() on an already initialized #GRWLock leads + * to undefined behaviour. + * + * Since: 2.32 + */ +void +g_rw_lock_init (GRWLock *rw_lock) +{ + g_rw_lock_init_impl (rw_lock); +} + +/** + * g_rw_lock_clear: + * @rw_lock: an initialized #GRWLock + * + * Frees the resources allocated to a lock with g_rw_lock_init(). + * + * This function should not be used with a #GRWLock that has been + * statically allocated. + * + * Calling g_rw_lock_clear() when any thread holds the lock + * leads to undefined behaviour. + * + * Since: 2.32 + */ +void +g_rw_lock_clear (GRWLock *rw_lock) +{ + g_rw_lock_clear_impl (rw_lock); +} + +/** + * g_rw_lock_writer_lock: + * @rw_lock: a #GRWLock + * + * Obtain a write lock on @rw_lock. If another thread currently holds + * a read or write lock on @rw_lock, the current thread will block + * until all other threads have dropped their locks on @rw_lock. + * + * Calling g_rw_lock_writer_lock() while the current thread already + * owns a read or write lock on @rw_lock leads to undefined behaviour. + * + * Since: 2.32 + */ +void +g_rw_lock_writer_lock (GRWLock *rw_lock) +{ + g_rw_lock_writer_lock_impl (rw_lock); +} + +/** + * g_rw_lock_writer_trylock: + * @rw_lock: a #GRWLock + * + * Tries to obtain a write lock on @rw_lock. If another thread + * currently holds a read or write lock on @rw_lock, it immediately + * returns %FALSE. + * Otherwise it locks @rw_lock and returns %TRUE. + * + * Returns: %TRUE if @rw_lock could be locked + * + * Since: 2.32 + */ +gboolean +g_rw_lock_writer_trylock (GRWLock *rw_lock) +{ + return g_rw_lock_writer_trylock_impl (rw_lock); +} + +/** + * g_rw_lock_writer_unlock: + * @rw_lock: a #GRWLock + * + * Release a write lock on @rw_lock. + * + * Calling g_rw_lock_writer_unlock() on a lock that is not held + * by the current thread leads to undefined behaviour. + * + * Since: 2.32 + */ +void +g_rw_lock_writer_unlock (GRWLock *rw_lock) +{ + g_rw_lock_writer_unlock_impl (rw_lock); +} + +/** + * g_rw_lock_reader_lock: + * @rw_lock: a #GRWLock + * + * Obtain a read lock on @rw_lock. If another thread currently holds + * the write lock on @rw_lock, the current thread will block until the + * write lock was (held and) released. If another thread does not hold + * the write lock, but is waiting for it, it is implementation defined + * whether the reader or writer will block. Read locks can be taken + * recursively. + * + * Calling g_rw_lock_reader_lock() while the current thread already + * owns a write lock leads to undefined behaviour. Read locks however + * can be taken recursively, in which case you need to make sure to + * call g_rw_lock_reader_unlock() the same amount of times. + * + * It is implementation-defined how many read locks are allowed to be + * held on the same lock simultaneously. If the limit is hit, + * or if a deadlock is detected, a critical warning will be emitted. + * + * Since: 2.32 + */ +void +g_rw_lock_reader_lock (GRWLock *rw_lock) +{ + g_rw_lock_reader_lock_impl (rw_lock); +} + +/** + * g_rw_lock_reader_trylock: + * @rw_lock: a #GRWLock + * + * Tries to obtain a read lock on @rw_lock and returns %TRUE if + * the read lock was successfully obtained. Otherwise it + * returns %FALSE. + * + * Returns: %TRUE if @rw_lock could be locked + * + * Since: 2.32 + */ +gboolean +g_rw_lock_reader_trylock (GRWLock *rw_lock) +{ + return g_rw_lock_reader_trylock_impl (rw_lock); +} + +/** + * g_rw_lock_reader_unlock: + * @rw_lock: a #GRWLock + * + * Release a read lock on @rw_lock. + * + * Calling g_rw_lock_reader_unlock() on a lock that is not held + * by the current thread leads to undefined behaviour. + * + * Since: 2.32 + */ +void +g_rw_lock_reader_unlock (GRWLock *rw_lock) +{ + g_rw_lock_reader_unlock_impl (rw_lock); +} + +/* {{{1 GCond */ + +/** + * g_cond_init: + * @cond: an uninitialized #GCond + * + * Initialises a #GCond so that it can be used. + * + * This function is useful to initialise a #GCond that has been + * allocated as part of a larger structure. It is not necessary to + * initialise a #GCond that has been statically allocated. + * + * To undo the effect of g_cond_init() when a #GCond is no longer + * needed, use g_cond_clear(). + * + * Calling g_cond_init() on an already-initialised #GCond leads + * to undefined behaviour. + * + * Since: 2.32 + */ +void +g_cond_init (GCond *cond) +{ + g_cond_init_impl (cond); +} + +/** + * g_cond_clear: + * @cond: an initialised #GCond + * + * Frees the resources allocated to a #GCond with g_cond_init(). + * + * This function should not be used with a #GCond that has been + * statically allocated. + * + * Calling g_cond_clear() for a #GCond on which threads are + * blocking leads to undefined behaviour. + * + * Since: 2.32 + */ +void +g_cond_clear (GCond *cond) +{ + g_cond_clear_impl (cond); +} + +/** + * g_cond_wait: + * @cond: a #GCond + * @mutex: a #GMutex that is currently locked + * + * Atomically releases @mutex and waits until @cond is signalled. + * When this function returns, @mutex is locked again and owned by the + * calling thread. + * + * When using condition variables, it is possible that a spurious wakeup + * may occur (ie: g_cond_wait() returns even though g_cond_signal() was + * not called). It's also possible that a stolen wakeup may occur. + * This is when g_cond_signal() is called, but another thread acquires + * @mutex before this thread and modifies the state of the program in + * such a way that when g_cond_wait() is able to return, the expected + * condition is no longer met. + * + * For this reason, g_cond_wait() must always be used in a loop. See + * the documentation for #GCond for a complete example. + **/ +void +g_cond_wait (GCond *cond, + GMutex *mutex) +{ + g_cond_wait_impl (cond, mutex); +} + +/** + * g_cond_signal: + * @cond: a #GCond + * + * If threads are waiting for @cond, at least one of them is unblocked. + * If no threads are waiting for @cond, this function has no effect. + * It is good practice to hold the same lock as the waiting thread + * while calling this function, though not required. + */ +void +g_cond_signal (GCond *cond) +{ + g_cond_signal_impl (cond); +} + +/** + * g_cond_broadcast: + * @cond: a #GCond + * + * If threads are waiting for @cond, all of them are unblocked. + * If no threads are waiting for @cond, this function has no effect. + * It is good practice to lock the same mutex as the waiting threads + * while calling this function, though not required. + */ +void +g_cond_broadcast (GCond *cond) +{ + g_cond_broadcast_impl (cond); +} + +/** + * g_cond_wait_until: + * @cond: a #GCond + * @mutex: a #GMutex that is currently locked + * @end_time: the monotonic time to wait until + * + * Waits until either @cond is signalled or @end_time has passed. + * + * As with g_cond_wait() it is possible that a spurious or stolen wakeup + * could occur. For that reason, waiting on a condition variable should + * always be in a loop, based on an explicitly-checked predicate. + * + * %TRUE is returned if the condition variable was signalled (or in the + * case of a spurious wakeup). %FALSE is returned if @end_time has + * passed. + * + * The following code shows how to correctly perform a timed wait on a + * condition variable (extending the example presented in the + * documentation for #GCond): + * + * |[ + * gpointer + * pop_data_timed (void) + * { + * gint64 end_time; + * gpointer data; + * + * g_mutex_lock (&data_mutex); + * + * end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND; + * while (!current_data) + * if (!g_cond_wait_until (&data_cond, &data_mutex, end_time)) + * { + * // timeout has passed. + * g_mutex_unlock (&data_mutex); + * return NULL; + * } + * + * // there is data for us + * data = current_data; + * current_data = NULL; + * + * g_mutex_unlock (&data_mutex); + * + * return data; + * } + * ]| + * + * Notice that the end time is calculated once, before entering the + * loop and reused. This is the motivation behind the use of absolute + * time on this API -- if a relative time of 5 seconds were passed + * directly to the call and a spurious wakeup occurred, the program would + * have to start over waiting again (which would lead to a total wait + * time of more than 5 seconds). + * + * Returns: %TRUE on a signal, %FALSE on a timeout + * Since: 2.32 + **/ +gboolean +g_cond_wait_until (GCond *cond, + GMutex *mutex, + gint64 end_time) +{ + return g_cond_wait_until_impl (cond, mutex, end_time); +} + +/* {{{1 GPrivate */ + +/** + * GPrivate: + * + * The #GPrivate struct is an opaque data structure to represent a + * thread-local data key. It is approximately equivalent to the + * pthread_setspecific()/pthread_getspecific() APIs on POSIX and to + * TlsSetValue()/TlsGetValue() on Windows. + * + * If you don't already know why you might want this functionality, + * then you probably don't need it. + * + * #GPrivate is a very limited resource (as far as 128 per program, + * shared between all libraries). It is also not possible to destroy a + * #GPrivate after it has been used. As such, it is only ever acceptable + * to use #GPrivate in static scope, and even then sparingly so. + * + * See G_PRIVATE_INIT() for a couple of examples. + * + * The #GPrivate structure should be considered opaque. It should only + * be accessed via the g_private_ functions. + */ + +/** + * G_PRIVATE_INIT: + * @notify: a #GDestroyNotify + * + * A macro to assist with the static initialisation of a #GPrivate. + * + * This macro is useful for the case that a #GDestroyNotify function + * should be associated with the key. This is needed when the key will be + * used to point at memory that should be deallocated when the thread + * exits. + * + * Additionally, the #GDestroyNotify will also be called on the previous + * value stored in the key when g_private_replace() is used. + * + * If no #GDestroyNotify is needed, then use of this macro is not + * required -- if the #GPrivate is declared in static scope then it will + * be properly initialised by default (ie: to all zeros). See the + * examples below. + * + * |[ + * static GPrivate name_key = G_PRIVATE_INIT (g_free); + * + * // return value should not be freed + * const gchar * + * get_local_name (void) + * { + * return g_private_get (&name_key); + * } + * + * void + * set_local_name (const gchar *name) + * { + * g_private_replace (&name_key, g_strdup (name)); + * } + * + * + * static GPrivate count_key; // no free function + * + * gint + * get_local_count (void) + * { + * return GPOINTER_TO_INT (g_private_get (&count_key)); + * } + * + * void + * set_local_count (gint count) + * { + * g_private_set (&count_key, GINT_TO_POINTER (count)); + * } + * ]| + * + * Since: 2.32 + **/ + +/** + * g_private_get: + * @key: a #GPrivate + * + * Returns the current value of the thread local variable @key. + * + * If the value has not yet been set in this thread, %NULL is returned. + * Values are never copied between threads (when a new thread is + * created, for example). + * + * Returns: the thread-local value + */ +gpointer +g_private_get (GPrivate *key) +{ + return g_private_get_impl (key); +} + +/** + * g_private_set: + * @key: a #GPrivate + * @value: the new value + * + * Sets the thread local variable @key to have the value @value in the + * current thread. + * + * This function differs from g_private_replace() in the following way: + * the #GDestroyNotify for @key is not called on the old value. + */ +void +g_private_set (GPrivate *key, + gpointer value) +{ + g_private_set_impl (key, value); +} + +/** + * g_private_replace: + * @key: a #GPrivate + * @value: the new value + * + * Sets the thread local variable @key to have the value @value in the + * current thread. + * + * This function differs from g_private_set() in the following way: if + * the previous value was non-%NULL then the #GDestroyNotify handler for + * @key is run on it. + * + * Since: 2.32 + **/ +void +g_private_replace (GPrivate *key, + gpointer value) +{ + g_private_replace_impl (key, value); +} + +/* {{{1 GThread */ + +/** + * g_thread_yield: + * + * Causes the calling thread to voluntarily relinquish the CPU, so + * that other threads can run. + * + * This function is often used as a method to make busy wait less evil. + */ +void +g_thread_yield (void) +{ + g_thread_yield_impl (); +} + /* Epilogue {{{1 */ /* vim: set foldmethod=marker: */ diff --git a/glib/gthreadprivate.h b/glib/gthreadprivate.h index 28d190c1a..0fd1598c9 100644 --- a/glib/gthreadprivate.h +++ b/glib/gthreadprivate.h @@ -175,4 +175,43 @@ guint g_thread_n_created (void); gpointer g_private_set_alloc0 (GPrivate *key, gsize size); +void g_mutex_init_impl (GMutex *mutex); +void g_mutex_clear_impl (GMutex *mutex); +void g_mutex_lock_impl (GMutex *mutex); +void g_mutex_unlock_impl (GMutex *mutex); +gboolean g_mutex_trylock_impl (GMutex *mutex); + +void g_rec_mutex_init_impl (GRecMutex *rec_mutex); +void g_rec_mutex_clear_impl (GRecMutex *rec_mutex); +void g_rec_mutex_lock_impl (GRecMutex *mutex); +void g_rec_mutex_unlock_impl (GRecMutex *rec_mutex); +gboolean g_rec_mutex_trylock_impl (GRecMutex *rec_mutex); + +void g_rw_lock_init_impl (GRWLock *rw_lock); +void g_rw_lock_clear_impl (GRWLock *rw_lock); +void g_rw_lock_writer_lock_impl (GRWLock *rw_lock); +gboolean g_rw_lock_writer_trylock_impl (GRWLock *rw_lock); +void g_rw_lock_writer_unlock_impl (GRWLock *rw_lock); +void g_rw_lock_reader_lock_impl (GRWLock *rw_lock); +gboolean g_rw_lock_reader_trylock_impl (GRWLock *rw_lock); +void g_rw_lock_reader_unlock_impl (GRWLock *rw_lock); + +void g_cond_init_impl (GCond *cond); +void g_cond_clear_impl (GCond *cond); +void g_cond_wait_impl (GCond *cond, + GMutex *mutex); +void g_cond_signal_impl (GCond *cond); +void g_cond_broadcast_impl (GCond *cond); +gboolean g_cond_wait_until_impl (GCond *cond, + GMutex *mutex, + gint64 end_time); + +gpointer g_private_get_impl (GPrivate *key); +void g_private_set_impl (GPrivate *key, + gpointer value); +void g_private_replace_impl (GPrivate *key, + gpointer value); + +void g_thread_yield_impl (void); + #endif /* __G_THREADPRIVATE_H__ */