aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS13
-rw-r--r--configure.ac18
-rw-r--r--m4/lock.m4301
-rw-r--r--m4/threadlib.m4341
-rw-r--r--src/Makefile.am44
-rw-r--r--src/err-codes.h.in6
-rw-r--r--src/gen-posix-lock-obj.c95
-rw-r--r--src/gen-w32-lock-obj.c55
-rw-r--r--src/gpg-error.def.in6
-rw-r--r--src/gpg-error.h.in35
-rw-r--r--src/lock.h24
-rw-r--r--src/mkheader.c18
-rw-r--r--src/posix-lock-obj.h32
-rw-r--r--src/posix-lock.c213
-rw-r--r--src/posix-thread.c63
-rw-r--r--src/thread.h24
-rw-r--r--src/version.c4
-rw-r--r--src/w32-lock-obj-pub.in44
-rw-r--r--src/w32-lock-obj.h38
-rw-r--r--src/w32-lock.c119
-rw-r--r--src/w32-thread.c44
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/t-common.h99
-rw-r--r--tests/t-lock.c318
24 files changed, 1665 insertions, 298 deletions
diff --git a/NEWS b/NEWS
index 2600b4e..c7f666b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,20 @@
Noteworthy changes in version 1.13 (unreleased)
-----------------------------------------------
- * Interface changes relative to the 1.11 release:
+ Add a portable mutex API.
+
+ * Interface changes relative to the 1.12 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPG_ERR_MAC_ALGO NEW.
+ GPG_ERR_INV_LOCK_OBJ NEW.
+ gpgrt_lock_t NEW.
+ GPGRT_LOCK_INITIALIZER NEW.
+ GPGRT_LOCK_DEFINE NEW.
+ gpgrt_lock_init NEW.
+ gpgrt_lock_lock NEW.
+ gpgrt_lock_unlock NEW.
+ gpgrt_lock_destroy NEW.
+ gpgrt_yield NEW.
Noteworthy changes in version 1.12 (2013-06-24)
diff --git a/configure.ac b/configure.ac
index 73de716..3d1e12f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,9 @@ AC_PROG_AWK
AC_CHECK_TOOL(AR, ar, :)
AC_GNU_SOURCE
+gl_THREADLIB_EARLY
+
+
LT_PREREQ([2.2.6])
LT_INIT([win32-dll disable-static])
LT_LANG([Windows Resource])
@@ -156,11 +159,26 @@ AC_MSG_WARN([[Without strerror_r, gpg_strerror_r might not be thread-safe]]))
;;
esac
+AC_CHECK_FUNCS([flockfile])
+
+
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
+
+# Check for thread library
+gl_LOCK
+if test "$gl_threads_api" = posix; then
+ AC_CHECK_SIZEOF(pthread_mutex_t,,[AC_INCLUDES_DEFAULT
+ #include <pthread.h>])
+fi
+
+
# Substitution used for gpg-error-config
GPG_ERROR_CONFIG_LIBS="-lgpg-error"
+if test "x$LIBTHREAD" != x; then
+ GPG_ERROR_CONFIG_LIBS="${GPG_ERROR_CONFIG_LIBS} ${LIBTHREAD}"
+fi
GPG_ERROR_CONFIG_CFLAGS=""
GPG_ERROR_CONFIG_ISUBDIRAFTER=""
GPG_ERROR_CONFIG_HOST="$host"
diff --git a/m4/lock.m4 b/m4/lock.m4
index d1ea1ca..73a3c54 100644
--- a/m4/lock.m4
+++ b/m4/lock.m4
@@ -1,289 +1,42 @@
-# lock.m4 serial 2 (gettext-0.15)
-dnl Copyright (C) 2005 Free Software Foundation, Inc.
+# lock.m4 serial 13 (gettext-0.18.2)
+dnl Copyright (C) 2005-2014 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.
dnl From Bruno Haible.
-dnl Tests for a multithreading library to be used.
-dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS,
-dnl USE_PTH_THREADS, USE_WIN32_THREADS
-dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use
-dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with
-dnl libtool).
-dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for
-dnl programs that really need multithread functionality. The difference
-dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak
-dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread".
-dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for
-dnl multithread-safe programs.
-
AC_DEFUN([gl_LOCK],
[
- AC_REQUIRE([gl_LOCK_BODY])
-])
-
-dnl The guts of gl_LOCK. Needs to be expanded only once.
-
-AC_DEFUN([gl_LOCK_BODY],
-[
- dnl Ordering constraints: This macro modifies CPPFLAGS in a way that
- dnl influences the result of the autoconf tests that test for *_unlocked
- dnl declarations, on AIX 5 at least. Therefore it must come early.
- AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl
- AC_BEFORE([$0], [gl_ARGP])dnl
-
- AC_REQUIRE([AC_CANONICAL_HOST])
- AC_REQUIRE([AC_GNU_SOURCE]) dnl needed for pthread_rwlock_t on glibc systems
- dnl Check for multithreading.
- AC_ARG_ENABLE(threads,
-AC_HELP_STRING([--enable-threads={posix|solaris|pth|win32}], [specify multithreading API])
-AC_HELP_STRING([--disable-threads], [build without multithread safety]),
- gl_use_threads=$enableval, gl_use_threads=yes)
- gl_threads_api=none
- LIBTHREAD=
- LTLIBTHREAD=
- LIBMULTITHREAD=
- LTLIBMULTITHREAD=
- if test "$gl_use_threads" != no; then
- dnl Check whether the compiler and linker support weak declarations.
- AC_MSG_CHECKING([whether imported symbols can be declared weak])
- gl_have_weak=no
- AC_TRY_LINK([extern void xyzzy ();
-#pragma weak xyzzy], [xyzzy();], [gl_have_weak=yes])
- AC_MSG_RESULT([$gl_have_weak])
- if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then
- # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that
- # it groks <pthread.h>.
- gl_save_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS -D_REENTRANT"
- AC_CHECK_HEADER(pthread.h, gl_have_pthread_h=yes, gl_have_pthread_h=no)
- CPPFLAGS="$gl_save_CPPFLAGS"
- if test "$gl_have_pthread_h" = yes; then
- # Other possible tests:
- # -lpthreads (FSU threads, PCthreads)
- # -lgthreads
- case "$host_os" in
- osf*)
- # On OSF/1, the compiler needs the flag -D_REENTRANT so that it
- # groks <pthread.h>. cc also understands the flag -pthread, but
- # we don't use it because 1. gcc-2.95 doesn't understand -pthread,
- # 2. putting a flag into CPPFLAGS that has an effect on the linker
- # causes the AC_TRY_LINK test below to succeed unexpectedly,
- # leading to wrong values of LIBTHREAD and LTLIBTHREAD.
- CPPFLAGS="$CPPFLAGS -D_REENTRANT"
- ;;
- esac
- gl_have_pthread=
- # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist
- # in libc. IRIX 6.5 has the first one in both libc and libpthread, but
- # the second one only in libpthread, and lock.c needs it.
- AC_TRY_LINK([#include <pthread.h>],
- [pthread_mutex_lock((pthread_mutex_t*)0);
- pthread_mutexattr_init((pthread_mutexattr_t*)0);],
- [gl_have_pthread=yes])
- # Test for libpthread by looking for pthread_kill. (Not pthread_self,
- # since it is defined as a macro on OSF/1.)
- if test -n "$gl_have_pthread"; then
- # The program links fine without libpthread. But it may actually
- # need to link with libpthread in order to create multiple threads.
- AC_CHECK_LIB(pthread, pthread_kill,
- [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread
- # On Solaris and HP-UX, most pthread functions exist also in libc.
- # Therefore pthread_in_use() needs to actually try to create a
- # thread: pthread_create from libc will fail, whereas
- # pthread_create will actually create a thread.
- case "$host_os" in
- solaris* | hpux*)
- AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], 1,
- [Define if the pthread_in_use() detection is hard.])
- esac
- ])
- else
- # Some library is needed. Try libpthread and libc_r.
- AC_CHECK_LIB(pthread, pthread_kill,
- [gl_have_pthread=yes
- LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread
- LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread])
- if test -z "$gl_have_pthread"; then
- # For FreeBSD 4.
- AC_CHECK_LIB(c_r, pthread_kill,
- [gl_have_pthread=yes
- LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r
- LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r])
- fi
- fi
- if test -n "$gl_have_pthread"; then
- gl_threads_api=posix
- AC_DEFINE([USE_POSIX_THREADS], 1,
- [Define if the POSIX multithreading library can be used.])
- if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then
- if test $gl_have_weak = yes; then
- AC_DEFINE([USE_POSIX_THREADS_WEAK], 1,
- [Define if references to the POSIX multithreading library should be made weak.])
- LIBTHREAD=
- LTLIBTHREAD=
- fi
- fi
- # OSF/1 4.0 and MacOS X 10.1 lack the pthread_rwlock_t type and the
- # pthread_rwlock_* functions.
- AC_CHECK_TYPE([pthread_rwlock_t],
- [AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1,
- [Define if the POSIX multithreading library has read/write locks.])],
- [],
- [#include <pthread.h>])
- # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro.
- AC_TRY_COMPILE([#include <pthread.h>],
- [#if __FreeBSD__ == 4
+ AC_REQUIRE([gl_THREADLIB])
+ if test "$gl_threads_api" = posix; then
+ # OSF/1 4.0 and Mac OS X 10.1 lack the pthread_rwlock_t type and the
+ # pthread_rwlock_* functions.
+ AC_CHECK_TYPE([pthread_rwlock_t],
+ [AC_DEFINE([HAVE_PTHREAD_RWLOCK], [1],
+ [Define if the POSIX multithreading library has read/write locks.])],
+ [],
+ [#include <pthread.h>])
+ # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro.
+ AC_COMPILE_IFELSE([
+ AC_LANG_PROGRAM(
+ [[#include <pthread.h>]],
+ [[
+#if __FreeBSD__ == 4
error "No, in FreeBSD 4.0 recursive mutexes actually don't work."
+#elif (defined __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ \
+ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
+error "No, in Mac OS X < 10.7 recursive mutexes actually don't work."
#else
int x = (int)PTHREAD_MUTEX_RECURSIVE;
-#endif],
- [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1,
- [Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE.])])
- # Some systems optimize for single-threaded programs by default, and
- # need special flags to disable these optimizations. For example, the
- # definition of 'errno' in <errno.h>.
- case "$host_os" in
- aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;;
- solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;;
- esac
- fi
- fi
- fi
- if test -z "$gl_have_pthread"; then
- if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then
- gl_have_solaristhread=
- gl_save_LIBS="$LIBS"
- LIBS="$LIBS -lthread"
- AC_TRY_LINK([#include <thread.h>
-#include <synch.h>],
- [thr_self();],
- [gl_have_solaristhread=yes])
- LIBS="$gl_save_LIBS"
- if test -n "$gl_have_solaristhread"; then
- gl_threads_api=solaris
- LIBTHREAD=-lthread
- LTLIBTHREAD=-lthread
- LIBMULTITHREAD="$LIBTHREAD"
- LTLIBMULTITHREAD="$LTLIBTHREAD"
- AC_DEFINE([USE_SOLARIS_THREADS], 1,
- [Define if the old Solaris multithreading library can be used.])
- if test $gl_have_weak = yes; then
- AC_DEFINE([USE_SOLARIS_THREADS_WEAK], 1,
- [Define if references to the old Solaris multithreading library should be made weak.])
- LIBTHREAD=
- LTLIBTHREAD=
- fi
- fi
- fi
- fi
- if test "$gl_use_threads" = pth; then
- gl_save_CPPFLAGS="$CPPFLAGS"
- AC_LIB_LINKFLAGS(pth)
- gl_have_pth=
- gl_save_LIBS="$LIBS"
- LIBS="$LIBS -lpth"
- AC_TRY_LINK([#include <pth.h>], [pth_self();], gl_have_pth=yes)
- LIBS="$gl_save_LIBS"
- if test -n "$gl_have_pth"; then
- gl_threads_api=pth
- LIBTHREAD="$LIBPTH"
- LTLIBTHREAD="$LTLIBPTH"
- LIBMULTITHREAD="$LIBTHREAD"
- LTLIBMULTITHREAD="$LTLIBTHREAD"
- AC_DEFINE([USE_PTH_THREADS], 1,
- [Define if the GNU Pth multithreading library can be used.])
- if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then
- if test $gl_have_weak = yes; then
- AC_DEFINE([USE_PTH_THREADS_WEAK], 1,
- [Define if references to the GNU Pth multithreading library should be made weak.])
- LIBTHREAD=
- LTLIBTHREAD=
- fi
- fi
- else
- CPPFLAGS="$gl_save_CPPFLAGS"
- fi
- fi
- if test -z "$gl_have_pthread"; then
- if test "$gl_use_threads" = yes || test "$gl_use_threads" = win32; then
- if { case "$host_os" in
- mingw*) true;;
- *) false;;
- esac
- }; then
- gl_threads_api=win32
- AC_DEFINE([USE_WIN32_THREADS], 1,
- [Define if the Win32 multithreading API can be used.])
- fi
- fi
- fi
+return !x;
+#endif
+ ]])],
+ [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], [1],
+ [Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE.])])
fi
- AC_MSG_CHECKING([for multithread API to use])
- AC_MSG_RESULT([$gl_threads_api])
- AC_SUBST(LIBTHREAD)
- AC_SUBST(LTLIBTHREAD)
- AC_SUBST(LIBMULTITHREAD)
- AC_SUBST(LTLIBMULTITHREAD)
gl_PREREQ_LOCK
])
-# Prerequisites of lib/lock.c.
-AC_DEFUN([gl_PREREQ_LOCK], [
- AC_REQUIRE([AC_C_INLINE])
-])
-
-dnl Survey of platforms:
-dnl
-dnl Platform Available Compiler Supports test-lock
-dnl flavours option weak result
-dnl --------------- --------- --------- -------- ---------
-dnl Linux 2.4/glibc posix -lpthread Y OK
-dnl
-dnl GNU Hurd/glibc posix
-dnl
-dnl FreeBSD 5.3 posix -lc_r Y
-dnl posix -lkse ? Y
-dnl posix -lpthread ? Y
-dnl posix -lthr Y
-dnl
-dnl FreeBSD 5.2 posix -lc_r Y
-dnl posix -lkse Y
-dnl posix -lthr Y
-dnl
-dnl FreeBSD 4.0,4.10 posix -lc_r Y OK
-dnl
-dnl NetBSD 1.6 --
-dnl
-dnl OpenBSD 3.4 posix -lpthread Y OK
-dnl
-dnl MacOS X 10.[123] posix -lpthread Y OK
-dnl
-dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK
-dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK
-dnl
-dnl HP-UX 11 posix -lpthread N (cc) OK
-dnl Y (gcc)
-dnl
-dnl IRIX 6.5 posix -lpthread Y 0.5
-dnl
-dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK
-dnl
-dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK
-dnl -lpthread (gcc) Y
-dnl
-dnl Cygwin posix -lpthread Y OK
-dnl
-dnl Any of the above pth -lpth 0.0
-dnl
-dnl Mingw win32 N OK
-dnl
-dnl BeOS 5 --
-dnl
-dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is
-dnl turned off:
-dnl OK if all three tests terminate OK,
-dnl 0.5 if the first test terminates OK but the second one loops endlessly,
-dnl 0.0 if the first test already loops endlessly.
+# Prerequisites of lib/glthread/lock.c.
+AC_DEFUN([gl_PREREQ_LOCK], [:])
diff --git a/m4/threadlib.m4 b/m4/threadlib.m4
new file mode 100644
index 0000000..a91e819
--- /dev/null
+++ b/m4/threadlib.m4
@@ -0,0 +1,341 @@
+# threadlib.m4 serial 10 (gettext-0.18.2) modified by wk 2014-01-15.
+dnl Copyright (C) 2005-2014 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.
+
+dnl From Bruno Haible.
+
+dnl gl_THREADLIB
+dnl ------------
+dnl Tests for a multithreading library to be used.
+dnl If the configure.ac contains a definition of the gl_THREADLIB_DEFAULT_NO
+dnl (it must be placed before the invocation of gl_THREADLIB_EARLY!), then the
+dnl default is 'no', otherwise it is system dependent. In both cases, the user
+dnl can change the choice through the options --enable-threads=choice or
+dnl --disable-threads.
+dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS,
+dnl USE_WINDOWS_THREADS
+dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use
+dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with
+dnl libtool).
+dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for
+dnl programs that really need multithread functionality. The difference
+dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak
+dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread".
+dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for
+dnl multithread-safe programs.
+
+AC_DEFUN([gl_THREADLIB_EARLY],
+[
+ AC_REQUIRE([gl_THREADLIB_EARLY_BODY])
+])
+
+dnl The guts of gl_THREADLIB_EARLY. Needs to be expanded only once.
+
+AC_DEFUN([gl_THREADLIB_EARLY_BODY],
+[
+ dnl Ordering constraints: This macro modifies CPPFLAGS in a way that
+ dnl influences the result of the autoconf tests that test for *_unlocked
+ dnl declarations, on AIX 5 at least. Therefore it must come early.
+ AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl
+ AC_BEFORE([$0], [gl_ARGP])dnl
+
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ dnl _GNU_SOURCE is needed for pthread_rwlock_t on glibc systems.
+ dnl AC_USE_SYSTEM_EXTENSIONS was introduced in autoconf 2.60 and obsoletes
+ dnl AC_GNU_SOURCE.
+ m4_ifdef([AC_USE_SYSTEM_EXTENSIONS],
+ [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])],
+ [AC_REQUIRE([AC_GNU_SOURCE])])
+ dnl Check for multithreading.
+ m4_ifdef([gl_THREADLIB_DEFAULT_NO],
+ [m4_divert_text([DEFAULTS], [gl_use_threads_default=no])],
+ [m4_divert_text([DEFAULTS], [gl_use_threads_default=])])
+ AC_ARG_ENABLE([threads],
+AC_HELP_STRING([--enable-threads={posix|solaris|windows}], [specify multithreading API])m4_ifdef([gl_THREADLIB_DEFAULT_NO], [], [
+AC_HELP_STRING([--disable-threads], [build without multithread safety])]),
+ [gl_use_threads=$enableval],
+ [if test -n "$gl_use_threads_default"; then
+ gl_use_threads="$gl_use_threads_default"
+ else
+changequote(,)dnl
+ case "$host_os" in
+ dnl Disable multithreading by default on OSF/1, because it interferes
+ dnl with fork()/exec(): When msgexec is linked with -lpthread, its
+ dnl child process gets an endless segmentation fault inside execvp().
+ dnl Disable multithreading by default on Cygwin 1.5.x, because it has
+ dnl bugs that lead to endless loops or crashes. See
+ dnl <http://cygwin.com/ml/cygwin/2009-08/msg00283.html>.
+ osf*) gl_use_threads=no ;;
+ cygwin*)
+ case `uname -r` in
+ 1.[0-5].*) gl_use_threads=no ;;
+ *) gl_use_threads=yes ;;
+ esac
+ ;;
+ *) gl_use_threads=yes ;;
+ esac
+changequote([,])dnl
+ fi
+ ])
+ if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then
+ # For using <pthread.h>:
+ case "$host_os" in
+ osf*)
+ # On OSF/1, the compiler needs the flag -D_REENTRANT so that it
+ # groks <pthread.h>. cc also understands the flag -pthread, but
+ # we don't use it because 1. gcc-2.95 doesn't understand -pthread,
+ # 2. putting a flag into CPPFLAGS that has an effect on the linker
+ # causes the AC_LINK_IFELSE test below to succeed unexpectedly,
+ # leading to wrong values of LIBTHREAD and LTLIBTHREAD.
+ CPPFLAGS="$CPPFLAGS -D_REENTRANT"
+ ;;
+ esac
+ # Some systems optimize for single-threaded programs by default, and
+ # need special flags to disable these optimizations. For example, the
+ # definition of 'errno' in <errno.h>.
+ case "$host_os" in
+ aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;;
+ solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;;
+ esac
+ fi
+])
+
+dnl The guts of gl_THREADLIB. Needs to be expanded only once.
+
+AC_DEFUN([gl_THREADLIB_BODY],
+[
+ AC_REQUIRE([gl_THREADLIB_EARLY_BODY])
+ gl_threads_api=none
+ LIBTHREAD=
+ LTLIBTHREAD=
+ LIBMULTITHREAD=
+ LTLIBMULTITHREAD=
+ if test "$gl_use_threads" != no; then
+ dnl Check whether the compiler and linker support weak declarations.
+ AC_CACHE_CHECK([whether imported symbols can be declared weak],
+ [gl_cv_have_weak],
+ [gl_cv_have_weak=no
+ dnl First, test whether the compiler accepts it syntactically.
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[extern void xyzzy ();
+#pragma weak xyzzy]],
+ [[xyzzy();]])],
+ [gl_cv_have_weak=maybe])
+ if test $gl_cv_have_weak = maybe; then
+ dnl Second, test whether it actually works. On Cygwin 1.7.2, with
+ dnl gcc 4.3, symbols declared weak always evaluate to the address 0.
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE([[
+#include <stdio.h>
+#pragma weak fputs
+int main ()
+{
+ return (fputs == NULL);
+}]])],
+ [gl_cv_have_weak=yes],
+ [gl_cv_have_weak=no],
+ [dnl When cross-compiling, assume that only ELF platforms support
+ dnl weak symbols.
+ AC_EGREP_CPP([Extensible Linking Format],
+ [#ifdef __ELF__
+ Extensible Linking Format
+ #endif
+ ],
+ [gl_cv_have_weak="guessing yes"],
+ [gl_cv_have_weak="guessing no"])
+ ])
+ fi
+ ])
+ if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then
+ # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that
+ # it groks <pthread.h>. It's added above, in gl_THREADLIB_EARLY_BODY.
+ AC_CHECK_HEADER([pthread.h],
+ [gl_have_pthread_h=yes], [gl_have_pthread_h=no])
+ if test "$gl_have_pthread_h" = yes; then
+ # Other possible tests:
+ # -lpthreads (FSU threads, PCthreads)
+ # -lgthreads
+ gl_have_pthread=
+ # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist
+ # in libc. IRIX 6.5 has the first one in both libc and libpthread, but
+ # the second one only in libpthread, and lock.c needs it.
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <pthread.h>]],
+ [[pthread_mutex_lock((pthread_mutex_t*)0);
+ pthread_mutexattr_init((pthread_mutexattr_t*)0);]])],
+ [gl_have_pthread=yes])
+ # Test for libpthread by looking for pthread_kill. (Not pthread_self,
+ # since it is defined as a macro on OSF/1.)
+ if test -n "$gl_have_pthread"; then
+ # The program links fine without libpthread. But it may actually
+ # need to link with libpthread in order to create multiple threads.
+ AC_CHECK_LIB([pthread], [pthread_kill],
+ [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread
+ # On Solaris and HP-UX, most pthread functions exist also in libc.
+ # Therefore pthread_in_use() needs to actually try to create a
+ # thread: pthread_create from libc will fail, whereas
+ # pthread_create will actually create a thread.
+ case "$host_os" in
+ solaris* | hpux*)
+ AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], [1],
+ [Define if the pthread_in_use() detection is hard.])
+ esac
+ ])
+ else
+ # Some library is needed. Try libpthread and libc_r.
+ AC_CHECK_LIB([pthread], [pthread_kill],
+ [gl_have_pthread=yes
+ LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread
+ LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread])
+ if test -z "$gl_have_pthread"; then
+ # For FreeBSD 4.
+ AC_CHECK_LIB([c_r], [pthread_kill],
+ [gl_have_pthread=yes
+ LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r
+ LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r])
+ fi
+ fi
+ if test -n "$gl_have_pthread"; then
+ gl_threads_api=posix
+ AC_DEFINE([USE_POSIX_THREADS], [1],
+ [Define if the POSIX multithreading library can be used.])
+ if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then
+ if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then
+ AC_DEFINE([USE_POSIX_THREADS_WEAK], [1],
+ [Define if references to the POSIX multithreading library should be made weak.])
+ LIBTHREAD=
+ LTLIBTHREAD=
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -z "$gl_have_pthread"; then
+ if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then
+ gl_have_solaristhread=
+ gl_save_LIBS="$LIBS"
+ LIBS="$LIBS -lthread"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+#include <thread.h>
+#include <synch.h>
+ ]],
+ [[thr_self();]])],
+ [gl_have_solaristhread=yes])
+ LIBS="$gl_save_LIBS"
+ if test -n "$gl_have_solaristhread"; then
+ gl_threads_api=solaris
+ LIBTHREAD=-lthread
+ LTLIBTHREAD=-lthread
+ LIBMULTITHREAD="$LIBTHREAD"
+ LTLIBMULTITHREAD="$LTLIBTHREAD"
+ AC_DEFINE([USE_SOLARIS_THREADS], [1],
+ [Define if the old Solaris multithreading library can be used.])
+ if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then
+ AC_DEFINE([USE_SOLARIS_THREADS_WEAK], [1],
+ [Define if references to the old Solaris multithreading library should be made weak.])
+ LIBTHREAD=
+ LTLIBTHREAD=
+ fi
+ fi
+ fi
+ fi
+ if test -z "$gl_have_pthread"; then
+ case "$gl_use_threads" in
+ yes | windows | win32) # The 'win32' is for backward compatibility.
+ if { case "$host_os" in
+ mingw*) true;;
+ *) false;;
+ esac
+ }; then
+ gl_threads_api=windows
+ AC_DEFINE([USE_WINDOWS_THREADS], [1],
+ [Define if the native Windows multithreading API can be used.])
+ fi
+ ;;
+ esac
+ fi
+ fi
+ AC_MSG_CHECKING([for multithread API to use])
+ AC_MSG_RESULT([$gl_threads_api])
+ AC_SUBST([LIBTHREAD])
+ AC_SUBST([LTLIBTHREAD])
+ AC_SUBST([LIBMULTITHREAD])
+ AC_SUBST([LTLIBMULTITHREAD])
+])
+
+AC_DEFUN([gl_THREADLIB],
+[
+ AC_REQUIRE([gl_THREADLIB_EARLY])
+ AC_REQUIRE([gl_THREADLIB_BODY])
+])
+
+
+dnl gl_DISABLE_THREADS
+dnl ------------------
+dnl Sets the gl_THREADLIB default so that threads are not used by default.
+dnl The user can still override it at installation time, by using the
+dnl configure option '--enable-threads'.
+
+AC_DEFUN([gl_DISABLE_THREADS], [
+ m4_divert_text([INIT_PREPARE], [gl_use_threads_default=no])
+])
+
+
+dnl Survey of platforms:
+dnl
+dnl Platform Available Compiler Supports test-lock
+dnl flavours option weak result
+dnl --------------- --------- --------- -------- ---------
+dnl Linux 2.4/glibc posix -lpthread Y OK
+dnl
+dnl GNU Hurd/glibc posix
+dnl
+dnl FreeBSD 5.3 posix -lc_r Y
+dnl posix -lkse ? Y
+dnl posix -lpthread ? Y
+dnl posix -lthr Y
+dnl
+dnl FreeBSD 5.2 posix -lc_r Y
+dnl posix -lkse Y
+dnl posix -lthr Y
+dnl
+dnl FreeBSD 4.0,4.10 posix -lc_r Y OK
+dnl
+dnl NetBSD 1.6 --
+dnl
+dnl OpenBSD 3.4 posix -lpthread Y OK
+dnl
+dnl Mac OS X 10.[123] posix -lpthread Y OK
+dnl
+dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK
+dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK
+dnl
+dnl HP-UX 11 posix -lpthread N (cc) OK
+dnl Y (gcc)
+dnl
+dnl IRIX 6.5 posix -lpthread Y 0.5
+dnl
+dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK
+dnl
+dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK
+dnl -lpthread (gcc) Y
+dnl
+dnl Cygwin posix -lpthread Y OK
+dnl
+dnl Any of the above pth -lpth 0.0
+dnl
+dnl Mingw windows N OK
+dnl
+dnl BeOS 5 --
+dnl
+dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is
+dnl turned off:
+dnl OK if all three tests terminate OK,
+dnl 0.5 if the first test terminates OK but the second one loops endlessly,
+dnl 0.0 if the first test already loops endlessly.
diff --git a/src/Makefile.am b/src/Makefile.am
index 74d89be..51b2ea9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,7 +30,15 @@ extra_cppflags =
endif
localedir = $(datadir)/locale
+
bin_PROGRAMS = gpg-error
+
+if HAVE_W32_SYSTEM
+noinst_PROGRAMS = gen-w32-lock-obj
+else
+noinst_PROGRAMS = gen-posix-lock-obj
+endif
+
lib_LTLIBRARIES = libgpg-error.la
include_HEADERS = gpg-error.h
bin_SCRIPTS = gpg-error-config
@@ -42,7 +50,8 @@ EXTRA_DIST = mkstrtable.awk err-sources.h.in err-codes.h.in \
mkerrcodes.awk mkerrcodes1.awk mkerrcodes2.awk mkerrcodes.c \
mkheader.c gpg-error.h.in mkw32errmap.c w32-add.h w32ce-add.h \
err-sources.h err-codes.h gpg-error-config.in gpg-error.m4 \
- gpg-error.def.in versioninfo.rc.in
+ gpg-error.def.in versioninfo.rc.in \
+ w32-lock-obj-pub.in
BUILT_SOURCES = err-sources.h err-codes.h code-to-errno.h code-from-errno.h \
err-sources-sym.h err-codes-sym.h errnos-sym.h gpg-error.h \
@@ -53,11 +62,10 @@ tmp_files = _mkerrcodes.h _gpg-error.def.h mkw32errmap.tab.h mkw32errmap.map.c
CLEANFILES = err-sources.h err-codes.h code-to-errno.h code-from-errno.h \
gpg-error.h mkerrcodes mkerrcodes.h gpg-error.def mkw32errmap.tab.h \
mkw32errmap.map.c err-sources-sym.h err-codes-sym.h errnos-sym.h \
- gpg-extra/errno.h mkheader $(tmp_files)
+ gpg-extra/errno.h mkheader $(tmp_files) posix-lock-obj-pub.in
if HAVE_W32_SYSTEM
-arch_sources = w32-gettext.c
-
+arch_sources = w32-gettext.c w32-lock.c w32-lock-obj.h w32-thread.c
RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
-DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) $(CPPFLAGS)
LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE)
@@ -82,7 +90,7 @@ libgpg_error_la_DEPENDENCIES = $(gpg_error_res) gpg-error.def
intllibs =
else
-arch_sources =
+arch_sources = posix-lock.c posix-lock-obj.h posix-thread.c
gpg_error_res =
no_undefined =
export_symbols =
@@ -98,17 +106,22 @@ libgpg_error_la_LDFLAGS = -version-info \
@LIBGPG_ERROR_LT_CURRENT@:@LIBGPG_ERROR_LT_REVISION@:@LIBGPG_ERROR_LT_AGE@ \
$(no_undefined) $(export_symbols)
-parts_of_gpg_error_h = \
- gpg-error.h.in \
- err-sources.h.in \
- err-codes.h.in \
- errnos.in \
- w32-add.h \
- w32ce-add.h
+parts_of_gpg_error_h = \
+ gpg-error.h.in \
+ err-sources.h.in \
+ err-codes.h.in \
+ errnos.in \
+ w32-add.h \
+ w32ce-add.h \
+ w32-lock-obj-pub.in
+
+if ! HAVE_W32_SYSTEM
+parts_of_gpg_error_h += posix-lock-obj-pub.in
+endif
libgpg_error_la_SOURCES = gpg-error.h gettext.h $(arch_sources) \
- init.c init.h version.c \
+ init.c init.h version.c lock.h thread.h \
strsource.c strerror.c code-to-errno.c code-from-errno.c
# Note that RCCOMPILE needs the same defines as ..._la_CPPFLAGS but
@@ -195,9 +208,14 @@ errnos-sym.h: Makefile mkstrtable.awk errnos.in
-v prefix=GPG_ERR_ -v namespace=errnos_ \
$(srcdir)/errnos.in >$@
+
mkheader: mkheader.c Makefile
$(CC_FOR_BUILD) -g -O0 -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c
+
+posix-lock-obj-pub.in: Makefile gen-posix-lock-obj posix-lock-obj.h
+ ./gen-posix-lock-obj >$@
+
# We also depend on versioninfo.rc because that is build by
# config.status and thus has up-to-date version numbers.
gpg-error.h: Makefile mkheader $(parts_of_gpg_error_h) versioninfo.rc
diff --git a/src/err-codes.h.in b/src/err-codes.h.in
index 4ecc24e..c912bcd 100644
--- a/src/err-codes.h.in
+++ b/src/err-codes.h.in
@@ -247,7 +247,11 @@
212 GPG_ERR_SEXP_ODD_HEX_NUMBERS Odd hexadecimal numbers in S-expression
213 GPG_ERR_SEXP_BAD_OCT_CHAR Bad octal character in S-expression
-# 214 to 254 are free to be used. 255 and 256 are RFU.
+# 214 to 253 are free to be used.
+
+254 GPG_ERR_INV_LOCK_OBJ Invalid lock object
+
+# 255 and 256 are RFU.
# Error codes pertaining to the Assuan IPC interface
257 GPG_ERR_ASS_GENERAL General IPC error
diff --git a/src/gen-posix-lock-obj.c b/src/gen-posix-lock-obj.c
new file mode 100644
index 0000000..b641fd0
--- /dev/null
+++ b/src/gen-posix-lock-obj.c
@@ -0,0 +1,95 @@
+/* gen-posix-lock-obj.c - Build tool to construct the lock object.
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+# error This module may not be build for Windows.
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+#include "posix-lock-obj.h"
+
+#define PGM "gen-posix-lock-obj"
+
+/* Check that configure did its job. */
+#if SIZEOF_PTHREAD_MUTEX_T < 4
+# error sizeof pthread_mutex_t is not known.
+#endif
+
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+
+
+int
+main (void)
+{
+ unsigned char *p;
+ int i;
+ struct {
+ pthread_mutex_t mtx;
+ long vers;
+ } dummyobj;
+
+ if (sizeof mtx != SIZEOF_PTHREAD_MUTEX_T)
+ {
+ fprintf (stderr, PGM ": pthread_mutex_t mismatch\n");
+ exit (1);
+ }
+
+ if (sizeof (dummyobj) != sizeof (_gpgrt_lock_t))
+ {
+ fprintf (stderr, PGM ": internal and external lock object mismatch\n");
+ exit (1);
+ }
+
+ /* To force a probably suitable alignment of the structure we use a
+ union and include a long and a pointer to a long. */
+ printf ("## File created by " PGM " - DO NOT EDIT\n"
+ "## To be included by mkheader into gpg-error.h\n"
+ "\n"
+ "typedef union\n"
+ "{\n"
+ " struct {\n"
+ " volatile char _priv[%d];\n"
+ " long _vers;\n"
+ " } d;\n"
+ " long _x_align;\n"
+ " long *_xp_align;\n"
+ "} gpgrt_lock_t;\n"
+ "\n"
+ "#define GPGRT_LOCK_INITIALIZER {{{",
+ SIZEOF_PTHREAD_MUTEX_T);
+ p = (unsigned char *)&mtx;
+ for (i=0; i < sizeof mtx; i++)
+ {
+ if (i && !(i % 8))
+ printf (" \\\n%*s", 34, "");
+ printf ("%u", p[i]);
+ if (i < sizeof mtx - 1)
+ putchar (',');
+ }
+ printf ("},%d}}\n", LOCK_ABI_VERSION);
+
+ return 0;
+}
diff --git a/src/gen-w32-lock-obj.c b/src/gen-w32-lock-obj.c
new file mode 100644
index 0000000..9e49d1e
--- /dev/null
+++ b/src/gen-w32-lock-obj.c
@@ -0,0 +1,55 @@
+/* gen-w32-lock-obj.c - Build tool to get the size of the lock object.
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef HAVE_W32_SYSTEM
+# error This module may only be build for Windows.
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windows.h>
+
+#include "w32-lock-obj.h"
+
+
+int
+main (void)
+{
+ _gpgrt_lock_t lk;
+ unsigned char *p;
+ int i;
+
+ printf ("sizeof CRITICAL_SECTION = %u\n", (int)sizeof (CRITICAL_SECTION));
+ printf ("sizeof _gpgrt_lock_t = %u\n", (int)sizeof lk);
+
+ memset (&lk, 0, sizeof lk);
+ lk.vers = LOCK_ABI_VERSION;
+ lk.started = -1;
+ printf ("#define GPGRT_LOCK_INITIALIZER {");
+ p = (unsigned char *)&lk;
+ for (i=0; i < sizeof lk - 1; i++)
+ printf ("%u,", p[i]);
+ printf ("%u}\n", p[sizeof(lk)-1]);
+
+ return 0;
+}
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index 62e0681..2ea482a 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -28,3 +28,9 @@ EXPORTS
#endif
gpg_err_deinit @18
gpg_error_check_version @19
+
+ gpgrt_lock_init @20
+ gpgrt_lock_lock @21
+ gpgrt_lock_unlock @22
+ gpgrt_lock_destroy @23
+ gpgrt_yield @24
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index a2fb044..adb796b 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -66,7 +66,10 @@ extern "C" {
GPG_ERR_ENABLE_GETTEXT_MACROS: Define to provide macros to map the
internal gettext API to standard names. This has only an effect on
- Windows platforms. */
+ Windows platforms.
+
+ In addition to the error codes, Libgpg-error also provides a set of
+ functions used by most GnuPG components. */
/* The error source type gpg_err_source_t.
@@ -279,9 +282,35 @@ gpg_error_from_syserror (void)
return gpg_error (gpg_err_code_from_syserror ());
}
+
+
+/* Lock functions. */
+
+@include:lock-obj@
+
+#define GPGRT_LOCK_DEFINE(name) \
+ static gpgrt_lock_t name = GPGRT_LOCK_INITIALIZER
+
+
+gpg_err_code_t gpgrt_lock_init (gpgrt_lock_t *lockhd);
+gpg_err_code_t gpgrt_lock_lock (gpgrt_lock_t *lockhd);
+gpg_err_code_t gpgrt_lock_unlock (gpgrt_lock_t *lockhd);
+gpg_err_code_t gpgrt_lock_destroy (gpgrt_lock_t *lockhd);
+
+
+
+/* Thread functions. */
+
+gpg_err_code_t gpgrt_yield (void);
+
+
+
+
+/* Estream */
+
+
+
#ifdef __cplusplus
}
#endif
-
-
#endif /* GPG_ERROR_H */
diff --git a/src/lock.h b/src/lock.h
new file mode 100644
index 0000000..b60f2c2
--- /dev/null
+++ b/src/lock.h
@@ -0,0 +1,24 @@
+/* lock.h - Declarations for *-lock.c
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LOCK_H
+#define LOCK_H
+
+
+#endif /*LOCK_H*/
diff --git a/src/mkheader.c b/src/mkheader.c
index eea7914..e7db729 100644
--- a/src/mkheader.c
+++ b/src/mkheader.c
@@ -132,7 +132,8 @@ write_errnos_in (char *line)
is not further expanded. It may have comments indicated by a
double hash mark at the begin of a line. OUTF is called for each
read line and passed a buffer with the content of line sans line
- line endings. */
+ line endings. If NAME is prefixed with "./" it is included from
+ the current directory and not from the source directory. */
static void
include_file (const char *fname, int lnr, const char *name, void (*outf)(char*))
{
@@ -147,7 +148,11 @@ include_file (const char *fname, int lnr, const char *name, void (*outf)(char*))
fputs (PGM ": out of core\n", stderr);
exit (1);
}
- strcpy (incfname, srcdir);
+
+ if (*name == '.' && name[1] == '/')
+ *incfname = 0;
+ else
+ strcpy (incfname, srcdir);
strcat (incfname, name);
fp = fopen (incfname, "r");
@@ -242,6 +247,15 @@ write_special (const char *fname, int lnr, const char *tag)
include_file (fname, lnr, "w32ce-add.h", write_line);
}
}
+ else if (!strcmp (tag, "include:lock-obj"))
+ {
+ if (!strcmp (host_os, "mingw32"))
+ {
+ include_file (fname, lnr, "w32-lock-obj-pub.in", write_line);
+ }
+ else
+ include_file (fname, lnr, "./posix-lock-obj-pub.in", write_line);
+ }
else
return 0; /* Unknown tag. */
diff --git a/src/posix-lock-obj.h b/src/posix-lock-obj.h
new file mode 100644
index 0000000..a5a9ee7
--- /dev/null
+++ b/src/posix-lock-obj.h
@@ -0,0 +1,32 @@
+/* posic-lock-obj.h - Declaration of the POSIX lock object
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef POSIX_LOCK_OBJ_H
+#define POSIX_LOCK_OBJ_H
+
+#define LOCK_ABI_VERSION 1
+
+typedef struct
+{
+ pthread_mutex_t mtx;
+ long vers;
+} _gpgrt_lock_t;
+
+
+#endif /*POSIX_LOCK_OBJ_H*/
diff --git a/src/posix-lock.c b/src/posix-lock.c
new file mode 100644
index 0000000..46e3a84
--- /dev/null
+++ b/src/posix-lock.c
@@ -0,0 +1,213 @@
+/* posix-lock.c - GPGRT lock functions for POSIX systems
+ Copyright (C) 2005-2009 Free Software Foundation, Inc.
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ Parts of the code, in particular use_pthreads_p, are based on code
+ from gettext, written by Bruno Haible <[email protected]>, 2005.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+# error This module may not be build for Windows.
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#if USE_POSIX_THREADS
+# include <pthread.h>
+#endif
+
+#include "gpg-error.h"
+#include "lock.h"
+#include "posix-lock-obj.h"
+
+
+#if USE_POSIX_THREADS
+# if USE_POSIX_THREADS_WEAK
+ /* On ELF systems it is easy to use pthreads using weak
+ references. Take care not to test the address of a weak
+ referenced function we actually use; some GCC versions have a
+ bug were &foo != NULL is always evaluated to true in PIC mode. */
+# pragma weak pthread_cancel
+# pragma weak pthread_mutex_init
+# pragma weak pthread_mutex_lock
+# pragma weak pthread_mutex_unlock
+# pragma weak pthread_mutex_destroy
+# if ! PTHREAD_IN_USE_DETECTION_HARD
+# define use_pthread_p() (!!pthread_cancel)
+# endif
+# else /*!USE_POSIX_THREADS_WEAK*/
+# if ! PTHREAD_IN_USE_DETECTION_HARD
+# define use_pthread_p() (1)
+# endif
+# endif /*!USE_POSIX_THREADS_WEAK*/
+# if PTHREAD_IN_USE_DETECTION_HARD
+/* The function to be executed by a dummy thread. */
+static void *
+dummy_thread_func (void *arg)
+{
+ return arg;
+}
+
+static int
+use_pthread_p (void)
+{
+ static int tested;
+ static int result; /* 1: linked with -lpthread, 0: only with libc */
+
+ if (!tested)
+ {
+ pthread_t thread;
+
+ if (pthread_create (&thread, NULL, dummy_thread_func, NULL))
+ result = 0; /* Thread creation failed. */
+ else
+ {
+ /* Thread creation works. */
+ void *retval;
+ if (pthread_join (thread, &retval) != 0)
+ abort ();
+ result = 1;
+ }
+ tested = 1;
+ }
+ return result;
+}
+#endif /*PTHREAD_IN_USE_DETECTION_HARD*/
+#endif /*USE_POSIX_THREADS*/
+
+
+
+static _gpgrt_lock_t *
+get_lock_object (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
+
+ if (lock->vers != LOCK_ABI_VERSION)
+ abort ();
+ if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
+ abort ();
+
+ return lock;
+}
+
+
+gpg_err_code_t
+gpgrt_lock_init (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+ int rc;
+
+#if USE_POSIX_THREADS
+ if (use_pthread_p())
+ {
+ rc = pthread_mutex_init (&lock->mtx, NULL);
+ if (rc)
+ rc = gpg_err_code_from_errno (rc);
+ }
+ else
+ rc = 0; /* Threads are not used. */
+#else /* Unknown thread system. */
+ rc = GPG_ERR_NOT_IMPLEMENTED;
+#endif /* Unknown thread system. */
+
+ return rc;
+}
+
+
+gpg_err_code_t
+gpgrt_lock_lock (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+ int rc;
+
+#if USE_POSIX_THREADS
+ if (use_pthread_p())
+ {
+ rc = pthread_mutex_lock (&lock->mtx);
+ if (rc)
+ rc = gpg_err_code_from_errno (rc);
+ }
+ else
+ rc = 0; /* Threads are not used. */
+#else /* Unknown thread system. */
+ rc = GPG_ERR_NOT_IMPLEMENTED;
+#endif /* Unknown thread system. */
+
+ return rc;
+}
+
+
+gpg_err_code_t
+gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+ int rc;
+
+#if USE_POSIX_THREADS
+ if (use_pthread_p())
+ {
+ rc = pthread_mutex_unlock (&lock->mtx);
+ if (rc)
+ rc = gpg_err_code_from_errno (rc);
+ }
+ else
+ rc = 0; /* Threads are not used. */
+#else /* Unknown thread system. */
+ rc = GPG_ERR_NOT_IMPLEMENTED;
+#endif /* Unknown thread system. */
+
+ return rc;
+}
+
+
+/* Note: Use this function only if no other thread holds or waits for
+ this lock. */
+gpg_err_code_t
+gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+ int rc;
+
+#if USE_POSIX_THREADS
+ if (use_pthread_p())
+ {
+ rc = pthread_mutex_destroy (&lock->mtx);
+ if (rc)
+ rc = gpg_err_code_from_errno (rc);
+ else
+ {
+ /* Re-init the the mutex so that it can be re-used. */
+ gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER;
+ memcpy (lockhd, &tmp, sizeof tmp);
+ }
+ }
+ else
+ rc = 0; /* Threads are not used. */
+#else /* Unknown thread system. */
+ rc = GPG_ERR_NOT_IMPLEMENTED;
+#endif /* Unknown thread system. */
+
+ return rc;
+}
diff --git a/src/posix-thread.c b/src/posix-thread.c
new file mode 100644
index 0000000..a739e40
--- /dev/null
+++ b/src/posix-thread.c
@@ -0,0 +1,63 @@
+/* posix-thread.c - GPGRT thread functions for POSIX systems
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+# error This module may not be build for Windows.
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h> /* Get posix option macros. */
+
+#if USE_POSIX_THREADS
+# ifdef _POSIX_PRIORITY_SCHEDULING
+# include <sched.h>
+# endif
+#elif USE_SOLARIS_THREADS
+# include <thread.h>
+#endif
+
+#include "gpg-error.h"
+
+#include "thread.h"
+
+
+gpg_err_code_t
+gpgrt_yield (void)
+{
+#if USE_POSIX_THREADS
+# ifdef _POSIX_PRIORITY_SCHEDULING
+ sched_yield ();
+# else
+ return GPG_ERR_NOT_SUPPORTED;
+# endif
+#elif USE_SOLARIS_THREADS
+ thr_yield ();
+#else
+ return GPG_ERR_NOT_SUPPORTED;
+#endif
+
+ return 0;
+}
diff --git a/src/thread.h b/src/thread.h
new file mode 100644
index 0000000..0b2cf04
--- /dev/null
+++ b/src/thread.h
@@ -0,0 +1,24 @@
+/* thread.h - Declarations for *-thread.c
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef THREAD_H
+#define THREAD_H
+
+
+#endif /*THREAD_H*/
diff --git a/src/version.c b/src/version.c
index 36e2d58..5b40537 100644
--- a/src/version.c
+++ b/src/version.c
@@ -1,5 +1,5 @@
/* version.c - Version checking
- * Copyright (C) 2001, 2002, 2012, 2013 g10 Code GmbH
+ * Copyright (C) 2001, 2002, 2012, 2013, 2014 g10 Code GmbH
*
* This file is part of libgpg-error.
*
@@ -39,7 +39,7 @@ cright_blurb (void)
static const char blurb[] =
"\n\n"
"This is Libgpg-error " PACKAGE_VERSION " - An error code library\n"
- "Copyright 2003, 2004, 2010, 2013 g10 Code GmbH\n"
+ "Copyright 2003, 2004, 2010, 2013, 2014 g10 Code GmbH\n"
"\n"
"(" BUILD_REVISION " " BUILD_TIMESTAMP ")\n"
"\n\n";
diff --git a/src/w32-lock-obj-pub.in b/src/w32-lock-obj-pub.in
new file mode 100644
index 0000000..2f3f911
--- /dev/null
+++ b/src/w32-lock-obj-pub.in
@@ -0,0 +1,44 @@
+## w32-lock-obj-pub.in - Include fragment for gpg-error.h -*- c-*-
+## Copyright (C) 2014 g10 Code GmbH
+##
+## This file is free software; as a special exception the author gives
+## unlimited permission to copy and/or distribute it, with or without
+## modifications, as long as this notice is preserved.
+##
+## This file is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+##
+##
+## This file defines the public version of the lock object for 32 bit
+## Windows. The actual used version is in w32-lock-obj.h. This file
+## is inserted into gpg-error.h by mkheader.c. The tool
+## gen-w32-lock-obj.c has been used to construct it.
+
+#ifdef _WIN64
+
+#pragma pack(push, 8)
+typedef struct
+{
+ volatile char priv[56];
+} gpgrt_lock_t;
+#pragma pack(pop)
+
+#define GPGRT_LOCK_INITIALIZER {1,0,0,0,0,0,0,0,255,255,255,255, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0,0,0,0,0}
+
+#else
+
+#pragma pack(push, 8)
+typedef struct
+{
+ volatile char priv[36];
+} gpgrt_lock_t;
+#pragma pack(pop)
+
+#define GPGRT_LOCK_INITIALIZER {1,0,0,0,0,0,0,0,255,255,255,255, \
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, \
+ 0,0,0,0,0,0,0,0}
+#endif
diff --git a/src/w32-lock-obj.h b/src/w32-lock-obj.h
new file mode 100644
index 0000000..ef53546
--- /dev/null
+++ b/src/w32-lock-obj.h
@@ -0,0 +1,38 @@
+/* w32-lock-obj.h - Declaration of the Windows lock object
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef W32_LOCK_OBJ_H
+#define W32_LOCK_OBJ_H
+
+#define LOCK_ABI_VERSION 1
+
+/* The real definition of our lock object. The public definition is
+ named gpgrt_lock_t and hides this internal structure. */
+#pragma pack(push, 8)
+typedef struct
+{
+ long vers;
+ volatile long initdone;
+ volatile long started;
+ CRITICAL_SECTION csec;
+} _gpgrt_lock_t;
+#pragma pack(pop)
+
+
+#endif /*W32_LOCK_OBJ_H*/
diff --git a/src/w32-lock.c b/src/w32-lock.c
new file mode 100644
index 0000000..0ad9409
--- /dev/null
+++ b/src/w32-lock.c
@@ -0,0 +1,119 @@
+/* w32-lock.c - GPGRT lock functions for Windows
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef HAVE_W32_SYSTEM
+# error This module may only be build for Windows.
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <gpg-error.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "lock.h"
+#include "w32-lock-obj.h"
+
+
+static _gpgrt_lock_t *
+get_lock_object (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
+
+ if (lock->vers != LOCK_ABI_VERSION)
+ abort ();
+
+ return lock;
+}
+
+
+gpg_err_code_t
+gpgrt_lock_init (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+
+ if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
+ abort ();
+ InitializeCriticalSection (&lock->csec);
+ lock->initdone = 1;
+}
+
+
+gpg_err_code_t
+gpgrt_lock_lock (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+
+ if (!lock->initdone)
+ {
+ if (!InterlockedIncrement (&lock->started))
+ {
+ /* The new value of started is 0. Because the initial value
+ if the variable was -1 we known that this thread is the
+ first who needs this lock. Thus we initialize now. All
+ other threads won't get 0 back from InterlockedIncrement
+ and thus fall into the wait loop below. We ignore that
+ STARTED may in theory overflow if this thread starves for
+ too long. */
+ gpgrt_lock_init (lockhd);
+ }
+ else
+ {
+ while (!lock->initdone)
+ Sleep (0);
+ }
+ }
+
+ EnterCriticalSection (&lock->csec);
+ return 0;
+}
+
+
+gpg_err_code_t
+gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+
+ if (!lock->initdone)
+ return GPG_ERR_INV_LOCK_OBJ;
+ LeaveCriticalSection (&lock->csec);
+ return 0;
+}
+
+
+/* Note: Use this function only if no other thread holds or waits for
+ this lock. */
+gpg_err_code_t
+gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
+{
+ _gpgrt_lock_t *lock = get_lock_object (lockhd);
+
+ if (!lock->initdone)
+ return GPG_ERR_INV_LOCK_OBJ;
+ DeleteCriticalSection (&lock->csec);
+ lock->initdone = 0;
+ lock->started = -1;
+ return 0;
+}
diff --git a/src/w32-thread.c b/src/w32-thread.c
new file mode 100644
index 0000000..f86be35
--- /dev/null
+++ b/src/w32-thread.c
@@ -0,0 +1,44 @@
+/* w32-thread.c - GPGRT thread functions for Windows
+ Copyright (C) 2014 g10 Code GmbH
+
+ This file is part of libgpg-error.
+
+ libgpg-error is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ libgpg-error 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef HAVE_W32_SYSTEM
+# error This module may only be build for Windows.
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <gpg-error.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "thread.h"
+
+
+gpg_err_code_t
+gpgrt_yield (void)
+{
+ Sleep (0);
+ return 0;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1a27f81..277a78b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -25,11 +25,16 @@ else
extra_includes =
endif
+gpg_error_lib = ../src/libgpg-error.la
-TESTS = t-version t-strerror t-syserror
+TESTS = t-version t-strerror t-syserror t-lock
INCLUDES = -I$(top_builddir)/src $(extra_includes)
-LDADD = ../src/libgpg-error.la
+
+LDADD = $(gpg_error_lib)
noinst_PROGRAMS = $(TESTS)
+noinst_HEADERS = t-common.h
+
+t_lock_LDADD = $(gpg_error_lib) $(LIBMULTITHREAD)
diff --git a/tests/t-common.h b/tests/t-common.h
new file mode 100644
index 0000000..85bcd51
--- /dev/null
+++ b/tests/t-common.h
@@ -0,0 +1,99 @@
+/* t-common.h - Common code for the tests.
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * This file is part of libgpg-error.
+ *
+ * libgpg-error is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * libgpg-error 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+
+#include "../src/gpg-error.h"
+
+#ifndef PGM
+# error Macro PGM not defined.
+#endif
+
+
+static int verbose;
+static int debug;
+static int errorcount;
+
+
+static void
+die (const char *format, ...)
+{
+ va_list arg_ptr ;
+
+ fflush (stdout);
+#ifdef HAVE_FLOCKFILE
+ flockfile (stderr);
+#endif
+ fprintf (stderr, "%s: ", PGM);
+ va_start (arg_ptr, format) ;
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ if (*format && format[strlen(format)-1] != '\n')
+ putc ('\n', stderr);
+#ifdef HAVE_FLOCKFILE
+ funlockfile (stderr);
+#endif
+ exit (1);
+}
+
+
+static void
+fail (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ fflush (stdout);
+#ifdef HAVE_FLOCKFILE
+ flockfile (stderr);
+#endif
+ fprintf (stderr, "%s: ", PGM);
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ if (*format && format[strlen(format)-1] != '\n')
+ putc ('\n', stderr);
+#ifdef HAVE_FLOCKFILE
+ funlockfile (stderr);
+#endif
+ errorcount++;
+ if (errorcount >= 50)
+ die ("stopped after 50 errors.");
+}
+
+
+static void
+show (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ if (!verbose)
+ return;
+#ifdef HAVE_FLOCKFILE
+ flockfile (stderr);
+#endif
+ fprintf (stderr, "%s: ", PGM);
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ if (*format && format[strlen(format)-1] != '\n')
+ putc ('\n', stderr);
+ va_end (arg_ptr);
+#ifdef HAVE_FLOCKFILE
+ funlockfile (stderr);
+#endif
+}
diff --git a/tests/t-lock.c b/tests/t-lock.c
new file mode 100644
index 0000000..91923fb
--- /dev/null
+++ b/tests/t-lock.c
@@ -0,0 +1,318 @@
+/* t-lock.c - Check the lock functions
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * This file is part of libgpg-error.
+ *
+ * libgpg-error is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * libgpg-error 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#ifdef _WIN32
+# include <windows.h>
+#else
+# include <pthread.h>
+#endif
+
+#define PGM "t-lock"
+
+#include "t-common.h"
+
+#ifdef _WIN32
+# define THREAD_RET_TYPE DWORD WINAPI
+# define THREAD_RET_VALUE 0
+#else
+# define THREAD_RET_TYPE void *
+# define THREAD_RET_VALUE NULL
+#endif
+
+
+/* Our tests works by having a a couple of accountant threads which do
+ random transactions between accounts and a revision threads which
+ checks that the balance of all accounts is invariant. The idea for
+ this check is due to Bruno Haible. */
+#define N_ACCOUNT 8
+#define ACCOUNT_VALUE 42
+static int account[N_ACCOUNT];
+GPGRT_LOCK_DEFINE (accounts_lock);
+
+/* Number of transactions done by each accountant. */
+#define N_TRANSACTIONS 1000
+
+/* Number of accountants to run. */
+#define N_ACCOUNTANTS 5
+
+/* Maximum transaction value. A quite low value is used so that we
+ would get an integer overflow. */
+#define MAX_TRANSACTION_VALUE 50
+
+/* Flag to tell the revision thread to finish. */
+static volatile int stop_revision_thread;
+
+
+/* Initialze all accounts. */
+static void
+init_accounts (void)
+{
+ int i;
+
+ for (i=0; i < N_ACCOUNT; i++)
+ account[i] = ACCOUNT_VALUE;
+}
+
+
+/* Check that the sum of all accounts matches the intial sum. */
+static void
+check_accounts (void)
+{
+ int i, sum;
+
+ sum = 0;
+ for (i = 0; i < N_ACCOUNT; i++)
+ sum += account[i];
+ if (sum != N_ACCOUNT * ACCOUNT_VALUE)
+ die ("accounts out of balance");
+}
+
+
+static void
+print_accounts (void)
+{
+ int i;
+
+ for (i=0; i < N_ACCOUNT; i++)
+ printf ("account %d: %6d\n", i, account[i]);
+}
+
+
+/* Get a a random integer value in the range 0 to HIGH. */
+static unsigned int
+get_rand (int high)
+{
+ return (unsigned int)(1+(int)((double)(high+1)*rand ()/(RAND_MAX+1.0))) - 1;
+}
+
+
+/* Pick a random account. Note that this fucntion is not
+ thread-safe. */
+static int
+pick_account (void)
+{
+ return get_rand (N_ACCOUNT - 1);
+}
+
+
+/* Pick a random value for a transaction. This is not thread-safe. */
+static int
+pick_value (void)
+{
+ return get_rand (MAX_TRANSACTION_VALUE);
+}
+
+
+/* This is the revision department. */
+static THREAD_RET_TYPE
+revision_thread (void *arg)
+{
+ gpg_err_code_t rc;
+ int i;
+
+ (void)arg;
+
+ while (!stop_revision_thread)
+ {
+ rc = gpgrt_lock_lock (&accounts_lock);
+ if (rc)
+ fail ("gpgrt_lock_lock failed at %d: %s", __LINE__, gpg_strerror (rc));
+
+ check_accounts ();
+ rc = gpgrt_lock_unlock (&accounts_lock);
+ if (rc)
+ fail ("gpgrt_lock_unlock failed at %d: %s", __LINE__,gpg_strerror (rc));
+ if (!(++i%7))
+ gpgrt_yield ();
+ }
+ return THREAD_RET_VALUE;
+}
+
+
+/* This is one of our accountants. */
+static THREAD_RET_TYPE
+accountant_thread (void *arg)
+{
+ gpg_err_code_t rc;
+ int i;
+ int acc1, acc2;
+ int value;
+
+ (void)arg;
+
+ for (i = 0; i < N_TRANSACTIONS; i++)
+ {
+ rc = gpgrt_lock_lock (&accounts_lock);
+ if (rc)
+ fail ("gpgrt_lock_lock failed at %d: %s", __LINE__, gpg_strerror (rc));
+
+ acc1 = pick_account ();
+ acc2 = pick_account ();
+ value = pick_value ();
+ account[acc1] += value;
+ account[acc2] -= value;
+
+ rc = gpgrt_lock_unlock (&accounts_lock);
+ if (rc)
+ fail ("gpgrt_lock_unlock failed at %d: %s", __LINE__,gpg_strerror (rc));
+ if (i && !(i%8))
+ gpgrt_yield ();
+ }
+ return THREAD_RET_VALUE;
+}
+
+
+static void
+run_test (void)
+{
+#ifdef _WIN32
+ HANDLE rthread;
+ HANDLE athreads[N_ACCOUNTANTS];
+ int i;
+ int rc;
+
+ stop_revision_thread = 0;
+ rthread = CreateThread (NULL, 0, revision_thread, NULL, 0, NULL);
+ if (!rthread)
+ die ("error creating revision thread: rc=%d", (int)GetLastError ());
+
+ for (i=0; i < N_ACCOUNTANTS; i++)
+ {
+ athreads[i] = CreateThread (NULL, 0, accountant_thread, NULL, 0, NULL);
+ if (!athreads[i])
+ die ("error creating accountant thread %d: rc=%d",
+ i, (int)GetLastError ());
+ }
+
+ for (i=0; i < N_ACCOUNTANTS; i++)
+ {
+ rc = WaitForSingleObject (athreads[i], INFINITE);
+ if (rc == WAIT_OBJECT_0)
+ show ("accountant thread %d has terminated", i);
+ else
+ fail ("waiting for accountant thread %d failed: %d",
+ i, (int)GetLastError ());
+ CloseHandle (athreads[i]);
+ }
+ stop_revision_thread = 1;
+
+ rc = WaitForSingleObject (rthread, INFINITE);
+ if (rc == WAIT_OBJECT_0)
+ show ("revision thread has terminated");
+ else
+ fail ("waiting for revision thread failed: %d", (int)GetLastError ());
+ CloseHandle (rthread);
+
+#else /*!_WIN32*/
+ pthread_t rthread;
+ pthread_t athreads[N_ACCOUNTANTS];
+ int i;
+
+ stop_revision_thread = 0;
+ pthread_create (&rthread, NULL, revision_thread, NULL);
+
+ for (i=0; i < N_ACCOUNTANTS; i++)
+ pthread_create (&athreads[i], NULL, accountant_thread, NULL);
+
+ for (i=0; i < N_ACCOUNTANTS; i++)
+ {
+ pthread_join (athreads[i], NULL);
+ show ("accountant thread %d has terminated", i);
+ }
+
+ stop_revision_thread = 1;
+ pthread_join (rthread, NULL);
+ show ("revision thread has terminated");
+
+#endif /*!_WIN32*/
+
+ gpgrt_lock_destroy (&accounts_lock);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ int rc;
+
+ if (argc)
+ {
+ argc--; argv++;
+ }
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--help"))
+ {
+ puts (
+"usage: ./t-lock [options]\n"
+"\n"
+"Options:\n"
+" --verbose Show what is going on\n"
+" --debug Flyswatter\n"
+);
+ exit (0);
+ }
+ if (!strcmp (*argv, "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ verbose = debug = 1;
+ argc--; argv++;
+ }
+ }
+
+ srand (time(NULL)*getpid());
+
+ if (!gpg_error_check_version (GPG_ERROR_VERSION))
+ {
+ die ("gpg_error_check_version returned an error");
+ errorcount++;
+ }
+
+ init_accounts ();
+ check_accounts ();
+ run_test ();
+ check_accounts ();
+ /* Run a second time to check deinit code. */
+ run_test ();
+ check_accounts ();
+ /* And a third time to test an explicit init. */
+ rc = gpgrt_lock_init (&accounts_lock);
+ if (rc)
+ fail ("gpgrt_lock_init failed at %d: %s", __LINE__, gpg_strerror (rc));
+ run_test ();
+ check_accounts ();
+ if (verbose)
+ print_accounts ();
+
+ return errorcount ? 1 : 0;
+}