[git] GPG-ERROR - branch, master, updated. libgpg-error-1.12-11-gff937c3

by Werner Koch cvs at cvs.gnupg.org
Thu Jan 16 10:01:44 CET 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Error codes used by GnuPG et al.".

The branch, master has been updated
       via  ff937c39febe63d52c55590d8e3bd3a460f26651 (commit)
       via  78a06348fb07f2dce861615cc6d19964818f7334 (commit)
      from  c1871fddf85cdddc33c1b35d5f1c8bae76388ee5 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ff937c39febe63d52c55590d8e3bd3a460f26651
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jan 9 19:14:09 2014 +0100

    Add gpgrt_lock_ functions.
    
    * src/gpg-error.h.in (GPGRT_LOCK_DEFINE): New.
    (gpgrt_lock_init): New.
    (gpgrt_lock_lock): New.
    (gpgrt_lock_unlock): New.
    (gpgrt_lock_destroy): New.
    (gpgrt_yield): New.
    * src/gpg-error.def.in: Add new functions.
    * m4/lock.m4, m4/threadlib.m4: New. Taken from current gnulib.
    * configure.ac: Call gl_LOCK.  Check size of pthread_mutex_t. Add
    LIBTHREAD to GPG_ERROR_CONFIG_LIBS.
    * src/err-codes.h.in (GPG_ERR_INV_LOCK_OBJ): New.
    * src/gen-posix-lock-obj.c: New.
    * src/gen-w32-lock-obj.c: New.
    * src/lock.h, src/thread.h: New.
    * src/posix-lock-obj.h, src/w32-lock-obj.h: New.
    * src/posix-lock.c, src/w32-lock.c: New.
    * src/posix-thread.c, src/w32-thread.c:
    * src/w32-lock-obj-pub.in: New.
    * src/mkheader.c (include_file): Support build time include files.
    (write_special): Add keyword "include:lock-obj".
    * src/Makefile.am:
    (posix-lock-obj-pub.in): New rule.
    (noinst_PROGRAMS): Add gen-*-lock-obj helpers.
    
    * tests/t-common.h: New.
    * tests/t-lock.c: New.
    * tests/Makefile.am (t_lock_LDADD): Add new test.
    
    --
    
    This patch introduces the gpgrt_ functions which will be extended over
    time to provide a library of commonly used code in GnuPG and
    Libgcrypt.  Having them in a library named libgpg-error is a misnomer
    but this way we can achieve a smooth upgrade path.
    
    In contrasts to other GnuPG libraries, the gpgrt_ functions return a
    simple gpg_err_code_t and not gpg_error_t.  The rationale for this is
    that a source of error identifier does not make sense here; it is
    better to use the source of error identifier of the caller.  This can
    easily be achieved in a component by wrapping these function in a
    gpg_error macro/inline.
    
    There is no cross-compiling support for Posix platforms; the
    gen-posix-lock-obj tool must be run on the target system.
    
    Note that the gen-w32-lock-obj tool is not needed at build time but
    was used to figure out ABI definitions for Windows.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

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.  */
+
+ at 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 <bruno at clisp.org>, 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;
+}

commit 78a06348fb07f2dce861615cc6d19964818f7334
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Jan 9 19:14:09 2014 +0100

    Improve maintainability by rewriting the mkheader helper.
    
    * src/mkheader.c: New.  Based on the mkheader from Libassuan.
    * src/mkheader.awk: Remove.
    * src/errnos.in: Add trailing linefeed.
    * src/gpg-error.h.in: Change meta include directives for use with
    mkheader.c.
    * src/Makefile.am (EXTRA_DIST): Replace mkheader.awk by mkheader.c
    (BUILT_SOURCES): Remove extra-h.in.
    (CLEANFILES): Remove extra-h.in.  Add mkheader.c.
    (parts_of_gpg_error_h): New.
    (extra-h.in): Remove rule.
    (mkheader): Add rule.
    (gpg-error.h): Change rule to use mkheader.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/Makefile.am b/src/Makefile.am
index 7143dbd..74d89be 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
 # Makefile.am for libgpg-error.
