From 3484457fbc078319e2ee5018acd08c5e490df3cf Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Tue, 3 Jan 2012 22:12:37 +0100 Subject: [PATCH] Port to npth. * 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. --- agent/Makefile.am | 4 +- agent/cache.c | 52 ++++--- agent/call-pinentry.c | 108 ++++++------- agent/call-scd.c | 64 +++----- agent/findkey.c | 4 +- agent/gpg-agent.c | 312 ++++++++++++++------------------------ agent/trustlist.c | 24 ++- common/Makefile.am | 10 +- common/estream.c | 29 ++-- common/exechelp-posix.c | 36 ++--- common/exechelp-w32.c | 10 +- common/exechelp-w32ce.c | 20 +-- common/http.c | 22 +-- common/init.c | 14 +- common/sysutils.c | 12 +- configure.ac | 49 +++--- dirmngr/Makefile.am | 4 +- dirmngr/certcache.c | 38 +++-- dirmngr/crlfetch.c | 4 +- dirmngr/dirmngr.c | 227 +++++++++------------------ dirmngr/dirmngr_ldap.c | 36 ++--- dirmngr/ldap-wrapper-ce.c | 218 +++++++++++++++++++------- dirmngr/ldap-wrapper.c | 223 +++++++++++++++------------ dirmngr/ldap.c | 2 +- g13/Makefile.am | 4 +- g13/call-gpg.c | 138 ++++++++--------- g13/g13.c | 181 +++++++++++----------- g13/runner.c | 29 ++-- m4/npth.m4 | 89 +++++++++++ scd/Makefile.am | 6 +- scd/apdu.c | 73 +++++---- scd/app.c | 49 +++--- scd/ccid-driver.c | 8 +- scd/command.c | 40 +++-- scd/scdaemon.c | 228 +++++++++++----------------- tools/Makefile.am | 4 +- 36 files changed, 1181 insertions(+), 1190 deletions(-) create mode 100644 m4/npth.m4 diff --git a/agent/Makefile.am b/agent/Makefile.am index 00b7d43c9..c9fa9c7e8 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -72,9 +72,9 @@ gpg_agent_res_deps = #endif -gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS) +gpg_agent_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) gpg_agent_LDADD = $(commonpth_libs) \ - $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \ + $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ $(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) gpg_agent_LDFLAGS = $(extra_bin_ldflags) $(gpg_agent_res_ldflags) gpg_agent_DEPENDENCIES = $(gpg_agent_res_deps) diff --git a/agent/cache.c b/agent/cache.c index 9c20469d2..9b90d93f4 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "agent.h" @@ -33,7 +33,7 @@ /* A mutex used to protect the encryption. This is required because we use one context to do all encryption and decryption. */ -static pth_mutex_t encryption_lock; +static npth_mutex_t encryption_lock; /* The encryption context. This is the only place where the encryption key for all cached entries is available. It would be nice to keep this (or just the key) in some hardware device, for example @@ -71,11 +71,12 @@ static ITEM thecache; void initialize_module_cache (void) { - if (!pth_mutex_init (&encryption_lock)) - { - gpg_error_t err = gpg_error_from_syserror (); - log_fatal ("error initializing cache module: %s\n", gpg_strerror (err)); - } + int err; + + err = npth_mutex_init (&encryption_lock, NULL); + + if (err) + log_fatal ("error initializing cache module: %s\n", strerror (err)); } @@ -98,12 +99,14 @@ init_encryption (void) { gpg_error_t err; void *key; + int res; if (encryption_handle) return 0; /* Shortcut - Already initialized. */ - if (!pth_mutex_acquire (&encryption_lock, 0, NULL)) - log_fatal ("failed to acquire cache encryption mutex\n"); + res = npth_mutex_lock (&encryption_lock); + if (res) + log_fatal ("failed to acquire cache encryption mutex: %s\n", strerror (res)); err = gcry_cipher_open (&encryption_handle, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, GCRY_CIPHER_SECURE); @@ -127,8 +130,9 @@ init_encryption (void) log_error ("error initializing cache encryption context: %s\n", gpg_strerror (err)); - if (!pth_mutex_release (&encryption_lock)) - log_fatal ("failed to release cache encryption mutex\n"); + res = npth_mutex_unlock (&encryption_lock); + if (res) + log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res)); return err? gpg_error (GPG_ERR_NOT_INITIALIZED) : 0; } @@ -148,6 +152,7 @@ new_data (const char *string, struct secret_data_s **r_data) struct secret_data_s *d, *d_enc; size_t length; int total; + int res; *r_data = NULL; @@ -178,13 +183,17 @@ new_data (const char *string, struct secret_data_s **r_data) } d_enc->totallen = total; - if (!pth_mutex_acquire (&encryption_lock, 0, NULL)) - log_fatal ("failed to acquire cache encryption mutex\n"); + res = npth_mutex_lock (&encryption_lock); + if (res) + log_fatal ("failed to acquire cache encryption mutex: %s\n", + strerror (res)); + err = gcry_cipher_encrypt (encryption_handle, d_enc->data, total, d->data, total - 8); xfree (d); - if (!pth_mutex_release (&encryption_lock)) - log_fatal ("failed to release cache encryption mutex\n"); + res = npth_mutex_unlock (&encryption_lock); + if (res) + log_fatal ("failed to release cache encryption mutex: %s\n", strerror (res)); if (err) { xfree (d_enc); @@ -378,6 +387,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode) gpg_error_t err; ITEM r; char *value = NULL; + int res; if (cache_mode == CACHE_MODE_IGNORE) return NULL; @@ -405,13 +415,17 @@ agent_get_cache (const char *key, cache_mode_t cache_mode) err = gpg_error_from_syserror (); else { - if (!pth_mutex_acquire (&encryption_lock, 0, NULL)) - log_fatal ("failed to acquire cache encryption mutex\n"); + res = npth_mutex_lock (&encryption_lock); + if (res) + log_fatal ("failed to acquire cache encryption mutex: %s\n", + strerror (res)); err = gcry_cipher_decrypt (encryption_handle, value, r->pw->totallen - 8, r->pw->data, r->pw->totallen); - if (!pth_mutex_release (&encryption_lock)) - log_fatal ("failed to release cache encryption mutex\n"); + res = npth_mutex_unlock (&encryption_lock); + if (res) + log_fatal ("failed to release cache encryption mutex: %s\n", + strerror (res)); } if (err) { diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 36093bb8b..34ab3840e 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -32,7 +32,7 @@ # include # include #endif -#include +#include #include "agent.h" #include @@ -62,10 +62,10 @@ static assuan_context_t entry_ctx; static ctrl_t entry_owner; /* A mutex used to serialize access to the pinentry. */ -static pth_mutex_t entry_lock; +static npth_mutex_t entry_lock; /* The thread ID of the popup working thread. */ -static pth_t popup_tid; +static npth_t popup_tid; /* A flag used in communication between the popup working thread and its stop function. */ @@ -95,39 +95,19 @@ initialize_module_call_pinentry (void) if (!initialized) { - if (pth_mutex_init (&entry_lock)) + if (npth_mutex_init (&entry_lock, NULL)) initialized = 1; } } -static void -dump_mutex_state (pth_mutex_t *m) -{ -#ifdef _W32_PTH_H - (void)m; - log_printf ("unknown under W32"); -#else - if (!(m->mx_state & PTH_MUTEX_INITIALIZED)) - log_printf ("not_initialized"); - else if (!(m->mx_state & PTH_MUTEX_LOCKED)) - log_printf ("not_locked"); - else - log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count); -#endif -} - - /* This function may be called to print infromation pertaining to the current state of this module to the log. */ void agent_query_dump_state (void) { - log_info ("agent_query_dump_state: entry_lock="); - dump_mutex_state (&entry_lock); - log_printf ("\n"); - log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n", + log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%lx\n", entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid); } @@ -151,13 +131,15 @@ static int unlock_pinentry (int rc) { assuan_context_t ctx = entry_ctx; + int err; entry_ctx = NULL; - if (!pth_mutex_release (&entry_lock)) + err = npth_mutex_unlock (&entry_lock); + if (err) { - log_error ("failed to release the entry lock\n"); + log_error ("failed to release the entry lock: %s\n", strerror (err)); if (!rc) - rc = gpg_error (GPG_ERR_INTERNAL); + rc = gpg_error_from_errno (err); } assuan_release (ctx); return rc; @@ -222,30 +204,31 @@ getinfo_pid_cb (void *opaque, const void *buffer, size_t length) static int start_pinentry (ctrl_t ctrl) { - int rc; + int rc = 0; const char *pgmname; assuan_context_t ctx; const char *argv[5]; int no_close_list[3]; int i; - pth_event_t evt; const char *tmpstr; unsigned long pinentry_pid; const char *value; + struct timespec abstime; + int err; - evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0)); - if (!pth_mutex_acquire (&entry_lock, 0, evt)) + npth_clock_gettime (&abstime); + abstime.tv_sec += LOCK_TIMEOUT; + err = npth_mutex_timedlock (&entry_lock, &abstime); + if (err) { - if (pth_event_occurred (evt)) - rc = gpg_error (GPG_ERR_TIMEOUT); + if (err == ETIMEDOUT) + rc = gpg_error (GPG_ERR_TIMEOUT); else - rc = gpg_error (GPG_ERR_INTERNAL); - pth_event_free (evt, PTH_FREE_THIS); + rc = gpg_error_from_errno (rc); log_error (_("failed to acquire the pinentry lock: %s\n"), gpg_strerror (rc)); return rc; } - pth_event_free (evt, PTH_FREE_THIS); entry_owner = ctrl; @@ -484,33 +467,37 @@ start_pinentry (ctrl_t ctrl) int pinentry_active_p (ctrl_t ctrl, int waitseconds) { + int err; (void)ctrl; if (waitseconds > 0) { - pth_event_t evt; + struct timespec abstime; int rc; - evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0)); - if (!pth_mutex_acquire (&entry_lock, 0, evt)) + npth_clock_gettime (&abstime); + abstime.tv_sec += waitseconds; + err = npth_mutex_timedlock (&entry_lock, &abstime); + if (err) { - if (pth_event_occurred (evt)) + if (err == ETIMEDOUT) rc = gpg_error (GPG_ERR_TIMEOUT); else rc = gpg_error (GPG_ERR_INTERNAL); - pth_event_free (evt, PTH_FREE_THIS); return rc; } - pth_event_free (evt, PTH_FREE_THIS); } else { - if (!pth_mutex_acquire (&entry_lock, 1, NULL)) + err = npth_mutex_trylock (&entry_lock); + if (err) return gpg_error (GPG_ERR_LOCKED); } - if (!pth_mutex_release (&entry_lock)) - log_error ("failed to release the entry lock at %d\n", __LINE__); + err = npth_mutex_unlock (&entry_lock); + if (err) + log_error ("failed to release the entry lock at %d: %s\n", __LINE__, + strerror (errno)); return 0; } @@ -1185,7 +1172,8 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) { int rc; char line[ASSUAN_LINELENGTH]; - pth_attr_t tattr; + npth_attr_t tattr; + int err; if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) return gpg_error (GPG_ERR_CANCELED); @@ -1212,22 +1200,22 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) return unlock_pinentry (rc); } - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message"); + err = npth_attr_init (&tattr); + if (err) + return unlock_pinentry (gpg_error_from_errno (err)); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); popup_finished = 0; - popup_tid = pth_spawn (tattr, popup_message_thread, NULL); - if (!popup_tid) + err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL); + npth_attr_destroy (&tattr); + if (err) { - rc = gpg_error_from_syserror (); + rc = gpg_error_from_errno (err); log_error ("error spawning popup message handler: %s\n", - strerror (errno) ); - pth_attr_destroy (tattr); + strerror (err) ); return unlock_pinentry (rc); } - pth_attr_destroy (tattr); + npth_setname_np (popup_tid, "popup-message"); return 0; } @@ -1277,11 +1265,13 @@ agent_popup_message_stop (ctrl_t ctrl) #endif /* Now wait for the thread to terminate. */ - rc = pth_join (popup_tid, NULL); + rc = npth_join (popup_tid, NULL); if (!rc) log_debug ("agent_popup_message_stop: pth_join failed: %s\n", strerror (errno)); - popup_tid = NULL; + /* Thread IDs are opaque, but we try our best here by resetting it + to the same content that a static global variable has. */ + memset (&popup_tid, '\0', sizeof (popup_tid)); entry_owner = NULL; /* Now we can close the connection. */ diff --git a/agent/call-scd.c b/agent/call-scd.c index 9a6884bd2..ccdb637d4 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -34,7 +34,7 @@ #ifndef HAVE_W32_SYSTEM #include #endif -#include +#include #include "agent.h" #include @@ -93,7 +93,7 @@ struct inq_needpin_s static struct scd_local_s *scd_local_list; /* A Mutex used inside the start_scd function. */ -static pth_mutex_t start_scd_lock; +static npth_mutex_t start_scd_lock; /* A malloced string with the name of the socket to be used for additional connections. May be NULL if not provided by @@ -120,47 +120,29 @@ static gpg_error_t membuf_data_cb (void *opaque, /* This function must be called once to initialize this module. This has to be done before a second thread is spawned. We can't do the - static initialization because Pth emulation code might not be able + static initialization because NPth emulation code might not be able to do a static init; in particular, it is not possible for W32. */ void initialize_module_call_scd (void) { static int initialized; + int err; if (!initialized) { - if (!pth_mutex_init (&start_scd_lock)) - log_fatal ("error initializing mutex: %s\n", strerror (errno)); + err = npth_mutex_init (&start_scd_lock, NULL); + if (err) + log_fatal ("error initializing mutex: %s\n", strerror (err)); initialized = 1; } } -static void -dump_mutex_state (pth_mutex_t *m) -{ -#ifdef _W32_PTH_H - (void)m; - log_printf ("unknown under W32"); -#else - if (!(m->mx_state & PTH_MUTEX_INITIALIZED)) - log_printf ("not_initialized"); - else if (!(m->mx_state & PTH_MUTEX_LOCKED)) - log_printf ("not_locked"); - else - log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count); -#endif -} - - /* This function may be called to print infromation pertaining to the current state of this module to the log. */ void agent_scd_dump_state (void) { - log_info ("agent_scd_dump_state: scd_lock="); - dump_mutex_state (&start_scd_lock); - log_printf ("\n"); log_info ("agent_scd_dump_state: primary_scd_ctx=%p pid=%ld reusable=%d\n", primary_scd_ctx, (long)assuan_get_pid (primary_scd_ctx), @@ -253,10 +235,11 @@ start_scd (ctrl_t ctrl) /* We need to protect the following code. */ - if (!pth_mutex_acquire (&start_scd_lock, 0, NULL)) + rc = npth_mutex_lock (&start_scd_lock); + if (rc) { log_error ("failed to acquire the start_scd lock: %s\n", - strerror (errno)); + strerror (rc)); return gpg_error (GPG_ERR_INTERNAL); } @@ -420,8 +403,9 @@ start_scd (ctrl_t ctrl) { ctrl->scd_local->ctx = ctx; } - if (!pth_mutex_release (&start_scd_lock)) - log_error ("failed to release the start_scd lock: %s\n", strerror (errno)); + rc = npth_mutex_unlock (&start_scd_lock); + if (rc) + log_error ("failed to release the start_scd lock: %s\n", strerror (rc)); return err; } @@ -440,35 +424,36 @@ agent_scd_check_running (void) void agent_scd_check_aliveness (void) { - pth_event_t evt; pid_t pid; #ifdef HAVE_W32_SYSTEM DWORD rc; #else int rc; #endif + struct timespec abstime; + int err; if (!primary_scd_ctx) return; /* No scdaemon running. */ /* This is not a critical function so we use a short timeout while acquiring the lock. */ - evt = pth_event (PTH_EVENT_TIME, pth_timeout (1, 0)); - if (!pth_mutex_acquire (&start_scd_lock, 0, evt)) + npth_clock_gettime (&abstime); + abstime.tv_sec += 1; + err = npth_mutex_timedlock (&start_scd_lock, &abstime); + if (err) { - if (pth_event_occurred (evt)) + if (err == ETIMEDOUT) { if (opt.verbose > 1) log_info ("failed to acquire the start_scd lock while" - " doing an aliveness check: %s\n", "timeout"); + " doing an aliveness check: %s\n", strerror (err)); } else log_error ("failed to acquire the start_scd lock while" - " doing an aliveness check: %s\n", strerror (errno)); - pth_event_free (evt, PTH_FREE_THIS); + " doing an aliveness check: %s\n", strerror (err)); return; } - pth_event_free (evt, PTH_FREE_THIS); if (primary_scd_ctx) { @@ -513,9 +498,10 @@ agent_scd_check_aliveness (void) } } - if (!pth_mutex_release (&start_scd_lock)) + err = npth_mutex_unlock (&start_scd_lock); + if (err) log_error ("failed to release the start_scd lock while" - " doing the aliveness check: %s\n", strerror (errno)); + " doing the aliveness check: %s\n", strerror (err)); } diff --git a/agent/findkey.c b/agent/findkey.c index 11b3cca4d..a03d0c423 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -29,7 +29,7 @@ #include #include #include -#include /* (we use pth_sleep) */ +#include /* (we use pth_sleep) */ #include "agent.h" #include "i18n.h" @@ -382,7 +382,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, { /* We need to give the other thread a chance to actually put it into the cache. */ - pth_sleep (1); + npth_sleep (1); goto retry; } /* Timeout - better call pinentry now the plain way. */ diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index c264ba3c3..d6c4f3463 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -38,7 +38,7 @@ #ifdef HAVE_SIGNAL_H # include #endif -#include +#include #define JNLIB_NEED_LOG_LOGV #define JNLIB_NEED_AFLOCAL @@ -268,6 +268,9 @@ static char *current_logfile; watched. */ static pid_t parent_pid = (pid_t)(-1); +/* Number of active connections. */ +static int active_connections; + /* Local prototypes. @@ -287,29 +290,7 @@ static void check_own_socket (void); static int check_for_running_agent (int silent, int mode); /* Pth wrapper function definitions. */ -ASSUAN_SYSTEM_PTH_IMPL; - -#if defined(GCRY_THREAD_OPTION_VERSION) && (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 - +ASSUAN_SYSTEM_NPTH_IMPL; /* @@ -624,19 +605,7 @@ 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; - err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); - if (err) - { - log_fatal ("can't register GNU Pth with Libgcrypt: %s\n", - gpg_strerror (err)); - } -#endif - + npth_init (); /* Check that the libraries are suitable. Do it here because the option parsing may need services of the library. */ @@ -651,7 +620,7 @@ main (int argc, char **argv ) malloc_hooks.free = gcry_free; assuan_set_malloc_hooks (&malloc_hooks); 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); @@ -1091,19 +1060,9 @@ main (int argc, char **argv ) /* Close the socket FD. */ close (fd); - /* Note that we used a standard fork so that Pth runs in - both the parent and the child. The pth_fork would - terminate Pth in the child but that is not the way we - want it. Thus we use a plain fork and terminate Pth here - in the parent. The pth_kill may or may not work reliable - but it should not harm to call it. Because Pth fiddles - with the signal mask the signal mask might not be correct - right now and thus we restore it. That is not strictly - necessary but some programs falsely assume a cleared - signal mask. */ -#warning need to do something about pth_kill - see bug#1320 - if ( !pth_kill () ) - log_error ("pth_kill failed in forked process\n"); + /* The signal mask might not be correct right now and thus + we restore it. That is not strictly necessary but some + programs falsely assume a cleared signal mask. */ #ifdef HAVE_SIGPROCMASK if (startup_signal_mask_valid) @@ -1432,9 +1391,9 @@ get_agent_ssh_socket_name (void) void * get_agent_scd_notify_event (void) { - static HANDLE the_event; + static HANDLE the_event = INVALID_HANDLE_VALUE; - if (!the_event) + if (the_event == INVALID_HANDLE_VALUE) { HANDLE h, h2; SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE}; @@ -1758,6 +1717,7 @@ agent_sigusr2_action (void) } +#ifndef HAVE_W32_SYSTEM /* The signal handler for this program. It is expected to be run in its own trhead and not in the context of a signal handler. */ static void @@ -1765,7 +1725,6 @@ handle_signal (int signo) { switch (signo) { -#ifndef HAVE_W32_SYSTEM case SIGHUP: agent_sighup_action (); break; @@ -1787,8 +1746,8 @@ handle_signal (int signo) if (!shutdown_pending) log_info ("SIGTERM received - shutting down ...\n"); else - log_info ("SIGTERM received - still %ld running threads\n", - pth_ctrl( PTH_CTRL_GETTHREADS )); + log_info ("SIGTERM received - still %i open connections\n", + active_connections); shutdown_pending++; if (shutdown_pending > 2) { @@ -1805,12 +1764,12 @@ handle_signal (int signo) cleanup (); agent_exit (0); break; -#endif + default: log_info ("signal %d received - no action defined\n", signo); } } - +#endif /* Check the nonce on a new connection. This is a NOP unless we we are using our Unix domain socket emulation under Windows. */ @@ -1838,19 +1797,20 @@ start_connection_thread (void *arg) if (check_nonce (ctrl, &socket_nonce)) { - log_error ("handler 0x%lx nonce check FAILED\n", pth_thread_id ()); + log_error ("handler 0x%lx nonce check FAILED\n", + (unsigned long) npth_self()); return NULL; } agent_init_default_ctrl (ctrl); if (opt.verbose) log_info (_("handler 0x%lx for fd %d started\n"), - pth_thread_id (), FD2INT(ctrl->thread_startup.fd)); + (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd)); start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd); if (opt.verbose) log_info (_("handler 0x%lx for fd %d terminated\n"), - pth_thread_id (), FD2INT(ctrl->thread_startup.fd)); + (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd)); agent_deinit_default_ctrl (ctrl); xfree (ctrl); @@ -1870,12 +1830,12 @@ start_connection_thread_ssh (void *arg) agent_init_default_ctrl (ctrl); if (opt.verbose) log_info (_("ssh handler 0x%lx for fd %d started\n"), - pth_thread_id (), FD2INT(ctrl->thread_startup.fd)); + (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd)); start_command_handler_ssh (ctrl, ctrl->thread_startup.fd); if (opt.verbose) log_info (_("ssh handler 0x%lx for fd %d terminated\n"), - pth_thread_id (), FD2INT(ctrl->thread_startup.fd)); + (unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd)); agent_deinit_default_ctrl (ctrl); xfree (ctrl); @@ -1888,59 +1848,46 @@ start_connection_thread_ssh (void *arg) static void handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) { - pth_attr_t tattr; - pth_event_t ev, time_ev; - sigset_t sigs; - int signo; + npth_attr_t tattr; struct sockaddr_un paddr; socklen_t plen; fd_set fdset, read_fdset; int ret; gnupg_fd_t fd; int nfd; + int saved_errno; + struct timespec abstime; + struct timespec curtime; + struct timespec timeout; +#ifdef HAVE_W32_SYSTEM + HANDLE events[2]; + int events_set; +#else + int signo; +#endif - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024); + ret = npth_attr_init(&tattr); + if (ret) + log_fatal ("error allocating thread attributes: %s\n", + gpg_strerror (ret)); + 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); +#ifndef HAVE_W32_SYSTEM + 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 (); #else # ifdef HAVE_W32CE_SYSTEM /* Use a dummy event. */ - sigs = 0; - ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); # else - sigs = 0; - ev = pth_event (PTH_EVENT_HANDLE, get_agent_scd_notify_event ()); - signo = 0; + events[0] = get_agent_scd_notify_event (); + events[1] = INVALID_HANDLE_VALUE; # endif #endif - time_ev = NULL; /* Set a flag to tell call-scd.c that it may enable event notifications. */ @@ -1956,15 +1903,15 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) nfd = FD2INT (listen_fd_ssh); } + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + for (;;) { - /* Make sure that our signals are not blocked. */ - pth_sigmask (SIG_UNBLOCK, &sigs, NULL); - /* Shutdown test. */ if (shutdown_pending) { - if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1) + if (active_connections == 0) break; /* ready */ /* Do not accept new connections but keep on running the @@ -1972,88 +1919,55 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) 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); - } - /* 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; - if (time_ev) - pth_event_concat (ev, time_ev, NULL); - - ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev); - if (time_ev) - pth_event_isolate (time_ev); - - if (ret == -1) + npth_clock_gettime (&curtime); + if (!(npth_timercmp (&curtime, &abstime, <))) { - if (pth_event_occurred (ev) - || (time_ev && pth_event_occurred (time_ev))) - { - if (pth_event_occurred (ev)) - { -#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE) - agent_sigusr2_action (); + /* Timeout. */ + handle_tick (); + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL; + } + npth_timersub (&abstime, &curtime, &timeout); + +#ifndef HAVE_W32_SYSTEM + ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask()); + saved_errno = errno; + + while (npth_sigev_get_pending(&signo)) + handle_signal (signo); #else - handle_signal (signo); + events_set = 0; + ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, events, &events_set); + saved_errno = errno; + + /* This is valid even if npth_eselect returns an error. */ + if (events_set & 1) + agent_sigusr2_action (); #endif - } - 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)) - { -#if defined(HAVE_W32_SYSTEM) && defined(PTH_EVENT_HANDLE) - agent_sigusr2_action (); -#else - handle_signal (signo); -#endif - } - - 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 new threads and because we don't want any - signals (as we are handling them here) to be delivered to a - new thread. Thus 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)) { ctrl_t ctrl; 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)); @@ -2073,20 +1987,18 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) } else { - char threadname[50]; + npth_t thread; - snprintf (threadname, sizeof threadname-1, - "conn fd=%d (gpg)", FD2INT(fd)); - threadname[sizeof threadname -1] = 0; - pth_attr_set (tattr, PTH_ATTR_NAME, threadname); ctrl->thread_startup.fd = fd; - if (!pth_spawn (tattr, start_connection_thread, ctrl)) + ret = npth_create (&thread, &tattr, start_connection_thread, ctrl); + if (ret) { log_error ("error spawning connection handler: %s\n", - strerror (errno) ); + strerror (ret)); assuan_sock_close (fd); xfree (ctrl); } + } fd = GNUPG_INVALID_FD; } @@ -2097,8 +2009,8 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) ctrl_t ctrl; plen = sizeof paddr; - fd = INT2FD(pth_accept (FD2INT(listen_fd_ssh), - (struct sockaddr *)&paddr, &plen)); + fd = INT2FD(npth_accept (FD2INT(listen_fd_ssh), + (struct sockaddr *)&paddr, &plen)); if (fd == GNUPG_INVALID_FD) { log_error ("accept failed for ssh: %s\n", strerror (errno)); @@ -2118,18 +2030,15 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) } else { - char threadname[50]; + npth_t thread; agent_init_default_ctrl (ctrl); - snprintf (threadname, sizeof threadname-1, - "conn fd=%d (ssh)", FD2INT(fd)); - threadname[sizeof threadname -1] = 0; - pth_attr_set (tattr, PTH_ATTR_NAME, threadname); ctrl->thread_startup.fd = fd; - if (!pth_spawn (tattr, start_connection_thread_ssh, ctrl) ) + ret = npth_create (&thread, &tattr, start_connection_thread_ssh, ctrl); + if (ret) { log_error ("error spawning ssh connection handler: %s\n", - strerror (errno) ); + strerror (ret)); assuan_sock_close (fd); xfree (ctrl); } @@ -2138,11 +2047,9 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh) } } - pth_event_free (ev, PTH_FREE_ALL); - if (time_ev) - pth_event_free (time_ev, PTH_FREE_ALL); cleanup (); log_info (_("%s %s stopped\n"), strusage(11), strusage(13)); + npth_attr_destroy (&tattr); } @@ -2234,7 +2141,9 @@ static void check_own_socket (void) { char *sockname; - pth_attr_t tattr; + npth_t thread; + npth_attr_t tattr; + int err; if (!opt.use_standard_socket) return; /* This check makes only sense in standard socket mode. */ @@ -2246,15 +2155,14 @@ check_own_socket (void) if (!sockname) return; /* Out of memory. */ - 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, "check-own-socket"); - - if (!pth_spawn (tattr, check_own_socket_thread, sockname)) - log_error ("error spawning check_own_socket_thread: %s\n", - strerror (errno) ); - pth_attr_destroy (tattr); + err = npth_attr_init (&tattr); + if (err) + return; + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); + err = npth_create (&thread, &tattr, check_own_socket_thread, sockname); + if (err) + log_error ("error spawning check_own_socket_thread: %s\n", strerror (err)); + npth_attr_destroy (&tattr); } diff --git a/agent/trustlist.c b/agent/trustlist.c index 68dd83364..8604d8432 100644 --- a/agent/trustlist.c +++ b/agent/trustlist.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include "agent.h" #include /* fixme: need a way to avoid assuan calls here */ @@ -53,7 +53,7 @@ typedef struct trustitem_s trustitem_t; static trustitem_t *trusttable; static size_t trusttablesize; /* A mutex used to protect the table. */ -static pth_mutex_t trusttable_lock; +static npth_mutex_t trusttable_lock; @@ -81,11 +81,13 @@ void initialize_module_trustlist (void) { static int initialized; + int err; if (!initialized) { - if (!pth_mutex_init (&trusttable_lock)) - log_fatal ("error initializing mutex: %s\n", strerror (errno)); + err = npth_mutex_init (&trusttable_lock, NULL); + if (err) + log_fatal ("error initializing mutex: %s\n", strerror (err)); initialized = 1; } } @@ -96,15 +98,21 @@ initialize_module_trustlist (void) static void lock_trusttable (void) { - if (!pth_mutex_acquire (&trusttable_lock, 0, NULL)) - log_fatal ("failed to acquire mutex in %s\n", __FILE__); + int err; + + err = npth_mutex_lock (&trusttable_lock); + if (err) + log_fatal ("failed to acquire mutex in %s: %s\n", __FILE__, strerror (err)); } static void unlock_trusttable (void) { - if (!pth_mutex_release (&trusttable_lock)) - log_fatal ("failed to release mutex in %s\n", __FILE__); + int err; + + err = npth_mutex_unlock (&trusttable_lock); + if (err) + log_fatal ("failed to release mutex in %s: %s\n", __FILE__, strerror (err)); } diff --git a/common/Makefile.am b/common/Makefile.am index bb996bab7..2ff4ade48 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -106,22 +106,22 @@ else common_sources += exechelp-posix.c endif -# Sources only useful without PTH. -without_pth_sources = \ +# Sources only useful without NPTH. +without_npth_sources = \ get-passphrase.c get-passphrase.h -libcommon_a_SOURCES = $(jnlib_sources) $(common_sources) $(without_pth_sources) +libcommon_a_SOURCES = $(jnlib_sources) $(common_sources) $(without_npth_sources) if USE_DNS_SRV libcommon_a_SOURCES += srv.c endif -libcommon_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) -DWITHOUT_GNU_PTH=1 +libcommon_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) -DWITHOUT_NPTH=1 libcommonpth_a_SOURCES = $(jnlib_sources) $(common_sources) if USE_DNS_SRV libcommonpth_a_SOURCES += srv.c endif -libcommonpth_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS) +libcommonpth_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) if !HAVE_W32CE_SYSTEM libsimple_pwquery_a_SOURCES = \ diff --git a/common/estream.c b/common/estream.c index 6b7bd8b75..81a12428a 100644 --- a/common/estream.c +++ b/common/estream.c @@ -85,13 +85,13 @@ # include /* ERRNO replacement. */ #endif -#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ -# undef HAVE_PTH -# undef USE_GNU_PTH +#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ +# undef HAVE_NPTH +# undef USE_NPTH #endif -#ifdef HAVE_PTH -# include +#ifdef HAVE_NPTH +# include #endif /* This is for the special hack to use estream.c in GnuPG. */ @@ -159,7 +159,7 @@ typedef void (*func_free_t) (void *mem); /* Locking. */ -#ifdef HAVE_PTH +#ifdef HAVE_NPTH typedef pth_mutex_t estream_mutex_t; # define ESTREAM_MUTEX_INITIALIZER PTH_MUTEX_INIT @@ -197,7 +197,7 @@ dummy_mutex_call_int (estream_mutex_t mutex) /* Primitive system I/O. */ -#ifdef HAVE_PTH +#ifdef HAVE_NPTH # define ESTREAM_SYS_READ do_pth_read # define ESTREAM_SYS_WRITE do_pth_write # define ESTREAM_SYS_YIELD() pth_yield (NULL) @@ -450,7 +450,7 @@ do_list_remove (estream_t stream, int with_locked_list) * write, assuming that we do I/O on a plain file where the operation * can't block. */ -#ifdef HAVE_PTH +#ifdef HAVE_NPTH static int do_pth_read (int fd, void *buffer, size_t size) { @@ -476,7 +476,7 @@ do_pth_write (int fd, const void *buffer, size_t size) return pth_write (fd, buffer, size); # endif /* !HAVE_W32_SYSTEM*/ } -#endif /*HAVE_PTH*/ +#endif /*HAVE_NPTH*/ @@ -507,7 +507,7 @@ do_init (void) if (!initialized) { -#ifdef HAVE_PTH +#ifdef HAVE_NPTH if (!pth_init () && errno != EPERM ) return -1; if (pth_mutex_init (&estream_list_lock)) @@ -1033,7 +1033,7 @@ es_func_w32_read (void *cookie, void *buffer, size_t size) { do { -#ifdef HAVE_PTH +#ifdef HAVE_NPTH /* Note: Our pth_read actually uses HANDLE! */ bytes_read = pth_read ((int)w32_cookie->hd, buffer, size); #else @@ -1078,7 +1078,7 @@ es_func_w32_write (void *cookie, const void *buffer, size_t size) { do { -#ifdef HAVE_PTH +#ifdef HAVE_NPTH /* Note: Our pth_write actually uses HANDLE! */ bytes_written = pth_write ((int)w32_cookie->hd, buffer, size); #else @@ -2713,7 +2713,6 @@ es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode) return stream; } - /* This is the same as es_fopenmem but intializes the memory with a copy of (DATA,DATALEN). The stream is initally set to the @@ -2744,10 +2743,6 @@ es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode, es_set_indicators (stream, 0, 0); } } - - if (stream) - stream->intern->func_ioctl = es_func_mem_ioctl; - return stream; } diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c index 5479fe3fc..976d0dde5 100644 --- a/common/exechelp-posix.c +++ b/common/exechelp-posix.c @@ -35,13 +35,13 @@ #include #include -#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ -#undef HAVE_PTH -#undef USE_GNU_PTH +#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ +#undef HAVE_NPTH +#undef USE_NPTH #endif -#ifdef USE_GNU_PTH -#include +#ifdef USE_NPTH +#include #endif #include @@ -388,11 +388,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], } -#ifdef USE_GNU_PTH - *pid = pth_fork? pth_fork () : fork (); -#else *pid = fork (); -#endif if (*pid == (pid_t)(-1)) { err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); @@ -454,11 +450,7 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[], { gpg_error_t err; -#ifdef USE_GNU_PTH - *pid = pth_fork? pth_fork () : fork (); -#else *pid = fork (); -#endif if (*pid == (pid_t)(-1)) { err = gpg_error_from_syserror (); @@ -491,16 +483,12 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode) if (pid == (pid_t)(-1)) return gpg_error (GPG_ERR_INV_VALUE); -#ifdef USE_GNU_PTH - if (pth_waitpid) - i = pth_waitpid (pid, &status, hang? 0:WNOHANG); - else +#ifdef USE_NPTH + i = npth_waitpid (pid, &status, hang? 0:WNOHANG); +#else + while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1) + && errno == EINTR); #endif - { - while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1) - && errno == EINTR) - ; - } if (i == (pid_t)(-1)) { @@ -569,11 +557,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[], if (access (pgmname, X_OK)) return gpg_error_from_syserror (); -#ifdef USE_GNU_PTH - pid = pth_fork? pth_fork () : fork (); -#else pid = fork (); -#endif if (pid == (pid_t)(-1)) { log_error (_("error forking process: %s\n"), strerror (errno)); diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c index a8fbd1587..a25a724a8 100644 --- a/common/exechelp-w32.c +++ b/common/exechelp-w32.c @@ -35,13 +35,13 @@ #include #include -#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ -#undef HAVE_PTH -#undef USE_GNU_PTH +#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ +#undef HAVE_NPTH +#undef USE_NPTH #endif -#ifdef USE_GNU_PTH -#include +#ifdef USE_NPTH +#include #endif #ifdef HAVE_STAT diff --git a/common/exechelp-w32ce.c b/common/exechelp-w32ce.c index 1bc2d6c3a..0583c0b53 100644 --- a/common/exechelp-w32ce.c +++ b/common/exechelp-w32ce.c @@ -35,13 +35,13 @@ #include #include -#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ -#undef HAVE_PTH -#undef USE_GNU_PTH +#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ +#undef HAVE_NPTH +#undef USE_NPTH #endif -#ifdef USE_GNU_PTH -#include +#ifdef USE_NPTH +#include #endif #ifdef HAVE_STAT @@ -73,7 +73,7 @@ #define handle_to_pid(a) ((int)(a)) -#ifdef USE_GNU_PTH +#ifdef USE_NPTH /* The data passed to the feeder_thread. */ struct feeder_thread_parms { @@ -171,9 +171,9 @@ leave: xfree (parm); return NULL; } -#endif /*USE_GNU_PTH*/ +#endif /*USE_NPTH*/ -#ifdef USE_GNU_PTH +#ifdef USE_NPTH static void feeder_onclose_notification (estream_t stream, void *opaque) { @@ -182,7 +182,7 @@ feeder_onclose_notification (estream_t stream, void *opaque) log_debug ("feeder(%p): received onclose note\n", parm->hd); parm->stream_valid = 0; } -#endif /*USE_GNU_PTH*/ +#endif /*USE_NPTH*/ /* Fire up a thread to copy data between STREAM and a pipe's descriptor FD. With DIRECTION set to true the copy takes place @@ -191,7 +191,7 @@ feeder_onclose_notification (estream_t stream, void *opaque) static gpg_error_t start_feeder (estream_t stream, HANDLE hd, int direction) { -#ifdef USE_GNU_PTH +#ifdef USE_NPTH gpg_error_t err; struct feeder_thread_parms *parm; pth_attr_t tattr; diff --git a/common/http.c b/common/http.c index 7df84576f..ac5928bc1 100644 --- a/common/http.c +++ b/common/http.c @@ -59,13 +59,13 @@ # include #endif /*!HAVE_W32_SYSTEM*/ -#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ -# undef HAVE_PTH -# undef USE_GNU_PTH +#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ +# undef HAVE_NPTH +# undef USE_NPTH #endif -#ifdef HAVE_PTH -# include +#ifdef HAVE_NPTH +# include #endif @@ -105,7 +105,7 @@ struct srventry #endif/*!USE_DNS_SRV*/ -#ifdef HAVE_PTH +#ifdef HAVE_NPTH # define my_select(a,b,c,d,e) pth_select ((a), (b), (c), (d), (e)) # define my_connect(a,b,c) pth_connect ((a), (b), (c)) # define my_accept(a,b,c) pth_accept ((a), (b), (c)) @@ -1887,15 +1887,15 @@ write_server (int sock, const char *data, size_t length) nleft = length; while (nleft > 0) { -#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_PTH) +#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_NPTH) nwritten = send (sock, data, nleft, 0); if ( nwritten == SOCKET_ERROR ) { log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ()); return gpg_error (GPG_ERR_NETWORK); } -#else /*!HAVE_W32_SYSTEM || HAVE_PTH*/ -# ifdef HAVE_PTH +#else /*!HAVE_W32_SYSTEM || HAVE_NPTH*/ +# ifdef HAVE_NPTH nwritten = pth_write (sock, data, nleft); # else nwritten = write (sock, data, nleft); @@ -1916,7 +1916,7 @@ write_server (int sock, const char *data, size_t length) log_info ("network write failed: %s\n", strerror (errno)); return gpg_error_from_syserror (); } -#endif /*!HAVE_W32_SYSTEM || HAVE_PTH*/ +#endif /*!HAVE_W32_SYSTEM || HAVE_NPTH*/ nleft -= nwritten; data += nwritten; } @@ -1971,7 +1971,7 @@ cookie_read (void *cookie, void *buffer, size_t size) { do { -#ifdef HAVE_PTH +#ifdef HAVE_NPTH nread = pth_read (c->sock->fd, buffer, size); #elif defined(HAVE_W32_SYSTEM) /* Under Windows we need to use recv for a socket. */ diff --git a/common/init.c b/common/init.c index bcb0cd4ea..f551416c5 100644 --- a/common/init.c +++ b/common/init.c @@ -19,16 +19,16 @@ #include -#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ -#undef HAVE_PTH -#undef USE_GNU_PTH +#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ +#undef HAVE_NPTH +#undef USE_NPTH #endif #ifdef HAVE_W32_SYSTEM #include #endif -#ifdef HAVE_PTH -#include +#ifdef HAVE_NPTH +#include #endif #ifdef HAVE_W32CE_SYSTEM # include /* For _assuan_w32ce_finish_pipe. */ @@ -87,7 +87,7 @@ init_common_subsystems (int *argcp, char ***argvp) places. If we are building with PTH we let pth_init do it. We can't do much on error so we ignore them. An error would anyway later pop up if one of the socket functions is used. */ -# ifdef HAVE_PTH +# ifdef HAVE_NPTH pth_init (); # else { @@ -95,7 +95,7 @@ init_common_subsystems (int *argcp, char ***argvp) WSAStartup (0x202, &wsadat); } -# endif /*!HAVE_PTH*/ +# endif /*!HAVE_NPTH*/ #endif #ifdef HAVE_W32CE_SYSTEM diff --git a/common/sysutils.c b/common/sysutils.c index 648e70fe6..2c16978f5 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -20,9 +20,9 @@ #include -#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ -# undef HAVE_PTH -# undef USE_GNU_PTH +#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */ +# undef HAVE_NPTH +# undef USE_NPTH #endif #include @@ -46,8 +46,8 @@ # define WINVER 0x0500 /* Required for AllowSetForegroundWindow. */ # include #endif -#ifdef HAVE_PTH -# include +#ifdef HAVE_NPTH +# include #endif #include @@ -259,7 +259,7 @@ check_permissions(const char *path,int extension,int checkonly) void gnupg_sleep (unsigned int seconds) { -#ifdef HAVE_PTH +#ifdef HAVE_NPTH /* With Pth we force a regular sleep for seconds == 0 so that also the process will give up its timeslot. */ if (!seconds) diff --git a/configure.ac b/configure.ac index ab847af09..82a2e15cc 100644 --- a/configure.ac +++ b/configure.ac @@ -51,6 +51,9 @@ NEED_LIBASSUAN_VERSION=2.0.3 NEED_KSBA_API=1 NEED_KSBA_VERSION=1.2.0 +NEED_NPTH_API=1 +NEED_NPTH_VERSION=0.0 + PACKAGE=$PACKAGE_NAME PACKAGE_GT=${PACKAGE_NAME}2 @@ -70,7 +73,7 @@ have_gpg_error=no have_libgcrypt=no have_libassuan=no have_ksba=no -have_pth=no +have_npth=no have_libusb=no have_adns=no @@ -505,10 +508,6 @@ AH_BOTTOM([ /* We always include support for the OpenPGP card. */ #define ENABLE_CARD_SUPPORT 1 -/* We explicitly need to disable PTH's soft mapping as Debian - currently enables it by default for no reason. */ -#define PTH_SYSCALL_SOFT 0 - /* We want to use the libgcrypt provided memory allocation for asprintf. */ #define _ESTREAM_PRINTF_REALLOC gcry_realloc @@ -821,22 +820,18 @@ AC_DEFINE_UNQUOTED(SHRED, # Check whether the GNU Pth library is available # Note, that we include a Pth emulation for W32. # -if test "$have_w32_system" = yes; then - GNUPG_PATH_PTH([2.0.4]) -else - GNUPG_PATH_PTH -fi -if test "$have_pth" = "yes"; then - AC_DEFINE(USE_GNU_PTH, 1, - [Defined if the GNU Portable Thread Library should be used]) +AM_PATH_NPTH("$NEED_NPTH_API:$NEED_NPTH_VERSION",have_npth=yes,have_npth=no) +if test "$have_npth" = "yes"; then + AC_DEFINE(USE_NPTH, 1, + [Defined if the New Portable Thread Library should be used]) else AC_MSG_WARN([[ *** *** To support concurrent access to the gpg-agent and the SCdaemon -*** we need the support of the GNU Portable Threads Library. -*** Download it from ftp://ftp.gnu.org/gnu/pth/ +*** we need the support of the New Portable Threads Library. +*** Download it from FIXME *** On a Debian GNU/Linux system you might want to try -*** apt-get install libpth-dev +*** apt-get install libnpth-dev ***]]) fi @@ -1500,7 +1495,7 @@ if test "$have_adns" = "yes"; then fi -missing_pth=no +missing_npth=no if test $have_ksba = no; then build_gpgsm=no build_scdaemon=no @@ -1508,19 +1503,19 @@ fi build_agent_threaded="" if test "$build_agent" = "yes"; then - if test $have_pth = no; then + if test $have_npth = no; then build_agent_threaded="(not multi-threaded)" - missing_pth=yes + missing_npth=yes fi fi build_scdaemon_extra="" if test "$build_scdaemon" = "yes"; then tmp="" - if test $have_pth = no; then + if test $have_npth = no; then build_scdaemon_extra="not multi-threaded" tmp=", " - missing_pth=yes + missing_npth=yes fi if test $have_libusb = no; then build_scdaemon_extra="${tmp}without internal CCID driver" @@ -1652,18 +1647,18 @@ if test "$gnupg_have_ldap" = "no"; then ***]]) fi fi -if test "$missing_pth" = "yes"; then +if test "$missing_npth" = "yes"; then AC_MSG_NOTICE([[ *** *** It is now required to build with support for the -*** GNU Portable Threads Library (Pth). Please install this +*** New Portable Threads Library (NPth). Please install this *** library first. The library is for example available at -*** ftp://ftp.gnu.org/gnu/pth/ +*** FIXME *** On a Debian GNU/Linux system you can install it using -*** apt-get install libpth-dev -*** To build GnuPG for Windows you need to use the W32PTH +*** apt-get install libnpth-dev +*** To build GnuPG for Windows you need to use the W32NPTH *** package; available at: -*** ftp://ftp.g10code.com/g10code/w32pth/ +*** ftp://ftp.g10code.com/g10code/w32npth/ ***]]) die=yes fi 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 #include #include -#include +#include #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 #include -#include +#include #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..43c6803c1 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -40,7 +40,7 @@ #ifdef HAVE_SIGNAL_H # include #endif -#include +#include #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 @@ -1624,13 +1596,13 @@ dirmngr_sighup_action (void) +#ifndef HAVE_W32_SYSTEM /* The signal handler. */ static void handle_signal (int signo) { switch (signo) { -#ifndef HAVE_W32_SYSTEM case SIGHUP: dirmngr_sighup_action (); break; @@ -1665,12 +1637,12 @@ handle_signal (int signo) cleanup (); dirmngr_exit (0); break; -#endif + default: log_info (_("signal %d received - no action defined\n"), signo); } } - +#endif /* This is the worker for the ticker. It is called every few seconds and may only do fast operations. */ @@ -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,32 @@ 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; +#ifndef HAVE_W32_SYSTEM int signo; +#endif 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 +1760,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 +1777,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 +1827,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 #include #ifndef USE_LDAPWRAPPER -# include +# include #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 #include #include -#include +#include #include #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++; - } + nwritten = buffer_put_data (cookie, buffer, size); + size -= nwritten; + src += nwritten; + amount += nwritten; + + if (was_empty) + npth_cond_signal (&cookie->wait_data); } while (size); /* Until done. */ - 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); - } - - 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"); - - if (pth_spawn (tattr, ldap_wrapper_thread, parms)) - parms = NULL; /* Now owned by the thread. */ - else + res = npth_attr_init(&tattr); + if (res) { - err = gpg_error_from_syserror (); - log_error ("error spawning ldap wrapper thread: %s\n", - strerror (errno) ); + err = gpg_error_from_errno (res); + ksba_reader_release (reader); + free_arg_list (parms->arg_list); + es_fclose (parms->outstream); + xfree (parms); + return err; } - pth_attr_destroy (tattr); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); + + res = npth_create (&thread, &tattr, ldap_wrapper_thread, parms); + npth_attr_destroy (&tattr); + if (res) + { + err = gpg_error_from_errno (res); + log_error ("error spawning ldap wrapper thread: %s\n", + strerror (res) ); + } + 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 #include #include -#include +#include #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); + + /* 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; + + if (ret == -1 && saved_errno != EINTR) + { + log_error (_("npth_select failed: %s - waiting 1s\n"), + strerror (saved_errno)); + npth_sleep (1); + continue; } - 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); - } - } + if (ret <= 0) + /* Interrupt or timeout. Will be handled when calculating the + next timeout. */ + continue; - /* 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); - - 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 #include #include -#include +#include #include "dirmngr.h" #include "exechelp.h" diff --git a/g13/Makefile.am b/g13/Makefile.am index b846dcda8..745ec40e6 100644 --- a/g13/Makefile.am +++ b/g13/Makefile.am @@ -26,7 +26,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) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS) +AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) g13_SOURCES = \ g13.c g13.h \ @@ -43,5 +43,5 @@ g13_SOURCES = \ be-truecrypt.c be-truecrypt.h g13_LDADD = $(libcommonpth) ../gl/libgnu.a \ - $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \ + $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) diff --git a/g13/call-gpg.c b/g13/call-gpg.c index c2b1e0c41..93b91d5e7 100644 --- a/g13/call-gpg.c +++ b/g13/call-gpg.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "g13.h" #include @@ -163,7 +163,7 @@ struct writer_thread_parms /* The thread started by start_writer. */ static void * -writer_thread (void *arg) +writer_thread_main (void *arg) { struct writer_thread_parms *parm = arg; const char *buffer = parm->data; @@ -173,7 +173,7 @@ writer_thread (void *arg) { ssize_t nwritten; - nwritten = pth_write (parm->fd, buffer, length < 4096? length:4096); + nwritten = npth_write (parm->fd, buffer, length < 4096? length:4096); if (nwritten < 0) { if (errno == EINTR) @@ -199,14 +199,15 @@ writer_thread (void *arg) finished. */ static gpg_error_t start_writer (int fd, const void *data, size_t datalen, - pth_t *r_tid, gpg_error_t *err_addr) + npth_t *r_thread, gpg_error_t *err_addr) { gpg_error_t err; struct writer_thread_parms *parm; - pth_attr_t tattr; - pth_t tid; + npth_attr_t tattr; + npth_t thread; + int ret; - *r_tid = NULL; + memset (r_thread, '\0', sizeof (*r_thread)); *err_addr = 0; parm = xtrymalloc (sizeof *parm); @@ -217,23 +218,22 @@ start_writer (int fd, const void *data, size_t datalen, parm->datalen = datalen; parm->err_addr = err_addr; - tattr = pth_attr_new (); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "fd-writer"); + npth_attr_init (&tattr); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); - tid = pth_spawn (tattr, writer_thread, parm); - if (!tid) + ret = npth_create (&thread, &tattr, writer_thread_main, parm); + if (ret) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (ret); log_error ("error spawning writer thread: %s\n", gpg_strerror (err)); } else { + npth_setname_np (thread, "fd-writer"); err = 0; - *r_tid = tid; + *r_thread = thread; } - pth_attr_destroy (tattr); + npth_attr_destroy (&tattr); return err; } @@ -251,13 +251,13 @@ struct reader_thread_parms /* The thread started by start_reader. */ static void * -reader_thread (void *arg) +reader_thread_main (void *arg) { struct reader_thread_parms *parm = arg; char buffer[4096]; int nread; - while ( (nread = pth_read (parm->fd, buffer, sizeof buffer)) ) + while ( (nread = npth_read (parm->fd, buffer, sizeof buffer)) ) { if (nread < 0) { @@ -282,14 +282,15 @@ reader_thread (void *arg) is stored at R_TID. After the thread has finished an error from the thread will be stored at ERR_ADDR. */ static gpg_error_t -start_reader (int fd, membuf_t *mb, pth_t *r_tid, gpg_error_t *err_addr) +start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr) { gpg_error_t err; struct reader_thread_parms *parm; - pth_attr_t tattr; - pth_t tid; + npth_attr_t tattr; + npth_t thread; + int ret; - *r_tid = NULL; + memset (r_thread, '\0', sizeof (*r_thread)); *err_addr = 0; parm = xtrymalloc (sizeof *parm); @@ -299,23 +300,22 @@ start_reader (int fd, membuf_t *mb, pth_t *r_tid, gpg_error_t *err_addr) parm->mb = mb; parm->err_addr = err_addr; - tattr = pth_attr_new (); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "fd-reader"); + npth_attr_init (&tattr); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); - tid = pth_spawn (tattr, reader_thread, parm); - if (!tid) + ret = npth_create (&thread, &tattr, reader_thread_main, parm); + if (ret) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (ret); log_error ("error spawning reader thread: %s\n", gpg_strerror (err)); } else { + npth_setname_np (thread, "fd-reader"); err = 0; - *r_tid = tid; + *r_thread = thread; } - pth_attr_destroy (tattr); + npth_attr_destroy (&tattr); return err; } @@ -335,12 +335,13 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, assuan_context_t ctx; int outbound_fds[2] = { -1, -1 }; int inbound_fds[2] = { -1, -1 }; - pth_t writer_tid = NULL; - pth_t reader_tid = NULL; + npth_t writer_thread; + npth_t reader_thread; gpg_error_t writer_err, reader_err; membuf_t reader_mb; char line[ASSUAN_LINELENGTH]; strlist_t sl; + int ret; *r_ciph = NULL; *r_ciphlen = 0; @@ -367,7 +368,7 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, /* Start a writer thread to feed the INPUT command of the server. */ err = start_writer (outbound_fds[1], plain, plainlen, - &writer_tid, &writer_err); + &writer_thread, &writer_err); if (err) return err; outbound_fds[1] = -1; /* The thread owns the FD now. */ @@ -375,7 +376,7 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, /* Start a reader thread to eat from the OUTPUT command of the server. */ err = start_reader (inbound_fds[0], &reader_mb, - &reader_tid, &reader_err); + &reader_thread, &reader_err); if (err) return err; outbound_fds[0] = -1; /* The thread owns the FD now. */ @@ -402,13 +403,15 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, } /* Wait for reader and return the data. */ - if (!pth_join (reader_tid, NULL)) + ret = npth_join (reader_thread, NULL); + if (ret) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (ret); log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err)); goto leave; } - reader_tid = NULL; + /* FIXME: Not really valid, as npth_t is an opaque type. */ + memset (&reader_thread, '\0', sizeof (reader_thread)); if (reader_err) { err = reader_err; @@ -417,13 +420,14 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, } /* Wait for the writer to catch a writer error. */ - if (!pth_join (writer_tid, NULL)) + ret = npth_join (writer_thread, NULL); + if (ret) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (ret); log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err)); goto leave; } - writer_tid = NULL; + memset (&writer_thread, '\0', sizeof (writer_thread)); if (writer_err) { err = writer_err; @@ -442,16 +446,11 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, } leave: - if (reader_tid) - { - pth_cancel (reader_tid); - pth_join (reader_tid, NULL); - } - if (writer_tid) - { - pth_cancel (writer_tid); - pth_join (writer_tid, NULL); - } + /* FIXME: Not valid, as npth_t is an opaque type. */ + if (reader_thread) + npth_detach (reader_thread); + if (writer_thread) + npth_detach (writer_thread); if (outbound_fds[0] != -1) close (outbound_fds[0]); if (outbound_fds[1] != -1) @@ -479,10 +478,11 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen, assuan_context_t ctx; int outbound_fds[2] = { -1, -1 }; int inbound_fds[2] = { -1, -1 }; - pth_t writer_tid = NULL; - pth_t reader_tid = NULL; + npth_t writer_thread; + npth_t reader_thread; gpg_error_t writer_err, reader_err; membuf_t reader_mb; + int ret; *r_plain = NULL; *r_plainlen = 0; @@ -509,7 +509,7 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen, /* Start a writer thread to feed the INPUT command of the server. */ err = start_writer (outbound_fds[1], ciph, ciphlen, - &writer_tid, &writer_err); + &writer_thread, &writer_err); if (err) return err; outbound_fds[1] = -1; /* The thread owns the FD now. */ @@ -517,7 +517,7 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen, /* Start a reader thread to eat from the OUTPUT command of the server. */ err = start_reader (inbound_fds[0], &reader_mb, - &reader_tid, &reader_err); + &reader_thread, &reader_err); if (err) return err; outbound_fds[0] = -1; /* The thread owns the FD now. */ @@ -532,13 +532,14 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen, } /* Wait for reader and return the data. */ - if (!pth_join (reader_tid, NULL)) + ret = npth_join (reader_thread, NULL); + if (ret) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (ret); log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err)); goto leave; } - reader_tid = NULL; + memset (&reader_thread, '\0', sizeof (reader_thread)); if (reader_err) { err = reader_err; @@ -547,13 +548,14 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen, } /* Wait for the writer to catch a writer error. */ - if (!pth_join (writer_tid, NULL)) + ret = npth_join (writer_thread, NULL); + if (ret) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (ret); log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err)); goto leave; } - writer_tid = NULL; + memset (&writer_thread, '\0', sizeof (writer_thread)); if (writer_err) { err = writer_err; @@ -572,16 +574,10 @@ gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen, } leave: - if (reader_tid) - { - pth_cancel (reader_tid); - pth_join (reader_tid, NULL); - } - if (writer_tid) - { - pth_cancel (writer_tid); - pth_join (writer_tid, NULL); - } + if (reader_thread) + npth_detach (reader_thread); + if (writer_thread) + npth_detach (writer_thread); if (outbound_fds[0] != -1) close (outbound_fds[0]); if (outbound_fds[1] != -1) diff --git a/g13/g13.c b/g13/g13.c index 0f7309490..b33ea61ed 100644 --- a/g13/g13.c +++ b/g13/g13.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "g13.h" @@ -188,7 +188,7 @@ static unsigned int debug_value; static int shutdown_pending; /* The thread id of the idle task. */ -static pth_t idle_task_tid; +static npth_t idle_task_thread; @@ -199,26 +199,11 @@ static void emergency_cleanup (void); static void start_idle_task (void); static void join_idle_task (void); + +/* Begin NPth wrapper functions. */ +ASSUAN_SYSTEM_NPTH_IMPL; -/* Begin Pth wrapper functions. */ -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 - -/* End Pth wrapper functions. */ - - static const char * my_strusage( int level ) { @@ -336,7 +321,7 @@ main ( int argc, char **argv) ARGPARSE_ARGS pargs; int orig_argc; char **orig_argv; - gpg_error_t err; + gpg_error_t err = 0; const char *fname; int may_coredump; FILE *configfp = NULL; @@ -368,18 +353,7 @@ 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; - err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); - if (err) - { - log_fatal ("can't register GNU Pth with Libgcrypt: %s\n", - gpg_strerror (err)); - } -#endif + npth_init (); /* Check that the Libgcrypt is suitable. */ if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) ) @@ -444,7 +418,7 @@ main ( int argc, char **argv) /* Prepare libassuan. */ assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT); - assuan_set_system_hooks (ASSUAN_SYSTEM_PTH); + assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH); setup_libassuan_logging (&opt.debug); /* Setup a default control structure for command line mode. */ @@ -795,7 +769,7 @@ g13_init_default_ctrl (struct server_control_s *ctrl) /* This function is called for each signal we catch. It is run in the - main context or the one of a Pth thread and thus it is not + main context or the one of a NPth thread and thus it is not restricted in what it may do. */ static void handle_signal (int signo) @@ -862,29 +836,28 @@ handle_tick (void) static void * idle_task (void *dummy_arg) { - sigset_t sigs; /* The set of signals we want to catch. */ - pth_event_t ev; /* The main event to catch signals. */ - pth_event_t time_ev; /* The time event. */ int signo; /* The number of a raised signal is stored here. */ + int saved_errno; + struct timespec abstime; + struct timespec curtime; + struct timespec timeout; + int ret; (void)dummy_arg; /* Create the event to catch the signals. */ #ifndef HAVE_W32_SYSTEM - sigemptyset (&sigs ); - sigaddset (&sigs, SIGHUP); - sigaddset (&sigs, SIGUSR1); - sigaddset (&sigs, SIGUSR2); - sigaddset (&sigs, SIGINT); - sigaddset (&sigs, SIGTERM); - pth_sigmask (SIG_UNBLOCK, &sigs, NULL); -#else - sigs = 0; + 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 - ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); - /* The time event neds to computed n tghe fly. */ - time_ev = NULL; + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL_SEC; for (;;) { @@ -897,41 +870,43 @@ idle_task (void *dummy_arg) break; /* ready */ } - /* 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; + npth_clock_gettime (&curtime); + if (!(npth_timercmp (&curtime, &abstime, <))) + { + /* Timeout. */ + handle_tick (); + npth_clock_gettime (&abstime); + abstime.tv_sec += TIMERTICK_INTERVAL_SEC; + } + npth_timersub (&abstime, &curtime, &timeout); - nexttick = pth_timeout (TIMERTICK_INTERVAL_SEC, 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); - } +#ifndef HAVE_W32_SYSTEM + ret = npth_pselect (0, NULL, NULL, NULL, &timeout, npth_sigev_sigmask()); + saved_errno = errno; - pth_event_concat (ev, time_ev, NULL); - pth_wait (ev); - pth_event_isolate (time_ev); + while (npth_sigev_get_pending(&signo)) + handle_signal (signo); +#else + ret = npth_eselect (0, NULL, NULL, NULL, &timeout, NULL, NULL); + saved_errno = errno; +#endif - if (pth_event_occurred (ev)) - { - handle_signal (signo); - } + if (ret == -1 && saved_errno != EINTR) + { + log_error (_("npth_pselect failed: %s - waiting 1s\n"), + strerror (saved_errno)); + npth_sleep (1); + continue; + } - if (time_ev && pth_event_occurred (time_ev)) - { - pth_event_free (time_ev, PTH_FREE_ALL); - time_ev = NULL; - handle_tick (); - } + if (ret <= 0) + /* Interrupt or timeout. Will be handled when calculating the + next timeout. */ + continue; + + /* Here one would add processing of file descriptors. */ } - pth_event_free (ev, PTH_FREE_ALL); - if (time_ev) - pth_event_free (time_ev, PTH_FREE_ALL); log_info (_("%s %s stopped\n"), strusage(11), strusage(13)); return NULL; } @@ -941,23 +916,36 @@ idle_task (void *dummy_arg) static void start_idle_task (void) { - pth_attr_t tattr; - pth_t tid; + npth_attr_t tattr; + npth_t thread; + sigset_t sigs; /* The set of signals we want to catch. */ + int err; - tattr = pth_attr_new (); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "idle-task"); +#ifndef HAVE_W32_SYSTEM + /* These signals should always go to the idle task, so they need to + be blocked everywhere else. We assume start_idle_task is called + from the main thread before any other threads are created. */ + sigemptyset (&sigs); + sigaddset (&sigs, SIGHUP); + sigaddset (&sigs, SIGUSR1); + sigaddset (&sigs, SIGUSR2); + sigaddset (&sigs, SIGINT); + sigaddset (&sigs, SIGTERM); + npth_sigmask (SIG_BLOCK, &sigs, NULL); +#endif - tid = pth_spawn (tattr, idle_task, NULL); - if (!tid) + npth_attr_init (&tattr); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); + + err = npth_create (&thread, &tattr, idle_task, NULL); + if (err) { - log_fatal ("error starting idle task: %s\n", - gpg_strerror (gpg_error_from_syserror ())); + log_fatal ("error starting idle task: %s\n", strerror (err)); return; /*NOTREACHED*/ } - idle_task_tid = tid; - pth_attr_destroy (tattr); + npth_setname_np (thread, "idle-task"); + idle_task_thread = thread; + npth_attr_destroy (&tattr); } @@ -965,10 +953,15 @@ start_idle_task (void) static void join_idle_task (void) { - if (idle_task_tid) + int err; + + /* FIXME: This assumes that a valid pthread_t is non-null. That is + not guaranteed. */ + if (idle_task_thread) { - if (!pth_join (idle_task_tid, NULL)) + err = npth_join (idle_task_thread, NULL); + if (err) log_error ("waiting for idle task thread failed: %s\n", - gpg_strerror (gpg_error_from_syserror ())); + strerror (err)); } } diff --git a/g13/runner.c b/g13/runner.c index 7e9c262c3..7680d3d5b 100644 --- a/g13/runner.c +++ b/g13/runner.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "g13.h" #include "i18n.h" @@ -40,7 +40,7 @@ struct runner_s unsigned int identifier; /* The runner identifier. */ int spawned; /* True if runner_spawn has been called. */ - pth_t threadid; /* The TID of the runner thread. */ + npth_t thread; /* The TID of the runner thread. */ runner_t next_running; /* Builds a list of all running threads. */ int canceled; /* Set if a cancel has already been send once. */ @@ -85,7 +85,7 @@ writen (int fd, const void *buf, size_t nbytes) while (nleft > 0) { - nwritten = pth_write (fd, buf, nleft); + nwritten = npth_write (fd, buf, nleft); if (nwritten < 0) { if (errno == EINTR) @@ -408,8 +408,9 @@ gpg_error_t runner_spawn (runner_t runner) { gpg_error_t err; - pth_attr_t tattr; - pth_t tid; + npth_attr_t tattr; + npth_t thread; + int ret; if (check_already_spawned (runner, "runner_spawn")) return gpg_error (GPG_ERR_BUG); @@ -433,26 +434,26 @@ runner_spawn (runner_t runner) runner->in_fd = -1; /* Now owned by status_fp. */ } - 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, runner->name); + npth_attr_init (&tattr); + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); - tid = pth_spawn (tattr, runner_thread, runner); - if (!tid) + ret = npth_create (&thread, &tattr, runner_thread, runner); + if (ret) { - err = gpg_error_from_syserror (); + err = gpg_error_from_errno (ret); log_error ("error spawning runner thread: %s\n", gpg_strerror (err)); return err; } + npth_setname_np (thread, runner->name); + /* The scheduler has not yet kicked in, thus we can safely set the spawned flag and the tid. */ runner->spawned = 1; - runner->threadid = tid; + runner->thread = thread; runner->next_running = running_threads; running_threads = runner; - pth_attr_destroy (tattr); + npth_attr_destroy (&tattr); /* The runner thread is now runnable. */ diff --git a/m4/npth.m4 b/m4/npth.m4 new file mode 100644 index 000000000..5b60e2cec --- /dev/null +++ b/m4/npth.m4 @@ -0,0 +1,89 @@ +# npth.m4 - autoconf macro to detect NPTH. +# Copyright (C) 2002, 2003, 2004, 2011 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. + +AC_DEFUN([_AM_PATH_NPTH_CONFIG], +[ AC_ARG_WITH(npth-prefix, + AC_HELP_STRING([--with-npth-prefix=PFX], + [prefix where NPTH is installed (optional)]), + npth_config_prefix="$withval", npth_config_prefix="") + if test "x$npth_config_prefix" != x ; then + NPTH_CONFIG="$npth_config_prefix/bin/npth-config" + fi + AC_PATH_PROG(NPTH_CONFIG, npth-config, no) + + if test "$NPTH_CONFIG" != "no" ; then + npth_version=`$NPTH_CONFIG --version` + fi + npth_version_major=`echo $npth_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + npth_version_minor=`echo $npth_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` +]) + +dnl AM_PATH_NPTH([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libnpth and define NPTH_CFLAGS and NPTH_LIBS. +dnl +AC_DEFUN([AM_PATH_NPTH], +[ AC_REQUIRE([_AM_PATH_NPTH_CONFIG])dnl + tmp=ifelse([$1], ,1:0.0,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_npth_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_npth_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_npth_api=0 + min_npth_version="$tmp" + fi + + AC_MSG_CHECKING(for NPTH - version >= $min_npth_version) + ok=no + if test "$NPTH_CONFIG" != "no" ; then + req_major=`echo $min_npth_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + req_minor=`echo $min_npth_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + + if test "$npth_version_major" -gt "$req_major"; then + ok=yes + else + if test "$npth_version_major" -eq "$req_major"; then + if test "$npth_version_minor" -ge "$req_minor"; then + ok=yes + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent NPTH, we should also check that the + # API is compatible. + if test "$req_npth_api" -gt 0 ; then + tmp=`$NPTH_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_npth_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + NPTH_CFLAGS=`$NPTH_CONFIG --cflags` + NPTH_LIBS=`$NPTH_CONFIG --libs` + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + NPTH_CFLAGS="" + NPTH_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(NPTH_CFLAGS) + AC_SUBST(NPTH_LIBS) +]) diff --git a/scd/Makefile.am b/scd/Makefile.am index b42e53dff..09aea0e84 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -29,7 +29,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) $(PTH_CFLAGS) + $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) card_apps = app-openpgp.c app-nks.c app-dinsig.c app-p15.c app-geldkarte.c @@ -45,7 +45,7 @@ scdaemon_SOURCES = \ scdaemon_LDADD = $(libcommonpth) ../gl/libgnu.a \ - $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \ + $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ $(LIBUSB_LIBS) $(GPG_ERROR_LIBS) \ $(LIBINTL) $(DL_LIBS) $(NETLIBS) $(LIBICONV) @@ -63,7 +63,7 @@ scdaemon_LDADD = $(libcommonpth) ../gl/libgnu.a \ #sc_copykeys_LDADD = \ # ../jnlib/libjnlib.a ../common/libcommon.a \ # ../common/libsimple-pwquery.a \ -# $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(PTH_LIBS) \ +# $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ # $(LIBUSB_LIBS) \ # -lgpg-error @LIBINTL@ @DL_LIBS@ # diff --git a/scd/apdu.c b/scd/apdu.c index 70c28cd30..064f0d636 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -19,7 +19,7 @@ */ /* NOTE: This module is also used by other software, thus the use of - the macro USE_GNU_PTH is mandatory. For GnuPG this macro is + the macro USE_NPTH is mandatory. For GnuPG this macro is guaranteed to be defined true. */ #include @@ -29,10 +29,10 @@ #include #include #include -#ifdef USE_GNU_PTH +#ifdef USE_NPTH # include # include -# include +# include #endif @@ -67,7 +67,7 @@ /* Due to conflicting use of threading libraries we usually can't link against libpcsclite. Instead we use a wrapper program. */ -#ifdef USE_GNU_PTH +#ifdef USE_NPTH #if !defined(HAVE_W32_SYSTEM) && !defined(__CYGWIN__) #define NEED_PCSC_WRAPPER 1 #endif @@ -144,9 +144,9 @@ struct reader_table_s { not yet been read; i.e. the card is not ready for use. */ unsigned int change_counter; -#ifdef USE_GNU_PTH +#ifdef USE_NPTH int lock_initialized; - pth_mutex_t lock; + npth_mutex_t lock; #endif }; typedef struct reader_table_s *reader_table_t; @@ -352,6 +352,7 @@ static int new_reader_slot (void) { int i, reader = -1; + int err; for (i=0; i < MAX_READER; i++) { @@ -363,17 +364,18 @@ new_reader_slot (void) log_error ("new_reader_slot: out of slots\n"); return -1; } -#ifdef USE_GNU_PTH +#ifdef USE_NPTH if (!reader_table[reader].lock_initialized) { - if (!pth_mutex_init (&reader_table[reader].lock)) + err = npth_mutex_init (&reader_table[reader].lock, NULL); + if (err) { - log_error ("error initializing mutex: %s\n", strerror (errno)); + log_error ("error initializing mutex: %s\n", strerror (err)); return -1; } reader_table[reader].lock_initialized = 1; } -#endif /*USE_GNU_PTH*/ +#endif /*USE_NPTH*/ reader_table[reader].connect_card = NULL; reader_table[reader].disconnect_card = NULL; reader_table[reader].close_reader = NULL; @@ -698,8 +700,8 @@ writen (int fd, const void *buf, size_t nbytes) while (nleft > 0) { -#ifdef USE_GNU_PTH - nwritten = pth_write (fd, buf, nleft); +#ifdef USE_NPTH + nwritten = npth_write (fd, buf, nleft); #else nwritten = write (fd, buf, nleft); #endif @@ -724,11 +726,11 @@ readn (int fd, void *buf, size_t buflen, size_t *nread) while (nleft > 0) { -#ifdef USE_GNU_PTH +#ifdef USE_NPTH # ifdef HAVE_W32_SYSTEM -# error Cannot use pth_read here because it expects a system HANDLE. +# error Cannot use npth_read here because it expects a system HANDLE. # endif - n = pth_read (fd, buf, nleft); + n = npth_read (fd, buf, nleft); #else n = read (fd, buf, nleft); #endif @@ -1874,8 +1876,8 @@ open_pcsc_reader_wrapped (const char *portstr) slotp->pcsc.rsp_fd = rp[0]; /* Wait for the intermediate child to terminate. */ -#ifdef USE_GNU_PTH -#define WAIT pth_waitpid +#ifdef USE_NPTH +#define WAIT npth_waitpid #else #define WAIT waitpid #endif @@ -2117,6 +2119,8 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1, pin_verify, len, result, &resultlen); xfree (pin_verify); if (sw || resultlen < 2) + return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE; + sw = (result[resultlen-2] << 8) | result[resultlen-1]; { log_error ("control_pcsc failed: %d\n", sw); return sw? sw: SW_HOST_INCOMPLETE_CARD_RESPONSE; @@ -2749,38 +2753,47 @@ open_rapdu_reader (int portno, static int lock_slot (int slot) { -#ifdef USE_GNU_PTH - if (!pth_mutex_acquire (&reader_table[slot].lock, 0, NULL)) +#ifdef USE_NPTH + int err; + + err = npth_mutex_lock (&reader_table[slot].lock); + if (err) { - log_error ("failed to acquire apdu lock: %s\n", strerror (errno)); + log_error ("failed to acquire apdu lock: %s\n", strerror (err)); return SW_HOST_LOCKING_FAILED; } -#endif /*USE_GNU_PTH*/ +#endif /*USE_NPTH*/ return 0; } static int trylock_slot (int slot) { -#ifdef USE_GNU_PTH - if (!pth_mutex_acquire (&reader_table[slot].lock, TRUE, NULL)) +#ifdef USE_NPTH + int err; + + err = npth_mutex_trylock (&reader_table[slot].lock); + if (err == EBUSY) + return SW_HOST_BUSY; + else if (err) { - if (errno == EBUSY) - return SW_HOST_BUSY; - log_error ("failed to acquire apdu lock: %s\n", strerror (errno)); + log_error ("failed to acquire apdu lock: %s\n", strerror (err)); return SW_HOST_LOCKING_FAILED; } -#endif /*USE_GNU_PTH*/ +#endif /*USE_NPTH*/ return 0; } static void unlock_slot (int slot) { -#ifdef USE_GNU_PTH - if (!pth_mutex_release (&reader_table[slot].lock)) +#ifdef USE_NPTH + int err; + + err = npth_mutex_unlock (&reader_table[slot].lock); + if (err) log_error ("failed to release apdu lock: %s\n", strerror (errno)); -#endif /*USE_GNU_PTH*/ +#endif /*USE_NPTH*/ } diff --git a/scd/app.c b/scd/app.c index 76dc8b4de..79e3eac0f 100644 --- a/scd/app.c +++ b/scd/app.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "scdaemon.h" #include "app-common.h" @@ -37,7 +37,7 @@ static struct { int initialized; - pth_mutex_t lock; + npth_mutex_t lock; app_t app; /* Application context in use or NULL. */ app_t last_app; /* Last application object used as this slot or NULL. */ } lock_table[10]; @@ -72,30 +72,30 @@ print_progress_line (void *opaque, const char *what, int pc, int cur, int tot) static gpg_error_t lock_reader (int slot, ctrl_t ctrl) { - gpg_error_t err; + int res; if (slot < 0 || slot >= DIM (lock_table)) return gpg_error (slot<0? GPG_ERR_INV_VALUE : GPG_ERR_RESOURCE_LIMIT); if (!lock_table[slot].initialized) { - if (!pth_mutex_init (&lock_table[slot].lock)) + res = npth_mutex_init (&lock_table[slot].lock, NULL); + if (res) { - err = gpg_error_from_syserror (); - log_error ("error initializing mutex: %s\n", strerror (errno)); - return err; + log_error ("error initializing mutex: %s\n", strerror (res)); + return gpg_error_from_errno (res); } lock_table[slot].initialized = 1; lock_table[slot].app = NULL; lock_table[slot].last_app = NULL; } - if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL)) + res = npth_mutex_lock (&lock_table[slot].lock); + if (res) { - err = gpg_error_from_syserror (); log_error ("failed to acquire APP lock for slot %d: %s\n", - slot, strerror (errno)); - return err; + slot, strerror (res)); + return gpg_error_from_errno (res); } apdu_set_progress_cb (slot, print_progress_line, ctrl); @@ -107,32 +107,18 @@ lock_reader (int slot, ctrl_t ctrl) static void unlock_reader (int slot) { + int res; + if (slot < 0 || slot >= DIM (lock_table) || !lock_table[slot].initialized) log_bug ("unlock_reader called for invalid slot %d\n", slot); apdu_set_progress_cb (slot, NULL, NULL); - if (!pth_mutex_release (&lock_table[slot].lock)) + res = npth_mutex_unlock (&lock_table[slot].lock); + if (res) log_error ("failed to release APP lock for slot %d: %s\n", - slot, strerror (errno)); -} - - -static void -dump_mutex_state (pth_mutex_t *m) -{ -#ifdef _W32_PTH_H - (void)m; - log_printf ("unknown under W32"); -#else - if (!(m->mx_state & PTH_MUTEX_INITIALIZED)) - log_printf ("not_initialized"); - else if (!(m->mx_state & PTH_MUTEX_LOCKED)) - log_printf ("not_locked"); - else - log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count); -#endif + slot, strerror (res)); } @@ -146,8 +132,7 @@ app_dump_state (void) for (slot=0; slot < DIM (lock_table); slot++) if (lock_table[slot].initialized) { - log_info ("app_dump_state: slot=%d lock=", slot); - dump_mutex_state (&lock_table[slot].lock); + log_info ("app_dump_state: slot=%d", slot); if (lock_table[slot].app) { log_printf (" app=%p", lock_table[slot].app); diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 8e2af6541..8b2ee8f24 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -85,9 +85,9 @@ #include #include #include -#ifdef HAVE_PTH -# include -#endif /*HAVE_PTH*/ +#ifdef HAVE_NPTH +# include +#endif /*HAVE_NPTH*/ #include @@ -328,7 +328,7 @@ set_msg_len (unsigned char *msg, unsigned int length) static void my_sleep (int seconds) { -#ifdef HAVE_PTH +#ifdef HAVE_NPTH /* With Pth we also call the standard sleep(0) so that the process may give up its timeslot. */ if (!seconds) diff --git a/scd/command.c b/scd/command.c index 88f8ec2c9..4c3646c99 100644 --- a/scd/command.c +++ b/scd/command.c @@ -26,8 +26,8 @@ #include #include #include -#ifdef USE_GNU_PTH -# include +#ifdef USE_NPTH +# include #endif #include "scdaemon.h" @@ -156,7 +156,7 @@ static struct server_local_s *locked_session; /* While doing a reset we need to make sure that the ticker does not call scd_update_reader_status_file while we are using it. */ -static pth_mutex_t status_file_update_lock; +static npth_mutex_t status_file_update_lock; /*-- Local prototypes --*/ @@ -173,10 +173,12 @@ void initialize_module_command (void) { static int initialized; + int err; if (!initialized) { - if (pth_mutex_init (&status_file_update_lock)) + err = npth_mutex_init (&status_file_update_lock, NULL); + if (!err) initialized = 1; } } @@ -304,6 +306,7 @@ do_reset (ctrl_t ctrl, int send_reset) { int vrdr = ctrl->server_local->vreader_idx; int slot; + int err; if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_table)))) BUG (); @@ -360,7 +363,8 @@ do_reset (ctrl_t ctrl, int send_reset) try to update the file. Calling update_reader_status_file is required to get hold of the new status of the card in the vreader table. */ - if (!pth_mutex_acquire (&status_file_update_lock, 0, NULL)) + err = npth_mutex_lock (&status_file_update_lock); + if (err) { log_error ("failed to acquire status_file_update lock\n"); ctrl->server_local->vreader_idx = -1; @@ -368,8 +372,10 @@ do_reset (ctrl_t ctrl, int send_reset) } update_reader_status_file (0); /* Update slot status table. */ update_card_removed (vrdr, 0); /* Clear card_removed flag. */ - if (!pth_mutex_release (&status_file_update_lock)) - log_error ("failed to release status_file_update lock\n"); + err = npth_mutex_unlock (&status_file_update_lock); + if (err) + log_error ("failed to release status_file_update lock: %s\n", + strerror (err)); /* Do this last, so that the update_card_removed above does its job. */ ctrl->server_local->vreader_idx = -1; @@ -1597,18 +1603,18 @@ cmd_lock (assuan_context_t ctx, char *line) else locked_session = ctrl->server_local; -#ifdef USE_GNU_PTH +#ifdef USE_NPTH if (rc && has_option (line, "--wait")) { rc = 0; - pth_sleep (1); /* Better implement an event mechanism. However, - for card operations this should be - sufficient. */ + npth_sleep (1); /* Better implement an event mechanism. However, + for card operations this should be + sufficient. */ /* FIXME: Need to check that the connection is still alive. This can be done by issuing status messages. */ goto retry; } -#endif /*USE_GNU_PTH*/ +#endif /*USE_NPTH*/ if (rc) log_error ("cmd_lock failed: %s\n", gpg_strerror (rc)); @@ -2395,9 +2401,13 @@ update_reader_status_file (int set_card_removed_flag) void scd_update_reader_status_file (void) { - if (!pth_mutex_acquire (&status_file_update_lock, 1, NULL)) + int err; + err = npth_mutex_lock (&status_file_update_lock); + if (err) return; /* locked - give up. */ update_reader_status_file (1); - if (!pth_mutex_release (&status_file_update_lock)) - log_error ("failed to release status_file_update lock\n"); + err = npth_mutex_unlock (&status_file_update_lock); + if (err) + log_error ("failed to release status_file_update lock: %s\n", + strerror (err)); } diff --git a/scd/scdaemon.c b/scd/scdaemon.c index e26beba13..e8073b7ee 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -35,7 +35,7 @@ #endif /*HAVE_W32_SYSTEM*/ #include #include -#include +#include #define JNLIB_NEED_LOG_LOGV #define JNLIB_NEED_AFLOCAL @@ -169,7 +169,7 @@ static ARGPARSE_OPTS opts[] = { easy way to block on card status changes it is the best we can do. For PC/SC we could in theory use an extra thread to wait for status changes but that requires a native thread because there is no way - to make the underlying PC/SC card change function block using a Pth + to make the underlying PC/SC card change function block using a Npth mechanism. Given that a native thread could only be used under W32 we don't do that at all. */ #define TIMERTICK_INTERVAL_SEC (0) @@ -206,20 +206,9 @@ static void *start_connection_thread (void *arg); static void handle_connections (int listen_fd); /* Pth wrapper function definitions. */ -ASSUAN_SYSTEM_PTH_IMPL; +ASSUAN_SYSTEM_NPTH_IMPL; -#if defined(GCRY_THREAD_OPTION_VERSION) && (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 +static int active_connections; static char * @@ -280,18 +269,18 @@ my_strusage (int level) static int tid_log_callback (unsigned long *rvalue) { -#ifdef PTH_HAVE_PTH_THREAD_ID - *rvalue = pth_thread_id (); -#else - *rvalue = (unsigned long)pth_self (); -#endif + int len = sizeof (*rvalue); + npth_t thread; + + thread = npth_self (); + if (sizeof (thread) < len) + len = sizeof (thread); + memcpy (rvalue, &thread, len); + return 2; /* Use use hex representation. */ } - - - /* Setup the debugging. With a LEVEL of NULL only the active debug flags are propagated to the subsystems. With LEVEL set, a specific set of debug flags is set; thus overriding all flags already @@ -382,9 +371,6 @@ main (int argc, char **argv ) { ARGPARSE_ARGS pargs; int orig_argc; -#ifdef USE_GCRY_THREAD_CBS - gpg_error_t err; -#endif char **orig_argv; FILE *configfp = NULL; char *configname = NULL; @@ -406,6 +392,8 @@ main (int argc, char **argv ) int allow_coredump = 0; int standard_socket = 0; struct assuan_malloc_hooks malloc_hooks; + int res; + npth_t pipecon_handler; set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); @@ -418,18 +406,7 @@ main (int argc, char **argv ) i18n_init (); init_common_subsystems (&argc, &argv); - - /* Libgcrypt requires us to register the threading model first. - Note that this will also do the pth_init. */ -#ifdef USE_GCRY_THREAD_CBS - gcry_threads_pth.init = fixed_gcry_pth_init; - err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); - if (err) - { - log_fatal ("can't register GNU Pth with Libgcrypt: %s\n", - gpg_strerror (err)); - } -#endif + npth_init (); /* Check that the libraries are suitable. Do it here because the option parsing may need services of the library */ @@ -446,7 +423,7 @@ main (int argc, char **argv ) malloc_hooks.free = gcry_free; assuan_set_malloc_hooks (&malloc_hooks); 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); @@ -712,7 +689,7 @@ main (int argc, char **argv ) { /* This is the simple pipe based server */ ctrl_t ctrl; - pth_attr_t tattr; + npth_attr_t tattr; int fd = -1; #ifndef HAVE_W32_SYSTEM @@ -751,10 +728,14 @@ main (int argc, char **argv ) socket_name, &socket_nonce)); } - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 512*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "pipe-connection"); + res = npth_attr_init (&tattr); + if (res) + { + log_error ("error allocating thread attributes: %s\n", + strerror (res)); + scd_exit (2); + } + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); ctrl = xtrycalloc (1, sizeof *ctrl); if ( !ctrl ) @@ -764,13 +745,16 @@ main (int argc, char **argv ) scd_exit (2); } ctrl->thread_startup.fd = GNUPG_INVALID_FD; - if ( !pth_spawn (tattr, start_connection_thread, ctrl) ) + res = npth_create (&pipecon_handler, &tattr, start_connection_thread, ctrl); + if (res) { log_error ("error spawning pipe connection handler: %s\n", - strerror (errno) ); + strerror (res) ); xfree (ctrl); scd_exit (2); } + npth_setname_np (pipecon_handler, "pipe-connection"); + npth_attr_destroy (&tattr); /* We run handle_connection to wait for the shutdown signal and to run the ticker stuff. */ @@ -981,8 +965,8 @@ handle_signal (int signo) if (!shutdown_pending) log_info ("SIGTERM received - shutting down ...\n"); else - log_info ("SIGTERM received - still %ld running threads\n", - pth_ctrl( PTH_CTRL_GETTHREADS )); + log_info ("SIGTERM received - still %i running threads\n", + active_connections); shutdown_pending++; if (shutdown_pending > 2) { @@ -1176,9 +1160,7 @@ start_connection_thread (void *arg) static void handle_connections (int 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; @@ -1186,25 +1168,24 @@ handle_connections (int listen_fd) int ret; int fd; int nfd; + 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, 512*1024); + ret = npth_attr_init(&tattr); + /* FIXME: Check error. */ + npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); -#ifndef HAVE_W32_SYSTEM /* fixme */ - sigemptyset (&sigs ); - sigaddset (&sigs, SIGHUP); - sigaddset (&sigs, SIGUSR1); - sigaddset (&sigs, SIGUSR2); - sigaddset (&sigs, SIGINT); - sigaddset (&sigs, SIGTERM); - pth_sigmask (SIG_UNBLOCK, &sigs, NULL); - ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); -#else - sigs = 0; - ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); +#ifndef HAVE_W32_SYSTEM + 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; FD_ZERO (&fdset); nfd = 0; @@ -1214,13 +1195,17 @@ handle_connections (int listen_fd) nfd = listen_fd; } + npth_clock_gettime (&curtime); + timeout.tv_sec = TIMERTICK_INTERVAL_SEC; + timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000; + npth_timeradd (&curtime, &timeout, &abstime); + /* We only require abstime here. The others will be reused. */ + for (;;) { - sigset_t oldsigs; - if (shutdown_pending) { - if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1) + if (active_connections == 0) break; /* ready */ /* Do not accept anymore connections but wait for existing @@ -1231,80 +1216,50 @@ handle_connections (int listen_fd) listen_fd = -1; } - /* Create a timeout event if needed. Round it up to the next - microsecond interval to help with power saving. */ - if (!time_ev) - { - pth_time_t nexttick = pth_timeout (TIMERTICK_INTERVAL_SEC, - TIMERTICK_INTERVAL_USEC/2); - if ((nexttick.tv_usec % (TIMERTICK_INTERVAL_USEC/2)) > 10) - { - nexttick.tv_usec = ((nexttick.tv_usec - /(TIMERTICK_INTERVAL_USEC/2)) - + 1) * (TIMERTICK_INTERVAL_USEC/2); - if (nexttick.tv_usec >= 1000000) - { - nexttick.tv_sec++; - nexttick.tv_usec = 0; - } - } - time_ev = pth_event (PTH_EVENT_TIME, nexttick); - } + npth_clock_gettime (&curtime); + if (!(npth_timercmp (&curtime, &abstime, <))) + { + /* Timeout. */ + handle_tick (); + timeout.tv_sec = TIMERTICK_INTERVAL_SEC; + timeout.tv_nsec = TIMERTICK_INTERVAL_USEC * 1000; + npth_timeradd (&curtime, &timeout, &abstime); + } + npth_timersub (&abstime, &curtime, &timeout); /* 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; - if (time_ev) - pth_event_concat (ev, time_ev, NULL); - ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev); - if (time_ev) - pth_event_isolate (time_ev); +#ifndef HAVE_W32_SYSTEM + ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask()); + saved_errno = errno; - if (ret == -1) + 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 && saved_errno != EINTR) { - 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); + 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 new threads and because we don't want any - signals - we are handling here - to be delivered to a new - thread. Thus we need to block those signals. */ - pth_sigmask (SIG_BLOCK, &sigs, &oldsigs); + if (ret <= 0) + /* Timeout. Will be handled when calculating the next timeout. */ + continue; if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset)) { ctrl_t ctrl; plen = sizeof paddr; - fd = pth_accept (listen_fd, (struct sockaddr *)&paddr, &plen); + fd = npth_accept (listen_fd, (struct sockaddr *)&paddr, &plen); if (fd == -1) { log_error ("accept failed: %s\n", strerror (errno)); @@ -1318,30 +1273,27 @@ handle_connections (int listen_fd) else { char threadname[50]; + npth_t thread; snprintf (threadname, sizeof threadname-1, "conn fd=%d", fd); threadname[sizeof threadname -1] = 0; - pth_attr_set (tattr, PTH_ATTR_NAME, threadname); ctrl->thread_startup.fd = INT2FD (fd); - if (!pth_spawn (tattr, start_connection_thread, ctrl)) + ret = npth_create (&thread, &tattr, start_connection_thread, ctrl); + if (ret) { log_error ("error spawning connection handler: %s\n", - strerror (errno) ); + strerror (ret)); xfree (ctrl); close (fd); } + else + npth_setname_np (thread, threadname); } fd = -1; } - - /* Restore the signal mask. */ - pth_sigmask (SIG_SETMASK, &oldsigs, NULL); - } - pth_event_free (ev, PTH_FREE_ALL); - if (time_ev) - pth_event_free (time_ev, PTH_FREE_ALL); cleanup (); log_info (_("%s %s stopped\n"), strusage(11), strusage(13)); + npth_attr_destroy (&tattr); } diff --git a/tools/Makefile.am b/tools/Makefile.am index 66be272aa..9d842748a 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -94,7 +94,7 @@ gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c no-libgcrypt.c # common sucks in gpg-error, will they, nil they (some compilers # do not eliminate the supposed-to-be-unused-inline-functions). gpgconf_LDADD = $(maybe_commonpth_libs) $(opt_libassuan_libs) \ - $(LIBINTL) $(GPG_ERROR_LIBS) $(PTH_LIBS) $(NETLIBS) \ + $(LIBINTL) $(GPG_ERROR_LIBS) $(NPTH_LIBS) $(NETLIBS) \ $(LIBICONV) $(W32SOCKLIBS) gpgconf_LDFLAGS = $(extra_bin_ldflags) @@ -112,7 +112,7 @@ watchgnupg_LDADD = $(NETLIBS) gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c # FIXME: remove PTH_LIBS (why do we need them at all?) gpg_connect_agent_LDADD = ../common/libgpgrl.a $(common_libs) \ - $(LIBASSUAN_LIBS) $(PTH_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ $(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV) if !HAVE_W32CE_SYSTEM