}
/* {{{1 GMutex */
+
+/**
+ * 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
+ * created with g_mutex_new(). Also see #G_MUTEX_INITIALIZER
+ * for an alternative way to initialize statically allocated mutexes.
+ *
+ * |[
+ * 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().
+ *
+ * Since: 2.32
+ */
void
g_mutex_init (GMutex *mutex)
{
g_thread_abort (status, "pthread_mutex_init");
}
+/**
+ * g_mutex_clear:
+ * @mutex: an initialized #GMutex
+ *
+ * Frees the resources allocated to a mutex with g_mutex_init().
+ *
+ * #GMutexes that have have been created with g_mutex_new() should
+ * be freed with g_mutex_free() instead.
+ *
+ * Sine: 2.32
+ */
void
g_mutex_clear (GMutex *mutex)
{
g_thread_abort (status, "pthread_mutex_destroy");
}
+/**
+ * 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.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ *
+ * <note>#GMutex is neither guaranteed to be recursive nor to be
+ * non-recursive, i.e. a thread could deadlock while calling
+ * g_mutex_lock(), if it already has locked @mutex. Use
+ * #GStaticRecMutex, if you need recursive mutexes.</note>
+ */
void
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 be woken and can lock @mutex itself.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ */
void
g_mutex_unlock (GMutex *mutex)
{
g_thread_abort (status, "pthread_mutex_lock");
}
+/**
+ * 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.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will immediately return %TRUE.
+ *
+ * <note>#GMutex is neither guaranteed to be recursive nor to be
+ * non-recursive, i.e. the return value of g_mutex_trylock() could be
+ * both %FALSE or %TRUE, if the current thread already has locked
+ * @mutex. Use #GStaticRecMutex, if you need recursive
+ * mutexes.</note>
+
+ * Returns: %TRUE, if @mutex could be locked
+ */
gboolean
g_mutex_trylock (GMutex *mutex)
{
/* {{{1 GCond */
+/**
+ * g_cond_init:
+ * @cond: an uninitialized #GCond
+ *
+ * Initialized a #GCond so that it can be used.
+ *
+ * This function is useful to initialize a #GCond that has been
+ * allocated on the stack, or as part of a larger structure.
+ * It is not necessary to initialize a #GCond that has been
+ * created with g_cond_new(). Also see #G_COND_INITIALIZER
+ * for an alternative way to initialize statically allocated
+ * #GConds.
+ *
+ * Since: 2.32
+ */
void
g_cond_init (GCond *cond)
{
g_thread_abort (status, "pthread_cond_init");
}
+/**
+ * g_cond_clear:
+ * @cond: an initialized #GCond
+ *
+ * Frees the resources allocated ot a #GCond with g_cond_init().
+ *
+ * #GConds that have been created with g_cond_new() should
+ * be freed with g_cond_free() instead.
+ *
+ * Since: 2.32
+ */
void
g_cond_clear (GCond *cond)
{
g_thread_abort (status, "pthread_cond_destroy");
}
+/**
+ * g_cond_wait:
+ * @cond: a #GCond
+ * @mutex: a #GMutex that is currently locked
+ *
+ * Waits until this thread is woken up on @cond.
+ * The @mutex is unlocked before falling asleep
+ * and locked again before resuming.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will immediately return.
+ */
void
g_cond_wait (GCond *cond,
GMutex *mutex)
g_thread_abort (status, "pthread_cond_wait");
}
+/**
+ * g_cond_signal:
+ * @cond: a #GCond
+ *
+ * If threads are waiting for @cond, exactly one of them is woken up.
+ * It is good practice to hold the same lock as the waiting thread
+ * while calling this function, though not required.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ */
void
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 woken up.
+ * It is good practice to lock the same mutex as the waiting threads
+ * while calling this function, though not required.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will do nothing.
+ */
void
g_cond_broadcast (GCond *cond)
{
g_thread_abort (status, "pthread_cond_broadcast");
}
+/**
+ * g_cond_timed_wait:
+ * @cond: a #GCond
+ * @mutex: a #GMutex that is currently locked
+ * @abs_time: a #GTimeVal, determining the final time
+ *
+ * Waits until this thread is woken up on @cond, but not longer than
+ * until the time specified by @abs_time. The @mutex is unlocked before
+ * falling asleep and locked again before resuming.
+ *
+ * If @abs_time is %NULL, g_cond_timed_wait() acts like g_cond_wait().
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will immediately return %TRUE.
+ *
+ * To easily calculate @abs_time a combination of g_get_current_time()
+ * and g_time_val_add() can be used.
+ *
+ * Returns: %TRUE if @cond was signalled, or %FALSE on timeout
+ */
gboolean
g_cond_timed_wait (GCond *cond,
GMutex *mutex,
return FALSE;
}
+/**
+ * g_cond_timedwait:
+ * @cond: a #GCond
+ * @mutex: a #GMutex that is currently locked
+ * @abs_time: the final time, in microseconds
+ *
+ * A variant of g_cond_timed_wait() that takes @abs_time
+ * as a #gint64 instead of a #GTimeVal.
+ * See g_cond_timed_wait() for details.
+ *
+ * Returns: %TRUE if @cond was signalled, or %FALSE on timeout
+ *
+ * Since: 2.32
+ */
gboolean
g_cond_timedwait (GCond *cond,
GMutex *mutex,
/* {{{1 GPrivate */
-GPrivate *
-(g_private_new) (GDestroyNotify notify)
-{
- GPrivate *key;
-
- key = malloc (sizeof (GPrivate));
- if G_UNLIKELY (key == NULL)
- g_thread_abort (errno, "malloc");
- g_private_init (key, notify);
-
- return key;
-}
-
void
g_private_init (GPrivate *key,
GDestroyNotify notify)
{
pthread_key_create (&key->key, notify);
+ key->ready = TRUE;
}
+/**
+ * g_private_get:
+ * @private_key: a #GPrivate
+ *
+ * Returns the pointer keyed to @private_key for the current thread. If
+ * g_private_set() hasn't been called for the current @private_key and
+ * thread yet, this pointer will be %NULL.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will return the value of @private_key
+ * casted to #gpointer. Note however, that private data set
+ * <emphasis>before</emphasis> g_thread_init() will
+ * <emphasis>not</emphasis> be retained <emphasis>after</emphasis> the
+ * call. Instead, %NULL will be returned in all threads directly after
+ * g_thread_init(), regardless of any g_private_set() calls issued
+ * before threading system initialization.
+ *
+ * Returns: the corresponding pointer
+ */
gpointer
-(g_private_get) (GPrivate *key)
+g_private_get (GPrivate *key)
{
+ if (!key->ready)
+ return key->single_value;
+
/* quote POSIX: No errors are returned from pthread_getspecific(). */
return pthread_getspecific (key->key);
}
+/**
+ * g_private_set:
+ * @private_key: a #GPrivate
+ * @data: the new pointer
+ *
+ * Sets the pointer keyed to @private_key for the current thread.
+ *
+ * This function can be used even if g_thread_init() has not yet been
+ * called, and, in that case, will set @private_key to @data casted to
+ * #GPrivate*. See g_private_get() for resulting caveats.
+ */
void
-(g_private_set) (GPrivate *key,
- gpointer value)
+g_private_set (GPrivate *key,
+ gpointer value)
{
gint status;
+ if (!key->ready)
+ {
+ key->single_value = value;
+ return;
+ }
+
if G_UNLIKELY ((status = pthread_setspecific (key->key, value)) != 0)
g_thread_abort (status, "pthread_setspecific");
}
#define posix_check_cmd(cmd) posix_check_err (cmd, #cmd)
-#ifdef G_ENABLE_DEBUG
-static gboolean posix_check_cmd_prio_warned = FALSE;
-# define posix_check_cmd_prio(cmd) G_STMT_START{ \
- int err = (cmd); \
- if (err == EPERM) \
- { \
- if (!posix_check_cmd_prio_warned) \
- { \
- posix_check_cmd_prio_warned = TRUE; \
- g_warning ("Priorities can only be changed " \
- "(resp. increased) by root."); \
- } \
- } \
- else \
- posix_check_err (err, #cmd); \
- }G_STMT_END
-#else /* G_ENABLE_DEBUG */
-# define posix_check_cmd_prio(cmd) G_STMT_START{ \
- int err = (cmd); \
- if (err != EPERM) \
- posix_check_err (err, #cmd); \
- }G_STMT_END
-#endif /* G_ENABLE_DEBUG */
-
-#if defined (POSIX_MIN_PRIORITY) && defined (POSIX_MAX_PRIORITY)
-# define HAVE_PRIORITIES 1
-static gint priority_normal_value;
-# ifdef __FreeBSD__
- /* FreeBSD threads use different priority values from the POSIX_
- * defines so we just set them here. The corresponding macros
- * PTHREAD_MIN_PRIORITY and PTHREAD_MAX_PRIORITY are implied to be
- * exported by the docs, but they aren't.
- */
-# define PRIORITY_LOW_VALUE 0
-# define PRIORITY_URGENT_VALUE 31
-# else /* !__FreeBSD__ */
-# define PRIORITY_LOW_VALUE POSIX_MIN_PRIORITY
-# define PRIORITY_URGENT_VALUE POSIX_MAX_PRIORITY
-# endif /* !__FreeBSD__ */
-# define PRIORITY_NORMAL_VALUE priority_normal_value
-
-# define PRIORITY_HIGH_VALUE \
- ((PRIORITY_NORMAL_VALUE + PRIORITY_URGENT_VALUE * 2) / 3)
-
-static gint
-g_thread_priority_map (GThreadPriority priority)
-{
- switch (priority)
- {
- case G_THREAD_PRIORITY_LOW:
- return PRIORITY_LOW_VALUE;
-
- case G_THREAD_PRIORITY_NORMAL:
- return PRIORITY_NORMAL_VALUE;
-
- case G_THREAD_PRIORITY_HIGH:
- return PRIORITY_HIGH_VALUE;
-
- case G_THREAD_PRIORITY_URGENT:
- return PRIORITY_URGENT_VALUE;
-
- default:
- g_assert_not_reached ();
- }
-}
-
-#endif /* POSIX_MIN_PRIORITY && POSIX_MAX_PRIORITY */
-
static gulong g_thread_min_stack_size = 0;
#define G_MUTEX_SIZE (sizeof (pthread_mutex_t))
#ifdef _SC_THREAD_STACK_MIN
g_thread_min_stack_size = MAX (sysconf (_SC_THREAD_STACK_MIN), 0);
#endif /* _SC_THREAD_STACK_MIN */
-#ifdef HAVE_PRIORITIES
- {
- struct sched_param sched;
- int policy;
- posix_check_cmd (pthread_getschedparam (pthread_self(), &policy, &sched));
- priority_normal_value = sched.sched_priority;
- }
-#endif /* HAVE_PRIORITIES */
}
-static void
-g_thread_create_posix_impl (GThreadFunc thread_func,
- gpointer arg,
- gulong stack_size,
- gboolean joinable,
- gboolean bound,
- GThreadPriority priority,
- gpointer thread,
- GError **error)
+void
+g_system_thread_create (GThreadFunc thread_func,
+ gpointer arg,
+ gulong stack_size,
+ gboolean joinable,
+ gboolean bound,
+ GThreadPriority priority,
+ gpointer thread,
+ GError **error)
{
pthread_attr_t attr;
gint ret;
g_return_if_fail (thread_func);
- g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
- g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
posix_check_cmd (pthread_attr_init (&attr));
posix_check_cmd (pthread_attr_setdetachstate (&attr,
joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
-#ifdef HAVE_PRIORITIES
- {
- struct sched_param sched;
- posix_check_cmd (pthread_attr_getschedparam (&attr, &sched));
- sched.sched_priority = g_thread_priority_map (priority);
- posix_check_cmd_prio (pthread_attr_setschedparam (&attr, &sched));
- }
-#endif /* HAVE_PRIORITIES */
ret = pthread_create (thread, &attr, (void* (*)(void*))thread_func, arg);
posix_check_cmd (pthread_attr_destroy (&attr));
posix_check_err (ret, "pthread_create");
}
-static void
-g_thread_yield_posix_impl (void)
+/**
+ * g_thread_yield:
+ *
+ * Gives way to other threads waiting to be scheduled.
+ *
+ * This function is often used as a method to make busy wait less evil.
+ * But in most cases you will encounter, there are better methods to do
+ * that. So in general you shouldn't use this function.
+ */
+void
+g_thread_yield (void)
{
- POSIX_YIELD_FUNC;
+ sched_yield ();
}
-static void
-g_thread_join_posix_impl (gpointer thread)
+void
+g_system_thread_join (gpointer thread)
{
gpointer ignore;
posix_check_cmd (pthread_join (*(pthread_t*)thread, &ignore));
}
-static void
-g_thread_exit_posix_impl (void)
+void
+g_system_thread_exit (void)
{
pthread_exit (NULL);
}
-static void
-g_thread_set_priority_posix_impl (gpointer thread, GThreadPriority priority)
-{
- g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
- g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
-#ifdef HAVE_PRIORITIES
- {
- struct sched_param sched;
- int policy;
- posix_check_cmd (pthread_getschedparam (*(pthread_t*)thread, &policy,
- &sched));
- sched.sched_priority = g_thread_priority_map (priority);
- posix_check_cmd_prio (pthread_setschedparam (*(pthread_t*)thread, policy,
- &sched));
- }
-#endif /* HAVE_PRIORITIES */
-}
-
-static void
-g_thread_self_posix_impl (gpointer thread)
+void
+g_system_thread_self (gpointer thread)
{
*(pthread_t*)thread = pthread_self();
}
-static gboolean
-g_thread_equal_posix_impl (gpointer thread1, gpointer thread2)
+gboolean
+g_system_thread_equal (gpointer thread1,
+ gpointer thread2)
{
return (pthread_equal (*(pthread_t*)thread1, *(pthread_t*)thread2) != 0);
}
/* {{{1 Epilogue */
-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,
- g_thread_create_posix_impl,
- g_thread_yield_posix_impl,
- g_thread_join_posix_impl,
- g_thread_exit_posix_impl,
- g_thread_set_priority_posix_impl,
- g_thread_self_posix_impl,
- g_thread_equal_posix_impl
-};
-
/* vim:set foldmethod=marker: */