-# Copyright (C) 2003, 2004 g10 Code GmbH
+# Copyright (C) 2003, 2004, 2014 g10 Code GmbH
 #
 # This file is part of libgpg-error.
 #
@@ -14,8 +14,7 @@
 # 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+# License along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 # We distribute the generated sources err-sources.h and err-codes.h,
 # because they are needed to build the po directory, and they don't
@@ -41,20 +40,20 @@ m4data_DATA = gpg-error.m4
 EXTRA_DIST = mkstrtable.awk err-sources.h.in err-codes.h.in \
 	mkerrnos.awk errnos.in README \
 	mkerrcodes.awk mkerrcodes1.awk mkerrcodes2.awk mkerrcodes.c \
-	mkheader.awk gpg-error.h.in mkw32errmap.c w32-add.h w32ce-add.h \
+	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
 
 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 \
-	gpg-error.def extra-h.in mkw32errmap.map.c
+	gpg-error.def mkw32errmap.map.c
 
 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 extra-h.in $(tmp_files)
+	gpg-extra/errno.h mkheader $(tmp_files)
 
 if HAVE_W32_SYSTEM
 arch_sources = w32-gettext.c
@@ -99,6 +98,15 @@ 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
+
+
 libgpg_error_la_SOURCES = gpg-error.h gettext.h $(arch_sources) \
 	init.c init.h version.c \
 	strsource.c strerror.c code-to-errno.c code-from-errno.c
@@ -187,32 +195,14 @@ errnos-sym.h: Makefile mkstrtable.awk errnos.in
 		-v prefix=GPG_ERR_ -v namespace=errnos_ \
 		$(srcdir)/errnos.in >$@
 
-# We depend on versioninfo.rc because that is build by config.status
-# and thus has up-to-date version numbers.
-extra-h.in: Makefile w32-add.h w32ce-add.h versioninfo.rc
-	-rm extra-h.in
-	echo "/* The version string of this header. */" >>extra-h.in
-	echo "#define GPG_ERROR_VERSION \"$(PACKAGE_VERSION)\"" >>extra-h.in
-	echo >>extra-h.in
-	echo "/* The version number of this header. */" >>extra-h.in
-	echo "#define GPG_ERROR_VERSION_NUMBER $(VERSION_NUMBER)" >>extra-h.in
-	echo >>extra-h.in
-if HAVE_W32_SYSTEM
-	cat $(srcdir)/w32-add.h >>extra-h.in
-endif
-if HAVE_W32CE_SYSTEM
-	cat $(srcdir)/w32ce-add.h >>extra-h.in
-endif
-	echo EOF >>extra-h.in
-
-gpg-error.h: Makefile mkheader.awk err-sources.h.in err-codes.h.in \
-	    	 errnos.in extra-h.in gpg-error.h.in
-	$(AWK) -f $(srcdir)/mkheader.awk \
-		$(srcdir)/err-sources.h.in \
-		$(srcdir)/err-codes.h.in \
-		$(srcdir)/errnos.in \
-		extra-h.in \
-		$(srcdir)/gpg-error.h.in > $@
+mkheader: mkheader.c Makefile
+	$(CC_FOR_BUILD) -g -O0 -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c
+
+# 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
+	./mkheader $(host_os) $(srcdir)/gpg-error.h.in \
+                   $(PACKAGE_VERSION) $(VERSION_NUMBER) >$@
 
 
 install-data-local:
