From: Art Cancro Date: Wed, 17 Nov 1999 04:15:06 +0000 (+0000) Subject: * Removed the session_count() function. Instead, keep a reference count X-Git-Tag: v7.86~7434 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=9c210ba0b55c056e6dd77c05ab57e57257aee36f * 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 --- diff --git a/citadel/ChangeLog b/citadel/ChangeLog index 9d95ab7db..e992c1f95 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -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 Fri Jul 10 1998 Art Cancro * Initial CVS import + diff --git a/citadel/citadel.h b/citadel/citadel.h index 88759d591..6b9991f63 100644 --- a/citadel/citadel.h +++ b/citadel/citadel.h @@ -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 diff --git a/citadel/citserver.c b/citadel/citserver.c index 0f96bf068..1bc99652c 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -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; diff --git a/citadel/config.c b/citadel/config.c index 3b81fec3f..978e20693 100644 --- a/citadel/config.c +++ b/citadel/config.c @@ -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; } diff --git a/citadel/control.c b/citadel/control.c index 2f1302fa3..74e2edea9 100644 --- a/citadel/control.c +++ b/citadel/control.c @@ -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; } diff --git a/citadel/routines2.c b/citadel/routines2.c index c903a756b..6c14b7489 100644 --- a/citadel/routines2.c +++ b/citadel/routines2.c @@ -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"); } diff --git a/citadel/sysdep.c b/citadel/sysdep.c index 333319b9c..7d7b1d043 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -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); } diff --git a/citadel/sysdep_decls.h b/citadel/sysdep_decls.h index e748522f4..5c613966c 100644 --- a/citadel/sysdep_decls.h +++ b/citadel/sysdep_decls.h @@ -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;