Le mardi 22 juillet 2008 à 01:44 +0200, Bruno Haible a écrit :
> > > > - Implement support for condition variable.
> > > 
> > > You are welcome to contribute a module for this.
> > 
> > I started working on condition variable support. To me, it make sense to
> > do that directly within the lock module (the code is very much similar
> > to what currently exist for mutex primitive). Any objection?
> 
> Yes, I continue to think that it belongs into a different module, because
> 
>   1) For 95% of all multithread programming, all one needs is
>        - locks,
>        - thread-local storage,
>        - starting and joining threads.
>      Wait queues and condition variables are less needed and harder to
>      use correctly (without introducing bugs or deadlocks).
> 
>   2) The 'lock' module is compiled into libintl, and therefore I prefer to
>      avoid increasing its .o file size for things that libintl does not need.

Attached is an initial implementation of the glcond module, based on
your lock module. 

Regards,

-- 
Yoann Vandoorselaere <[EMAIL PROTECTED]>
diff --git a/lib/glcond.h b/lib/glcond.h
new file mode 100644
index 0000000..012f316
--- /dev/null
+++ b/lib/glcond.h
@@ -0,0 +1,301 @@
+/* Locking in multithreaded situations.
+   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 Bruno Haible <[EMAIL PROTECTED]>, 2005.
+   Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
+   gthr-win32.h.  */
+
+/* This file contains locking primitives for use with a given thread library.
+   It does not contain primitives for creating threads or for other
+   synchronization primitives.
+
+   Condition variable:
+     Type:                gl_cond_t
+     Declaration:         gl_cond_define(extern, name)
+     Initializer:         gl_cond_define_initialized(, name)
+     Waiting:             gl_cond_wait(name)
+     Timed wait:          gl_cond_timedwait(name, tv)
+     Signaling:           gl_cond_signal(name)
+     Broadcasting:        gl_cond_broadcast(name)
+*/
+
+
+#ifndef _GLCOND_H
+#define _GLCOND_H
+
+#include <errno.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
+
+#  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, TS) \
+    (pthread_in_use () ? pthread_cond_timedwait (COND, LOCK, TS) : 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) : 0)
+# define glthread_cond_wait(COND, LOCK) \
+    (pth_in_use () ? pth_cond_await (COND, LOCK, NULL) : 0)
+# define glthread_cond_timedwait(COND, LOCK, TS) \
+    (pth_in_use () ? pth_cond_await (COND, LOCK, pth_event(PTH_EVENT_TIME, pth_timeout((TS)->tv_sec, (TS)->tv_nsec / 1000))) : 0)
+# define glthread_cond_signal(COND) \
+    (pth_in_use () ? pth_cond_notify (COND, FALSE) : 0)
+# define glthread_cond_broadcast(COND) \
+    (pth_in_use () ? pth_cond_notify (COND, TRUE) : 0)
+# define glhread_cond_destroy(COND) \
+    (void)
+
+#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, TS) \
+    (pthread_in_use () ? cond_timedwait (COND, LOCK, TS) : 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_signal(COND) 0
+# define glthread_cond_broadcast(COND) 0
+# define glthread_cond_wait(COND, LOCK) 0
+# define glthread_cond_timedwait(COND, LOCK, TS) 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_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 /* _GLCOND_H */
diff --git a/m4/glcond.m4 b/m4/glcond.m4
new file mode 100644
index 0000000..b31d6ae
--- /dev/null
+++ b/m4/glcond.m4
@@ -0,0 +1,10 @@
+# glcond.m4 serial 1 (gettext-0.15)
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_COND],
+[
+  AC_REQUIRE([gl_LOCK])
+])
diff --git a/modules/glcond b/modules/glcond
new file mode 100644
index 0000000..1ea412f
--- /dev/null
+++ b/modules/glcond
@@ -0,0 +1,22 @@
+Description:
+Condition in multithreaded situations.
+
+Files:
+lib/glcond.h
+m4/glcond.m4
+
+configure.ac:
+gl_COND
+
+Makefile.am:
+lib_SOURCES += glcond.h
+
+Include:
+"glcond.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+Yoann Vandoorselaere
+

Reply via email to