diff --git a/src/errnos.in b/src/errnos.in
index 0688047..018fb9a 100644
--- a/src/errnos.in
+++ b/src/errnos.in
@@ -1,5 +1,5 @@
-# errnos.h.in - List of system error values input file.
-/* errnos.h - List of system error values.
+# errnos.in - List of system error values input file.
+/* errnos.in - List of system error values.
    Copyright (C) 2003, 2004 g10 Code GmbH
 
    This file is part of libgpg-error.
@@ -8,12 +8,12 @@
    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 libgpg-error; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
@@ -169,4 +169,4 @@
 137	EUSERS
 138	EWOULDBLOCK
 139	EXDEV
-140	EXFULL
\ No newline at end of file
+140	EXFULL
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index 303fac0..a2fb044 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -1,5 +1,5 @@
-/* gpg-error.h - Public interface to libgpg-error.
-   Copyright (C) 2003, 2004, 2010, 2013 g10 Code GmbH
+/* gpg-error.h - Public interface to libgpg-error.               -*- c -*-
+   Copyright (C) 2003, 2004, 2010, 2013, 2014 g10 Code GmbH
 
    This file is part of libgpg-error.
 
@@ -15,6 +15,8 @@
 
    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/>.
+
+   @configure_input@
  */
 
 
@@ -77,7 +79,7 @@ extern "C" {
    entries.  */
 typedef enum
   {
- at include err-sources.h.in
+ at include:err-sources@
 
     /* This is one more than the largest allowed entry.  */
     GPG_ERR_SOURCE_DIM = 128
@@ -90,11 +92,11 @@ typedef enum
    entries.  */
 typedef enum
   {
- at include err-codes.h.in
+ at include:err-codes@
 
     /* The following error codes are used to map system errors.  */
 #define GPG_ERR_SYSTEM_ERROR	(1 << 15)
- at include errnos.in
+ at include:errnos@
 
     /* This is one more than the largest allowed entry.  */
     GPG_ERR_CODE_DIM = 65536
@@ -248,7 +250,13 @@ void gpg_err_set_errno (int err);
 /* Return or check the version.  */
 const char *gpg_error_check_version (const char *req_version);
 
- at include extra-h.in
+/* The version string of this header. */
+#define GPG_ERROR_VERSION @version@
+
+/* The version number of this header. */
+#define GPG_ERROR_VERSION_NUMBER @version-number@
+
+ at include:os-add@
 

 /* Self-documenting convenience functions.  */
 
diff --git a/src/mkheader.awk b/src/mkheader.awk
deleted file mode 100644
index 0ff08f9..0000000
--- a/src/mkheader.awk
+++ /dev/null
@@ -1,218 +0,0 @@
-# mkheader.awk
-# Copyright (C) 2003, 2004 g10 Code GmbH
-# 
-# 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 of
-# the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-#
-# As a special exception, g10 Code GmbH gives unlimited permission to
-# copy, distribute and modify the C source files that are the output
-# of mkheader.awk.  You need not follow the terms of the GNU General
-# Public License when using or distributing such scripts, even though
-# portions of the text of mkheader.awk appear in them.  The GNU
-# General Public License (GPL) does govern all other use of the material
-# that constitutes the mkheader.awk program.
-#
-# Certain portions of the mkheader.awk source text are designed to be
-# copied (in certain cases, depending on the input) into the output of
-# mkheader.awk.  We call these the "data" portions.  The rest of the
-# mkheader.awk source text consists of comments plus executable code
-# that decides which of the data portions to output in any given case.
-# We call these comments and executable code the "non-data" portions.
-# mkheader.h never copies any of the non-data portions into its output.
-#
-# This special exception to the GPL applies to versions of mkheader.awk
-# released by g10 Code GmbH.  When you make and distribute a modified version
-# of mkheader.awk, you may extend this special exception to the GPL to
-# apply to your modified version as well, *unless* your modified version
-# has the potential to copy into its output some of the text that was the
-# non-data portion of the version that you started with.  (In other words,
-# unless your change moves or copies text from the non-data portions to the
-# data portions.)  If your modification has such potential, you must delete
-# any notice of this special exception to the GPL from your modified version.
-
-# This script processes gpg-error.h.in in an awful way.
-# Its input is, one after another, the content of the err-sources.h.in file,
-# the err-codes.h.in file, the errnos.in file, and then gpg-error.h.in.
-# There is nothing fancy about this.
-#
-# An alternative would be to use getline to get the content of the first three files,
-# but then we need to pre-process gpg-error.h.in with configure to get
-# at the full path of the files in @srcdir at .
-
-BEGIN {
-  FS = "[\t]+";
-# sources_nr holds the number of error sources.
-  sources_nr = 0;
-# codes_nr holds the number of error codes.
-  codes_nr = 0;
-# errnos_nr holds the number of system errors.
-  errnos_nr = 0;
-# extra_nr holds the number of extra lines to be included.
-  extra_nr = 0
-
-# These variables walk us through our input.
-  sources_header = 1;
-  sources_body = 0;
-  between_sources_and_codes = 0;
-  codes_body = 0;
-  between_codes_and_errnos = 0;
-  errnos_body = 0;
-  extra_body = 0;
-  gpg_error_h = 0;
-
-  print "/* Output of mkheader.awk.  DO NOT EDIT.  -*- buffer-read-only: t -*- */";
-  print "";
-
-}
-
-
-sources_header {
-  if ($1 ~ /^[0123456789]+$/)
-    {
-      sources_header = 0;
-      sources_body = 1;
-    }      
-}
-
-sources_body {
-  sub (/\#.+/, "");
-  sub (/[ 	]+$/, ""); # Strip trailing space and tab characters.
-
-  if (/^$/)
-    next;
-
-  if ($1 == "")
-    {
-      sources_body = 0;
-      between_sources_and_codes = 1;
-    }
-  else
-    {
-# Remember the error source number and symbol of each error source.
-      sources_idx[sources_nr] = $1;
-      sources_sym[sources_nr] = $2;
-      sources_nr++;
-    }
-}
-
-between_sources_and_codes {
-  if ($1 ~ /^[0123456789]+$/)
-    {
-      between_sources_and_codes = 0;
-      codes_body = 1;
-    }      
-}
-
-codes_body {
-  sub (/\#.+/, "");
-  sub (/[ 	]+$/, ""); # Strip trailing space and tab characters.
-
-  if (/^$/)
-    next;
-
-  if ($1 == "")
-    {
-      codes_body = 0;
-      between_codes_and_errnos = 1;
-    }
-  else
-    {
-# Remember the error code number and symbol of each error source.
-      codes_idx[codes_nr] = $1;
-      codes_sym[codes_nr] = $2;
-      codes_nr++;
-    }
-}
-
-between_codes_and_errnos {
-  if ($1 ~ /^[0-9]/)
-    {
-      between_codes_and_errnos = 0;
-      errnos_body = 1;
-    }
-}
-
-errnos_body {
-  sub (/\#.+/, "");
-  sub (/[ 	]+$/, ""); # Strip trailing space and tab characters.
-
-  if (/^$/)
-    next;
-
-  if ($1 !~ /^[0-9]/)
-    {
-# Note that this assumes that extra_body.in doesn't start with a digit.
-      errnos_body = 0;
-      extra_body = 1;
-    }
-  else
-    {
-      errnos_idx[errnos_nr] = "GPG_ERR_SYSTEM_ERROR | " $1;
-      errnos_sym[errnos_nr] = "GPG_ERR_" $2;
-      errnos_nr++;
-    }
-}
-
-extra_body {
-  if (/^##/)
-    next
-
-  if (/^EOF/)
-    {
-      extra_body = 0;
-      gpg_error_h = 1;
-      next;
-    }
-  else
-    {
-      extra_line[extra_nr] = $0;
-      extra_nr++;
-    }
-}
-
-gpg_error_h {
-  if ($0 ~ /^@include err-sources/)
-    {
-      for (i = 0; i < sources_nr; i++)
-	{
-	  print "    " sources_sym[i] " = " sources_idx[i] ",";
-#	  print "#define " sources_sym[i] " (" sources_idx[i] ")";
-	}
-    }
-  else if ($0 ~ /^@include err-codes/)
-    {
-      for (i = 0; i < codes_nr; i++)
-	{
-	  print "    " codes_sym[i] " = " codes_idx[i] ",";
-#	  print "#define " codes_sym[i] " (" codes_idx[i] ")";
-	}
-    }
-  else if ($0 ~ /^@include errnos/)
-    {
-      for (i = 0; i < errnos_nr; i++)
-       {
-         print "    " errnos_sym[i] " = " errnos_idx[i] ",";
-#        print "#define " errnos_sym[i] " (" errnos_idx[i] ")";
-       }
-    }
-  else if ($0 ~ /^@include extra-h.in/)
-    {
-      for (i = 0; i < extra_nr; i++)
-	{
-            print extra_line[i];
-	}
-    }
-  else
-    print;
-}
diff --git a/src/mkheader.c b/src/mkheader.c
new file mode 100644
index 0000000..eea7914
--- /dev/null
+++ b/src/mkheader.c
@@ -0,0 +1,363 @@
+/* mkheader.c - Create a header file for libgpg-error
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ * 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.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define PGM "mkheader"
+
+#define LINESIZE 1024
+
+static const char *host_os;
+static char *srcdir;
+static const char *hdr_version;
+static const char *hdr_version_number;
+
+
+/* Write LINE to stdout.  The function is allowed to modify LINE.  */
+static void
+write_str (char *line)
+{
+  if (fputs (line, stdout) == EOF)
+    {
+      fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
+      exit (1);
+    }
+}
+
+static void
+write_line (char *line)
+{
+  if (puts (line) == EOF)
+    {
+      fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
+      exit (1);
+    }
+}
+
+
+/* Write SOURCE or CODES line to stdout.  The function is allowed to
+   modify LINE.  Trailing white space is already removed.  Passing
+   NULL resets the internal state.  */
+static void
+write_sources_or_codes (char *line)
+{
+  static int in_intro;
+  char *p1, *p2;
+
+  if (!line)
+    {
+      in_intro = 1;
+      return;
+    }
+
+  if (!*line)
+    return;
+
+  if (in_intro)
+    {
+      if (!strchr ("0123456789", *line))
+        return;
+      in_intro = 0;
+    }
+
+  p1 = strtok (line, " \t");
+  p2 = p1? strtok (NULL, " \t") : NULL;
+
+  if (p1 && p2 && strchr ("0123456789", *p1) && *p2)
+    {
+      write_str ("    ");
+      write_str (p2);
+      write_str (" = ");
+      write_str (p1);
+      write_str (",\n");
+    }
+}
+
+
+/* Write system errnos to stdout.  The function is allowed to
+   modify LINE.  Trailing white space is already removed.  Passing
+   NULL resets the internal state.  */
+static void
+write_errnos_in (char *line)
+{
+  static int state;
+  char *p1, *p2;
+
+  if (!line)
+    {
+      state = 0;
+      return;
+    }
+
+  if (!*line)
+    return;
+
+  if (!state && strchr ("0123456789", *line))
+    state = 1;
+  else if (state == 1 && !strchr ("0123456789", *line))
+    state = 2;
+
+  if (state != 1)
+    return;
+
+  p1 = strtok (line, " \t");
+  p2 = p1? strtok (NULL, " \t") : NULL;
+
+  if (p1 && p2 && strchr ("0123456789", *p1) && *p2)
+    {
+      write_str ("    GPG_ERR_");
+      write_str (p2);
+      write_str (" = GPG_ERR_SYSTEM_ERROR | ");
+      write_str (p1);
+      write_str (",\n");
+    }
+}
+
+
+/* Include the file NAME from the source directory.  The included file
+   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. */
+static void
+include_file (const char *fname, int lnr, const char *name, void (*outf)(char*))
+{
+  FILE *fp;
+  char *incfname;
+  int inclnr;
+  char line[LINESIZE];
+
+  incfname = malloc (strlen (srcdir) + strlen (name) + 1);
+  if (!incfname)
+    {
+      fputs (PGM ": out of core\n", stderr);
+      exit (1);
+    }
+  strcpy (incfname, srcdir);
+  strcat (incfname, name);
+
+  fp = fopen (incfname, "r");
+  if (!fp)
+    {
+      fprintf (stderr, "%s:%d: error including `%s': %s\n",
+               fname, lnr, incfname, strerror (errno));
+      exit (1);
+    }
+
+  inclnr = 0;
+  while (fgets (line, LINESIZE, fp))
+    {
+      size_t n = strlen (line);
+
+      inclnr++;
+      if (!n || line[n-1] != '\n')
+        {
+          fprintf (stderr,
+                   "%s:%d: trailing linefeed missing, line too long or "
+                   "embedded nul character\n", incfname, inclnr);
+          fprintf (stderr,"%s:%d: note: file '%s' included from here\n",
+                   fname, lnr, incfname);
+          exit (1);
+        }
+      line[--n] = 0;
+      while (line[n] == ' ' || line[n] == '\t' || line[n] == '\r')
+        {
+          line[n] = 0;
+          if (!n)
+            break;
+          n--;
+        }
+
+      if (line[0] == '#' && line[1] == '#')
+        {
+          if (!strncmp (line+2, "EOF##", 5))
+            break; /* Forced EOF.  */
+        }
+      else
+        outf (line);
+    }
+  if (ferror (fp))
+    {
+      fprintf (stderr, "%s:%d: error reading `%s': %s\n",
+               fname, lnr, incfname, strerror (errno));
+      exit (1);
+    }
+  fclose (fp);
+  free (incfname);
+}
+
+
+static int
+write_special (const char *fname, int lnr, const char *tag)
+{
+  if (!strcmp (tag, "version"))
+    {
+      putchar ('\"');
+      fputs (hdr_version, stdout);
+      putchar ('\"');
+      putchar ('\n');
+    }
+  else if (!strcmp (tag, "version-number"))
+    {
+      fputs (hdr_version_number, stdout);
+      putchar ('\n');
+    }
+  else if (!strcmp (tag, "include:err-sources"))
+    {
+      write_sources_or_codes (NULL);
+      include_file (fname, lnr, "err-sources.h.in", write_sources_or_codes);
+    }
+  else if (!strcmp (tag, "include:err-codes"))
+    {
+      write_sources_or_codes (NULL);
+      include_file (fname, lnr, "err-codes.h.in", write_sources_or_codes);
+    }
+  else if (!strcmp (tag, "include:errnos"))
+    {
+      include_file (fname, lnr, "errnos.in", write_errnos_in);
+    }
+  else if (!strcmp (tag, "include:os-add"))
+    {
+      if (!strcmp (host_os, "mingw32"))
+        {
+          include_file (fname, lnr, "w32-add.h", write_line);
+        }
+      else if (!strcmp (host_os, "mingw32ce"))
+        {
+          include_file (fname, lnr, "w32-add.h", write_line);
+          include_file (fname, lnr, "w32ce-add.h", write_line);
+        }
+    }
+  else
+    return 0; /* Unknown tag.  */
+
+  return 1; /* Tag processed.  */
+}
+
+
+int
+main (int argc, char **argv)
+{
+  FILE *fp;
+  char line[LINESIZE];
+  int lnr = 0;
+  const char *fname, *s;
+  char *p1, *p2;
+
+  if (argc)
+    {
+      argc--; argv++;
+    }
+
+  if (argc != 4)
+    {
+      fputs ("usage: " PGM " host_os template.h version version_number\n",
+             stderr);
+      return 1;
+    }
+  host_os = argv[0];
+  fname = argv[1];
+  hdr_version = argv[2];
+  hdr_version_number = argv[3];
+
+  srcdir = malloc (strlen (fname) + 2 + 1);
+  if (!srcdir)
+    {
+      fputs (PGM ": out of core\n", stderr);
+      return 1;
+    }
+  strcpy (srcdir, fname);
+  p1 = strrchr (srcdir, '/');
+  if (p1)
+    p1[1] = 0;
+  else
+    strcpy (srcdir, "./");
+
+  fp = fopen (fname, "r");
+  if (!fp)
+    {
+      fprintf (stderr, "%s:%d: can't open file: %s",
+               fname, lnr, strerror (errno));
+      return 1;
+    }
+
+  while (fgets (line, LINESIZE, fp))
+    {
+      size_t n = strlen (line);
+
+      lnr++;
+      if (!n || line[n-1] != '\n')
+        {
+          fprintf (stderr,
+                   "%s:%d: trailing linefeed missing, line too long or "
+                   "embedded nul character\n", fname, lnr);
+          break;
+        }
+      line[--n] = 0;
+
+      p1 = strchr (line, '@');
+      p2 = p1? strchr (p1+1, '@') : NULL;
+      if (!p1 || !p2 || p2-p1 == 1)
+        {
+          puts (line);
+          continue;
+        }
+      *p1++ = 0;
+      *p2++ = 0;
+      fputs (line, stdout);
+
+      if (!strcmp (p1, "configure_input"))
+        {
+          s = strrchr (fname, '/');
+          printf ("Do not edit.  Generated from %s by %s for %s.",
+                  s? s+1 : fname, PGM, host_os);
+          fputs (p2, stdout);
+          putchar ('\n');
+        }
+      else if (!write_special (fname, lnr, p1))
+        {
+          putchar ('@');
+          fputs (p1, stdout);
+          putchar ('@');
+          fputs (p2, stdout);
+          putchar ('\n');
+        }
+    }
+
+  if (ferror (fp))
+    {
+      fprintf (stderr, "%s:%d: error reading file: %s\n",
+               fname, lnr, strerror (errno));
+      return 1;
+    }
+
+  fputs ("/*\n"
+         "Loc" "al Variables:\n"
+         "buffer-read-only: t\n"
+         "End:\n"
+         "*/\n", stdout);
+
+  if (ferror (stdout))
+    {
+      fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
+      return 1;
+    }
+
+  fclose (fp);
+
+  return 0;
+}

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                  |   13 +-
 configure.ac                          |   18 ++
 m4/lock.m4                            |  301 +++-----------------------
 m4/threadlib.m4                       |  341 +++++++++++++++++++++++++++++
 src/Makefile.am                       |   82 +++----
 src/err-codes.h.in                    |    6 +-
 src/errnos.in                         |   10 +-
 src/gen-posix-lock-obj.c              |   95 +++++++++
 src/gen-w32-lock-obj.c                |   55 +++++
 src/gpg-error.def.in                  |    6 +
 src/gpg-error.h.in                    |   55 ++++-
 src/lock.h                            |   24 +++
 src/mkheader.awk                      |  218 -------------------
 src/mkheader.c                        |  377 +++++++++++++++++++++++++++++++++
 src/{strsource.c => posix-lock-obj.h} |   39 ++--
 src/posix-lock.c                      |  213 +++++++++++++++++++
 src/posix-thread.c                    |   63 ++++++
 src/thread.h                          |   24 +++
 src/version.c                         |    4 +-
 src/w32-lock-obj-pub.in               |   44 ++++
 src/{strsource.c => w32-lock-obj.h}   |   45 ++--
 src/w32-lock.c                        |  119 +++++++++++
 src/{strsource.c => w32-thread.c}     |   39 ++--
 tests/Makefile.am                     |    9 +-
 tests/t-common.h                      |   99 +++++++++
 tests/t-lock.c                        |  318 +++++++++++++++++++++++++++
 26 files changed, 2008 insertions(+), 609 deletions(-)
 create mode 100644 m4/threadlib.m4
 create mode 100644 src/gen-posix-lock-obj.c
 create mode 100644 src/gen-w32-lock-obj.c
 create mode 100644 src/lock.h
 delete mode 100644 src/mkheader.awk
 create mode 100644 src/mkheader.c
 copy src/{strsource.c => posix-lock-obj.h} (50%)
 create mode 100644 src/posix-lock.c
 create mode 100644 src/posix-thread.c
 create mode 100644 src/thread.h
 create mode 100644 src/w32-lock-obj-pub.in
 copy src/{strsource.c => w32-lock-obj.h} (50%)
 create mode 100644 src/w32-lock.c
 copy src/{strsource.c => w32-thread.c} (55%)
 create mode 100644 tests/t-common.h
 create mode 100644 tests/t-lock.c


hooks/post-receive
-- 
Error codes used by GnuPG et al.
http://git.gnupg.org




More information about the Gnupg-commits mailing list