X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=gnupg2.git;a=blobdiff_plain;f=agent%2Fgpg-agent.c;h=0e53549479f56044d4b26a9de2482193a41ceddd;hp=f5ecea544cb92f8293bdc89830fe788691d9191a;hb=refs%2Fheads%2F841143-extra-debug-messages;hpb=5c0ca5b715ab6b35b44df738153e05daa592d859 diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index f5ecea5..0e53549 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -382,6 +382,9 @@ 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; @@ -2020,7 +2023,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,17 +2267,32 @@ 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. */ static void handle_tick (void) { - static time_t last_minute; - - if (!last_minute) - last_minute = time (NULL); - /* Check whether the scdaemon has died and cleanup in this case. */ agent_scd_check_aliveness (); @@ -2293,16 +2311,6 @@ handle_tick (void) } } #endif /*HAVE_W32_SYSTEM*/ - - /* Code to be run from time to time. */ -#if CHECK_OWN_SOCKET_INTERVAL > 0 - if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL)) - { - check_own_socket (); - last_minute = time (NULL); - } -#endif - } @@ -2337,7 +2345,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) { @@ -2361,6 +2369,10 @@ 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"); @@ -2699,6 +2711,22 @@ start_connection_thread_ssh (void *arg) } +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 +tv_is_set (struct timespec tv) +{ + return tv.tv_sec || tv.tv_nsec; +} + + /* Connection handler loop. Wait for connection requests and spawn a thread after accepting a connection. */ static void @@ -2716,9 +2744,11 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t fd; int nfd; int saved_errno; + int idx; struct timespec abstime; struct timespec curtime; struct timespec timeout; + struct timespec *select_timeout; #ifdef HAVE_W32_SYSTEM HANDLE events[2]; unsigned int events_set; @@ -2734,6 +2764,14 @@ handle_connections (gnupg_fd_t listen_fd, { "browser", start_connection_thread_browser }, { "ssh", start_connection_thread_ssh } }; + struct { + struct timespec interval; + void (*func) (void); + struct timespec next; + } timertbl[] = { + { { TIMERTICK_INTERVAL, 0 }, handle_tick }, + { { CHECK_OWN_SOCKET_INTERVAL, 0 }, check_own_socket } + }; ret = npth_attr_init(&tattr); @@ -2748,8 +2786,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. */ @@ -2761,6 +2801,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))) @@ -2823,9 +2864,6 @@ handle_connections (gnupg_fd_t listen_fd, listentbl[2].l_fd = listen_fd_browser; listentbl[3].l_fd = listen_fd_ssh; - npth_clock_gettime (&abstime); - abstime.tv_sec += TIMERTICK_INTERVAL; - for (;;) { /* Shutdown test. */ @@ -2854,18 +2892,52 @@ 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); - if (!(npth_timercmp (&curtime, &abstime, <))) - { - /* Timeout. */ - handle_tick (); - npth_clock_gettime (&abstime); - abstime.tv_sec += TIMERTICK_INTERVAL; - } - npth_timersub (&abstime, &curtime, &timeout); + abstime.tv_sec = abstime.tv_nsec = 0; + for (idx=0; idx < DIM(timertbl); idx++) + { + /* schedule any unscheduled timers */ + if ((!tv_is_set (timertbl[idx].next)) && tv_is_set (timertbl[idx].interval)) + npth_timeradd (&timertbl[idx].interval, &curtime, &timertbl[idx].next); + /* if a timer is due, fire it ... */ + if (tv_is_set (timertbl[idx].next)) + { + if (!(npth_timercmp (&curtime, &timertbl[idx].next, <))) + { + timertbl[idx].func (); + npth_clock_gettime (&curtime); + /* ...and reschedule it, if desired: */ + if (tv_is_set (timertbl[idx].interval)) + npth_timeradd (&timertbl[idx].interval, &curtime, &timertbl[idx].next); + else + timertbl[idx].next.tv_sec = timertbl[idx].next.tv_nsec = 0; + } + } + /* accumulate next timer to come due in abstime: */ + if (tv_is_set (timertbl[idx].next) && + ((!tv_is_set (abstime)) || + (npth_timercmp (&abstime, &timertbl[idx].next, >)))) + abstime = timertbl[idx].next; + } + /* choose a timeout for the select loop: */ + if (tv_is_set (abstime)) + { + npth_timersub (&abstime, &curtime, &timeout); + select_timeout = &timeout; + } + else + select_timeout = NULL; + #ifndef HAVE_W32_SYSTEM - ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, + ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, select_timeout, npth_sigev_sigmask ()); saved_errno = errno; @@ -2875,7 +2947,7 @@ handle_connections (gnupg_fd_t listen_fd, handle_signal (signo); } #else - ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, + ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, select_timeout, events, &events_set); saved_errno = errno; @@ -2898,7 +2970,6 @@ handle_connections (gnupg_fd_t listen_fd, if (!shutdown_pending) { - int idx; ctrl_t ctrl; npth_t thread;