#endif
/* Flag to indicate that a shutdown was requested. */
-static int shutdown_pending;
+static int shutdown_pending; /* xxx threaded accesses lack locking */
/* Counter for the currently running own socket checks. */
-static int check_own_socket_running;
+static int check_own_socket_running; /* xxx threaded accesses lack locking */
/* Flags to indicate that check_own_socket shall not be called. */
static int disable_check_own_socket;
static int is_supervised;
/* Flag to inhibit socket removal in cleanup. */
-static int inhibit_socket_removal;
+static int inhibit_socket_removal; /* xxx threaded accesses lack locking */
/* It is possible that we are currently running under setuid permissions */
static int maybe_setuid = 1;
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;
+static int active_connections_value;
+static npth_mutex_t active_connections_lock;
/* This object is used to dispatch progress messages from Libgcrypt to
* the right thread. Given that we will have at max only a few dozen
}
+static void
+lock_active_connections (void)
+{
+ int err;
+
+ err = npth_mutex_lock (&active_connections_lock);
+ if (err)
+ log_fatal ("failed to acquire active connection count mutex: %s\n",
+ strerror (err));
+}
+
+static void
+unlock_active_connections (void)
+{
+ int err;
+
+ err = npth_mutex_unlock (&active_connections_lock);
+ if (err)
+ log_fatal ("failed to release active connection count mutex: %s\n",
+ strerror (err));
+}
+
/* Return the number of active connections. */
int
get_agent_active_connection_count (void)
{
- return active_connections;
+ int value;
+
+ lock_active_connections();
+ value = active_connections_value;
+ unlock_active_connections();
+ return value;
+}
+
+/* Increment/decrement the number of active connections. */
+static void
+adjust_agent_active_connections (int delta)
+{
+ lock_active_connections();
+ active_connections_value += delta;
+ if (active_connections_value == 0)
+ interrupt_main_thread_loop ();
+ unlock_active_connections();
}
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);
}
}
+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. */
#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)
{
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");
else
log_info ("SIGTERM received - still %i open connections\n",
- active_connections);
+ get_agent_active_connection_count());
shutdown_pending++;
if (shutdown_pending > 2)
{
static void *
do_start_connection_thread (ctrl_t ctrl)
{
- active_connections++;
+ adjust_agent_active_connections(+1);
agent_init_default_ctrl (ctrl);
if (opt.verbose && !DBG_IPC)
log_info (_("handler 0x%lx for fd %d started\n"),
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
- active_connections--;
+ adjust_agent_active_connections(-1);
return NULL;
}
if (check_nonce (ctrl, &socket_nonce_ssh))
return NULL;
- active_connections++;
+ adjust_agent_active_connections(+1);
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d started\n"),
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
- active_connections--;
+ adjust_agent_active_connections(-1);
return NULL;
}
+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
{ { CHECK_OWN_SOCKET_INTERVAL, 0 }, check_own_socket }
};
+ ret = npth_mutex_init (&active_connections_lock, NULL);
+ if (ret)
+ log_fatal ("error allocating active connections mutex: %s\n",
+ strerror (ret));
ret = npth_attr_init(&tattr);
if (ret)
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. */
# endif
#endif
+
if (disable_check_own_socket)
my_inotify_fd = -1;
else if ((err = gnupg_inotify_watch_socket (&my_inotify_fd, socket_name)))
/* Shutdown test. */
if (shutdown_pending)
{
- if (active_connections == 0)
+ if (get_agent_active_connection_count() == 0)
break; /* ready */
/* Do not accept new connections but keep on running the
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);