* Removed the session_count() function. Instead, keep a reference count
authorArt Cancro <ajc@citadel.org>
Wed, 17 Nov 1999 04:15:06 +0000 (04:15 +0000)
committerArt Cancro <ajc@citadel.org>
Wed, 17 Nov 1999 04:15:06 +0000 (04:15 +0000)
  updated when sessions begin and end.
* Replaced fixed number of worker threads with lower and upper limits; current
  code now tries to make thread count == session count, within these limits

citadel/ChangeLog
citadel/citadel.h
citadel/citserver.c
citadel/config.c
citadel/control.c
citadel/routines2.c
citadel/sysdep.c
citadel/sysdep_decls.h

index 9d95ab7db1ff945c873e492c38a980370506838c..e992c1f956ce821026cf6384cc5ff1dd6ac60d03 100644 (file)
@@ -1,4 +1,10 @@
 $Log$
+Revision 1.416  1999/11/17 04:15:05  ajc
+* Removed the session_count() function.  Instead, keep a reference count
+  updated when sessions begin and end.
+* Replaced fixed number of worker threads with lower and upper limits; current
+  code now tries to make thread count == session count, within these limits
+
 Revision 1.415  1999/11/15 03:17:39  ajc
 * Put lockfile in /tmp instead of in /var/lock.   The latter is not guaranteed
   to exist, nor is it guaranteed to be writable by BBSUID
@@ -1439,3 +1445,4 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
        * Initial CVS import 
+
index 88759d591deaf8b519ef9783d538341356dfb516..6b9991f6343ddcc707188d840bda801a663cacda 100644 (file)
@@ -76,7 +76,8 @@ struct config {
        char c_logpages[ROOMNAMELEN];   /* Room to log pages to (or not)    */
        char c_createax;                /* Axlevel required to create rooms */
        long c_maxmsglen;               /* Maximum message length           */
-       int c_worker_threads;           /* Number of worker threads to start*/
+       int c_min_workers;              /* Lower limit on number of threads */
+       int c_max_workers;              /* Upper limit on number of threads */
 };
 
 #define NODENAME               config.c_nodename
index 0f96bf0686c25664e667996b97ad8f6d51fa1c18..1bc99652ccdf46ce1c9b03cf3a0bc994f3aecc22 100644 (file)
@@ -130,19 +130,22 @@ void RemoveContext (struct CitContext *con)
                }
 
        /* Remove the context from the global context list.  This needs
-        * to get done FIRST to avoid concurrency problems.
+        * to get done FIRST to avoid concurrency problems.  It is *vitally*
+        * important to keep num_sessions accurate!!
         */
        lprintf(7, "Removing context for session %d\n", con->cs_pid);
        begin_critical_section(S_SESSION_TABLE);
        if (ContextList == con) {
                ToFree = ContextList;
                ContextList = ContextList->next;
+               --num_sessions;
                }
        else {
                for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
                        if (ptr->next == con) {
                                ToFree = ptr->next;
                                ptr->next = ptr->next->next;
+                               --num_sessions;
                                }
                        }
                }
@@ -847,7 +850,7 @@ void cmd_scdn(char *argbuf)
  */
 void begin_session(struct CitContext *con)
 {
-       int num_sessions, len;
+       int len;
        struct sockaddr_in sin;
 
        /* 
@@ -875,7 +878,6 @@ void begin_session(struct CitContext *con)
        con->dl_is_net = 0;
        con->FirstSessData = NULL;
 
-       num_sessions = session_count();
        con->nologin = 0;
        if ((config.c_maxsessions > 0)&&(num_sessions > config.c_maxsessions))
                con->nologin = 1;
index 3b81fec3f1fcb67fbf64ba28ac1759a722a9c2da..978e20693b1b4c51c76395339422666791239445 100644 (file)
@@ -79,14 +79,16 @@ void get_config(void) {
         if (config.c_maxmsglen < 8192)
                 config.c_maxmsglen = 8192;
 
-        /* Default number of worker threads is 15 and the minimum is 5
-         */
-       /* Can't have fewer than two worker threads */
-       if (config.c_worker_threads == 0)
-               config.c_worker_threads = 15;
-       if (config.c_worker_threads < 5)
-               config.c_worker_threads = 5;
-               
+        /* Default lower and upper limits on number of worker threads */
+
+       if (config.c_min_workers < 3)           /* no less than 3 */
+               config.c_min_workers = 5;
+
+       if (config.c_max_workers == 0)                  /* default maximum */
+               config.c_max_workers = 256;
+
+       if (config.c_max_workers < config.c_min_workers)   /* max >= min */
+               config.c_max_workers = config.c_min_workers;
 }
 
 
