* Assign session numbers in a more portable and less arbitrary way.
$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
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
Fri Jul 10 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
* Initial CVS import
+
#include "tools.h"
struct CitContext *ContextList = NULL;
+char *unique_session_numbers;
int ScheduledShutdown = 0;
int do_defrag = 0;
/* 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) {
/*
- * 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;
}
/* 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");
/* Free up the memory used by this context */
phree(ToFree);
- lprintf(7, "Done with cleanup()\n");
+ lprintf(7, "Done with RemoveContext()\n");
}
{
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);
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 {
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);
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);
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)) {
/* $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);
/*
* 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];
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);
+}
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 */
/* 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 */
};
* 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) {
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);
}
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;
}
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;
}
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);
+/*
+ * 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);
+}
+
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 {
}
}
-
+ dead_session_purge();
}
pthread_exit(NULL);