From: Art Cancro Date: Fri, 29 Oct 1999 01:03:03 +0000 (+0000) Subject: * Debugged all possible ways for a session to terminate; do them cleanly. X-Git-Tag: v7.86~7476 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=f8d64fe1834b505edf6a3b559ee457c65acb96f2 * Debugged all possible ways for a session to terminate; do them cleanly. * Assign session numbers in a more portable and less arbitrary way. --- diff --git a/citadel/ChangeLog b/citadel/ChangeLog index e4cb2988c..4f18c04be 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -1,4 +1,8 @@ $Log$ +Revision 1.402 1999/10/29 01:03:03 ajc +* Debugged all possible ways for a session to terminate; do them cleanly. +* Assign session numbers in a more portable and less arbitrary way. + Revision 1.401 1999/10/28 19:50:55 ajc * Fixed a problem where the client protocol would spit out two responses and therefore get out of sync if ASUP command set the access level to @@ -12,8 +16,7 @@ Revision 1.400 1999/10/28 05:08:49 ajc Revision 1.399 1999/10/28 03:20:17 ajc * Fixed the problem of worker threads waking up prematurely. -* 'QUIT'-terminated sessions now exit properly. Still need to fix code for - sessions which are terminated from another session or by the server. +* 'QUIT'-terminated sessions now exit properly. Revision 1.398 1999/10/27 04:26:58 ajc * Initial hack of worker-thread rearchitecture. Right now it is successfully @@ -1385,3 +1388,4 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant Fri Jul 10 1998 Art Cancro * Initial CVS import + diff --git a/citadel/citserver.c b/citadel/citserver.c index c9e9c1af3..7bc73d1af 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -36,6 +36,7 @@ #include "tools.h" struct CitContext *ContextList = NULL; +char *unique_session_numbers; int ScheduledShutdown = 0; int do_defrag = 0; @@ -66,9 +67,11 @@ void master_cleanup(void) { /* Cancel all running sessions */ lprintf(7, "Cancelling running sessions...\n"); + +/* FIX do something here while (ContextList != NULL) { - kill_session(ContextList->cs_pid); } + */ /* Run any cleanup routines registered by loadable modules */ for (fcn = CleanupHookTable; fcn != NULL; fcn = fcn->next) { @@ -113,16 +116,16 @@ void deallocate_user_data(struct CitContext *con) /* - * Gracefully terminate a session which is marked as CON_DYING. + * Terminate a session and remove its context data structure. */ -void cleanup(struct CitContext *con) +void RemoveContext (struct CitContext *con) { struct CitContext *ptr = NULL; struct CitContext *ToFree = NULL; - lprintf(9, "cleanup() called\n"); + lprintf(9, "RemoveContext() called\n"); if (con==NULL) { - lprintf(5, "WARNING: cleanup() called with NULL!\n"); + lprintf(5, "WARNING: RemoveContext() called with NULL!\n"); return; } @@ -141,11 +144,6 @@ void cleanup(struct CitContext *con) /* Deallocate any user-data attached to this session */ deallocate_user_data(con); - /* And flag the context as in need of being killed. - * (Probably done already, but just in case) - */ - con->state = CON_DYING; - /* delete context */ lprintf(7, "Removing context\n"); @@ -176,7 +174,7 @@ void cleanup(struct CitContext *con) /* Free up the memory used by this context */ phree(ToFree); - lprintf(7, "Done with cleanup()\n"); + lprintf(7, "Done with RemoveContext()\n"); } @@ -704,7 +702,7 @@ void cmd_term(char *cmdbuf) { int session_num; struct CitContext *ccptr; - int session_to_kill = 0; + int found_it = 0; if (!CC->logged_in) { cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN); @@ -727,15 +725,13 @@ void cmd_term(char *cmdbuf) begin_critical_section(S_SESSION_TABLE); for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { if (session_num == ccptr->cs_pid) { - session_to_kill = ccptr->cs_pid; + ccptr->kill_me = 1; + found_it = 1; } } end_critical_section(S_SESSION_TABLE); - lprintf(9, "session_to_kill == %d\n", session_to_kill); - if (session_to_kill > 0) { - lprintf(9, "calling kill_session()\n"); - kill_session(session_to_kill); + if (found_it) { cprintf("%d Session terminated.\n", OK); } else { @@ -845,7 +841,6 @@ void begin_session(struct CitContext *con) con->internal_pgm = 0; con->download_fp = NULL; con->upload_fp = NULL; - con->cs_pid = con->client_socket; /* not necessarily portable */ con->FirstExpressMessage = NULL; time(&con->lastcmd); time(&con->lastidle); @@ -901,7 +896,7 @@ void do_command_loop(void) { memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */ if (client_gets(cmdbuf) < 1) { lprintf(3, "Client socket is broken. Ending session.\n"); - CC->state = CON_DYING; + CC->kill_me = 1; return; } lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf); @@ -932,7 +927,7 @@ void do_command_loop(void) { else if (!strncasecmp(cmdbuf,"QUIT",4)) { cprintf("%d Goodbye.\n",OK); - CC->state = CON_DYING; + CC->kill_me = 1; } else if (!strncasecmp(cmdbuf,"LOUT",4)) { diff --git a/citadel/citserver.h b/citadel/citserver.h index c206bd72a..8c344a252 100644 --- a/citadel/citserver.h +++ b/citadel/citserver.h @@ -1,7 +1,7 @@ /* $Id$ */ void master_startup (void); void master_cleanup (void); -void cleanup (struct CitContext *); +void RemoveContext (struct CitContext *); void set_wtmpsupp (char *newtext); void set_wtmpsupp_to_current_room(void); void cmd_info (void); diff --git a/citadel/database.c b/citadel/database.c index 4267b4f83..79ae19813 100644 --- a/citadel/database.c +++ b/citadel/database.c @@ -39,7 +39,8 @@ GDBM_FILE gdbms[MAXCDB]; /* * We also keep these around, for sequential searches... (one per - * session. Maybe there's a better way?) + * session. Maybe there's a better way?) FIX ... there _is_ a better + * way. We have TSD functions now; use them. */ #define MAXKEYS 256 datum dtkey[MAXKEYS]; diff --git a/citadel/housekeeping.c b/citadel/housekeeping.c index 72c1f4aa7..81dd76eba 100644 --- a/citadel/housekeeping.c +++ b/citadel/housekeeping.c @@ -44,25 +44,18 @@ void terminate_idle_sessions(void) { time_t now; int session_to_kill; - do { - now = time(NULL); - session_to_kill = 0; - begin_critical_section(S_SESSION_TABLE); - for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { - if ( (ccptr!=CC) - && (config.c_sleeping > 0) - && (now - (ccptr->lastcmd) > config.c_sleeping) ) { - session_to_kill = ccptr->cs_pid; - } - } - end_critical_section(S_SESSION_TABLE); - if (session_to_kill > 0) { - lprintf(3, "Session %d timed out. Terminating it...\n", - session_to_kill); - kill_session(session_to_kill); - } - } while(session_to_kill > 0); + now = time(NULL); + session_to_kill = 0; + begin_critical_section(S_SESSION_TABLE); + for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { + if ( (ccptr!=CC) + && (config.c_sleeping > 0) + && (now - (ccptr->lastcmd) > config.c_sleeping) ) { + ccptr->kill_me = 1; + } } + end_critical_section(S_SESSION_TABLE); +} diff --git a/citadel/server.h b/citadel/server.h index 72dc9f4d6..61228feea 100644 --- a/citadel/server.h +++ b/citadel/server.h @@ -56,6 +56,7 @@ struct CitContext { struct quickroom quickroom; int state; /* thread state (see CON_ values below) */ + int kill_me; /* Set to nonzero to flag for termination */ char curr_user[32]; /* name of current user */ int logged_in; /* logged in */ @@ -105,8 +106,7 @@ typedef struct CitContext t_context; /* Values for CitContext.state */ enum { CON_IDLE, /* This context is doing nothing */ - CON_EXECUTING, /* This context is bound to a thread */ - CON_DYING /* This context is being terminated */ + CON_EXECUTING /* This context is bound to a thread */ }; diff --git a/citadel/sysdep.c b/citadel/sysdep.c index 7eea262a3..f1545b7dc 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -312,7 +312,8 @@ struct CitContext *MyContext(void) { * Initialize a new context and place it in the list. */ struct CitContext *CreateNewContext(void) { - struct CitContext *me; + struct CitContext *me, *ptr; + int num = 1; me = (struct CitContext *) mallok(sizeof(struct CitContext)); if (me == NULL) { @@ -328,8 +329,19 @@ struct CitContext *CreateNewContext(void) { me->state = CON_EXECUTING; begin_critical_section(S_SESSION_TABLE); + + /* obtain a unique session number */ + for (ptr = ContextList; ptr != NULL; ptr = ptr->next) { + if (ptr->cs_pid == num) { + ++num; + ptr = ContextList; + } + } + + me->cs_pid = num; me->next = ContextList; ContextList = me; + end_critical_section(S_SESSION_TABLE); return(me); } @@ -367,7 +379,8 @@ void client_write(char *buf, int nbytes) if (retval < 1) { lprintf(2, "client_write() failed: %s\n", strerror(errno)); - CC->state = CON_DYING; + CC->kill_me = 1; + return; } bytes_written = bytes_written + retval; } @@ -423,7 +436,8 @@ int client_read_to(char *buf, int bytes, int timeout) if (rlen<1) { lprintf(2, "client_read() failed: %s\n", strerror(errno)); - CC->state = CON_DYING; + CC->kill_me = 1; + return(-1); } len = len + rlen; } @@ -494,7 +508,7 @@ void kill_session(int session_to_kill) { begin_critical_section(S_SESSION_TABLE); for (ptr = ContextList; ptr != NULL; ptr = ptr->next) { if (ptr->cs_pid == session_to_kill) { - ptr->state = CON_DYING; + ptr->kill_me = 1; } } end_critical_section(S_SESSION_TABLE); @@ -610,6 +624,36 @@ int convert_login(char NameToConvert[]) { +/* + * Purge all sessions which have the 'kill_me' flag set. + * 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. + */ +void dead_session_purge(void) { + static time_t last_purge = 0; + struct CitContext *ptr, *rem; + + if ( (time(NULL) - last_purge) < 5 ) return; /* Too soon, go away */ + + do { + rem = NULL; + begin_critical_section(S_SESSION_TABLE); + for (ptr = ContextList; ptr != NULL; ptr = ptr->next) { + if ( (ptr->state == CON_IDLE) && (ptr->kill_me) ) { + rem = ptr; + } + } + end_critical_section(S_SESSION_TABLE); + + /* RemoveContext() enters its own S_SESSION_TABLE critical + * section, so we have to do it like this. + */ + if (rem != NULL) RemoveContext(rem); + + } while (rem != NULL); +} + @@ -918,12 +962,10 @@ SETUP_FD: FD_ZERO(&readfds); pthread_setspecific(MyConKey, (void *)bind_me); do_command_loop(); pthread_setspecific(MyConKey, (void *)NULL); - if (bind_me->state == CON_DYING) { - cleanup(bind_me); + bind_me->state = CON_IDLE; + if (bind_me->kill_me == 1) { + RemoveContext(bind_me); } - else { - bind_me->state = CON_IDLE; - } write(rescan[1], &junk, 1); } else { @@ -932,7 +974,7 @@ SETUP_FD: FD_ZERO(&readfds); } } - + dead_session_purge(); } pthread_exit(NULL);