From 1421d26887f154439d2cd27075c7e85dc22f644f Mon Sep 17 00:00:00 2001 From: Dave West Date: Sun, 1 Nov 2009 18:09:14 +0000 Subject: [PATCH] Fixed the bug that prevented DOWN from working properly. Also broke the context handling routines out of sysdep.c and other places and put them in context.c / .h This has been done to make it easier to improve the speed with which we create / destroy contexts and threads. --- citadel/Makefile.in | 5 +- citadel/citserver.c | 44 +- citadel/citserver.h | 1 - citadel/context.c | 419 +++++++++++++++++++ citadel/context.h | 28 ++ citadel/modules/checkpoint/serv_checkpoint.c | 1 + citadel/modules/expire/serv_expire.c | 1 + citadel/modules/fulltext/serv_fulltext.c | 1 + citadel/modules/network/serv_network.c | 1 + citadel/modules/rssclient/serv_rssclient.c | 1 + citadel/server_main.c | 4 +- citadel/sysdep.c | 299 +------------ citadel/sysdep_decls.h | 10 - citadel/threads.c | 15 +- 14 files changed, 467 insertions(+), 363 deletions(-) create mode 100644 citadel/context.c create mode 100644 citadel/context.h diff --git a/citadel/Makefile.in b/citadel/Makefile.in index e06269236..cb952e569 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -86,7 +86,8 @@ SOURCES=utils/aidepost.c utils/stress.c utils/whobbs.c utils/citmail.c \ housekeeping.c ical_dezonify.c internet_addressing.c ecrash.c \ locate_host.c md5.c auth.c msgbase.c parsedate.c policy.c \ room_ops.c euidindex.c server_main.c snprintf.c ldap.c \ - support.c sysdep.c user_ops.c journaling.c threads.c + support.c sysdep.c user_ops.c journaling.c threads.c \ + context.c include Make_sources @@ -153,7 +154,7 @@ SERV_OBJS = server_main.o utillib/citadel_dirs.o\ file_ops.o msgbase.o euidindex.o \ locate_host.o housekeeping.o \ internet_addressing.o journaling.o \ - parsedate.o genstamp.o ecrash.o threads.o\ + parsedate.o genstamp.o ecrash.o threads.o context.o \ clientsocket.o modules_init.o modules_upgrade.o $(AUTH) $(SERV_MODULES) \ svn_revision.o ldap.o diff --git a/citadel/citserver.c b/citadel/citserver.c index 2f5f24690..e8e310f0d 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -73,6 +73,7 @@ #include "policy.h" #include "control.h" #include "euidindex.h" +#include "context.h" #include "svn_revision.h" #ifndef HAVE_SNPRINTF @@ -82,8 +83,6 @@ #include "ctdl_module.h" -struct CitContext *ContextList = NULL; -struct CitContext* next_session = NULL; char *unique_session_numbers; int ScheduledShutdown = 0; time_t server_startup_time; @@ -251,46 +250,6 @@ void master_cleanup(int exitcode) { -/* - * Terminate a session. - */ -void RemoveContext (struct CitContext *con) -{ - if (con==NULL) { - CtdlLogPrintf(CTDL_ERR, - "WARNING: RemoveContext() called with NULL!\n"); - return; - } - CtdlLogPrintf(CTDL_DEBUG, "RemoveContext() session %d\n", con->cs_pid); - - /* Run any cleanup routines registered by loadable modules. - * Note: We have to "become_session()" because the cleanup functions - * might make references to "CC" assuming it's the right one. - */ - become_session(con); - logout(); - PerformSessionHooks(EVT_STOP); - become_session(NULL); - - CtdlLogPrintf(CTDL_NOTICE, "[%3d] Session ended.\n", con->cs_pid); - - /* If the client is still connected, blow 'em away. */ - CtdlLogPrintf(CTDL_DEBUG, "Closing socket %d\n", con->client_socket); - close(con->client_socket); - - /* If using AUTHMODE_LDAP, free the DN */ - if (con->ldap_dn) { - free(con->ldap_dn); - con->ldap_dn = NULL; - } - - CtdlLogPrintf(CTDL_DEBUG, "Done with RemoveContext()\n"); -} - - - - - /* * cmd_info() - tell the client about this server */ @@ -873,6 +832,7 @@ void cmd_down(char *argbuf) { { cprintf(Reply, CIT_OK + SERVER_SHUTTING_DOWN); } + CC->kill_me = 1; /* Even the DOWN command has to follow correct proceedure when disconecting */ CtdlThreadStopAll(); } diff --git a/citadel/citserver.h b/citadel/citserver.h index 3e9ead3ec..1eb8cd804 100644 --- a/citadel/citserver.h +++ b/citadel/citserver.h @@ -33,7 +33,6 @@ void cit_backtrace(void); void cit_panic_backtrace(int SigNum); void master_startup (void); void master_cleanup (int exitcode); -void RemoveContext (struct CitContext *); void set_wtmpsupp (char *newtext); void set_wtmpsupp_to_current_room(void); void do_command_loop(void); diff --git a/citadel/context.c b/citadel/context.c new file mode 100644 index 000000000..4985de9e1 --- /dev/null +++ b/citadel/context.c @@ -0,0 +1,419 @@ +/* + * $Id: sysdep.c 7989 2009-10-31 15:29:37Z davew $ + * + * Citadel context management stuff. + * See COPYING for copyright information. + * + * Here's where we (hopefully) have all the code that manipulates contexts. + * + */ + +#include "sysdep.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "citadel.h" +#include "server.h" +#include "sysdep_decls.h" +#include "citserver.h" +#include "support.h" +#include "config.h" +#include "database.h" +#include "housekeeping.h" +#include "modules/crypto/serv_crypto.h" /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */ +#include "ecrash.h" + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#ifndef HAVE_SNPRINTF +#include "snprintf.h" +#endif + +#include "ctdl_module.h" +#include "threads.h" +#include "user_ops.h" +#include "control.h" + + + +citthread_key_t MyConKey; /* TSD key for MyContext() */ + + +struct CitContext masterCC; +struct CitContext *ContextList = NULL; +// struct CitContext* next_session = NULL; + +time_t last_purge = 0; /* Last dead session purge */ +int num_sessions = 0; /* Current number of sessions */ + +/* Flag for single user mode */ +static int want_single_user = 0; + +/* Try to go single user */ + +int CtdlTrySingleUser(void) +{ + int can_do = 0; + + begin_critical_section(S_SINGLE_USER); + if (want_single_user) + can_do = 0; + else + { + can_do = 1; + want_single_user = 1; + } + end_critical_section(S_SINGLE_USER); + return can_do; +} + +void CtdlEndSingleUser(void) +{ + begin_critical_section(S_SINGLE_USER); + want_single_user = 0; + end_critical_section(S_SINGLE_USER); +} + + +int CtdlWantSingleUser(void) +{ + return want_single_user; +} + +int CtdlIsSingleUser(void) +{ + if (want_single_user) + { + /* check for only one context here */ + if (num_sessions == 1) + return TRUE; + } + return FALSE; +} + + +/* + * Return a pointer to the CitContext structure bound to the thread which + * called this function. If there's no such binding (for example, if it's + * called by the housekeeper thread) then a generic 'master' CC is returned. + * + * This function is used *VERY* frequently and must be kept small. + */ +struct CitContext *MyContext(void) { + + register struct CitContext *c; + + return ((c = (struct CitContext *) citthread_getspecific(MyConKey), + c == NULL) ? &masterCC : c + ); +} + + + + +/* + * Terminate a session. + */ +void RemoveContext (struct CitContext *con) +{ + if (con==NULL) { + CtdlLogPrintf(CTDL_ERR, + "WARNING: RemoveContext() called with NULL!\n"); + return; + } + CtdlLogPrintf(CTDL_DEBUG, "RemoveContext() session %d\n", con->cs_pid); + + /* Run any cleanup routines registered by loadable modules. + * Note: We have to "become_session()" because the cleanup functions + * might make references to "CC" assuming it's the right one. + */ + become_session(con); + logout(); + PerformSessionHooks(EVT_STOP); + become_session(NULL); + + CtdlLogPrintf(CTDL_NOTICE, "[%3d] Session ended.\n", con->cs_pid); + + /* If the client is still connected, blow 'em away. */ + CtdlLogPrintf(CTDL_DEBUG, "Closing socket %d\n", con->client_socket); + close(con->client_socket); + + /* If using AUTHMODE_LDAP, free the DN */ + if (con->ldap_dn) { + free(con->ldap_dn); + con->ldap_dn = NULL; + } + + CtdlLogPrintf(CTDL_DEBUG, "Done with RemoveContext()\n"); +} + + + + + +/* + * Initialize a new context and place it in the list. The session number + * used to be the PID (which is why it's called cs_pid), but that was when we + * had one process per session. Now we just assign them sequentially, starting + * at 1 (don't change it to 0 because masterCC uses 0). + */ +struct CitContext *CreateNewContext(void) { + struct CitContext *me; + static int next_pid = 0; + + me = (struct CitContext *) malloc(sizeof(struct CitContext)); + if (me == NULL) { + CtdlLogPrintf(CTDL_ALERT, "citserver: can't allocate memory!!\n"); + return NULL; + } + + memset(me, 0, sizeof(struct CitContext)); + + /* Give the contaxt a name. Hopefully makes it easier to track */ + strcpy (me->user.fullname, "SYS_notauth"); + + /* The new context will be created already in the CON_EXECUTING state + * in order to prevent another thread from grabbing it while it's + * being set up. + */ + me->state = CON_EXECUTING; + /* + * Generate a unique session number and insert this context into + * the list. + */ + begin_critical_section(S_SESSION_TABLE); + me->cs_pid = ++next_pid; + me->prev = NULL; + me->next = ContextList; + ContextList = me; + if (me->next != NULL) { + me->next->prev = me; + } + ++num_sessions; + end_critical_section(S_SESSION_TABLE); + return (me); +} + + +struct CitContext *CtdlGetContextArray(int *count) +{ + int nContexts, i; + struct CitContext *nptr, *cptr; + + nContexts = num_sessions; + nptr = malloc(sizeof(struct CitContext) * nContexts); + if (!nptr) + return NULL; + begin_critical_section(S_SESSION_TABLE); + for (cptr = ContextList, i=0; cptr != NULL && i < nContexts; cptr = cptr->next, i++) + memcpy(&nptr[i], cptr, sizeof (struct CitContext)); + end_critical_section (S_SESSION_TABLE); + + *count = i; + return nptr; +} + + + +/** + * This function fills in a context and its user field correctly + * Then creates/loads that user + */ +void CtdlFillSystemContext(struct CitContext *context, char *name) +{ + char sysname[USERNAME_SIZE]; + + memset(context, 0, sizeof(struct CitContext)); + context->internal_pgm = 1; + context->cs_pid = 0; + strcpy (sysname, "SYS_"); + strcat (sysname, name); + /* internal_create_user has the side effect of loading the user regardless of wether they + * already existed or needed to be created + */ + internal_create_user (sysname, &(context->user), -1) ; + + /* Check to see if the system user needs upgrading */ + if (context->user.usernum == 0) + { /* old system user with number 0, upgrade it */ + context->user.usernum = get_new_user_number(); + CtdlLogPrintf(CTDL_DEBUG, "Upgrading system user \"%s\" from user number 0 to user number %d\n", context->user.fullname, context->user.usernum); + /* add user to the database */ + CtdlPutUser(&(context->user)); + cdb_store(CDB_USERSBYNUMBER, &(context->user.usernum), sizeof(long), context->user.fullname, strlen(context->user.fullname)+1); + } +} + +/* + * Cleanup any contexts that are left lying around + */ +void context_cleanup(void) +{ + struct CitContext *ptr = NULL; + struct CitContext *rem = NULL; + + /* + * Clean up the contexts. + * There are no threads so no critical_section stuff is needed. + */ + ptr = ContextList; + + /* We need to update the ContextList because some modules may want to itterate it + * Question is should we NULL it before iterating here or should we just keep updating it + * as we remove items? + * + * Answer is to NULL it first to prevent modules from doing any actions on the list at all + */ + ContextList=NULL; + while (ptr != NULL){ + /* Remove the session from the active list */ + rem = ptr->next; + --num_sessions; + + CtdlLogPrintf(CTDL_DEBUG, "Purging session %d\n", ptr->cs_pid); + RemoveContext(ptr); + free (ptr); + ptr = rem; + } +} + + + +/* + * Terminate another session. + * (This could justifiably be moved out of sysdep.c because it + * no longer does anything that is system-dependent.) + */ +void kill_session(int session_to_kill) { + struct CitContext *ptr; + + begin_critical_section(S_SESSION_TABLE); + for (ptr = ContextList; ptr != NULL; ptr = ptr->next) { + if (ptr->cs_pid == session_to_kill) { + 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. To force it to run + * anyway, set "force" to nonzero. + */ +void dead_session_purge(int force) { + struct CitContext *ptr, *ptr2; /* general-purpose utility pointer */ + struct CitContext *rem = NULL; /* list of sessions to be destroyed */ + + if (force == 0) { + if ( (time(NULL) - last_purge) < 5 ) { + return; /* Too soon, go away */ + } + } + time(&last_purge); + + if (try_critical_section(S_SESSION_TABLE)) + return; + + ptr = ContextList; + while (ptr) { + ptr2 = ptr; + ptr = ptr->next; + + if ( (ptr2->state == CON_IDLE) && (ptr2->kill_me) ) { + /* Remove the session from the active list */ + if (ptr2->prev) { + ptr2->prev->next = ptr2->next; + } + else { + ContextList = ptr2->next; + } + if (ptr2->next) { + ptr2->next->prev = ptr2->prev; + } + + --num_sessions; + /* And put it on our to-be-destroyed list */ + ptr2->next = rem; + rem = ptr2; + } + } + end_critical_section(S_SESSION_TABLE); + + /* Now that we no longer have the session list locked, we can take + * our time and destroy any sessions on the to-be-killed list, which + * is allocated privately on this thread's stack. + */ + while (rem != NULL) { + CtdlLogPrintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid); + RemoveContext(rem); + ptr = rem; + rem = rem->next; + free(ptr); + } +} + + + + + +/* + * masterCC is the context we use when not attached to a session. This + * function initializes it. + */ +void InitializeMasterCC(void) { + memset(&masterCC, 0, sizeof(struct CitContext)); + masterCC.internal_pgm = 1; + masterCC.cs_pid = 0; +} + + + + +/* + * Bind a thread to a context. (It's inline merely to speed things up.) + */ +INLINE void become_session(struct CitContext *which_con) { + citthread_setspecific(MyConKey, (void *)which_con ); +} + + + diff --git a/citadel/context.h b/citadel/context.h new file mode 100644 index 000000000..b136f5334 --- /dev/null +++ b/citadel/context.h @@ -0,0 +1,28 @@ +/* $Id: sysdep_decls.h 7265 2009-03-25 23:18:46Z dothebart $ */ + +#ifndef CONTEXT_H +#define CONTEXT_H + +#include +#include "sysdep.h" +#include "server.h" +#include "sysdep_decls.h" +#include "threads.h" + + +extern citthread_key_t MyConKey; /* TSD key for MyContext() */ +extern int num_sessions; +extern struct CitContext masterCC; + +struct CitContext *MyContext (void); +void RemoveContext (struct CitContext *); +struct CitContext *CreateNewContext (void); +void context_cleanup(void); +void kill_session (int session_to_kill); +INLINE void become_session(struct CitContext *which_con); +void InitializeMasterCC(void); +void dead_session_purge(int force); + + + +#endif /* CONTEXT_H */ diff --git a/citadel/modules/checkpoint/serv_checkpoint.c b/citadel/modules/checkpoint/serv_checkpoint.c index f94a41dc3..da04ac4b9 100644 --- a/citadel/modules/checkpoint/serv_checkpoint.c +++ b/citadel/modules/checkpoint/serv_checkpoint.c @@ -56,6 +56,7 @@ #include "threads.h" #include "ctdl_module.h" +#include "context.h" /* * Main loop for the checkpoint thread. diff --git a/citadel/modules/expire/serv_expire.c b/citadel/modules/expire/serv_expire.c index b0824e2fb..94e716216 100644 --- a/citadel/modules/expire/serv_expire.c +++ b/citadel/modules/expire/serv_expire.c @@ -82,6 +82,7 @@ #include "control.h" #include "serv_network.h" /* Needed for definition of UseTable */ #include "threads.h" +#include "context.h" #include "ctdl_module.h" diff --git a/citadel/modules/fulltext/serv_fulltext.c b/citadel/modules/fulltext/serv_fulltext.c index 68f5f4136..b52d959e9 100644 --- a/citadel/modules/fulltext/serv_fulltext.c +++ b/citadel/modules/fulltext/serv_fulltext.c @@ -58,6 +58,7 @@ #include "serv_fulltext.h" #include "ft_wordbreaker.h" #include "threads.h" +#include "context.h" #include "ctdl_module.h" diff --git a/citadel/modules/network/serv_network.c b/citadel/modules/network/serv_network.c index dddf90b47..b289851dc 100644 --- a/citadel/modules/network/serv_network.c +++ b/citadel/modules/network/serv_network.c @@ -82,6 +82,7 @@ #include "snprintf.h" #endif +#include "context.h" #include "ctdl_module.h" diff --git a/citadel/modules/rssclient/serv_rssclient.c b/citadel/modules/rssclient/serv_rssclient.c index e60c5ad94..b1610d67b 100644 --- a/citadel/modules/rssclient/serv_rssclient.c +++ b/citadel/modules/rssclient/serv_rssclient.c @@ -56,6 +56,7 @@ #include "database.h" #include "citadel_dirs.h" #include "md5.h" +#include "context.h" struct rssnetcfg { diff --git a/citadel/server_main.c b/citadel/server_main.c index 71f81feb3..5d73d7a52 100644 --- a/citadel/server_main.c +++ b/citadel/server_main.c @@ -57,6 +57,8 @@ #include "svn_revision.h" #include "citadel_dirs.h" +#include "context.h" + #include "modules_init.h" #include "ecrash.h" @@ -71,8 +73,6 @@ const char *CitadelServiceUDS="citadel-UDS"; const char *CitadelServiceTCP="citadel-TCP"; -extern struct CitContext masterCC; - void go_threading(void); diff --git a/citadel/sysdep.c b/citadel/sysdep.c index 433f3467b..3ddc662aa 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -60,6 +60,7 @@ #include "housekeeping.h" #include "modules/crypto/serv_crypto.h" /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */ #include "ecrash.h" +#include "context.h" #ifdef HAVE_SYS_SELECT_H #include @@ -87,64 +88,12 @@ struct igheap *igheap = NULL; #endif -citthread_key_t MyConKey; /* TSD key for MyContext() */ - int verbosity = DEFAULT_VERBOSITY; /* Logging level */ -struct CitContext masterCC; -time_t last_purge = 0; /* Last dead session purge */ -int num_sessions = 0; /* Current number of sessions */ - int syslog_facility = LOG_DAEMON; int enable_syslog = 0; -/* Flag for single user mode */ -static int want_single_user = 0; - -/* Try to go single user */ - -int CtdlTrySingleUser(void) -{ - int can_do = 0; - - begin_critical_section(S_SINGLE_USER); - if (want_single_user) - can_do = 0; - else - { - can_do = 1; - want_single_user = 1; - } - end_critical_section(S_SINGLE_USER); - return can_do; -} - -void CtdlEndSingleUser(void) -{ - begin_critical_section(S_SINGLE_USER); - want_single_user = 0; - end_critical_section(S_SINGLE_USER); -} - - -int CtdlWantSingleUser(void) -{ - return want_single_user; -} - -int CtdlIsSingleUser(void) -{ - if (want_single_user) - { - /* check for only one context here */ - if (num_sessions == 1) - return TRUE; - } - return FALSE; -} - - /* * CtdlLogPrintf() ... Write logging information */ @@ -445,116 +394,6 @@ int ig_uds_server(char *sockpath, int queue_len, char **errormessage) -/* - * Return a pointer to the CitContext structure bound to the thread which - * called this function. If there's no such binding (for example, if it's - * called by the housekeeper thread) then a generic 'master' CC is returned. - * - * This function is used *VERY* frequently and must be kept small. - */ -struct CitContext *MyContext(void) { - - register struct CitContext *c; - - return ((c = (struct CitContext *) citthread_getspecific(MyConKey), - c == NULL) ? &masterCC : c - ); -} - - -/* - * Initialize a new context and place it in the list. The session number - * used to be the PID (which is why it's called cs_pid), but that was when we - * had one process per session. Now we just assign them sequentially, starting - * at 1 (don't change it to 0 because masterCC uses 0). - */ -struct CitContext *CreateNewContext(void) { - struct CitContext *me; - static int next_pid = 0; - - me = (struct CitContext *) malloc(sizeof(struct CitContext)); - if (me == NULL) { - CtdlLogPrintf(CTDL_ALERT, "citserver: can't allocate memory!!\n"); - return NULL; - } - - memset(me, 0, sizeof(struct CitContext)); - - /* Give the contaxt a name. Hopefully makes it easier to track */ - strcpy (me->user.fullname, "SYS_notauth"); - - /* The new context will be created already in the CON_EXECUTING state - * in order to prevent another thread from grabbing it while it's - * being set up. - */ - me->state = CON_EXECUTING; - /* - * Generate a unique session number and insert this context into - * the list. - */ - begin_critical_section(S_SESSION_TABLE); - me->cs_pid = ++next_pid; - me->prev = NULL; - me->next = ContextList; - ContextList = me; - if (me->next != NULL) { - me->next->prev = me; - } - ++num_sessions; - end_critical_section(S_SESSION_TABLE); - return (me); -} - - -struct CitContext *CtdlGetContextArray(int *count) -{ - int nContexts, i; - struct CitContext *nptr, *cptr; - - nContexts = num_sessions; - nptr = malloc(sizeof(struct CitContext) * nContexts); - if (!nptr) - return NULL; - begin_critical_section(S_SESSION_TABLE); - for (cptr = ContextList, i=0; cptr != NULL && i < nContexts; cptr = cptr->next, i++) - memcpy(&nptr[i], cptr, sizeof (struct CitContext)); - end_critical_section (S_SESSION_TABLE); - - *count = i; - return nptr; -} - - - -/** - * This function fills in a context and its user field correctly - * Then creates/loads that user - */ -void CtdlFillSystemContext(struct CitContext *context, char *name) -{ - char sysname[USERNAME_SIZE]; - - memset(context, 0, sizeof(struct CitContext)); - context->internal_pgm = 1; - context->cs_pid = 0; - strcpy (sysname, "SYS_"); - strcat (sysname, name); - /* internal_create_user has the side effect of loading the user regardless of wether they - * already existed or needed to be created - */ - internal_create_user (sysname, &(context->user), -1) ; - - /* Check to see if the system user needs upgrading */ - if (context->user.usernum == 0) - { /* old system user with number 0, upgrade it */ - context->user.usernum = get_new_user_number(); - CtdlLogPrintf(CTDL_DEBUG, "Upgrading system user \"%s\" from user number 0 to user number %d\n", context->user.fullname, context->user.usernum); - /* add user to the database */ - CtdlPutUser(&(context->user)); - cdb_store(CDB_USERSBYNUMBER, &(context->user.usernum), sizeof(long), context->user.fullname, strlen(context->user.fullname)+1); - } -} - /* * The following functions implement output buffering on operating systems which * support it (such as Linux and various BSD flavors). @@ -792,36 +631,6 @@ int client_getln(char *buf, int bufsize) /* * Cleanup any contexts that are left lying around */ -void context_cleanup(void) -{ - struct CitContext *ptr = NULL; - struct CitContext *rem = NULL; - - /* - * Clean up the contexts. - * There are no threads so no critical_section stuff is needed. - */ - ptr = ContextList; - - /* We need to update the ContextList because some modules may want to itterate it - * Question is should we NULL it before iterating here or should we just keep updating it - * as we remove items? - * - * Answer is to NULL it first to prevent modules from doing any actions on the list at all - */ - ContextList=NULL; - while (ptr != NULL){ - /* Remove the session from the active list */ - rem = ptr->next; - --num_sessions; - - CtdlLogPrintf(CTDL_DEBUG, "Purging session %d\n", ptr->cs_pid); - RemoveContext(ptr); - free (ptr); - ptr = rem; - } -} - void close_masters (void) @@ -885,23 +694,6 @@ void sysdep_master_cleanup(void) { -/* - * Terminate another session. - * (This could justifiably be moved out of sysdep.c because it - * no longer does anything that is system-dependent.) - */ -void kill_session(int session_to_kill) { - struct CitContext *ptr; - - begin_critical_section(S_SESSION_TABLE); - for (ptr = ContextList; ptr != NULL; ptr = ptr->next) { - if (ptr->cs_pid == session_to_kill) { - ptr->kill_me = 1; - } - } - end_critical_section(S_SESSION_TABLE); -} - pid_t current_child; void graceful_shutdown(int signum) { kill(current_child, signum); @@ -1043,92 +835,6 @@ 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. To force it to run - * anyway, set "force" to nonzero. - */ -void dead_session_purge(int force) { - struct CitContext *ptr, *ptr2; /* general-purpose utility pointer */ - struct CitContext *rem = NULL; /* list of sessions to be destroyed */ - - if (force == 0) { - if ( (time(NULL) - last_purge) < 5 ) { - return; /* Too soon, go away */ - } - } - time(&last_purge); - - if (try_critical_section(S_SESSION_TABLE)) - return; - - ptr = ContextList; - while (ptr) { - ptr2 = ptr; - ptr = ptr->next; - - if ( (ptr2->state == CON_IDLE) && (ptr2->kill_me) ) { - /* Remove the session from the active list */ - if (ptr2->prev) { - ptr2->prev->next = ptr2->next; - } - else { - ContextList = ptr2->next; - } - if (ptr2->next) { - ptr2->next->prev = ptr2->prev; - } - - --num_sessions; - /* And put it on our to-be-destroyed list */ - ptr2->next = rem; - rem = ptr2; - } - } - end_critical_section(S_SESSION_TABLE); - - /* Now that we no longer have the session list locked, we can take - * our time and destroy any sessions on the to-be-killed list, which - * is allocated privately on this thread's stack. - */ - while (rem != NULL) { - CtdlLogPrintf(CTDL_DEBUG, "Purging session %d\n", rem->cs_pid); - RemoveContext(rem); - ptr = rem; - rem = rem->next; - free(ptr); - } -} - - - - - -/* - * masterCC is the context we use when not attached to a session. This - * function initializes it. - */ -void InitializeMasterCC(void) { - memset(&masterCC, 0, sizeof(struct CitContext)); - masterCC.internal_pgm = 1; - masterCC.cs_pid = 0; -} - - - - -/* - * Bind a thread to a context. (It's inline merely to speed things up.) - */ -INLINE void become_session(struct CitContext *which_con) { - if (which_con) - ctdl_thread_internal_change_state(CT, CTDL_THREAD_RUNNING); - - citthread_setspecific(MyConKey, (void *)which_con ); -} - /* @@ -1189,7 +895,8 @@ do_select: force_purge = 0; begin_critical_section(S_SESSION_TABLE); for (ptr = ContextList; ptr != NULL; ptr = ptr->next) { - if (ptr->state == CON_IDLE) { + /* Dont select on dead sessions only truly idle ones */ + if ((ptr->state == CON_IDLE)) { FD_SET(ptr->client_socket, &readfds); if (ptr->client_socket > highest) highest = ptr->client_socket; diff --git a/citadel/sysdep_decls.h b/citadel/sysdep_decls.h index 802ae3305..3c463f755 100644 --- a/citadel/sysdep_decls.h +++ b/citadel/sysdep_decls.h @@ -49,16 +49,11 @@ void cprintf (const char *format, ...); void CtdlLogPrintf(enum LogLevel loglevel, const char *format, ...); void vCtdlLogPrintf (enum LogLevel loglevel, const char *format, va_list arg_ptr); -extern pthread_key_t MyConKey; /* TSD key for MyContext() */ - extern int enable_syslog; void init_sysdep (void); int ig_tcp_server (char *ip_addr, int port_number, int queue_len,char **errormessage); int ig_uds_server(char *sockpath, int queue_len, char **errormessage); -struct CitContext *MyContext (void); -struct CitContext *CreateNewContext (void); -void InitMyContext (struct CitContext *con); void buffer_output(void); void unbuffer_output(void); void flush_output(void); @@ -68,20 +63,15 @@ int client_read (char *buf, int bytes); int client_getln (char *buf, int maxbytes); void sysdep_master_cleanup (void); void kill_session (int session_to_kill); -void *sd_context_loop (struct CitContext *con); void start_daemon (int do_close_stdio); void checkcrash(void); void cmd_nset (char *cmdbuf); int convert_login (char *NameToConvert); void *worker_thread (void *arg); -void *context_cleanup_thread (void *arg); -void become_session(struct CitContext *which_con); -void InitializeMasterCC(void); void init_master_fdset(void); void create_worker(void); -extern int num_sessions; extern volatile int exit_signal; extern volatile int shutdown_and_halt; extern volatile int running_as_daemon; diff --git a/citadel/threads.c b/citadel/threads.c index 4f9d1428c..9782d05fc 100644 --- a/citadel/threads.c +++ b/citadel/threads.c @@ -38,6 +38,7 @@ #include "config.h" #include "citserver.h" #include "sysdep_decls.h" +#include "context.h" /* * define this to use the new worker_thread method of handling connections @@ -1196,14 +1197,7 @@ int CtdlThreadSelect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds * or timeout so this thread could stop if asked to do so. * Anything else means it needs to continue unless the system is shutting down */ - if (ret <= 0) - { - /** - * select says nothing to do so we can change to running if we haven't been asked to stop. - */ - ctdl_thread_internal_change_state(CT, CTDL_THREAD_RUNNING); - } - else + if (ret > 0) { /** * The select says this thread needs to do something useful. @@ -1227,6 +1221,8 @@ int CtdlThreadSelect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds citthread_mutex_unlock(&CT->ThreadMutex); } + ctdl_thread_internal_change_state(CT, CTDL_THREAD_RUNNING); + return ret; } @@ -1347,7 +1343,7 @@ void go_threading(void) } CtdlThreadGC(); - + if (CtdlThreadGetCount() <= 1) // Shutting down clean up the garbage collector { CtdlThreadGC(); @@ -1574,7 +1570,6 @@ int execute_session(struct CitContext *bind_me) -extern void dead_session_purge(int force); /* * A new worker_thread loop. -- 2.30.2