[GPGME PATCH] core: Use gpgrt locking for thread safety

Andre Heinecke aheinecke at intevation.de
Tue Nov 8 17:38:38 CET 2016


* configure.ac: Require libgpg-error 1.17
* doc/gpgme.texi: Document removed neccessity for thread
safe gpgme flavours.
* src/sema.h (DEFINE_GLOBAL_LOCK),
(DEFINE_STATIC_LOCK, INIT_LOCK, DECLARE_LOCK)
(DESTROY_LOCK, LOCK, UNLOCK): Change to gpgrt equivalents.
* src/posix-sema.c, src/w32-sema.c: Removed.
* src/Makefile.am: Update accordingly.
* src/ath.c, src/ath.h (ath_mutex_init)
(ath_mutex_destroy, ath_mutex_lock, ath_mutex_unlock): Removed.
* src/ath.h (ATH_MUTEX_INITIALIZER): Removed.
* src/version.c (do_subsystem_inits): sema_subsystem_init is
no longer required.
* src/Makefile.am
* tests/gpg/Makefile.am: Add new threading tests.
(t_thread1_LDADD, t_cancel_LDADD):
Use just gpgme.
* tests/gpg/t-thread-keylist-verify.c,
tests/gpg/t-thread-keylist.c: New.

--
This makes the "default" flavor as thread safe as the
pthread flavor.

As the cpp bindings link against libgpgme
and not libgpgme-pthread this fixes threading problems
with them.

Using gpgrt locks instead of pthread locks also removes
the neccessity to link pthread directly to gpgme and
have a different, thread safe flavor of gpgme.

libgpgme-pthread is still installed for compatibility but
is now exactly the same as libgpgme.
---
 configure.ac                        |   3 +-
 doc/gpgme.texi                      |  36 ++-----
 src/Makefile.am                     |  34 +++----
 src/ath-pthread.c                   | 188 ------------------------------------
 src/ath.c                           |  51 ----------
 src/ath.h                           |  13 ---
 src/posix-sema.c                    |  68 -------------
 src/sema.h                          |  43 ++-------
 src/version.c                       |   1 -
 src/w32-sema.c                      | 117 ----------------------
 tests/gpg/Makefile.am               |   9 +-
 tests/gpg/t-thread-keylist-verify.c | 129 +++++++++++++++++++++++++
 tests/gpg/t-thread-keylist.c        |  76 +++++++++++++++
 13 files changed, 240 insertions(+), 528 deletions(-)
 delete mode 100644 src/ath-pthread.c
 delete mode 100644 src/posix-sema.c
 delete mode 100644 src/w32-sema.c
 create mode 100644 tests/gpg/t-thread-keylist-verify.c
 create mode 100644 tests/gpg/t-thread-keylist.c

diff --git a/configure.ac b/configure.ac
index b52f214..031b83c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,7 +71,7 @@ LIBQGPGME_LT_REVISION=0
 GPGME_CONFIG_API_VERSION=1
 ##############################################
 
-NEED_GPG_ERROR_VERSION=1.11
+NEED_GPG_ERROR_VERSION=1.17
 NEED_LIBASSUAN_API=2
 NEED_LIBASSUAN_VERSION=2.0.2
 
@@ -905,7 +905,6 @@ echo "
 
         UI Server:         $uiserver
         FD Passing:        $use_descriptor_passing
-        GPGME Pthread:     $have_pthread
 
         Language bindings: ${enabled_languages_v:-$enabled_languages}
 "
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index a70418d..f4ec9f6 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -458,12 +458,6 @@ specifying both options to @command{gpgme-config}:
 gcc -o foo foo.c `gpgme-config --cflags --libs`
 @end example
 
-If you want to link to one of the thread-safe versions of
- at acronym{GPGME}, you must specify the @option{--thread} option before
-any other option to select the thread package you want to link with.
-Supported thread packages are @option{--thread=pth} and
- at option{--thread=pthread}.
-
 If you need to detect the installed language bindings you can use list
 them using:
 
@@ -614,7 +608,9 @@ that can be used with GNU Pth, and defines @code{GPGME_PTH_CFLAGS} and
 
 @code{AM_PATH_GPGME_PTHREAD} checks for the version of @acronym{GPGME}
 that can be used with the native pthread implementation, and defines
