aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeebs <seebs@seebs.net>2017-12-18 14:21:33 -0600
committerSeebs <seebs@seebs.net>2017-12-18 14:21:33 -0600
commit0b39d16ac61b0a483617c1c99b76d06835fc82b4 (patch)
tree033a189624edeec54e776128201093b1d0c93edd
parentb6b68db896f9963558334aff7fca61adde4ec10f (diff)
downloadpseudo-0b39d16ac61b0a483617c1c99b76d06835fc82b4.tar.gz
pseudo-0b39d16ac61b0a483617c1c99b76d06835fc82b4.tar.bz2
pseudo-0b39d16ac61b0a483617c1c99b76d06835fc82b4.zip
Print list of clients on SIGUSR2
This patch relates to some debugging of handling of large numbers of clients, but actually it seems useful to have, so checking it in. Signed-off-by: Seebs <seebs@seebs.net>
-rw-r--r--ChangeLog.txt4
-rw-r--r--pseudo_server.c32
2 files changed, 36 insertions, 0 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 8ba1ffa..888334a 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,3 +1,7 @@
+2017-12-18:
+ * (seebs) Add a list of clients as a handler for SIGUSR2. (Useful
+ for debugging, maybe.)
+
2017-04-13:
* (seebs) don't unset LD_PRELOAD or the like, because if you
do that, bash can segfault because it "knows" how many
diff --git a/pseudo_server.c b/pseudo_server.c
index 7c2db2f..68433b3 100644
--- a/pseudo_server.c
+++ b/pseudo_server.c
@@ -62,6 +62,7 @@ static int active_clients = 0, highest_client = 0, max_clients = 0;
int pseudo_server_timeout = DEFAULT_PSEUDO_SERVER_TIMEOUT;
static int die_peacefully = 0;
static int die_forcefully = 0;
+static sig_atomic_t do_list_clients = 0;
/* when the client is linked with pseudo_wrappers, these are defined there.
* when it is linked with pseudo_server, though, we have to provide different
@@ -77,6 +78,11 @@ quit_now(int signal) {
die_forcefully = 1;
}
+static void
+set_do_list_clients(int sig) {
+ do_list_clients = sig;
+}
+
static int messages = 0, responses = 0;
static struct timeval message_time = { .tv_sec = 0 };
@@ -581,9 +587,14 @@ pseudo_server_loop(void) {
int rc;
int fd;
int loop_timeout = pseudo_server_timeout;
+ struct sigaction eat_usr2 = {
+ .sa_handler = set_do_list_clients
+ };
clients = malloc(16 * sizeof(*clients));
+ sigaction(SIGUSR2, &eat_usr2, NULL);
+
clients[0].fd = listen_fd;
clients[0].pid = getpid();
@@ -616,7 +627,12 @@ pseudo_server_loop(void) {
/* EINTR tends to come from profiling, so it is not a good reason to
* exit; other signals are caught and set the flag causing a graceful
* exit. */
+ sigset_t maskusr2;
+ sigemptyset(&maskusr2);
+ sigaddset(&maskusr2, SIGUSR2);
+ sigprocmask(SIG_BLOCK, &maskusr2, NULL);
while ((rc = select(max_fd + 1, &reads, &writes, &events, &timeout)) >= 0 || (errno == EINTR)) {
+ sigprocmask(SIG_UNBLOCK, &maskusr2, NULL);
if (rc == 0 || (rc == -1 && errno == EINTR)) {
/* If there's no clients, start timing out. If there
* are active clients, never time out.
@@ -692,6 +708,21 @@ pseudo_server_loop(void) {
}
pseudo_debug(PDBGF_SERVER, "server loop complete [%d clients left]\n", active_clients);
}
+ if (do_list_clients) {
+ do_list_clients = 0;
+ pseudo_diag("listing clients [1 through %d]:\n", highest_client);
+ for (i = 1; i <= highest_client; ++i) {
+ if (clients[i].fd == -1) {
+ pseudo_diag("client %4d: inactive.\n", i);
+ continue;
+ }
+ pseudo_diag("client %4d: fd %4d, pid %5d, state %s, program %s\n",
+ i, clients[i].fd, clients[i].pid,
+ FD_ISSET(clients[i].fd, &reads) ? "R" : "-",
+ clients[i].program ? clients[i].program : "<unspecified>");
+ }
+ pseudo_diag("done.\n");
+ }
if (die_peacefully || die_forcefully) {
pseudo_debug(PDBGF_SERVER, "quitting.\n");
pseudo_debug(PDBGF_SERVER | PDBGF_BENCHMARK, "server %d exiting: handled %d messages in %.4f seconds\n",
@@ -735,6 +766,7 @@ pseudo_server_loop(void) {
}
/* reinitialize timeout because Linux select alters it */
timeout = (struct timeval) { .tv_sec = LOOP_DELAY, .tv_usec = 0 };
+ sigprocmask(SIG_BLOCK, &maskusr2, NULL);
}
pseudo_diag("select failed: %s\n", strerror(errno));
}