-/* 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:
- *
- * <example>
- * <title>An array with access functions</title>
- * <programlisting>
- * 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);
- * }
- * </programlisting>
- * </example>
- *
- * This example shows an array which can be accessed by many readers
- * (the <function>my_array_get()</function> function) simultaneously,
- * whereas the writers (the <function>my_array_set()</function>
- * 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 <function>g_static_rw_lock_*</function> functions can be
- * used even if g_thread_init() has not been called. Then they do
- * nothing, apart from <function>g_static_rw_lock_*_trylock</function>,
- * which does nothing but returning %TRUE.
- *
- * <note><para>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.</para></note>
- **/
-
-/**
- * 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().
- *
- * <informalexample>
- * <programlisting>
- * GStaticRWLock my_lock = G_STATIC_RW_LOCK_INIT;
- * </programlisting>
- * </informalexample>
- **/
-
-/**
- * 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.
- **/
-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.
- **/
-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().
- **/
-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.
- **/
-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().
- **/
-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().
- **/
-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.
- **/
-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.
- **/
-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 ---------------------------------------------------------- */
-
-/**
- * g_thread_foreach
- * @thread_func: function to call for all GThread structures
- * @user_data: second argument to @thread_func
- *
- * Call @thread_func on all existing #GThread structures. Note that
- * threads may decide to exit while @thread_func is running, so
- * without intimate knowledge about the lifetime of foreign threads,
- * @thread_func shouldn't access the GThread* pointer passed in as
- * first argument. However, @thread_func will not be called for threads
- * which are known to have exited already.
- *
- * Due to thread lifetime checks, this function has an execution complexity
- * which is quadratic in the number of existing threads.
- *
- * Since: 2.10
- */
-void
-g_thread_foreach (GFunc thread_func,
- gpointer user_data)
-{
- GSList *slist = NULL;
- GRealThread *thread;
- g_return_if_fail (thread_func != NULL);
- /* snapshot the list of threads for iteration */
- G_LOCK (g_thread);
- for (thread = g_thread_all_threads; thread; thread = thread->next)
- slist = g_slist_prepend (slist, thread);
- G_UNLOCK (g_thread);
- /* walk the list, skipping non-existant threads */
- while (slist)
- {
- GSList *node = slist;
- slist = node->next;
- /* check whether the current thread still exists */
- G_LOCK (g_thread);
- for (thread = g_thread_all_threads; thread; thread = thread->next)
- if (thread == node->data)
- break;
- G_UNLOCK (g_thread);
- if (thread)
- thread_func (thread, user_data);
- g_slist_free_1 (node);
- }
-}
-
-/**
- * g_thread_get_initialized
- *
- * Indicates if g_thread_init() has been called.
- *
- * Returns: %TRUE if threads have been initialized.
- *
- * Since: 2.20
- */
-gboolean
-g_thread_get_initialized ()
-{
- return g_thread_supported ();
-}