index 2f1302fa3d8c37a59105025a7812270ca6dda3d3..74e2edea994d0d43f27946e2d0be8826571d8bbd 100644 (file)
@@ -161,7 +161,8 @@ void cmd_conf(char *argbuf) {
                cprintf("%s\n", config.c_logpages);
                cprintf("%d\n", config.c_createax);
                cprintf("%d\n", config.c_maxmsglen);
-               cprintf("%d\n", config.c_worker_threads);
+               cprintf("%d\n", config.c_min_workers);
+               cprintf("%d\n", config.c_max_workers);
                cprintf("000\n");
                }
 
@@ -238,7 +239,9 @@ void cmd_conf(char *argbuf) {
                                        config.c_maxmsglen = atoi(buf);
                                break;
                        case 21: if (atoi(buf) >= 2)
-                                       config.c_worker_threads = atoi(buf);
+                                       config.c_min_workers = atoi(buf);
+                       case 22: if (atoi(buf) >= config.c_min_workers)
+                                       config.c_max_workers = atoi(buf);
                        }
                    ++a;
                    }
index c903a756b7f280b8f37b86de22e7f42b88ee76b8..6c14b74897987ee046b5e62da9d38d93262cf3e3 100644 (file)
@@ -624,7 +624,7 @@ void read_bio(void)
 void do_system_configuration(void)
 {
        char buf[256];
-       char sc[22][256];
+       char sc[23][256];
        int expire_mode = 0;
        int expire_value = 0;
        int a;
@@ -638,7 +638,7 @@ void do_system_configuration(void)
        if (buf[0] == '1') {
                a = 0;
                while (serv_gets(buf), strcmp(buf, "000")) {
-                       if (a < 22)
+                       if (a < 23)
                                strcpy(&sc[a][0], buf);
                        ++a;
                }
@@ -688,7 +688,8 @@ void do_system_configuration(void)
        strprompt("Default room purge time (days)", &sc[17][0], 5);
        strprompt("Name of room to log pages", &sc[18][0], ROOMNAMELEN);
        strprompt("Maximum message length", &sc[20][0], 20);
-       strprompt("Number of worker threads", &sc[21][0], 3);
+       strprompt("Minimum number of worker threads", &sc[21][0], 3);
+       strprompt("Maximum number of worker threads", &sc[22][0], 3);
 
        /* Angels and demons dancing in my head... */
        do {
@@ -721,7 +722,7 @@ void do_system_configuration(void)
                serv_puts("CONF set");
                serv_gets(buf);
                if (buf[0] == '4') {
-                       for (a = 0; a < 22; ++a)
+                       for (a = 0; a < 23; ++a)
                                serv_puts(&sc[a][0]);
                        serv_puts("000");
                }
index 333319b9cfcec0c262cee6bd957ccd1027276761..7d7b1d043ec98647b66cfb88aed2cd7482d5e375 100644 (file)
@@ -70,6 +70,8 @@ int verbosity = DEFAULT_VERBOSITY;            /* Logging level */
 struct CitContext masterCC;
 int rescan[2];                                 /* The Rescan Pipe */
 time_t last_purge = 0;                         /* Last dead session purge */
+int num_threads = 0;                           /* Current number of threads */
+int num_sessions = 0;                          /* Current number of sessions */
 
 /*
  * lprintf()  ...   Write logging information
@@ -344,6 +346,7 @@ struct CitContext *CreateNewContext(void) {
        me->cs_pid = num;
        me->next = ContextList;
        ContextList = me;
+       ++num_sessions;
 
        end_critical_section(S_SESSION_TABLE);
        return(me);
@@ -351,24 +354,6 @@ struct CitContext *CreateNewContext(void) {
 
 
 
-/*
- * Return the number of sessions currently running.
- * (This should probably be moved out of sysdep.c)
- */
-int session_count(void) {
-       struct CitContext *ptr;
-       int TheCount = 0;
-
-       begin_critical_section(S_SESSION_TABLE);
-       for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
-               ++TheCount;
-       }
-       end_critical_section(S_SESSION_TABLE);
-
-       return(TheCount);
-}
-
-
 /*
  * client_write()   ...    Send binary data to the client.
  */
@@ -632,9 +617,14 @@ int convert_login(char NameToConvert[]) {
  * This function has code to prevent it from running more than once every
  * few seconds, because running it after every single unbind would waste a lot
  * of CPU time and keep the context list locked too much.
+ *
+ * After that's done, we raise or lower the size of the worker thread pool
+ * if such an action is appropriate.
  */
 void dead_session_purge(void) {
        struct CitContext *ptr, *rem;
+        pthread_attr_t attr;
+       pthread_t newthread;
 
        if ( (time(NULL) - last_purge) < 5 ) return;    /* Too soon, go away */
        time(&last_purge);
@@ -644,7 +634,7 @@ void dead_session_purge(void) {
                begin_critical_section(S_SESSION_TABLE);
                for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
                        if ( (ptr->state == CON_IDLE) && (ptr->kill_me) ) {
-                               rem = ptr;      
+                               rem = ptr;
                        }
                }
                end_critical_section(S_SESSION_TABLE);
@@ -658,6 +648,31 @@ void dead_session_purge(void) {
                }
 
        } while (rem != NULL);
+
+
+       /* Raise or lower the size of the worker thread pool if such
+        * an action is appropriate.
+        */
+
+       if ( (num_sessions > num_threads)
+          && (num_threads < config.c_max_workers) ) {
+
+               pthread_attr_init(&attr);
+                       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+               if (pthread_create(&newthread, &attr,
+                  (void* (*)(void*)) worker_thread, NULL) != 0) {
+                       lprintf(1, "Can't create worker thead: %s\n",
+                       strerror(errno));
+               }
+
+       }
+       
+       else if ( (num_sessions < num_threads)
+          && (num_threads > config.c_min_workers) ) {
+               --num_threads;
+               pthread_exit(NULL);
+       }
+
 }
 
 
@@ -813,7 +828,7 @@ int main(int argc, char **argv)
        /*
         * Now create a bunch of worker threads.
         */
-       for (i=0; i<(config.c_worker_threads-1); ++i) {
+       for (i=0; i<(config.c_min_workers-1); ++i) {
                pthread_attr_init(&attr);
                        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
                if (pthread_create(&HousekeepingThread, &attr,
@@ -852,10 +867,11 @@ void worker_thread(void) {
        int alen;                       /* Data for master socket */
        int ssock;                      /* Descriptor for client socket */
 
+       ++num_threads;
        while (!time_to_die) {
 
                /* 
-                * In a stupid environment, we would have all idle threads
+                * A naive implementation would have all idle threads
                 * calling select() and then they'd all wake up at once.  We
                 * solve this problem by putting the select() in a critical
                 * section, so only one thread has the opportunity to wake
@@ -984,6 +1000,7 @@ SETUP_FD:  FD_ZERO(&readfds);
 
        /* If control reaches this point, the server is shutting down */        
        master_cleanup();
+       --num_threads;
        pthread_exit(NULL);
 }
 
index e748522f430fb472e31ba38b5798eb144d20baf2..5c613966c3435ef0a35b2a8d118d91c0bc53e056 100644 (file)
@@ -7,7 +7,6 @@ int ig_tcp_server (int port_number, int queue_len);
 struct CitContext *MyContext (void);
 struct CitContext *CreateNewContext (void);
 void InitMyContext (struct CitContext *con);
-int session_count (void);
 void client_write (char *buf, int nbytes);
 void cprintf (const char *format, ...);
 int client_read_to (char *buf, int bytes, int timeout);
@@ -20,3 +19,5 @@ void start_daemon (int do_close_stdio);
 void cmd_nset (char *cmdbuf);
 int convert_login (char *NameToConvert);
 void worker_thread (void);
+
+extern int num_sessions;