diff options
author | Marcus Brinkmann <[email protected]> | 2012-01-03 21:12:37 +0000 |
---|---|---|
committer | Marcus Brinkmann <[email protected]> | 2012-01-25 13:07:08 +0000 |
commit | e917c07b2664bb01a5f7b5975723b90da0f396c9 (patch) | |
tree | e31e737fe07e96b596f8bbbaf16a1e122ac683ae /dirmngr | |
parent | Require gitlog-to-changelog to be installed. (diff) | |
download | gnupg-npth-3.tar.gz gnupg-npth-3.zip |
Port to npth.npth-3
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/npth.m4: New file.
* agent/Makefile.am, agent/cache.c, agent/call-pinentry.c,
agent/call-scd.c, agent/findkey.c, agent/gpg-agent.c,
agent/trustlist.c, common/Makefile.am, common/estream.c,
common/exechelp-posix.c, common/exechelp-w32.c,
common/exechelp-w32ce.c, common/http.c, common/init.c,
common/sysutils.c, dirmngr/Makefile.am, dirmngr/crlfetch.c,
dirmngr/dirmngr.c, dirmngr/dirmngr_ldap.c, dirmngr/ldap-wrapper-ce.c,
dirmngr/ldap-wrapper.c, dirmngr/ldap.c, g13/Makefile.am,
g13/call-gpg.c, g13/g13.c, g13/runner.c, scd/Makefile.am,
scd/apdu.c, scd/app.c, scd/ccid-driver.c, scd/command.c,
scd/scdaemon.c, tools/Makefile.am: Port to npth.
Diffstat (limited to 'dirmngr')
-rw-r--r-- | dirmngr/Makefile.am | 4 | ||||
-rw-r--r-- | dirmngr/certcache.c | 38 | ||||
-rw-r--r-- | dirmngr/crlfetch.c | 4 | ||||
-rw-r--r-- | dirmngr/dirmngr.c | 219 | ||||
-rw-r--r-- | dirmngr/dirmngr_ldap.c | 36 | ||||
-rw-r--r-- | dirmngr/ldap-wrapper-ce.c | 214 | ||||
-rw-r--r-- | dirmngr/ldap-wrapper.c | 221 | ||||
-rw-r--r-- | dirmngr/ldap.c | 2 |
8 files changed, 404 insertions, 334 deletions
diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index e90daa41c..c5f073e3b 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -32,7 +32,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common include $(top_srcdir)/am/cmacros.am AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) \ - $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS) + $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(NPTH_CFLAGS) BUILT_SOURCES = no-libgcrypt.c @@ -61,7 +61,7 @@ endif dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \ - $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL) $(LIBICONV) + $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(NPTH_LIBS) $(LIBINTL) $(LIBICONV) if !USE_LDAPWRAPPER dirmngr_LDADD += $(LDAPLIBS) endif diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c index a8b84e6e3..73916b03e 100644 --- a/dirmngr/certcache.c +++ b/dirmngr/certcache.c @@ -25,7 +25,7 @@ #include <assert.h> #include <sys/types.h> #include <dirent.h> -#include <pth.h> +#include <npth.h> #include "dirmngr.h" #include "misc.h" @@ -80,10 +80,10 @@ static cert_item_t cert_cache[256]; /* This is the global cache_lock variable. In general looking is not needed but it would take extra efforts to make sure that no - indirect use of pth functions is done, so we simply lock it always. - Note: We can't use static initialization, as that is not available - through w32-pth. */ -static pth_rwlock_t cert_cache_lock; + indirect use of npth functions is done, so we simply lock it + always. Note: We can't use static initialization, as that is not + available through w32-pth. */ +static npth_rwlock_t cert_cache_lock; /* Flag to track whether the cache has been initialized. */ static int initialization_done; @@ -99,33 +99,45 @@ static unsigned int total_extra_certificates; static void init_cache_lock (void) { - if (!pth_rwlock_init (&cert_cache_lock)) + int err; + + err = npth_rwlock_init (&cert_cache_lock, NULL); + if (err) log_fatal (_("can't initialize certificate cache lock: %s\n"), - strerror (errno)); + strerror (err)); } static void acquire_cache_read_lock (void) { - if (!pth_rwlock_acquire (&cert_cache_lock, PTH_RWLOCK_RD, FALSE, NULL)) + int err; + + err = npth_rwlock_rdlock (&cert_cache_lock); + if (err) log_fatal (_("can't acquire read lock on the certificate cache: %s\n"), - strerror (errno)); + strerror (err)); } static void acquire_cache_write_lock (void) { - if (!pth_rwlock_acquire (&cert_cache_lock, PTH_RWLOCK_RW, FALSE, NULL)) + int err; + + err = npth_rwlock_wrlock (&cert_cache_lock); + if (err) log_fatal (_("can't acquire write lock on the certificate cache: %s\n"), - strerror (errno)); + strerror (err)); } static void release_cache_lock (void) { - if (!pth_rwlock_release (&cert_cache_lock)) + int err; + + err = npth_rwlock_unlock (&cert_cache_lock); + if (err) log_fatal (_("can't release lock on the certificate cache: %s\n"), - strerror (errno)); + strerror (err)); } diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index 822584b49..91e8d0406 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -22,7 +22,7 @@ #include <stdio.h> #include <errno.h> -#include <pth.h> +#include <npth.h> #include "crlfetch.h" #include "dirmngr.h" @@ -72,7 +72,7 @@ register_file_reader (ksba_reader_t reader, struct reader_cb_context_s *cb_ctx) return; } log_info (_("reader to file mapping table full - waiting\n")); - pth_sleep (2); + npth_sleep (2); } } diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 2256c591c..b0410afd0 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -40,7 +40,7 @@ #ifdef HAVE_SIGNAL_H # include <signal.h> #endif -#include <pth.h> +#include <npth.h> #define JNLIB_NEED_LOG_LOGV @@ -254,7 +254,7 @@ static int active_connections; /* This union is used to avoid compiler warnings in case a pointer is 64 bit and an int 32 bit. We store an integer in a pointer and get - it back later (pth_key_getdata et al.). */ + it back later (npth_getspecific et al.). */ union int_and_ptr_u { int aint; @@ -277,27 +277,8 @@ static ldap_server_t parse_ldapserver_file (const char* filename); static fingerprint_list_t parse_ocsp_signer (const char *string); static void handle_connections (assuan_fd_t listen_fd); -/* Pth wrapper function definitions. */ -ASSUAN_SYSTEM_PTH_IMPL; - -#if GCRY_THREAD_OPTION_VERSION == 0 -#define USE_GCRY_THREAD_CBS 1 -#endif - -#ifdef USE_GCRY_THREAD_CBS -GCRY_THREAD_OPTION_PTH_IMPL; -static int fixed_gcry_pth_init (void) -{ - return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0; -} -#endif - -#ifndef PTH_HAVE_PTH_THREAD_ID -static unsigned long pth_thread_id (void) -{ - return (unsigned long)pth_self (); -} -#endif +/* NPth wrapper function definitions. */ +ASSUAN_SYSTEM_NPTH_IMPL; static const char * my_strusage( int level ) @@ -557,7 +538,7 @@ pid_suffix_callback (unsigned long *r_suffix) { union int_and_ptr_u value; - value.aptr = pth_key_getdata (my_tlskey_current_fd); + value.aptr = npth_getspecific (my_tlskey_current_fd); *r_suffix = value.aint; return (*r_suffix != -1); /* Use decimal representation. */ } @@ -624,17 +605,8 @@ main (int argc, char **argv) i18n_init (); init_common_subsystems (&argc, &argv); -#ifdef USE_GCRY_THREAD_CBS - /* Libgcrypt requires us to register the threading model first. - Note that this will also do the pth_init. */ - gcry_threads_pth.init = fixed_gcry_pth_init; - rc = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); - if (rc) - { - log_fatal ("can't register GNU Pth with Libgcrypt: %s\n", - gpg_strerror (rc)); - } -#endif + npth_init (); + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); /* Check that the libraries are suitable. Do it here because @@ -658,7 +630,7 @@ main (int argc, char **argv) assuan_set_malloc_hooks (&malloc_hooks); assuan_set_assuan_log_prefix (log_get_prefix (NULL)); assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT); - assuan_set_system_hooks (ASSUAN_SYSTEM_PTH); + assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH); assuan_sock_init (); setup_libassuan_logging (&opt.debug); @@ -671,12 +643,12 @@ main (int argc, char **argv) opt.homedir = default_homedir (); - /* Now with Pth running we can set the logging callback. Our - windows implementation does not yet feature the Pth TLS + /* Now with NPth running we can set the logging callback. Our + windows implementation does not yet feature the NPth TLS functions. */ #ifndef HAVE_W32_SYSTEM - if (pth_key_create (&my_tlskey_current_fd, NULL)) - if (pth_key_setdata (my_tlskey_current_fd, NULL)) + if (npth_key_create (&my_tlskey_current_fd, NULL) == 0) + if (npth_setspecific (my_tlskey_current_fd, NULL) == 0) log_set_pid_suffix_cb (pid_suffix_callback); #endif /*!HAVE_W32_SYSTEM*/ @@ -1036,7 +1008,7 @@ main (int argc, char **argv) pid = getpid (); es_printf ("set DIRMNGR_INFO=%s;%lu;1\n", socket_name, (ulong) pid); #else - pid = pth_fork (); + pid = fork(); if (pid == (pid_t)-1) { log_fatal (_("error forking process: %s\n"), strerror (errno)); @@ -1562,7 +1534,7 @@ parse_ocsp_signer (const char *string) /* Reread parts of the configuration. Note, that this function is - obviously not thread-safe and should only be called from the PTH + obviously not thread-safe and should only be called from the NPTH signal handler. Fixme: Due to the way the argument parsing works, we create a @@ -1723,12 +1695,12 @@ start_connection_thread (void *arg) if (check_nonce (fd, &socket_nonce)) { - log_error ("handler 0x%lx nonce check FAILED\n", pth_thread_id ()); + log_error ("handler nonce check FAILED\n"); return NULL; } #ifndef HAVE_W32_SYSTEM - pth_key_setdata (my_tlskey_current_fd, argval.aptr); + npth_setspecific (my_tlskey_current_fd, argval.aptr); #endif active_connections++; @@ -1743,7 +1715,7 @@ start_connection_thread (void *arg) #ifndef HAVE_W32_SYSTEM argval.afd = ASSUAN_INVALID_FD; - pth_key_setdata (my_tlskey_current_fd, argval.aptr); + npth_setspecific (my_tlskey_current_fd, argval.aptr); #endif return NULL; @@ -1754,53 +1726,30 @@ start_connection_thread (void *arg) static void handle_connections (assuan_fd_t listen_fd) { - pth_attr_t tattr; - pth_event_t ev, time_ev; - sigset_t sigs; + npth_attr_t tattr; int signo; struct sockaddr_un paddr; socklen_t plen = sizeof( paddr ); gnupg_fd_t fd; int nfd, ret; fd_set fdset, read_fdset; + struct timespec abstime; + struct timespec curtime; + struct timespec timeout; + int saved_errno; - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 1024*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "dirmngr"); + npth_attr_init (&tattr); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); #ifndef HAVE_W32_SYSTEM /* FIXME */ - /* Make sure that the signals we are going to handle are not blocked - and create an event object for them. We also set the default - action to ignore because we use an Pth event to get notified - about signals. This avoids that the default action is taken in - case soemthing goes wrong within Pth. The problem might also be - a Pth bug. */ - sigemptyset (&sigs ); - { - static const int mysigs[] = { SIGHUP, SIGUSR1, SIGUSR2, SIGINT, SIGTERM }; - struct sigaction sa; - int i; - - for (i=0; i < DIM (mysigs); i++) - { - sigemptyset (&sa.sa_mask); - sa.sa_handler = SIG_IGN; - sa.sa_flags = 0; - sigaction (mysigs[i], &sa, NULL); - - sigaddset (&sigs, mysigs[i]); - } - } - - pth_sigmask (SIG_UNBLOCK, &sigs, NULL); - ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); -#else - /* Use a dummy event. */ - sigs = 0; - ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); + npth_sigev_init (); + npth_sigev_add (SIGHUP); + npth_sigev_add (SIGUSR1); + npth_sigev_add (SIGUSR2); + npth_sigev_add (SIGINT); + npth_sigev_add (SIGTERM); + npth_sigev_fini (); #endif - time_ev = NULL; /* Setup the fdset. It has only one member. This is because we use pth_select instead of pth_accept to properly sync timeouts with @@ -1809,12 +1758,12 @@ handle_connections (assuan_fd_t listen_fd) FD_SET (FD2INT (listen_fd), &fdset); nfd = FD2INT (listen_fd); + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + /* Main loop. */ for (;;) { - /* Make sure that our signals are not blocked. */ - pth_sigmask (SIG_UNBLOCK, &sigs, NULL); - /* Shutdown test. */ if (shutdown_pending) { @@ -1826,76 +1775,48 @@ handle_connections (assuan_fd_t listen_fd) FD_ZERO (&fdset); } - /* Create a timeout event if needed. To help with power saving - we syncronize the ticks to the next full second. */ - if (!time_ev) - { - pth_time_t nexttick; - - nexttick = pth_timeout (TIMERTICK_INTERVAL, 0); - if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */ - { - nexttick.tv_sec++; - nexttick.tv_usec = 0; - } - time_ev = pth_event (PTH_EVENT_TIME, nexttick); - } - /* Take a copy of the fdset. */ read_fdset = fdset; - if (time_ev) - pth_event_concat (ev, time_ev, NULL); + npth_clock_gettime (&curtime); + if (!(npth_timercmp (&curtime, &abstime, <))) + { + /* Timeout. */ + handle_tick (); + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + } + npth_timersub (&abstime, &curtime, &timeout); - ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev); +#ifndef HAVE_W32_SYSTEM + ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask()); + saved_errno = errno; - if (time_ev) - pth_event_isolate (time_ev); + while (npth_sigev_get_pending(&signo)) + handle_signal (signo); +#else + ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, NULL, NULL); + saved_errno = errno; +#endif - if (ret == -1) - { - if (pth_event_occurred (ev) - || (time_ev && pth_event_occurred (time_ev)) ) - { - if (pth_event_occurred (ev)) - handle_signal (signo); - if (time_ev && pth_event_occurred (time_ev)) - { - pth_event_free (time_ev, PTH_FREE_ALL); - time_ev = NULL; - handle_tick (); - } - continue; - } - log_error (_("pth_select failed: %s - waiting 1s\n"), - strerror (errno)); - pth_sleep (1); + if (ret == -1 && saved_errno != EINTR) + { + log_error (_("npth_pselect failed: %s - waiting 1s\n"), + strerror (saved_errno)); + npth_sleep (1); continue; } - if (pth_event_occurred (ev)) - { - handle_signal (signo); - } - - if (time_ev && pth_event_occurred (time_ev)) - { - pth_event_free (time_ev, PTH_FREE_ALL); - time_ev = NULL; - handle_tick (); - } - - - /* We now might create a new thread and because we don't want - any signals (as we are handling them here) to be delivered to - a new thread we need to block those signals. */ - pth_sigmask (SIG_BLOCK, &sigs, NULL); + if (ret <= 0) + /* Interrupt or timeout. Will be handled when calculating the + next timeout. */ + continue; if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset)) { plen = sizeof paddr; - fd = INT2FD (pth_accept (FD2INT(listen_fd), - (struct sockaddr *)&paddr, &plen)); + fd = INT2FD (npth_accept (FD2INT(listen_fd), + (struct sockaddr *)&paddr, &plen)); if (fd == GNUPG_INVALID_FD) { log_error ("accept failed: %s\n", strerror (errno)); @@ -1904,27 +1825,27 @@ handle_connections (assuan_fd_t listen_fd) { char threadname[50]; union int_and_ptr_u argval; + npth_t thread; argval.afd = fd; snprintf (threadname, sizeof threadname-1, "conn fd=%d", FD2INT(fd)); threadname[sizeof threadname -1] = 0; - pth_attr_set (tattr, PTH_ATTR_NAME, threadname); - if (!pth_spawn (tattr, start_connection_thread, argval.aptr)) + + ret = npth_create (&thread, &tattr, start_connection_thread, argval.aptr); + if (ret) { log_error ("error spawning connection handler: %s\n", - strerror (errno) ); + strerror (ret) ); assuan_sock_close (fd); } + npth_setname_np (thread, threadname); } fd = GNUPG_INVALID_FD; } } - pth_event_free (ev, PTH_FREE_ALL); - if (time_ev) - pth_event_free (time_ev, PTH_FREE_ALL); - pth_attr_destroy (tattr); + npth_attr_destroy (&tattr); cleanup (); log_info ("%s %s stopped\n", strusage(11), strusage(13)); } diff --git a/dirmngr/dirmngr_ldap.c b/dirmngr/dirmngr_ldap.c index 8433bbf81..f166f19e2 100644 --- a/dirmngr/dirmngr_ldap.c +++ b/dirmngr/dirmngr_ldap.c @@ -33,7 +33,7 @@ #include <sys/time.h> #include <unistd.h> #ifndef USE_LDAPWRAPPER -# include <pth.h> +# include <npth.h> #endif #ifdef HAVE_W32_SYSTEM @@ -58,13 +58,13 @@ #include "i18n.h" #include "util.h" -/* With the ldap wrapper, there is no need for the pth_enter and leave +/* With the ldap wrapper, there is no need for the npth_unprotect and leave functions; thus we redefine them to nops. If we are not using the ldap wrapper process we need to include the prototype for our module's main function. */ #ifdef USE_LDAPWRAPPER -static void pth_enter (void) { } -static void pth_leave (void) { } +static void npth_unprotect (void) { } +static void npth_protect (void) { } #else # include "./ldap-wrapper.h" #endif @@ -392,9 +392,9 @@ print_ldap_entries (my_opt_t myopt, LDAP *ld, LDAPMessage *msg, char *want_attr) LDAPMessage *item; int any = 0; - for (pth_enter (), item = ldap_first_entry (ld, msg), pth_leave (); + for (npth_unprotect (), item = ldap_first_entry (ld, msg), npth_protect (); item; - pth_enter (), item = ldap_next_entry (ld, item), pth_leave ()) + npth_unprotect (), item = ldap_next_entry (ld, item), npth_protect ()) { BerElement *berctx; char *attr; @@ -414,11 +414,11 @@ print_ldap_entries (my_opt_t myopt, LDAP *ld, LDAPMessage *msg, char *want_attr) } - for (pth_enter (), attr = my_ldap_first_attribute (ld, item, &berctx), - pth_leave (); + for (npth_unprotect (), attr = my_ldap_first_attribute (ld, item, &berctx), + npth_protect (); attr; - pth_enter (), attr = my_ldap_next_attribute (ld, item, berctx), - pth_leave ()) + npth_unprotect (), attr = my_ldap_next_attribute (ld, item, berctx), + npth_protect ()) { struct berval **values; int idx; @@ -455,9 +455,9 @@ print_ldap_entries (my_opt_t myopt, LDAP *ld, LDAPMessage *msg, char *want_attr) } } - pth_enter (); + npth_unprotect (); values = my_ldap_get_values_len (ld, item, attr); - pth_leave (); + npth_protect (); if (!values) { @@ -618,19 +618,19 @@ fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp) set_timeout (myopt); - pth_enter (); + npth_unprotect (); ld = my_ldap_init (host, port); - pth_leave (); + npth_protect (); if (!ld) { log_error (_("LDAP init to `%s:%d' failed: %s\n"), host, port, strerror (errno)); return -1; } - pth_enter (); + npth_unprotect (); /* Fixme: Can we use MYOPT->user or is it shared with other theeads?. */ ret = my_ldap_simple_bind_s (ld, myopt->user, myopt->pass); - pth_leave (); + npth_protect (); if (ret) { log_error (_("binding to `%s:%d' failed: %s\n"), @@ -640,13 +640,13 @@ fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp) } set_timeout (myopt); - pth_enter (); + npth_unprotect (); rc = my_ldap_search_st (ld, dn, ludp->lud_scope, filter, myopt->multi && !myopt->attr && ludp->lud_attrs? ludp->lud_attrs:attrs, 0, &myopt->timeout, &msg); - pth_leave (); + npth_protect (); if (rc == LDAP_SIZELIMIT_EXCEEDED && myopt->multi) { if (es_fwrite ("E\0\0\0\x09truncated", 14, 1, myopt->outstream) != 1) diff --git a/dirmngr/ldap-wrapper-ce.c b/dirmngr/ldap-wrapper-ce.c index d50beb153..9af70af87 100644 --- a/dirmngr/ldap-wrapper-ce.c +++ b/dirmngr/ldap-wrapper-ce.c @@ -35,7 +35,7 @@ #include <unistd.h> #include <fcntl.h> #include <time.h> -#include <pth.h> +#include <npth.h> #include <assert.h> #include "dirmngr.h" @@ -106,12 +106,93 @@ struct outstream_cookie_s { int refcount; /* Reference counter - possible values are 1 and 2. */ + /* We don't need a mutex for the conditions, as npth provides a + simpler condition interface that relies on the global lock. This + can be used if we never yield between testing the condition and + waiting on it. */ + npth_cond_t wait_data; /* Condition that data is available. */ + npth_cond_t wait_space; /* Condition that space is available. */ + int eof_seen; /* EOF indicator. */ - size_t buffer_len; /* The valid length of the BUFFER. */ + char buffer[4000]; /* Data ring buffer. */ + size_t buffer_len; /* The amount of data in the BUFFER. */ size_t buffer_pos; /* The next read position of the BUFFER. */ - char buffer[4000]; /* Data buffer. */ }; +#define BUFFER_EMPTY(c) ((c)->buffer_len == 0) +#define BUFFER_FULL(c) ((c)->buffer_len == DIM((c)->buffer)) +#define BUFFER_DATA_AVAILABLE(c) ((c)->buffer_len) +#define BUFFER_SPACE_AVAILABLE(c) (DIM((c)->buffer) - (c)->buffer_len) +#define BUFFER_INC_POS(c,n) (c)->buffer_pos = ((c)->buffer_pos + (n)) % DIM((c)->buffer) +#define BUFFER_CUR_POS(c) (&(c)->buffer[(c)->buffer_pos]) + +static int +buffer_get_data (struct outstream_cookie_s *cookie, char *dst, int cnt) +{ + int amount; + int left; + int chunk; + + amount = cnt; + if (BUFFER_DATA_AVAILABLE (cookie) < amount) + amount = BUFFER_DATA_AVAILABLE (cookie); + left = amount; + + /* How large is the part up to the end of the buffer array? */ + chunk = DIM(cookie->buffer) - cookie->buffer_pos; + if (chunk > left) + chunk = left; + + memcpy (dst, BUFFER_CUR_POS (cookie), chunk); + BUFFER_INC_POS (cookie, chunk); + left -= chunk; + dst += chunk; + + if (left) + { + memcpy (dst, BUFFER_CUR_POS (cookie), left); + BUFFER_INC_POS (cookie, left); + } + + return amount; +} + + +static int +buffer_put_data (struct outstream_cookie_s *cookie, const char *src, int cnt) +{ + int amount; + int remain; + int left; + int chunk; + + remain = DIM(cookie->buffer) - cookie->buffer_len; + + amount = cnt; + if (remain < amount) + amount = remain; + left = amount; + + /* How large is the part up to the end of the buffer array? */ + chunk = DIM(cookie->buffer) - cookie->buffer_pos; + if (chunk > left) + chunk = left; + + memcpy (BUFFER_CUR_POS (cookie), src, chunk); + BUFFER_INC_POS (cookie, chunk); + left -= chunk; + src += chunk; + + if (left) + { + memcpy (BUFFER_CUR_POS (cookie), src, left); + BUFFER_INC_POS (cookie, left); + } + + cookie->buffer_len -= amount; + return amount; +} + /* The writer function for the outstream. This is used to transfer the output of the ldap wrapper thread to the ksba reader object. */ @@ -120,43 +201,42 @@ outstream_cookie_writer (void *cookie_arg, const void *buffer, size_t size) { struct outstream_cookie_s *cookie = cookie_arg; const char *src; - char *dst; ssize_t nwritten = 0; + int res; + ssize_t amount = 0; src = buffer; do { + int was_empty = 0; + /* Wait for free space. */ - while (cookie->buffer_len == DIM (cookie->buffer)) + while (BUFFER_FULL(cookie)) { /* Buffer is full: Wait for space. */ - pth_yield (NULL); + res = npth_cond_wait (&cookie->wait_space, NULL); + if (res) + { + gpg_err_set_errno (res); + return -1; + } } + if (BUFFER_EMPTY(cookie)) + was_empty = 1; + /* Copy data. */ - dst = cookie->buffer + cookie->buffer_len; - while (size && cookie->buffer_len < DIM (cookie->buffer)) - { - *dst++ = *src++; - size--; - cookie->buffer_len++; - nwritten++; - } - } - while (size); /* Until done. */ + nwritten = buffer_put_data (cookie, buffer, size); + size -= nwritten; + src += nwritten; + amount += nwritten; - if (nwritten) - { - /* Signal data is available - a pth_yield is sufficient because - the test is explicit. To increase performance we could do a - pth_yield to the other thread and only fall back to yielding - to any thread if that returns an error (i.e. the other thread - is not runnable). However our w32pth does not yet support - yielding to a specific thread, thus this won't help. */ - pth_yield (NULL); + if (was_empty) + npth_cond_signal (&cookie->wait_data); } + while (size); /* Until done. */ - return nwritten; + return amount; } @@ -165,7 +245,11 @@ outstream_release_cookie (struct outstream_cookie_s *cookie) { cookie->refcount--; if (!cookie->refcount) - xfree (cookie); + { + npth_cond_destroy (&cookie->wait_data); + npth_cond_destroy (&cookie->wait_space); + xfree (cookie); + } } @@ -198,6 +282,7 @@ outstream_reader_cb (void *cb_value, char *buffer, size_t count, char *dst; const char *src; size_t nread = 0; + int was_full = 0; if (!buffer && !count && !r_nread) return gpg_error (GPG_ERR_NOT_SUPPORTED); /* Rewind is not supported. */ @@ -205,31 +290,26 @@ outstream_reader_cb (void *cb_value, char *buffer, size_t count, *r_nread = 0; dst = buffer; - while (cookie->buffer_pos == cookie->buffer_len) + while (BUFFER_EMPTY(cookie)) { if (cookie->eof_seen) return gpg_error (GPG_ERR_EOF); /* Wait for data to become available. */ - pth_yield (NULL); + npth_cond_wait (&cookie->wait_data, NULL); } + if (BUFFER_FULL(cookie)) + was_full = 1; + src = cookie->buffer + cookie->buffer_pos; - while (count && cookie->buffer_pos < cookie->buffer_len) + nread = buffer_get_data (cookie, buffer, count); + + if (was_full) { - *dst++ = *src++; - count--; - cookie->buffer_pos++; - nread++; + npth_cond_signal (&cookie->wait_space); } - if (cookie->buffer_pos == cookie->buffer_len) - cookie->buffer_pos = cookie->buffer_len = 0; - - /* Now there should be some space available. We do this even if - COUNT was zero so to give the writer end a chance to continue. */ - pth_yield (NULL); - *r_nread = nread; return 0; /* Success. */ } @@ -351,10 +431,12 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *r_reader, const char *argv[]) { gpg_error_t err; struct ldap_wrapper_thread_parms *parms; - pth_attr_t tattr; + npth_attr_t tattr; es_cookie_io_functions_t outstream_func = { NULL }; struct outstream_cookie_s *outstream_cookie; ksba_reader_t reader; + int res; + npth_t thread; (void)ctrl; @@ -381,6 +463,22 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *r_reader, const char *argv[]) } outstream_cookie->refcount++; + res = npth_cond_init (&outstream_cookie->wait_data, NULL); + if (res) + { + free_arg_list (parms->arg_list); + xfree (parms); + return gpg_error_from_errno (res); + } + res = npth_cond_init (&outstream_cookie->wait_space, NULL); + if (res) + { + npth_cond_destroy (&outstream_cookie->wait_data); + free_arg_list (parms->arg_list); + xfree (parms); + return gpg_error_from_errno (res); + } + err = ksba_reader_new (&reader); if (!err) err = ksba_reader_set_release_notify (reader, @@ -407,27 +505,37 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *r_reader, const char *argv[]) if (!parms->outstream) { err = gpg_error_from_syserror (); - free_arg_list (parms->arg_list); + ksba_reader_release (reader); outstream_release_cookie (outstream_cookie); + free_arg_list (parms->arg_list); xfree (parms); return err; } outstream_cookie->refcount++; - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 128*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-wrapper"); + res = npth_attr_init(&tattr); + if (res) + { + err = gpg_error_from_errno (res); + ksba_reader_release (reader); + free_arg_list (parms->arg_list); + es_fclose (parms->outstream); + xfree (parms); + return err; + } + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); - if (pth_spawn (tattr, ldap_wrapper_thread, parms)) - parms = NULL; /* Now owned by the thread. */ - else + res = npth_create (&thread, &tattr, ldap_wrapper_thread, parms); + npth_attr_destroy (&tattr); + if (res) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (res); log_error ("error spawning ldap wrapper thread: %s\n", - strerror (errno) ); + strerror (res) ); } - pth_attr_destroy (tattr); + else + parms = NULL; /* Now owned by the thread. */ + if (parms) { free_arg_list (parms->arg_list); diff --git a/dirmngr/ldap-wrapper.c b/dirmngr/ldap-wrapper.c index dd378d1ae..203b47263 100644 --- a/dirmngr/ldap-wrapper.c +++ b/dirmngr/ldap-wrapper.c @@ -55,7 +55,7 @@ #include <unistd.h> #include <fcntl.h> #include <time.h> -#include <pth.h> +#include <npth.h> #include "dirmngr.h" #include "exechelp.h" @@ -82,7 +82,7 @@ #define INACTIVITY_TIMEOUT (opt.ldaptimeout + 60*5) /* seconds */ - +#define TIMERTICK_INTERVAL 2 /* To keep track of the LDAP wrapper state we use this structure. */ struct wrapper_context_s @@ -96,7 +96,6 @@ struct wrapper_context_s gpg_error_t fd_error; /* Set to the gpg_error of the last read error if any. */ int log_fd; /* Connected with stderr of the ldap wrapper. */ - pth_event_t log_ev; ctrl_t ctrl; /* Connection data. */ int ready; /* Internally used to mark to be removed contexts. */ ksba_reader_t reader; /* The ksba reader object or NULL. */ @@ -117,8 +116,8 @@ static struct wrapper_context_s *wrapper_list; static int shutting_down; /* Close the pth file descriptor FD and set it to -1. */ -#define SAFE_PTH_CLOSE(fd) \ - do { int _fd = fd; if (_fd != -1) { pth_close (_fd); fd = -1;} } while (0) +#define SAFE_CLOSE(fd) \ + do { int _fd = fd; if (_fd != -1) { close (_fd); fd = -1;} } while (0) @@ -152,10 +151,8 @@ destroy_wrapper (struct wrapper_context_s *ctx) gnupg_release_process (ctx->pid); } ksba_reader_release (ctx->reader); - SAFE_PTH_CLOSE (ctx->fd); - SAFE_PTH_CLOSE (ctx->log_fd); - if (ctx->log_ev) - pth_event_free (ctx->log_ev, PTH_FREE_THIS); + SAFE_CLOSE (ctx->fd); + SAFE_CLOSE (ctx->log_fd); xfree (ctx->line); xfree (ctx); } @@ -228,9 +225,9 @@ read_log_data (struct wrapper_context_s *ctx) int n; char line[256]; - /* We must use the pth_read function for pipes, always. */ + /* We must use the npth_read function for pipes, always. */ do - n = pth_read (ctx->log_fd, line, sizeof line - 1); + n = npth_read (ctx->log_fd, line, sizeof line - 1); while (n < 0 && errno == EINTR); if (n <= 0) /* EOF or error. */ @@ -239,9 +236,7 @@ read_log_data (struct wrapper_context_s *ctx) log_error (_("error reading log from ldap wrapper %d: %s\n"), ctx->pid, strerror (errno)); print_log_line (ctx, NULL); - SAFE_PTH_CLOSE (ctx->log_fd); - pth_event_free (ctx->log_ev, PTH_FREE_THIS); - ctx->log_ev = NULL; + SAFE_CLOSE (ctx->log_fd); return 1; } @@ -261,58 +256,72 @@ ldap_wrapper_thread (void *dummy) int nfds; struct wrapper_context_s *ctx; struct wrapper_context_s *ctx_prev; - time_t current_time; + struct timespec abstime; + struct timespec curtime; + struct timespec timeout; + int saved_errno; + fd_set fdset, read_fdset; + int ret; + time_t exptime; (void)dummy; + FD_ZERO (&fdset); + nfds = -1; + for (ctx = wrapper_list; ctx; ctx = ctx->next) + { + if (ctx->log_fd != -1) + { + FD_SET (ctx->log_fd, &fdset); + if (ctx->log_fd > nfds) + nfds = ctx->log_fd; + } + } + nfds++; + + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + for (;;) { - pth_event_t timeout_ev; int any_action = 0; - pth_time_t nexttick; - /* We timeout the pth_wait every 2 seconds. To help with power - saving we syncronize the timeouts to the next full second. */ - nexttick = pth_timeout (2, 0); - if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */ - { - nexttick.tv_sec++; - nexttick.tv_usec = 0; - } - timeout_ev = pth_event (PTH_EVENT_TIME, nexttick); - if (! timeout_ev) + /* POSIX says that fd_set should be implemented as a structure, + thus a simple assignment is fine to copy the entire set. */ + read_fdset = fdset; + + npth_clock_gettime (&curtime); + if (!(npth_timercmp (&curtime, &abstime, <))) { - log_error (_("pth_event failed: %s\n"), strerror (errno)); - pth_sleep (10); - continue; + /* Inactivity is checked below. Nothing else to do. */ + // handle_tick (); + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; } + npth_timersub (&abstime, &curtime, &timeout); - for (ctx = wrapper_list; ctx; ctx = ctx->next) - { - if (ctx->log_fd != -1) - { - pth_event_isolate (ctx->log_ev); - pth_event_concat (timeout_ev, ctx->log_ev, NULL); - } - } + /* FIXME: For Windows, we have to use a reader thread on the + pipe that signals an event (and a npth_select_ev variant). */ + ret = npth_pselect (nfds + 1, &read_fdset, NULL, NULL, &timeout, NULL); + saved_errno = errno; - /* Note that the read FDs are actually handles. Thus, we can - not use pth_select, but have to use pth_wait. */ - nfds = pth_wait (timeout_ev); - if (nfds < 0) - { - pth_event_free (timeout_ev, PTH_FREE_THIS); - log_error (_("pth_wait failed: %s\n"), strerror (errno)); - pth_sleep (10); - continue; - } - if (pth_event_status (timeout_ev) == PTH_STATUS_OCCURRED) - nfds--; - pth_event_free (timeout_ev, PTH_FREE_THIS); + if (ret == -1 && saved_errno != EINTR) + { + log_error (_("npth_select failed: %s - waiting 1s\n"), + strerror (saved_errno)); + npth_sleep (1); + continue; + } + + if (ret <= 0) + /* Interrupt or timeout. Will be handled when calculating the + next timeout. */ + continue; - current_time = time (NULL); - if (current_time > INACTIVITY_TIMEOUT) - current_time -= INACTIVITY_TIMEOUT; + /* All timestamps before exptime should be considered expired. */ + exptime = time (NULL); + if (exptime > INACTIVITY_TIMEOUT) + exptime -= INACTIVITY_TIMEOUT; /* Note that there is no need to lock the list because we always add entries at the head (with a pending event status) and @@ -322,8 +331,7 @@ ldap_wrapper_thread (void *dummy) for (ctx = wrapper_list; ctx; ctx = ctx->next) { /* Check whether there is any logging to be done. */ - if (nfds && ctx->log_fd != -1 - && pth_event_status (ctx->log_ev) == PTH_STATUS_OCCURRED) + if (nfds && ctx->log_fd != -1 && FD_ISSET (ctx->log_fd, &read_fdset)) { if (read_log_data (ctx)) any_action = 1; @@ -368,7 +376,7 @@ ldap_wrapper_thread (void *dummy) /* Check whether we should terminate the process. */ if (ctx->pid != (pid_t)(-1) - && ctx->stamp != (time_t)(-1) && ctx->stamp < current_time) + && ctx->stamp != (time_t)(-1) && ctx->stamp < exptime) { gnupg_kill_process (ctx->pid); ctx->stamp = (time_t)(-1); @@ -376,7 +384,7 @@ ldap_wrapper_thread (void *dummy) (int)ctx->pid); /* We need to close the log fd because the cleanup loop waits for it. */ - SAFE_PTH_CLOSE (ctx->log_fd); + SAFE_CLOSE (ctx->log_fd); any_action = 1; } } @@ -426,24 +434,26 @@ void ldap_wrapper_launch_thread (void) { static int done; - pth_attr_t tattr; + npth_attr_t tattr; + npth_t thread; + int err; if (done) return; done = 1; - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper"); + npth_attr_init (&tattr); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); - if (!pth_spawn (tattr, ldap_wrapper_thread, NULL)) + err = npth_create (&thread, &tattr, ldap_wrapper_thread, NULL); + if (err) { log_error (_("error spawning ldap wrapper reaper thread: %s\n"), - strerror (errno) ); + strerror (err) ); dirmngr_exit (1); } - pth_attr_destroy (tattr); + npth_setname_np (thread, "ldap-reaper"); + npth_attr_destroy (&tattr); } @@ -456,8 +466,9 @@ void ldap_wrapper_wait_connections () { shutting_down = 1; + /* FIXME: This is a busy wait. */ while (wrapper_list) - pth_yield (NULL); + npth_yield (); } @@ -482,7 +493,7 @@ ldap_wrapper_release_context (ksba_reader_t reader) ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0); ctx->reader = NULL; - SAFE_PTH_CLOSE (ctx->fd); + SAFE_CLOSE (ctx->fd); if (ctx->ctrl) { ctx->ctrl->refcount--; @@ -515,6 +526,7 @@ ldap_wrapper_connection_cleanup (ctrl_t ctrl) } } + /* This is the callback used by the ldap wrapper to feed the ksba reader with the wrappers stdout. See the description of ksba_reader_set_cb for details. */ @@ -523,6 +535,13 @@ reader_callback (void *cb_value, char *buffer, size_t count, size_t *nread) { struct wrapper_context_s *ctx = cb_value; size_t nleft = count; + int nfds; + struct timespec abstime; + struct timespec curtime; + struct timespec timeout; + int saved_errno; + fd_set fdset, read_fdset; + int ret; /* FIXME: We might want to add some internal buffering because the ksba code does not do any buffering for itself (because a ksba @@ -542,57 +561,73 @@ reader_callback (void *cb_value, char *buffer, size_t count, size_t *nread) return -1; } + FD_ZERO (&fdset); + FD_SET (ctx->fd, &fdset); + nfds = ctx->fd + 1; + + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + while (nleft > 0) { int n; - pth_event_t evt; gpg_error_t err; - evt = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0)); - n = pth_read_ev (ctx->fd, buffer, nleft, evt); - if (n < 0 && evt && pth_event_occurred (evt)) - { - n = 0; - err = dirmngr_tick (ctx->ctrl); + npth_clock_gettime (&curtime); + if (!(npth_timercmp (&curtime, &abstime, <))) + { + err = dirmngr_tick (ctx->ctrl); if (err) { ctx->fd_error = err; - SAFE_PTH_CLOSE (ctx->fd); - if (evt) - pth_event_free (evt, PTH_FREE_THIS); + SAFE_CLOSE (ctx->fd); return -1; } + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + } + npth_timersub (&abstime, &curtime, &timeout); + read_fdset = fdset; + ret = npth_pselect (nfds, &read_fdset, NULL, NULL, &timeout, NULL); + saved_errno = errno; + + if (ret == -1 && saved_errno != EINTR) + { + ctx->fd_error = gpg_error_from_errno (errno); + SAFE_CLOSE (ctx->fd); + return -1; } - else if (n < 0) + if (ret <= 0) + /* Timeout. Will be handled when calculating the next timeout. */ + continue; + + /* This should not block now that select returned with a file + descriptor. So it shouldn't be necessary to use npth_read + (and it is slightly dangerous in the sense that a concurrent + thread might (accidentially?) change the status of ctx->fd + before we read. FIXME: Set ctx->fd to nonblocking? */ + n = read (ctx->fd, buffer, nleft); + if (n < 0) { ctx->fd_error = gpg_error_from_errno (errno); - SAFE_PTH_CLOSE (ctx->fd); - if (evt) - pth_event_free (evt, PTH_FREE_THIS); + SAFE_CLOSE (ctx->fd); return -1; } else if (!n) { if (nleft == count) - { - if (evt) - pth_event_free (evt, PTH_FREE_THIS); - return -1; /* EOF. */ - } + return -1; /* EOF. */ break; } nleft -= n; buffer += n; - if (evt) - pth_event_free (evt, PTH_FREE_THIS); if (n > 0 && ctx->stamp != (time_t)(-1)) ctx->stamp = time (NULL); } *nread = count - nleft; return 0; - } /* Fork and exec the LDAP wrapper and returns a new libksba reader @@ -702,12 +737,6 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[]) ctx->printable_pid = (int) pid; ctx->fd = outpipe[0]; ctx->log_fd = errpipe[0]; - ctx->log_ev = pth_event (PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, ctx->log_fd); - if (! ctx->log_ev) - { - xfree (ctx); - return gpg_error_from_syserror (); - } ctx->ctrl = ctrl; ctrl->refcount++; ctx->stamp = time (NULL); diff --git a/dirmngr/ldap.c b/dirmngr/ldap.c index 638348b5b..13b3c8883 100644 --- a/dirmngr/ldap.c +++ b/dirmngr/ldap.c @@ -28,7 +28,7 @@ #include <unistd.h> #include <fcntl.h> #include <time.h> -#include <pth.h> +#include <npth.h> #include "dirmngr.h" #include "exechelp.h" |