X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=gnupg2.git;a=blobdiff_plain;f=agent%2Fgpg-agent.c;h=121bb0ed4f6a7e8b9d3486c4855e3811776db57e;hp=82c8ae0621a443e604cb785711aaa16925f9e6a4;hb=refs%2Fheads%2F841143-bugfix;hpb=c224dda498a321a715e9f1a5e61c371d289f8657 diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 82c8ae0..121bb0e 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -316,10 +316,10 @@ static int startup_signal_mask_valid; #endif /* Flag to indicate that a shutdown was requested. */ -static int shutdown_pending; +static int shutdown_pending; /* xxx threaded accesses lack locking */ /* Counter for the currently running own socket checks. */ -static int check_own_socket_running; +static int check_own_socket_running; /* xxx threaded accesses lack locking */ /* Flags to indicate that check_own_socket shall not be called. */ static int disable_check_own_socket; @@ -328,7 +328,7 @@ static int disable_check_own_socket; static int is_supervised; /* Flag to inhibit socket removal in cleanup. */ -static int inhibit_socket_removal; +static int inhibit_socket_removal; /* xxx threaded accesses lack locking */ /* It is possible that we are currently running under setuid permissions */ static int maybe_setuid = 1; @@ -382,8 +382,12 @@ static char *current_logfile; watched. */ static pid_t parent_pid = (pid_t)(-1); +/* Record the pid of the main thread, for easier signalling */ +static pid_t main_thread_pid = (pid_t)(-1); + /* Number of active connections. */ -static int active_connections; +static int active_connections_value; +static npth_mutex_t active_connections_lock; /* This object is used to dispatch progress messages from Libgcrypt to * the right thread. Given that we will have at max only a few dozen @@ -1985,11 +1989,49 @@ get_agent_ssh_socket_name (void) } +static void +lock_active_connections (void) +{ + int err; + + err = npth_mutex_lock (&active_connections_lock); + if (err) + log_fatal ("failed to acquire active connection count mutex: %s\n", + strerror (err)); +} + +static void +unlock_active_connections (void) +{ + int err; + + err = npth_mutex_unlock (&active_connections_lock); + if (err) + log_fatal ("failed to release active connection count mutex: %s\n", + strerror (err)); +} + /* Return the number of active connections. */ int get_agent_active_connection_count (void) { - return active_connections; + int value; + + lock_active_connections(); + value = active_connections_value; + unlock_active_connections(); + return value; +} + +/* Increment/decrement the number of active connections. */ +static void +adjust_agent_active_connections (int delta) +{ + lock_active_connections(); + active_connections_value += delta; + if (active_connections_value == 0) + interrupt_main_thread_loop (); + unlock_active_connections(); } @@ -2020,7 +2062,7 @@ get_agent_scd_notify_event (void) GetCurrentProcess(), &h2, EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0)) { - log_error ("setting syncronize for scd notify event failed: %s\n", + log_error ("setting synchronize for scd notify event failed: %s\n", w32_strerror (-1) ); CloseHandle (h); } @@ -2264,6 +2306,26 @@ create_directories (void) } +static int +need_tick (void) +{ +#ifdef HAVE_W32_SYSTEM + /* We do not know how to interrupt the select loop on Windows, so we + always need a short tick there. */ + return 1; +#else + /* if we were invoked like "gpg-agent cmd arg1 arg2" then we need to + watch our parent. */ + if (parent_pid != (pid_t)(-1)) + return 1; + /* if scdaemon is running, we need to check that it's alive */ + if (agent_scd_check_running ()) + return 1; + /* otherwise, nothing fine-grained to do. */ + return 0; +#endif /*HAVE_W32_SYSTEM*/ +} + /* This is the worker for the ticker. It is called every few seconds and may only do fast operations. */ @@ -2322,7 +2384,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. */ + its own thread and not in the context of a signal handler. */ static void handle_signal (int signo) { @@ -2346,12 +2408,16 @@ handle_signal (int signo) agent_sigusr2_action (); break; + /* nothing to do here, just take an extra cycle on the select loop */ + case SIGCONT: + break; + case SIGTERM: if (!shutdown_pending) log_info ("SIGTERM received - shutting down ...\n"); else log_info ("SIGTERM received - still %i open connections\n", - active_connections); + get_agent_active_connection_count()); shutdown_pending++; if (shutdown_pending > 2) { @@ -2586,7 +2652,7 @@ putty_message_thread (void *arg) static void * do_start_connection_thread (ctrl_t ctrl) { - active_connections++; + adjust_agent_active_connections(+1); agent_init_default_ctrl (ctrl); if (opt.verbose && !DBG_IPC) log_info (_("handler 0x%lx for fd %d started\n"), @@ -2599,7 +2665,7 @@ do_start_connection_thread (ctrl_t ctrl) agent_deinit_default_ctrl (ctrl); xfree (ctrl); - active_connections--; + adjust_agent_active_connections(-1); return NULL; } @@ -2666,7 +2732,7 @@ start_connection_thread_ssh (void *arg) if (check_nonce (ctrl, &socket_nonce_ssh)) return NULL; - active_connections++; + adjust_agent_active_connections(+1); agent_init_default_ctrl (ctrl); if (opt.verbose) log_info (_("ssh handler 0x%lx for fd %d started\n"), @@ -2679,11 +2745,18 @@ start_connection_thread_ssh (void *arg) agent_deinit_default_ctrl (ctrl); xfree (ctrl); - active_connections--; + adjust_agent_active_connections(-1); return NULL; } +void interrupt_main_thread_loop (void) +{ +#ifndef HAVE_W32_SYSTEM + kill (main_thread_pid, SIGCONT); +#endif +} + /* helper function for readability: test whether a given struct timespec is set to all-zeros */ static inline int @@ -2739,6 +2812,10 @@ handle_connections (gnupg_fd_t listen_fd, { { CHECK_OWN_SOCKET_INTERVAL, 0 }, check_own_socket } }; + ret = npth_mutex_init (&active_connections_lock, NULL); + if (ret) + log_fatal ("error allocating active connections mutex: %s\n", + strerror (ret)); ret = npth_attr_init(&tattr); if (ret) @@ -2752,8 +2829,10 @@ handle_connections (gnupg_fd_t listen_fd, npth_sigev_add (SIGUSR1); npth_sigev_add (SIGUSR2); npth_sigev_add (SIGINT); + npth_sigev_add (SIGCONT); npth_sigev_add (SIGTERM); npth_sigev_fini (); + main_thread_pid = getpid (); #else # ifdef HAVE_W32CE_SYSTEM /* Use a dummy event. */ @@ -2765,6 +2844,7 @@ handle_connections (gnupg_fd_t listen_fd, # endif #endif + if (disable_check_own_socket) my_inotify_fd = -1; else if ((err = gnupg_inotify_watch_socket (&my_inotify_fd, socket_name))) @@ -2832,7 +2912,7 @@ handle_connections (gnupg_fd_t listen_fd, /* Shutdown test. */ if (shutdown_pending) { - if (active_connections == 0) + if (get_agent_active_connection_count() == 0) break; /* ready */ /* Do not accept new connections but keep on running the @@ -2855,6 +2935,11 @@ handle_connections (gnupg_fd_t listen_fd, thus a simple assignment is fine to copy the entire set. */ read_fdset = fdset; + /* avoid a fine-grained timer if we don't need one: */ + timertbl[0].interval.tv_sec = need_tick () ? TIMERTICK_INTERVAL : 0; + /* avoid waking up to check sockets if we can count on inotify */ + timertbl[1].interval.tv_sec = (my_inotify_fd == -1) ? CHECK_OWN_SOCKET_INTERVAL : 0; + /* loop through all timers, fire any registered functions, and plan next timer to trigger */ npth_clock_gettime (&curtime);