- at code{GPGME_PTHREAD_CFLAGS} and @code{GPGME_PTHREAD_LIBS}.
+ at code{GPGME_PTHREAD_CFLAGS} and @code{GPGME_PTHREAD_LIBS}. Since
+verison 1.7.2 this is no longer required to GPGME_PTHREAD as
+ at acronym{GPGME} itself is thread safe.
 
 This macro searches for @command{gpgme-config} along the PATH.  If
 you are cross-compiling, it is useful to set the environment variable
@@ -814,32 +810,12 @@ application is multi-threaded, and you install a signal action for
 @cindex thread-safeness
 @cindex multi-threading
 
-The @acronym{GPGME} library is not entirely thread-safe, but it can
-still be used in a multi-threaded environment if some care is taken.
-If the following requirements are met, there should be no race
-conditions to worry about:
+The @acronym{GPGME} library is mostly thread-safe, an can be used
+in a mulithreaded environment but there are some requirements
+for mutlithreaded use:
 
 @itemize @bullet
 @item
- at acronym{GPGME} supports the thread libraries pthread and GNU Pth.
-The support for this has to be enabled at compile time.
- at acronym{GPGME} will automatically detect the location in which the
-thread libraries are installed and activate the support for them at
-build time.
-
-Support for other thread libraries is very easy to add.  Please
-contact us if you have the need.
-
- at item
-If you want to use @acronym{GPGME} with threads, you must link to the
-right version of the library.  The name of the right library is
- at code{libgpgme-} followed by the name of the thread package you use.
-For example, if you use GNU Pth, the right name is
- at code{libgpgme-pth}.  Use the Automake macros or
- at command{gpgme-config} program for simplicity.
-
-
- at item
 The function @code{gpgme_check_version} must be called before any
 other function in the library, because it initializes the thread
 support subsystem in @acronym{GPGME}.  To achieve this in
diff --git a/src/Makefile.am b/src/Makefile.am
index eddd192..0512ce1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,20 +28,13 @@ nodist_include_HEADERS = gpgme.h
 
 bin_PROGRAMS = gpgme-tool
 
-if HAVE_PTHREAD
-ltlib_gpgme_pthread = libgpgme-pthread.la
-else
-ltlib_gpgme_pthread =
-endif
-
 if BUILD_W32_GLIB
 ltlib_gpgme_glib = libgpgme-glib.la
 else
 ltlib_gpgme_glib =
 endif
 
-lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \
-	$(ltlib_gpgme_pthread)
+lib_LTLIBRARIES = libgpgme.la libgpgme-pthread.la $(ltlib_gpgme_glib)
 
 if HAVE_LD_VERSION_SCRIPT
 libgpgme_version_script_cmd = -Wl,--version-script=$(srcdir)/libgpgme.vers
@@ -50,10 +43,10 @@ libgpgme_version_script_cmd =
 endif
 
 if HAVE_DOSISH_SYSTEM
-system_components = w32-util.c w32-sema.c
+system_components = w32-util.c
 system_components_not_extra = w32-io.c
 else
-system_components = ath.h posix-util.c posix-sema.c posix-io.c
+system_components = ath.h posix-util.c posix-io.c
 system_components_not_extra =
 endif
 
@@ -93,12 +86,10 @@ main_sources =								\
 	engine-spawn.c 	                                                \
 	gpgconf.c queryswdb.c						\
 	sema.h priv-io.h $(system_components) sys-util.h dirinfo.c	\
-	debug.c debug.h gpgme.c version.c error.c
-
-libgpgme_la_SOURCES = $(main_sources)					\
+	debug.c debug.h gpgme.c version.c error.c \
 	ath.h ath.c $(system_components_not_extra)
-libgpgme_pthread_la_SOURCES = $(main_sources)				\
-	ath.h ath-pthread.c $(system_components_not_extra)
+
+libgpgme_la_SOURCES = $(main_sources)
 
 if BUILD_W32_GLIB
 libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c
@@ -163,13 +154,12 @@ libgpgme_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps)
 libgpgme_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
 	             @GPG_ERROR_LIBS@
 
