summaryrefslogtreecommitdiff
path: root/lib/glthread/cond.h
diff options
context:
space:
mode:
authorYoann Vandoorselaere <yoann.v@prelude-ids.com>2008-08-17 17:21:35 +0200
committerBruno Haible <bruno@clisp.org>2008-08-17 17:21:35 +0200
commitf507f9b0607c290db1efc87893943161e48bd01c (patch)
tree5bd2c45b3689aac2f9f9cf831b64403a98d1f225 /lib/glthread/cond.h
parent429bd1c00170c0e6d449e6269b71803b10ce6af0 (diff)
downloadgnulib-f507f9b0607c290db1efc87893943161e48bd01c.tar.gz
New module 'cond'.
Diffstat (limited to 'lib/glthread/cond.h')
-rw-r--r--lib/glthread/cond.h330
1 files changed, 330 insertions, 0 deletions
diff --git a/lib/glthread/cond.h b/lib/glthread/cond.h
new file mode 100644
index 0000000000..e8ed12ced7
--- /dev/null
+++ b/lib/glthread/cond.h
@@ -0,0 +1,330 @@
+/* Condition variables for multithreading.
+ Copyright (C) 2005-2008 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Yoann Vandoorselaere <yoann@prelude-ids.org>, 2008.
+ Based on Bruno Haible <bruno@clisp.org> lock.h */
+
+/*
+ Condition variables can be used for waiting until a condition
+ becomes true. In this respect, they are similar to wait queues. But
+ contrary to wait queues, condition variables have different
+ semantics that allows events to be lost when there is no thread
+ waiting for them.
+
+ Condition variable:
+ Type: gl_cond_t
+ Declaration: gl_cond_define(extern, name)
+ Initializer: gl_cond_define_initialized(, name)
+ Initialization: gl_cond_init (name);
+ Waiting: gl_cond_wait (name, lock);
+ Timed wait: bool timedout = gl_cond_timedwait (name, lock, abstime);
+ where lock is a gl_lock_t variable (cf. <glthread/lock.h>)
+ Signaling: gl_cond_signal (name);
+ Broadcasting: gl_cond_broadcast (name);
+ De-initialization: gl_cond_destroy (name);
+ Equivalent functions with control of error handling:
+ Initialization: err = glthread_cond_init (&name);
+ Waiting: err = glthread_cond_wait (&name);
+ Timed wait: err = glthread_cond_timedwait (&name, &lock, abstime);
+ Signaling: err = glthread_cond_signal (&name);
+ Broadcasting: err = glthread_cond_broadcast (&name);
+ De-initialization: err = glthread_cond_destroy (&name);
+*/
+
+
+#ifndef _GLTHREAD_COND_H
+#define _GLTHREAD_COND_H
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include "glthread/lock.h"
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS
+
+/* Use the POSIX threads library. */
+
+# include <pthread.h>
+# include <stdlib.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if PTHREAD_IN_USE_DETECTION_HARD
+
+/* The pthread_in_use() detection needs to be done at runtime. */
+# define pthread_in_use() \
+ glthread_in_use ()
+extern int glthread_in_use (void);
+
+# endif
+
+# if USE_POSIX_THREADS_WEAK
+
+/* Use weak references to the POSIX threads library. */
+
+/* Weak references avoid dragging in external libraries if the other parts
+ of the program don't use them. Here we use them, because we don't want
+ every program that uses libintl to depend on libpthread. This assumes
+ that libpthread would not be loaded after libintl; i.e. if libintl is
+ loaded first, by an executable that does not depend on libpthread, and
+ then a module is dynamically loaded that depends on libpthread, libintl
+ will not be multithread-safe. */
+
+/* The way to test at runtime whether libpthread is present is to test
+ whether a function pointer's value, such as &pthread_mutex_init, is
+ non-NULL. However, some versions of GCC have a bug through which, in
+ PIC mode, &foo != NULL always evaluates to true if there is a direct
+ call to foo(...) in the same function. To avoid this, we test the
+ address of a function in libpthread that we don't use. */
+
+# pragma weak pthread_cond_init
+# pragma weak pthread_cond_wait
+# pragma weak pthread_cond_timedwait
+# pragma weak pthread_cond_signal
+# pragma weak pthread_cond_broadcast
+# pragma weak pthread_cond_destroy
+# ifndef pthread_self
+# pragma weak pthread_self
+# endif
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# pragma weak pthread_cancel
+# define pthread_in_use() (pthread_cancel != NULL)
+# endif
+
+# else
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# define pthread_in_use() 1
+# endif
+
+# endif
+
+/* -------------------------- gl_cond_t datatype -------------------------- */
+
+typedef pthread_cond_t gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_cond_t NAME;
+# define gl_cond_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_cond_t NAME = gl_cond_initializer;
+# define gl_cond_initializer \
+ PTHREAD_COND_INITIALIZER
+# define glthread_cond_init(COND) \
+ (pthread_in_use () ? pthread_cond_init (COND, NULL) : 0)
+# define glthread_cond_wait(COND, LOCK) \
+ (pthread_in_use () ? pthread_cond_wait (COND, LOCK) : 0)
+# define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
+ (pthread_in_use () ? pthread_cond_timedwait (COND, LOCK, ABSTIME) : 0)
+# define glthread_cond_signal(COND) \
+ (pthread_in_use () ? pthread_cond_signal (COND) : 0)
+# define glthread_cond_broadcast(COND) \
+ (pthread_in_use () ? pthread_cond_broadcast (COND) : 0)
+# define glthread_cond_destroy(COND) \
+ (pthread_in_use () ? pthread_cond_destroy (COND) : 0)
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_PTH_THREADS
+
+/* Use the GNU Pth threads library. */
+
+# include <pth.h>
+# include <stdlib.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_PTH_THREADS_WEAK
+
+/* Use weak references to the GNU Pth threads library. */
+
+# pragma weak pth_cond_init
+# pragma weak pth_cond_await
+# pragma weak pth_cond_notify
+# pragma weak pth_event
+# pragma weak pth_timeout
+
+# pragma weak pth_cancel
+# define pth_in_use() (pth_cancel != NULL)
+
+# else
+
+# define pth_in_use() 1
+
+# endif
+
+/* -------------------------- gl_cond_t datatype -------------------------- */
+
+typedef pth_cond_t gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME) \
+ STORAGECLASS pth_cond_t NAME;
+# define gl_cond_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pth_cond_t NAME = gl_cond_initializer;
+# define gl_cond_initializer \
+ PTH_COND_INIT
+# define glthread_cond_init(COND) \
+ (pth_in_use () && !pth_cond_init (COND) ? errno : 0)
+# define glthread_cond_wait(COND, LOCK) \
+ (pth_in_use () && !pth_cond_await (COND, LOCK, NULL) ? errno : 0)
+# define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
+ (pth_in_use () ? glthread_cond_timedwait_multithreaded (COND, LOCK, ABSTIME) : 0)
+# define glthread_cond_signal(COND) \
+ (pth_in_use () && !pth_cond_notify (COND, FALSE) ? errno : 0)
+# define glthread_cond_broadcast(COND) \
+ (pth_in_use () && !pth_cond_notify (COND, TRUE) ? errno : 0)
+# define glthread_cond_destroy(COND) 0
+extern int glthread_cond_timedwait_multithreaded (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime);
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_SOLARIS_THREADS
+
+/* Use the old Solaris threads library. */
+
+# include <thread.h>
+# include <synch.h>
+# include <stdlib.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_SOLARIS_THREADS_WEAK
+
+/* Use weak references to the old Solaris threads library. */
+
+# pragma weak cond_init
+# pragma weak cond_wait
+# pragma weak cond_timedwait
+# pragma weak cond_signal
+# pragma weak cond_broadcast
+# pragma weak cond_destroy
+# pragma weak thr_suspend
+# define thread_in_use() (thr_suspend != NULL)
+
+# else
+
+# define thread_in_use() 1
+
+# endif
+
+/* -------------------------- gl_cond_t datatype -------------------------- */
+
+#define ETIMEDOUT ETIME
+
+typedef pthread_cond_t gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME) \
+ STORAGECLASS cond_t NAME;
+# define gl_cond_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS cond_t NAME = gl_cond_initializer;
+# define gl_cond_initializer \
+ DEFAULTCV
+# define glthread_cond_init(COND) \
+ (pthread_in_use () ? cond_init (COND, USYNC_THREAD, NULL) : 0)
+# define glthread_cond_wait(COND, LOCK) \
+ (pthread_in_use () ? cond_wait (COND, LOCK) : 0)
+# define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
+ (pthread_in_use () ? cond_timedwait (COND, LOCK, ABSTIME) : 0)
+# define glthread_cond_signal(COND) \
+ (pthread_in_use () ? cond_signal (COND) : 0)
+# define glthread_cond_broadcast(COND) \
+ (pthread_in_use () ? cond_broadcast (COND) : 0)
+# define glthread_cond_destroy(COND) \
+ (pthread_in_use () ? cond_destroy (COND) : 0)
+
+#endif
+
+/* ========================================================================= */
+
+#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
+
+/* Provide dummy implementation if threads are not supported. */
+
+typedef int gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME)
+# define gl_cond_define_initialized(STORAGECLASS, NAME)
+# define glthread_cond_init(COND) 0
+# define glthread_cond_wait(COND, LOCK) 0
+# define glthread_cond_timedwait(COND, LOCK, ABSTIME) 0
+# define glthread_cond_signal(COND) 0
+# define glthread_cond_broadcast(COND) 0
+# define glthread_cond_destroy(COND) 0
+
+#endif
+
+/* ========================================================================= */
+
+/* Macros with built-in error handling. */
+
+#define gl_cond_init(COND) \
+ do \
+ { \
+ if (glthread_cond_init (&COND)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_wait(COND, LOCK) \
+ do \
+ { \
+ if (glthread_cond_wait (&COND, &LOCK)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_timedwait(COND, LOCK, ABSTIME) \
+ gl_cond_timedwait_func (&COND, &LOCK, ABSTIME)
+static inline bool
+gl_cond_timedwait_func (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime)
+{
+ int err = glthread_cond_timedwait (cond, lock, abstime);
+ if (err == ETIMEDOUT)
+ return true;
+ if (err != 0)
+ abort ();
+ return false;
+}
+#define gl_cond_signal(COND) \
+ do \
+ { \
+ if (glthread_cond_signal (&COND)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_broadcast(COND) \
+ do \
+ { \
+ if (glthread_cond_broadcast (&COND)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_destroy(COND) \
+ do \
+ { \
+ if (glthread_cond_destroy (&COND)) \
+ abort (); \
+ } \
+ while (0)
+
+#endif /* _GLTHREAD_COND_H */