* Debugged all possible ways for a session to terminate; do them cleanly.
authorArt Cancro <ajc@citadel.org>
Fri, 29 Oct 1999 01:03:03 +0000 (01:03 +0000)
committerArt Cancro <ajc@citadel.org>
Fri, 29 Oct 1999 01:03:03 +0000 (01:03 +0000)
* Assign session numbers in a more portable and less arbitrary way.

citadel/ChangeLog
citadel/citserver.c
citadel/citserver.h
citadel/database.c
citadel/housekeeping.c
citadel/server.h
citadel/sysdep.c

index e4cb2988c6ee7620eb1549e493c035a675aff428..4f18c04be64f83d06b778338e709f6a702a7a37e 100644 (file)
@@ -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 <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
        * Initial CVS import 
+
index c9e9c1af3059f44dfe4d0cb3c05d8bf58e1486b6..7bc73d1af1ef861b25ebf76f84385846b49dfe1b 100644 (file)
@@ -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)) {
index c206bd72a707fcc543cd433872037e2d22876722..8c344a252ecc8d1879dbb9271dbea1ced52eb17a 100644 (file)
@@ -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);
index 4267b4f8378e3e7a99c4dc9490b0a777412e8ada..79ae1981344ccdd24c7b36b0f556370626e718ac 100644 (file)
@@ -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];
index 72c1f4aa731e7ae6bc03cf7959435be160b9a9a1..81dd76ebab8fc5acf8350c9dd3350e80431a151f 100644 (file)
@@ -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);
+}
 
 
 
index 72dc9f4d647293c588d6865401d2c172633beb1a..61228feea1a988e6765a1c3ac6c1f0b4570ae763 100644 (file)
@@ -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 */
 };
 
 
index 7eea262a32c7fd67f4dc59b1c69799b6466a2937..f1545b7dc88f7334523f4c5df317dfd862e9bf56 100644 (file)
@@ -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);