-libgpgme_pthread_la_LDFLAGS = \
-        $(no_undefined) $(export_symbols) $(extra_ltoptions) \
-	$(libgpgme_version_script_cmd) -version-info \
-	@LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
-libgpgme_pthread_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers
-libgpgme_pthread_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
-	-lpthread @GPG_ERROR_LIBS@
+# This should probably be removed at some point as libgpgme_pthread
+# is the same as libgpgme
+libgpgme_pthread_la_SOURCES = $(libgpgme_la_SOURCES)
+libgpgme_pthread_la_LDFLAGS = $(libgpgme_la_LDFLAGS)
+libgpgme_pthread_la_DEPENDENCIES = $(libgpgme_la_DEPENDENCIES)
+libgpgme_pthread_la_LIBADD = $(libgpgme_la_LIBADD)
 
 if BUILD_W32_GLIB
 libgpgme_glib_la_LDFLAGS = \
diff --git a/src/ath-pthread.c b/src/ath-pthread.c
deleted file mode 100644
index 47b38ee..0000000
--- a/src/ath-pthread.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* ath-pthread.c - pthread module for self-adapting thread-safeness library
-   Copyright (C) 2002, 2003, 2004 g10 Code GmbH
-
-   This file is part of GPGME.
-
-   GPGME 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.
-
-   GPGME 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, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <errno.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#else
-# ifdef HAVE_SYS_TIME_H
-#  include <sys/time.h>
-# endif
-#endif
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <pthread.h>
-
-#include "gpgme.h"
-
-#include "ath.h"
-
-
-/* The lock we take while checking for lazy lock initialization.  */
-static pthread_mutex_t check_init_lock = PTHREAD_MUTEX_INITIALIZER;
-
-/* Initialize the mutex *PRIV.  If JUST_CHECK is true, only do this if
-   it is not already initialized.  */
-static int
-mutex_pthread_init (ath_mutex_t *priv, int just_check)
-{
-  int err = 0;
-
-  if (just_check)
-    pthread_mutex_lock (&check_init_lock);
-  if (!*priv || !just_check)
-    {
-      pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
-      if (!lock)
-	err = ENOMEM;
-      if (!err)
-	{
-	  err = pthread_mutex_init (lock, NULL);
-	  if (err)
-	    free (lock);
-	  else
-	    *priv = (ath_mutex_t) lock;
-	}
-    }
-  if (just_check)
-    pthread_mutex_unlock (&check_init_lock);
-  return err;
-}
-
-
-void
-ath_init (void)
-{
-  /* Nothing to do.  */
-}
-
-
-uintptr_t
-ath_self (void)
-{
-  return (uintptr_t) pthread_self ();
-}
-
-
-int
-ath_mutex_init (ath_mutex_t *lock)
-{
-  return mutex_pthread_init (lock, 0);
-}
-
-
-int
-ath_mutex_destroy (ath_mutex_t *lock)
-{
-  int err = mutex_pthread_init (lock, 1);
-  if (!err)
-    {
-      err = pthread_mutex_destroy ((pthread_mutex_t *) *lock);
-      free (*lock);
-    }
-  return err;
-}
-
-
-int
-ath_mutex_lock (ath_mutex_t *lock)
-{
-  int ret = mutex_pthread_init (lock, 1);
-  if (ret)
-    return ret;
-
-  return pthread_mutex_lock ((pthread_mutex_t *) *lock);
-}
-
-
-int
-ath_mutex_unlock (ath_mutex_t *lock)
-{
-  int ret = mutex_pthread_init (lock, 1);
-  if (ret)
-    return ret;
-
-  return pthread_mutex_unlock ((pthread_mutex_t *) *lock);
-}
-
-
-gpgme_ssize_t
-ath_read (int fd, void *buf, size_t nbytes)
-{
-  return read (fd, buf, nbytes);
-}
-
-
-gpgme_ssize_t
-ath_write (int fd, const void *buf, size_t nbytes)
-{
-  return write (fd, buf, nbytes);
-}
-
-
-gpgme_ssize_t
-ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
-	    struct timeval *timeout)
-{
-  return select (nfd, rset, wset, eset, timeout);
-}
-
-
-gpgme_ssize_t
-ath_waitpid (pid_t pid, int *status, int options)
-{
-  return waitpid (pid, status, options);
-}
-
-
-int
-ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr)
-{
-  return accept (s, addr, length_ptr);
-}
-
-
-int
-ath_connect (int s, const struct sockaddr *addr, socklen_t length)
-{
-  return connect (s, addr, length);
-}
-
-int
-ath_sendmsg (int s, const struct msghdr *msg, int flags)
-{
-  return sendmsg (s, msg, flags);
-}
-
-
-int
-ath_recvmsg (int s, struct msghdr *msg, int flags)
-{
-  return recvmsg (s, msg, flags);
-}
diff --git a/src/ath.c b/src/ath.c
index ddd8a87..6b4667e 100644
--- a/src/ath.c
+++ b/src/ath.c
@@ -49,11 +49,6 @@
 #include "ath.h"
 
 
