time_t last_purge = 0; /* Last dead session purge */
static int num_threads = 0; /* Current number of threads */
int num_sessions = 0; /* Current number of sessions */
+static int rescan[2]; /* The rescan pipe */
pthread_t initial_thread; /* tid for main() thread */
* socket breaks.
*/
signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Set up the rescan pipe. When a session goes idle, it writes a
+ * single byte to this pipe to wake up the thread calling select(),
+ * which tells it to rescan the list of session sockets.
+ */
+ if (pipe(rescan) != 0) {
+ lprintf(CTDL_EMERG, "Cannot create rescan pipe: %s\n",
+ strerror(errno));
+ abort();
+ }
}
do_select: force_purge = 0;
bind_me = NULL; /* Which session shall we handle? */
- /* Initialize the fdset. */
+ /* Initialize the fdset. Start with the rescan pipe. */
FD_ZERO(&readfds);
- highest = 0;
+ FD_SET(rescan[0], &readfds);
+ highest = rescan[0] + 1;
begin_critical_section(S_SESSION_TABLE);
for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
serviceptr->h_greeting_function();
become_session(NULL);
con->state = CON_IDLE;
+
+ /* Wake up the currently blocking select() by
+ * writing a dummy byte to the rescan pipe.
+ */
+ write(rescan[1], &i, 1);
goto do_select;
}
}
break;
}
+ /* If the rescan pipe went active, read a dummy byte from it */
+ if (FD_ISSET(rescan[0], &readfds)) {
+ read(rescan[0], &i, 1);
+ goto do_select;
+ }
+
/* It must be a client socket. Find a context that has data
* waiting on its socket *and* is in the CON_IDLE state. Any
* active sockets other than our chosen one are marked as
force_purge = CC->kill_me;
become_session(NULL);
bind_me->state = CON_IDLE;
+
+ /* Wake up the currently blocking select() by writing
+ * a dummy byte to the rescan pipe.
+ */
+ write(rescan[1], &i, 1);
}
dead_session_purge(force_purge);