From: Daniel Kahn Gillmor Date: Tue, 1 Nov 2016 00:14:10 -0400 Subject: agent: Avoid tight timer tick when possible. * agent/gpg-agent.c (need_tick): Evaluate whether the short-phase handle_tick() is needed. (handle_connections): On each cycle of the select loop, adjust whether we should call handle_tick() or not. (start_connection_thread_ssh, do_start_connection_thread): Signal the main loop when the child terminates. * agent/call-scd.c (start_scd): Call interrupt_main_thread_loop() once the scdaemon thread context has started up. -- With this change, an idle gpg-agent that has no scdaemon running only wakes up once a minute (to check_own_socket). Thanks to Ian Jackson and NIIBE Yutaka who helped me improve some of the blocking and corner cases. Signed-off-by: Daniel Kahn Gillmor --- agent/call-scd.c | 2 ++ agent/gpg-agent.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/agent/call-scd.c b/agent/call-scd.c index c5b95f4..762de82 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -414,6 +414,8 @@ start_scd (ctrl_t ctrl) primary_scd_ctx = ctx; primary_scd_ctx_reusable = 0; + /* notify the main loop that something has changed */ + interrupt_main_thread_loop (); leave: xfree (abs_homedir); diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 2882767..0801449 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -2374,6 +2374,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. */ @@ -2730,7 +2750,8 @@ do_start_connection_thread (ctrl_t ctrl) agent_deinit_default_ctrl (ctrl); xfree (ctrl); - active_connections--; + if (--active_connections == 0) + interrupt_main_thread_loop(); return NULL; } @@ -2810,7 +2831,8 @@ start_connection_thread_ssh (void *arg) agent_deinit_default_ctrl (ctrl); xfree (ctrl); - active_connections--; + if (--active_connections == 0) + interrupt_main_thread_loop(); return NULL; } @@ -3020,6 +3042,9 @@ 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; + /* loop through all timers, fire any registered functions, and plan next timer to trigger */ npth_clock_gettime (&curtime);