-#define MUTEX_UNLOCKED	((ath_mutex_t) 0)
-#define MUTEX_LOCKED	((ath_mutex_t) 1)
-#define MUTEX_DESTROYED	((ath_mutex_t) 2)
-
-
 #ifdef HAVE_W32_SYSTEM
 #include <windows.h>
 uintptr_t
@@ -80,52 +75,6 @@ ath_self (void)
 #endif
 
 
-int
-ath_mutex_init (ath_mutex_t *lock)
-{
-#ifndef NDEBUG
-  *lock = MUTEX_UNLOCKED;
-#endif
-  return 0;
-}
-
-
-int
-ath_mutex_destroy (ath_mutex_t *lock)
-{
-#ifndef NDEBUG
-  assert (*lock == MUTEX_UNLOCKED);
-
-  *lock = MUTEX_DESTROYED;
-#endif
-  return 0;
-}
-
-
-int
-ath_mutex_lock (ath_mutex_t *lock)
-{
-#ifndef NDEBUG
-  assert (*lock == MUTEX_UNLOCKED);
-
-  *lock = MUTEX_LOCKED;
-#endif
-  return 0;
-}
-
-
-int
-ath_mutex_unlock (ath_mutex_t *lock)
-{
-#ifndef NDEBUG
-  assert (*lock == MUTEX_LOCKED);
-
-  *lock = MUTEX_UNLOCKED;
-#endif
-  return 0;
-}
-
-
 gpgme_ssize_t
 ath_read (int fd, void *buf, size_t nbytes)
 {
diff --git a/src/ath.h b/src/ath.h
index 8eb9eb9..a1be9e5 100644
--- a/src/ath.h
+++ b/src/ath.h
@@ -60,10 +60,6 @@
 #define _ATH_PREFIX1(x,y) x ## y
 #define _ATH_PREFIX2(x,y) _ATH_PREFIX1(x,y)
 #define _ATH_PREFIX(x) _ATH_PREFIX2(_ATH_EXT_SYM_PREFIX,x)
-#define ath_mutex_init _ATH_PREFIX(ath_mutex_init)
-#define ath_mutex_destroy _ATH_PREFIX(ath_mutex_destroy)
-#define ath_mutex_lock _ATH_PREFIX(ath_mutex_lock)
-#define ath_mutex_unlock _ATH_PREFIX(ath_mutex_unlock)
 #define ath_read _ATH_PREFIX(ath_read)
 #define ath_write _ATH_PREFIX(ath_write)
 #define ath_select _ATH_PREFIX(ath_select)
@@ -75,17 +71,8 @@
 #endif
 
 
-typedef void *ath_mutex_t;
-#define ATH_MUTEX_INITIALIZER 0;
-
 uintptr_t ath_self (void);
 
-/* Functions for mutual exclusion.  */
-int ath_mutex_init (ath_mutex_t *mutex);
-int ath_mutex_destroy (ath_mutex_t *mutex);
-int ath_mutex_lock (ath_mutex_t *mutex);
-int ath_mutex_unlock (ath_mutex_t *mutex);
-
 /* Replacement for the POSIX functions, which can be used to allow
    other (user-level) threads to run.  */
 gpgme_ssize_t ath_read (int fd, void *buf, size_t nbytes);
diff --git a/src/posix-sema.c b/src/posix-sema.c
deleted file mode 100644
index d04ce61..0000000
--- a/src/posix-sema.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* posix-sema.c
-   Copyright (C) 2001 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2004, 2007 g10 Code GmbH
-
-   This file is part of GPGME.
-
-   GPGME 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.
-
-   GPGME 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, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#include "util.h"
-#include "sema.h"
-#include "ath.h"
-
-void
-_gpgme_sema_subsystem_init ()
-{
-}
-
-void
-_gpgme_sema_cs_enter (struct critsect_s *s)
-{
-  _gpgme_ath_mutex_lock (&s->priv);
-}
-
-void
-_gpgme_sema_cs_leave (struct critsect_s *s)
-{
-  _gpgme_ath_mutex_unlock (&s->priv);
-}
-
-void
-_gpgme_sema_cs_destroy (struct critsect_s *s)
-{
-  _gpgme_ath_mutex_destroy (&s->priv);
-  s->priv = NULL;
-}
diff --git a/src/sema.h b/src/sema.h
index 4b7c0af..5b0d53d 100644
--- a/src/sema.h
+++ b/src/sema.h
@@ -22,46 +22,23 @@
 #ifndef SEMA_H
 #define SEMA_H
 
-struct critsect_s
-{
-  const char *name;
-  void *priv;
-};
+#include <gpg-error.h>
 
 #define DEFINE_GLOBAL_LOCK(name) \
-  struct critsect_s name = { #name, NULL }
+  gpgrt_lock_t name  = GPGRT_LOCK_INITIALIZER
+
 #define DEFINE_STATIC_LOCK(name) \
-  static struct critsect_s name  = { #name, NULL }
+  static gpgrt_lock_t name = GPGRT_LOCK_INITIALIZER
 
-#define DECLARE_LOCK(name) \
-  struct critsect_s name
-#define INIT_LOCK(a)			\
-  do					\
-    {					\
-      (a).name = #a;			\
-      (a).priv = NULL;			\
-    }					\
-  while (0)
-#define DESTROY_LOCK(name) _gpgme_sema_cs_destroy (&(name))
+#define INIT_LOCK(name) \
+  name = (gpgrt_lock_t) GPGRT_LOCK_INITIALIZER
 
+#define DECLARE_LOCK(name) gpgrt_lock_t name
 
-#define LOCK(name)			\
-  do					\
-    {					\
-      _gpgme_sema_cs_enter (&(name));	\
-    }					\
-  while (0)
+#define DESTROY_LOCK(name) gpgrt_lock_destroy(&name)
 
-#define UNLOCK(name)			\
-  do					\
-    {					\
-      _gpgme_sema_cs_leave (&(name));	\
-    }					\
-  while (0)
+#define LOCK(name) gpgrt_lock_lock(&name)
 
-void _gpgme_sema_subsystem_init (void);
-void _gpgme_sema_cs_enter (struct critsect_s *s);
-void _gpgme_sema_cs_leave (struct critsect_s *s);
-void _gpgme_sema_cs_destroy (struct critsect_s *s);
+#define UNLOCK(name) gpgrt_lock_unlock(&name)
 
 #endif /* SEMA_H */
diff --git a/src/version.c b/src/version.c
index 8bc898f..99698fa 100644
--- a/src/version.c
+++ b/src/version.c
@@ -74,7 +74,6 @@ do_subsystem_inits (void)
   }
 #endif
 
-  _gpgme_sema_subsystem_init ();
   _gpgme_debug_subsystem_init ();
   _gpgme_io_subsystem_init ();
   _gpgme_status_init ();
diff --git a/src/w32-sema.c b/src/w32-sema.c
deleted file mode 100644
index 648a6bb..0000000
--- a/src/w32-sema.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/* w32-sema.c
-   Copyright (C) 2001 Werner Koch (dd9jn)
-   Copyright (C) 2001, 2002, 2004, 2007 g10 Code GmbH
-
-   This file is part of GPGME.
-
-   GPGME 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.
-
-   GPGME 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, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#include <io.h>
-
-#include "util.h"
-#include "sema.h"
-#include "debug.h"
-
-static void
-sema_fatal (const char *text)
-{
-    fprintf (stderr, "sema.c: %s\n", text);
-    abort ();
-}
-
-
-static void
-critsect_init (struct critsect_s *s)
-{
-    CRITICAL_SECTION *mp;
-    static CRITICAL_SECTION init_lock;
-    static int initialized;
-
-    if (!initialized) {
-        /* The very first time we call this function, we assume that
-	   only one thread is running, so that we can bootstrap the
-	   semaphore code.  */
-        InitializeCriticalSection (&init_lock);
-        initialized = 1;
-    }
-    if (!s)
-        return; /* we just want to initialize ourself */
-
-    /* first test whether it is really not initialized */
-    EnterCriticalSection (&init_lock);
-    if ( s->priv ) {
-        LeaveCriticalSection (&init_lock);
-        return;
-    }
-    /* now init it */
-    mp = malloc ( sizeof *mp );
-    if (!mp) {
-        LeaveCriticalSection (&init_lock);
-        sema_fatal ("out of core while creating critical section lock");
-    }
-    InitializeCriticalSection (mp);
-    s->priv = mp;
-    LeaveCriticalSection (&init_lock);
-}
-
-void
-_gpgme_sema_subsystem_init ()
-{
-    /* fixme: we should check that there is only one thread running */
-    critsect_init (NULL);
-}
-
-
-void
-_gpgme_sema_cs_enter ( struct critsect_s *s )
-{
-    if (!s->priv)
-        critsect_init (s);
-    EnterCriticalSection ( (CRITICAL_SECTION*)s->priv );
-}
-
-void
-_gpgme_sema_cs_leave (struct critsect_s *s)
-{
-    if (!s->priv)
-        critsect_init (s);
-    LeaveCriticalSection ((CRITICAL_SECTION*)s->priv);
-}
-
-void
-_gpgme_sema_cs_destroy ( struct critsect_s *s )
-{
-    if (s && s->priv) {
-        DeleteCriticalSection ((CRITICAL_SECTION*)s->priv);
-        free (s->priv);
-        s->priv = NULL;
-    }
-}
diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am
index 2538f63..dd33b0a 100644
--- a/tests/gpg/Makefile.am
+++ b/tests/gpg/Makefile.am
@@ -38,7 +38,8 @@ c_tests = \
         t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers		\
 	t-decrypt t-verify t-decrypt-verify t-sig-notation t-export	\
 	t-import t-trustlist t-edit t-keylist t-keylist-sig t-wait	\
