chiark / gitweb /
Import gnupg2_2.1.18-8~deb9u1.debian.tar.bz2
[gnupg2.git] / patches / gpg-agent-idling / 0001-agent-Create-framework-of-scheduled-timers.patch
1 From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2 Date: Mon, 31 Oct 2016 21:27:36 -0400
3 Subject: agent: Create framework of scheduled timers.
4
5 agent/gpg-agent.c (handle_tick): Remove intermittent call to
6 check_own_socket.
7 (tv_is_set): Add inline helper function for readability.
8 (handle_connections) Create general table of pending scheduled
9 timeouts.
10
11 --
12
13 handle_tick() does fine-grained, rapid activity.  check_own_socket()
14 is supposed to happen at a different interval.
15
16 Mixing the two of them makes it a requirement that one interval be a
17 multiple of the other, which isn't ideal if there are different delay
18 strategies that we might want in the future.
19
20 Creating an extensible regular timer framework in handle_connections
21 should make it possible to have any number of cadenced timers fire
22 regularly, without requiring that they happen in cadences related to
23 each other.
24
25 It should also make it possible to dynamically change the cadence of
26 any regularly-scheduled timeout.
27
28 Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
29 ---
30  agent/gpg-agent.c | 87 ++++++++++++++++++++++++++++++++++++-------------------
31  1 file changed, 58 insertions(+), 29 deletions(-)
32
33 diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
34 index 31bf3370a..25aae6af0 100644
35 --- a/agent/gpg-agent.c
36 +++ b/agent/gpg-agent.c
37 @@ -2282,11 +2282,6 @@ create_directories (void)
38  static void
39  handle_tick (void)
40  {
41 -  static time_t last_minute;
42 -
43 -  if (!last_minute)
44 -    last_minute = time (NULL);
45 -
46    /* Check whether the scdaemon has died and cleanup in this case. */
47    agent_scd_check_aliveness ();
48  
49 @@ -2305,16 +2300,6 @@ handle_tick (void)
50          }
51      }
52  #endif /*HAVE_W32_SYSTEM*/
53 -
54 -  /* Code to be run from time to time.  */
55 -#if CHECK_OWN_SOCKET_INTERVAL > 0
56 -  if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL))
57 -    {
58 -      check_own_socket ();
59 -      last_minute = time (NULL);
60 -    }
61 -#endif
62 -
63  }
64  
65  
66 @@ -2711,6 +2696,15 @@ start_connection_thread_ssh (void *arg)
67  }
68  
69  
70 +/* helper function for readability: test whether a given struct
71 +   timespec is set to all-zeros */
72 +static inline int
73 +tv_is_set (struct timespec tv)
74 +{
75 +  return tv.tv_sec || tv.tv_nsec;
76 +}
77 +
78 +
79  /* Connection handler loop.  Wait for connection requests and spawn a
80     thread after accepting a connection.  */
81  static void
82 @@ -2728,9 +2722,11 @@ handle_connections (gnupg_fd_t listen_fd,
83    gnupg_fd_t fd;
84    int nfd;
85    int saved_errno;
86 +  int idx;
87    struct timespec abstime;
88    struct timespec curtime;
89    struct timespec timeout;
90 +  struct timespec *select_timeout;
91  #ifdef HAVE_W32_SYSTEM
92    HANDLE events[2];
93    unsigned int events_set;
94 @@ -2746,6 +2742,14 @@ handle_connections (gnupg_fd_t listen_fd,
95      { "browser", start_connection_thread_browser },
96      { "ssh",    start_connection_thread_ssh   }
97    };
98 +  struct {
99 +    struct timespec interval;
100 +    void (*func) (void);
101 +    struct timespec next;
102 +  } timertbl[] = {
103 +    { { TIMERTICK_INTERVAL, 0 }, handle_tick },
104 +    { { CHECK_OWN_SOCKET_INTERVAL, 0 }, check_own_socket }
105 +  };
106  
107  
108    ret = npth_attr_init(&tattr);
109 @@ -2835,9 +2839,6 @@ handle_connections (gnupg_fd_t listen_fd,
110    listentbl[2].l_fd = listen_fd_browser;
111    listentbl[3].l_fd = listen_fd_ssh;
112  
113 -  npth_clock_gettime (&abstime);
114 -  abstime.tv_sec += TIMERTICK_INTERVAL;
115 -
116    for (;;)
117      {
118        /* Shutdown test.  */
119 @@ -2866,18 +2867,47 @@ handle_connections (gnupg_fd_t listen_fd,
120           thus a simple assignment is fine to copy the entire set.  */
121        read_fdset = fdset;
122  
123 +      /* loop through all timers, fire any registered functions, and
124 +         plan next timer to trigger */
125        npth_clock_gettime (&curtime);
126 -      if (!(npth_timercmp (&curtime, &abstime, <)))
127 -       {
128 -         /* Timeout.  */
129 -         handle_tick ();
130 -         npth_clock_gettime (&abstime);
131 -         abstime.tv_sec += TIMERTICK_INTERVAL;
132 -       }
133 -      npth_timersub (&abstime, &curtime, &timeout);
134 +      abstime.tv_sec = abstime.tv_nsec = 0;
135 +      for (idx=0; idx < DIM(timertbl); idx++)
136 +        {
137 +          /* schedule any unscheduled timers */
138 +          if ((!tv_is_set (timertbl[idx].next)) && tv_is_set (timertbl[idx].interval))
139 +            npth_timeradd (&timertbl[idx].interval, &curtime, &timertbl[idx].next);
140 +          /* if a timer is due, fire it ... */
141 +          if (tv_is_set (timertbl[idx].next))
142 +            {
143 +              if (!(npth_timercmp (&curtime, &timertbl[idx].next, <)))
144 +                {
145 +                  timertbl[idx].func ();
146 +                  npth_clock_gettime (&curtime);
147 +                  /* ...and reschedule it, if desired: */
148 +                  if (tv_is_set (timertbl[idx].interval))
149 +                    npth_timeradd (&timertbl[idx].interval, &curtime, &timertbl[idx].next);
150 +                  else
151 +                    timertbl[idx].next.tv_sec = timertbl[idx].next.tv_nsec = 0;
152 +                }
153 +            }
154 +          /* accumulate next timer to come due in abstime: */
155 +          if (tv_is_set (timertbl[idx].next) &&
156 +              ((!tv_is_set (abstime)) ||
157 +               (npth_timercmp (&abstime, &timertbl[idx].next, >))))
158 +            abstime = timertbl[idx].next;
159 +        }
160 +      /* choose a timeout for the select loop: */
161 +      if (tv_is_set (abstime))
162 +        {
163 +          npth_timersub (&abstime, &curtime, &timeout);
164 +          select_timeout = &timeout;
165 +        }
166 +      else
167 +          select_timeout = NULL;
168 +      
169  
170  #ifndef HAVE_W32_SYSTEM
171 -      ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
172 +      ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, select_timeout,
173                            npth_sigev_sigmask ());
174        saved_errno = errno;
175  
176 @@ -2887,7 +2917,7 @@ handle_connections (gnupg_fd_t listen_fd,
177            handle_signal (signo);
178        }
179  #else
180 -      ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
181 +      ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, select_timeout,
182                            events, &events_set);
183        saved_errno = errno;
184  
185 @@ -2910,7 +2940,6 @@ handle_connections (gnupg_fd_t listen_fd,
186  
187        if (!shutdown_pending)
188          {
189 -          int idx;
190            ctrl_t ctrl;
191            npth_t thread;
192