]> code.citadel.org Git - citadel.git/blobdiff - citadel/sysdep.c
* Scheduler fix ... added the rescan pipe back in
[citadel.git] / citadel / sysdep.c
index d463683eb69b9425cb1067c53d84b80012b93d45..cee6c1fd583be5e5ddf9eaee6340088d3625877f 100644 (file)
@@ -94,6 +94,7 @@ struct CitContext masterCC;
 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 */
 
@@ -236,6 +237,17 @@ void init_sysdep(void) {
         * 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();
+       }
 }
 
 
@@ -894,9 +906,10 @@ void *worker_thread(void *arg) {
 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) {
@@ -1005,6 +1018,11 @@ do_select:       force_purge = 0;
                                        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;
                                }
                        }
@@ -1015,6 +1033,12 @@ do_select:       force_purge = 0;
                        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
@@ -1059,6 +1083,11 @@ SKIP_SELECT:
                        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);