-	t-encrypt-large t-file-name t-gpgconf t-encrypt-mixed $(tests_unix)
+	t-encrypt-large t-file-name t-gpgconf t-encrypt-mixed $(tests_unix) \
+	t-thread-keylist t-thread-keylist-verify
 
 TESTS = initial.test $(c_tests) final.test
 
@@ -61,8 +62,10 @@ EXTRA_DIST = initial.test final.test \
 AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@
 AM_LDFLAGS = -no-install
 LDADD = ../../src/libgpgme.la
-t_thread1_LDADD = ../../src/libgpgme-pthread.la -lpthread
-t_cancel_LDADD = ../../src/libgpgme-pthread.la -lpthread
+t_thread1_LDADD = ../../src/libgpgme.la -lpthread
+t_thread_keylist_LDADD = ../../src/libgpgme.la -lpthread
+t_thread_keylist_verify_LDADD = ../../src/libgpgme.la -lpthread
+t_cancel_LDADD = ../../src/libgpgme.la -lpthread
 
 # We don't run t-genkey and t-cancel in the test suite, because it
 # takes too long
diff --git a/tests/gpg/t-thread-keylist-verify.c b/tests/gpg/t-thread-keylist-verify.c
new file mode 100644
index 0000000..55af88a
--- /dev/null
+++ b/tests/gpg/t-thread-keylist-verify.c
@@ -0,0 +1,129 @@
+/* t-thread-verify.c - Regression test.
+   Copyright (C) 2015 Intevation GmbH
+
+   This file is part of GPGME.
+
+   GPGME 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.
+
+   GPGME 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#include <pthread.h>
+
+#include "t-support.h"
+
+#define THREAD_COUNT 500
+
+static const char test_text1[] = "Just GNU it!\n";
+static const char test_sig1[] =
+"-----BEGIN PGP SIGNATURE-----\n"
+"\n"
+"iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n"
+"bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv\n"
+"b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw\n"
+"Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n"
+"dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA==\n"
+"=nts1\n"
+"-----END PGP SIGNATURE-----\n";
+
+void *
+start_keylist (void *arg)
+{
+  gpgme_error_t err;
+  gpgme_ctx_t ctx;
+  gpgme_key_t key;
+
+  err = gpgme_new (&ctx);
+  fail_if_err (err);
+
+  err = gpgme_op_keylist_start (ctx, NULL, 0);
+  fail_if_err (err);
+
+  while (!(err = gpgme_op_keylist_next (ctx, &key)));
+
+  return NULL;
+}
+
+void *
+start_verify (void *arg)
+{
+  gpgme_ctx_t ctx;
+  gpgme_error_t err;
+  gpgme_data_t sig, text;
+  gpgme_verify_result_t result;
+  gpgme_signature_t signature;
+
+  err = gpgme_new (&ctx);
+  fail_if_err (err);
+
+  /* Checking a valid message.  */
+  err = gpgme_data_new_from_mem (&text, test_text1, strlen (test_text1), 0);
+  fail_if_err (err);
+  err = gpgme_data_new_from_mem (&sig, test_sig1, strlen (test_sig1), 0);
+  fail_if_err (err);
+  err = gpgme_op_verify (ctx, sig, text, NULL);
+  fail_if_err (err);
+  result = gpgme_op_verify_result (ctx);
+
+  signature = result->signatures;
+
+  if (strcmp (signature->fpr, "A0FF4590BB6122EDEF6E3C542D727CC768697734"))
+    {
+      fprintf (stderr, "%s:%i: Unexpected fingerprint: %s\n",
+               __FILE__, __LINE__, signature->fpr);
+      exit (1);
+    }
+  if (gpgme_err_code (signature->status) != GPG_ERR_NO_ERROR)
+    {
+      fprintf (stderr, "%s:%i: Unexpected signature status: %s\n",
+               __FILE__, __LINE__, gpgme_strerror (signature->status));
+      exit (1);
+    }
+  return NULL;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+  pthread_t verify_threads[THREAD_COUNT];
+  pthread_t keylist_threads[THREAD_COUNT];
+  init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+  for (i = 0; i < THREAD_COUNT; i++)
+    {
+      if (pthread_create(&verify_threads[i], NULL, start_verify, NULL) ||
+          pthread_create(&keylist_threads[i], NULL, start_keylist, NULL))
+        {
+          fprintf(stderr, "%s:%i: failed to create threads \n",
+                       __FILE__, __LINE__);
+          exit(1);
+        }
+   }
+  for (i = 0; i < THREAD_COUNT; i++)
+    {
+      pthread_join (verify_threads[i], NULL);
+      pthread_join (keylist_threads[i], NULL);
+    }
+  return 0;
+}
diff --git a/tests/gpg/t-thread-keylist.c b/tests/gpg/t-thread-keylist.c
new file mode 100644
index 0000000..14f7718
--- /dev/null
+++ b/tests/gpg/t-thread-keylist.c
@@ -0,0 +1,76 @@
+/* t-thread-verify.c - Regression test.
+   Copyright (C) 2015 Intevation GmbH
+
+   This file is part of GPGME.
+
+   GPGME 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.
+
+   GPGME 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#include <pthread.h>
+
+#include "t-support.h"
+
+#define THREAD_COUNT 500
+
+void *
+start_keylist (void *arg)
+{
+  gpgme_error_t err;
+  gpgme_ctx_t ctx;
+  gpgme_key_t key;
+
+  err = gpgme_new (&ctx);
+  fail_if_err (err);
+
+  err = gpgme_op_keylist_start (ctx, NULL, 0);
+  fail_if_err (err);
+
+  while (!(err = gpgme_op_keylist_next (ctx, &key)));
+
+  return NULL;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+  pthread_t keylist_threads[THREAD_COUNT];
+  init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+  for (i = 0; i < THREAD_COUNT; i++)
+    {
+      if (pthread_create(&keylist_threads[i], NULL, start_keylist, NULL))
+        {
+          fprintf(stderr, "%s:%i: failed to create threads \n",
+                       __FILE__, __LINE__);
+          exit(1);
+        }
+   }
+  for (i = 0; i < THREAD_COUNT; i++)
+    {
+      pthread_join (keylist_threads[i], NULL);
+    }
+  return 0;
+}
-- 
2.1.4
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 659 bytes
Desc: This is a digitally signed message part.
URL: </pipermail/attachments/20161108/f14272eb/attachment-0001.sig>


More information about the Gnupg-devel mailing list