core: Use gpgrt locking for thread safeness

* configure.ac: Require libgpg-error 1.17. No longer
check for pthread.
* 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: Remove libpthread and
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.
* 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.
* src/gpgme-config.in: Use -lgpgme for thread-model pthread.

--
Using gpgrt locks instead of pthread locks removes
the neccessity to link pthread directly to gpgme and
have a different, thread safe flavor of gpgme. Now
gpgme is thread-safe if the conditions mentioned
in the doc are met.

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

libgpgme-pthread is removed but gpgme-config still supports
--thread=pthread for compatibility with find scripts.
This commit is contained in:
Andre Heinecke 2016-11-08 15:32:14 +01:00
parent f1f341062e
commit 09b6455432
14 changed files with 239 additions and 539 deletions

View File

@ -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
@ -211,11 +211,6 @@ case "${host}" in
;;
*)
AC_CHECK_LIB(pthread,pthread_create,have_pthread=yes)
if test "$have_pthread" = yes; then
AC_DEFINE(HAVE_PTHREAD, ,[Define if we have pthread.])
fi
# XXX: Probably use exec-prefix here?
# GPG_DEFAULT='/usr/bin/gpg'
# GPGSM_DEFAULT='/usr/bin/gpgsm'
@ -257,8 +252,6 @@ AM_CONDITIONAL(HAVE_ANDROID_SYSTEM, test "$have_android_system" = yes)
AM_CONDITIONAL(BUILD_W32_GLIB, test "$build_w32_glib" = yes)
AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes")
AC_ARG_ENABLE([fixed-path],
AC_HELP_STRING([--enable-fixed-path=PATH],
@ -905,7 +898,6 @@ echo "
UI Server: $uiserver
FD Passing: $use_descriptor_passing
GPGME Pthread: $have_pthread
Language bindings: ${enabled_languages_v:-$enabled_languages}
"

View File

@ -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
@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
@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
@code{GPGME_PTHREAD_CFLAGS} and @code{GPGME_PTHREAD_LIBS}.
@code{GPGME_PTHREAD_CFLAGS} and @code{GPGME_PTHREAD_LIBS}. Since
version 1.8.0 this is no longer required to GPGME_PTHREAD as
@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,31 +810,11 @@ 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
@acronym{GPGME} supports the thread libraries pthread and GNU Pth.
The support for this has to be enabled at compile time.
@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.
@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
@code{libgpgme-} followed by the name of the thread package you use.
For example, if you use GNU Pth, the right name is
@code{libgpgme-pth}. Use the Automake macros or
@command{gpgme-config} program for simplicity.
@item
The function @code{gpgme_check_version} must be called before any
other function in the library, because it initializes the thread

View File

@ -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 $(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,14 +154,6 @@ 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@
if BUILD_W32_GLIB
libgpgme_glib_la_LDFLAGS = \
$(no_undefined) $(export_symbols) $(extra_ltoptions) \

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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);

View File

@ -32,7 +32,9 @@ gpg_error_libs="@GPG_ERROR_LIBS@"
# Configure thread packages.
thread_modules=""
@HAVE_PTHREAD_TRUE@thread_modules="$thread_modules pthread"
# For compatibility we keep proving the
# thread modules variable.
thread_modules="$thread_modules pthread"
libs_pthread="-lpthread"
cflags_pthread=""
@ -50,7 +52,6 @@ usage()
cat <<EOF
Usage: gpgme-config [OPTIONS]
Options:
--thread={${thread_modules}}]
--prefix
--exec-prefix
--version
@ -139,7 +140,8 @@ while test $# -gt 0; do
result=
tmp_x=
case "$thread_module" in
pthread) tmp_l="-lgpgme-pthread"; tmp_x="$libs_pthread" ;;
# deprecated
pthread) tmp_l="-lgpgme" ;;
*)
if test "x$with_glib" = "xyes" ; then
tmp_l="-lgpgme-glib"

View File

@ -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;
}

View File

@ -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 */

View File

@ -74,7 +74,6 @@ do_subsystem_inits (void)
}
#endif
_gpgme_sema_subsystem_init ();
_gpgme_debug_subsystem_init ();
_gpgme_io_subsystem_init ();
_gpgme_status_init ();

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}