summaryrefslogtreecommitdiffstats
path: root/debian/patches/gpg-agent-idling
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/gpg-agent-idling')
-rw-r--r--debian/patches/gpg-agent-idling/agent-Allow-threads-to-interrupt-main-select-loop-wi.patch84
-rw-r--r--debian/patches/gpg-agent-idling/agent-Avoid-scheduled-checks-on-socket-when-inotify-.patch26
-rw-r--r--debian/patches/gpg-agent-idling/agent-Avoid-tight-timer-tick-when-possible.patch101
-rw-r--r--debian/patches/gpg-agent-idling/agent-Create-framework-of-scheduled-timers.patch191
4 files changed, 402 insertions, 0 deletions
diff --git a/debian/patches/gpg-agent-idling/agent-Allow-threads-to-interrupt-main-select-loop-wi.patch b/debian/patches/gpg-agent-idling/agent-Allow-threads-to-interrupt-main-select-loop-wi.patch
new file mode 100644
index 0000000..f0f1ef6
--- /dev/null
+++ b/debian/patches/gpg-agent-idling/agent-Allow-threads-to-interrupt-main-select-loop-wi.patch
@@ -0,0 +1,84 @@
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+Date: Tue, 1 Nov 2016 00:45:23 -0400
+Subject: agent: Allow threads to interrupt main select loop with SIGCONT.
+
+* agent/gpg-agent.c (interrupt_main_thread_loop): New function on
+non-windows platforms, allows other threads to interrupt the main loop
+if there's something that the main loop might be interested in.
+
+--
+
+For example, the main loop might be interested in changes in program
+state that affect the timers it expects to see.
+
+I don't know how to do this on Windows platforms, but i welcome any
+proposed improvements.
+
+Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+---
+ agent/agent.h | 1 +
+ agent/gpg-agent.c | 16 ++++++++++++++++
+ 2 files changed, 17 insertions(+)
+
+diff --git a/agent/agent.h b/agent/agent.h
+index fb46412..4abc6ed 100644
+--- a/agent/agent.h
++++ b/agent/agent.h
+@@ -375,6 +375,7 @@ void *get_agent_scd_notify_event (void);
+ #endif
+ void agent_sighup_action (void);
+ int map_pk_openpgp_to_gcry (int openpgp_algo);
++void interrupt_main_thread_loop (void);
+
+ /*-- command.c --*/
+ gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid,
+diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
+index 69705ed..752552c 100644
+--- a/agent/gpg-agent.c
++++ b/agent/gpg-agent.c
+@@ -430,6 +430,9 @@ static int have_homedir_inotify;
+ * works reliable. */
+ static int reliable_homedir_inotify;
+
++/* 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;
+
+@@ -2458,6 +2461,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");
+@@ -2796,6 +2803,13 @@ 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
+@@ -2865,8 +2879,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. */
diff --git a/debian/patches/gpg-agent-idling/agent-Avoid-scheduled-checks-on-socket-when-inotify-.patch b/debian/patches/gpg-agent-idling/agent-Avoid-scheduled-checks-on-socket-when-inotify-.patch
new file mode 100644
index 0000000..3cef203
--- /dev/null
+++ b/debian/patches/gpg-agent-idling/agent-Avoid-scheduled-checks-on-socket-when-inotify-.patch
@@ -0,0 +1,26 @@
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+Date: Tue, 1 Nov 2016 00:57:44 -0400
+Subject: agent: Avoid scheduled checks on socket when inotify is working.
+
+* agent/gpg-agent.c (handle_connections): When inotify is working, we
+do not need to schedule a timer to evaluate whether we control our own
+socket or not.
+
+Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+---
+ agent/gpg-agent.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
+index eff82ca..3ae77c6 100644
+--- a/agent/gpg-agent.c
++++ b/agent/gpg-agent.c
+@@ -3032,6 +3032,8 @@ handle_connections (gnupg_fd_t listen_fd,
+
+ /* 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 = (sock_inotify_fd == -1) ? CHECK_OWN_SOCKET_INTERVAL : 0;
+
+ /* loop through all timers, fire any registered functions, and
+ plan next timer to trigger */
diff --git a/debian/patches/gpg-agent-idling/agent-Avoid-tight-timer-tick-when-possible.patch b/debian/patches/gpg-agent-idling/agent-Avoid-tight-timer-tick-when-possible.patch
new file mode 100644
index 0000000..3900cf4
--- /dev/null
+++ b/debian/patches/gpg-agent-idling/agent-Avoid-tight-timer-tick-when-possible.patch
@@ -0,0 +1,101 @@
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+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 <dkg@fifthhorseman.net>
+---
+ 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 6438693..ee69bb4 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 752552c..eff82ca 100644
+--- a/agent/gpg-agent.c
++++ b/agent/gpg-agent.c
+@@ -2362,6 +2362,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. */
+@@ -2718,7 +2738,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;
+ }
+
+@@ -2798,7 +2819,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;
+ }
+
+@@ -3008,6 +3030,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);
diff --git a/debian/patches/gpg-agent-idling/agent-Create-framework-of-scheduled-timers.patch b/debian/patches/gpg-agent-idling/agent-Create-framework-of-scheduled-timers.patch
new file mode 100644
index 0000000..29bbd54
--- /dev/null
+++ b/debian/patches/gpg-agent-idling/agent-Create-framework-of-scheduled-timers.patch
@@ -0,0 +1,191 @@
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+Date: Mon, 31 Oct 2016 21:27:36 -0400
+Subject: agent: Create framework of scheduled timers.
+
+agent/gpg-agent.c (handle_tick): Remove intermittent call to
+check_own_socket.
+(tv_is_set): Add inline helper function for readability.
+(handle_connections) Create general table of pending scheduled
+timeouts.
+
+--
+
+handle_tick() does fine-grained, rapid activity. check_own_socket()
+is supposed to happen at a different interval.
+
+Mixing the two of them makes it a requirement that one interval be a
+multiple of the other, which isn't ideal if there are different delay
+strategies that we might want in the future.
+
+Creating an extensible regular timer framework in handle_connections
+should make it possible to have any number of cadenced timers fire
+regularly, without requiring that they happen in cadences related to
+each other.
+
+It should also make it possible to dynamically change the cadence of
+any regularly-scheduled timeout.
+
+Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
+---
+ agent/gpg-agent.c | 84 +++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 57 insertions(+), 27 deletions(-)
+
+diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
+index 5afcf11..69705ed 100644
+--- a/agent/gpg-agent.c
++++ b/agent/gpg-agent.c
+@@ -2365,12 +2365,8 @@ create_directories (void)
+ static void
+ handle_tick (void)
+ {
+- static time_t last_minute;
+ struct stat statbuf;
+
+- if (!last_minute)
+- last_minute = time (NULL);
+-
+ /* Check whether the scdaemon has died and cleanup in this case. */
+ agent_scd_check_aliveness ();
+
+@@ -2390,15 +2386,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
+-
+ /* Need to check for expired cache entries. */
+ agent_cache_housekeeping ();
+
+@@ -2809,6 +2796,15 @@ start_connection_thread_ssh (void *arg)
+ }
+
+
++/* 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
+@@ -2826,9 +2822,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;
+@@ -2845,6 +2843,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);
+@@ -2952,9 +2958,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. */
+@@ -2989,18 +2992,46 @@ handle_connections (gnupg_fd_t listen_fd,
+ thus a simple assignment is fine to copy the entire set. */
+ read_fdset = fdset;
+
++ /* 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;
+
+@@ -3010,7 +3041,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;
+
+@@ -3055,7 +3086,6 @@ handle_connections (gnupg_fd_t listen_fd,
+
+ if (!shutdown_pending)
+ {
+- int idx;
+ ctrl_t ctrl;
+ npth_t thread;
+