summaryrefslogtreecommitdiffstats
path: root/debian/patches/gpg-agent-idling/agent-Create-framework-of-scheduled-timers.patch
blob: 5b6e1ffbe48d16c3ec1951cc991fcfca4206f81c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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 3f7aaae..309e87c 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -2377,12 +2377,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 ();
 
@@ -2402,15 +2398,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 ();
 
@@ -2821,6 +2808,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
@@ -2838,9 +2834,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;
@@ -2857,6 +2855,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);
@@ -2964,9 +2970,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.  */
@@ -3001,18 +3004,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;
 
@@ -3022,7 +3053,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;
 
@@ -3067,7 +3098,6 @@ handle_connections (gnupg_fd_t listen_fd,
 
       if (!shutdown_pending)
         {
-          int idx;
           ctrl_t ctrl;
           npth_t thread;