From 7e5d9e93cc7fdc560eac95647fe329d818444226 Mon Sep 17 00:00:00 2001 From: Dave West Date: Sat, 29 Mar 2008 01:15:32 +0000 Subject: [PATCH] Fix up ARTV import so that imports actually work. Fixed various client_getln loops so that they don't go endless if the client disappears. ARTV import now makes use of the internal base64 decoder so it should be quicker. ARTV import now sends lots of dots to the client. This is to kick the watchdog timer in sendcommand so that it doesn't expire while we process a big message. Changes in threads.* are in preperation for cancelling threads and using signals to interrupt threads. They are #ifdef excluded. --- citadel/citserver.c | 2 +- citadel/control.c | 2 +- citadel/modules/bio/serv_bio.c | 2 +- citadel/modules/chat/serv_chat.c | 3 +- citadel/modules/network/serv_network.c | 2 +- citadel/modules/vandelay/serv_vandelay.c | 176 +++++++++++++++++------ citadel/msgbase.c | 2 +- citadel/sysdep.c | 34 +++-- citadel/sysdep_decls.h | 2 +- citadel/threads.c | 41 ++++-- citadel/threads.h | 4 +- 11 files changed, 197 insertions(+), 73 deletions(-) diff --git a/citadel/citserver.c b/citadel/citserver.c index f334f5cfd..bf2395156 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -637,7 +637,7 @@ void cmd_emsg(char *mname) } cprintf("%d %s\n", SEND_LISTING, targ); - while (client_getln(buf, sizeof buf), strcmp(buf, "000")) { + while (client_getln(buf, sizeof buf) >=0 && strcmp(buf, "000")) { fprintf(mfp, "%s\n", buf); } diff --git a/citadel/control.c b/citadel/control.c index 2522c7f3a..ea0865d49 100644 --- a/citadel/control.c +++ b/citadel/control.c @@ -342,7 +342,7 @@ void cmd_conf(char *argbuf) unbuffer_output(); cprintf("%d Send configuration...\n", SEND_LISTING); a = 0; - while (client_getln(buf, sizeof buf), strcmp(buf, "000")) { + while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) { switch (a) { case 0: safestrncpy(config.c_nodename, buf, diff --git a/citadel/modules/bio/serv_bio.c b/citadel/modules/bio/serv_bio.c index 276e7d981..d6cbb7537 100644 --- a/citadel/modules/bio/serv_bio.c +++ b/citadel/modules/bio/serv_bio.c @@ -68,7 +68,7 @@ void cmd_ebio(char *cmdbuf) { return; } cprintf("%d \n",SEND_LISTING); - while(client_getln(buf, sizeof buf), strcmp(buf,"000")) { + while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) { if (ftell(fp) < config.c_maxmsglen) { fprintf(fp,"%s\n",buf); } diff --git a/citadel/modules/chat/serv_chat.c b/citadel/modules/chat/serv_chat.c index 9a517f0ce..afc03dbb4 100644 --- a/citadel/modules/chat/serv_chat.c +++ b/citadel/modules/chat/serv_chat.c @@ -724,8 +724,7 @@ void cmd_sexp(char *argbuf) SEND_LISTING, message_sent); x_big_msgbuf = malloc(SIZ); memset(x_big_msgbuf, 0, SIZ); - while (client_getln(x_msg, sizeof x_msg), - strcmp(x_msg, "000")) { + while (client_getln(x_msg, sizeof x_msg) >= 0 && strcmp(x_msg, "000")) { x_big_msgbuf = realloc(x_big_msgbuf, strlen(x_big_msgbuf) + strlen(x_msg) + 4); if (!IsEmptyStr(x_big_msgbuf)) diff --git a/citadel/modules/network/serv_network.c b/citadel/modules/network/serv_network.c index deb9f8cbb..eb2a7c8f0 100644 --- a/citadel/modules/network/serv_network.c +++ b/citadel/modules/network/serv_network.c @@ -415,7 +415,7 @@ void cmd_snet(char *argbuf) { } cprintf("%d %s\n", SEND_LISTING, tempfilename); - while (client_getln(buf, sizeof buf), strcmp(buf, "000")) { + while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) { fprintf(fp, "%s\n", buf); } fclose(fp); diff --git a/citadel/modules/vandelay/serv_vandelay.c b/citadel/modules/vandelay/serv_vandelay.c index 42878ccea..c55329ea4 100644 --- a/citadel/modules/vandelay/serv_vandelay.c +++ b/citadel/modules/vandelay/serv_vandelay.c @@ -56,7 +56,7 @@ char artv_tempfilename2[PATH_MAX]; FILE *artv_global_message_list; void artv_export_users_backend(struct ctdluser *buf, void *data) { - cprintf("user\n"); + client_write("user\n", 5); /* #include "artv_serialize.h" #include "dtds/user-defs.h" @@ -78,15 +78,28 @@ void artv_export_users_backend(struct ctdluser *buf, void *data) { } void artv_dump_users_backend(struct ctdluser *buf, void *data) { - cprintf("user\n"); + client_write("user\n", 5); #include "artv_dump.h" #include "dtds/user-defs.h" #include "undef_data.h" - cprintf("\n"); + client_write("\n", 1); } +INLINE int cprintdot (long *iterations) +{ + int retval = 0; + + retval += client_write(".", 1); + ++(*iterations); + if ((*iterations) % 64 == 0) + retval += client_write("\n", 1); + return retval; +} + + + void artv_export_users(void) { ForEachUser(artv_export_users_backend, NULL); } @@ -104,12 +117,12 @@ void artv_export_room_msg(long msgnum, void *userdata) { void artv_dump_room_msg(long msgnum, void *userdata) { cprintf(" msgnum: %ld\n", msgnum); fprintf(artv_global_message_list, "%ld\n", msgnum); - cprintf("\n"); + client_write("\n", 1); }//// TODO void artv_export_rooms_backend(struct ctdlroom *buf, void *data) { - cprintf("room\n"); + client_write("room\n", 5); /* #include "artv_serialize.h" #include "dtds/room-defs.h" @@ -143,12 +156,12 @@ void artv_export_rooms_backend(struct ctdlroom *buf, void *data) { */ CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, artv_export_room_msg, NULL); - cprintf("0\n"); + client_write("0\n", 2); } void artv_dump_rooms_backend(struct ctdlroom *buf, void *data) { - cprintf("room\n"); + client_write("room\n", 5); #include "artv_dump.h" #include "dtds/room-defs.h" @@ -165,7 +178,7 @@ void artv_dump_rooms_backend(struct ctdlroom *buf, void *data) { */ CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, artv_dump_room_msg, NULL); - cprintf("\n\n"); + client_write("\n\n", 2); } @@ -217,7 +230,7 @@ void artv_export_floors(void) { int i; for (i=0; i < MAXFLOORS; ++i) { - cprintf("floor\n"); + client_write("floor\n", 5); cprintf("%d\n", i); getfloor(&qfbuf, i); buf = &qfbuf; @@ -240,7 +253,7 @@ void artv_dump_floors(void) { int i; for (i=0; i < MAXFLOORS; ++i) { - cprintf("floor\n"); + client_write("floor\n", 5); cprintf("%d\n", i); getfloor(&qfbuf, i); buf = &qfbuf; @@ -271,7 +284,7 @@ void artv_export_visits(void) { sizeof(struct visit) : cdbv->len)); cdb_free(cdbv); - cprintf("visit\n"); + client_write("visit\n", 6); cprintf("%ld\n", vbuf.v_roomnum); cprintf("%ld\n", vbuf.v_roomgen); cprintf("%ld\n", vbuf.v_usernum); @@ -305,7 +318,7 @@ void artv_dump_visits(void) { sizeof(struct visit) : cdbv->len)); cdb_free(cdbv); - cprintf("---visit---\n"); + client_write("---visit---\n", 12); cprintf(" Room-Num: %ld\n", vbuf.v_roomnum); cprintf(" Room-Gen%ld\n", vbuf.v_roomgen); cprintf(" User-Num%ld\n", vbuf.v_usernum); @@ -335,7 +348,7 @@ void artv_export_message(long msgnum) { msg = CtdlFetchMessage(msgnum, 1); if (msg == NULL) return; /* fail silently */ - cprintf("message\n"); + client_write("message\n", 8); GetMetaData(&smi, msgnum); cprintf("%ld\n", msgnum); cprintf("%d\n", smi.meta_refcount); @@ -372,7 +385,7 @@ void artv_dump_message(long msgnum) { msg = CtdlFetchMessage(msgnum, 1); if (msg == NULL) return; /* fail silently */ - cprintf("message\n"); + client_write("message\n", 8); GetMetaData(&smi, msgnum); cprintf(" MessageNum: %ld\n", msgnum); cprintf(" MetaRefcount: %d\n", smi.meta_refcount); @@ -452,16 +465,16 @@ void artv_do_export(void) { cprintf("version\n%d\n", REV_LEVEL); /* export the config file (this is done using x-macros) */ - cprintf("config\n"); + client_write("config\n", 7); #include "artv_serialize.h" #include "dtds/config-defs.h" #include "undef_data.h" - cprintf("\n"); + client_write("\n", 1); /* Export the control file */ get_control(); - cprintf("control\n"); + client_write("control\n", 8); cprintf("%ld\n", CitControl.MMhighest); cprintf("%u\n", CitControl.MMflags); cprintf("%ld\n", CitControl.MMnextuser); @@ -478,7 +491,7 @@ void artv_do_export(void) { if (Ctx->kill_me != 1) artv_export_messages(); - cprintf("000\n"); + client_write("000\n", 4); } void artv_do_dump(void) { @@ -492,7 +505,7 @@ void artv_do_dump(void) { cprintf("version\n%d\n", REV_LEVEL); /* export the config file (this is done using x-macros) */ - cprintf("config\n"); + client_write("config\n", 7); #include "artv_dump.h" #include "dtds/config-defs.h" @@ -500,7 +513,7 @@ void artv_do_dump(void) { /* Export the control file */ get_control(); - cprintf("control\n"); + client_write("control\n", 8); cprintf(" MMhighest: %ld\n", CitControl.MMhighest); cprintf(" MMflags: %u\n", CitControl.MMflags); cprintf(" MMnextuser: %ld\n", CitControl.MMnextuser); @@ -517,7 +530,7 @@ void artv_do_dump(void) { if (Ctx->kill_me != 1) artv_dump_messages(); - cprintf("000\n"); + client_write("000\n", 4); } @@ -617,13 +630,9 @@ void artv_import_room(long *iterations) { /* format of message list export is all message numbers output * one per line terminated by a 0. */ - while (client_getln(cbuf, sizeof cbuf), msgnum = atol(cbuf), msgnum > 0) { - CtdlLogPrintf(CTDL_DEBUG, "import room message link %d\n", msgnum); + while ((client_getln(cbuf, sizeof cbuf) >= 0) && (msgnum = atol(cbuf))) { CtdlSaveMsgPointerInRoom(qrbuf.QRname, msgnum, 0, NULL); - cprintf("."); - ++(*iterations); - if ((*iterations) % 64 == 0) - cprintf("\n"); + cprintdot(iterations); ++msgcount; if (CtdlThreadCheckStop()) break; @@ -683,7 +692,7 @@ void artv_import_visit(void) { -void artv_import_message(long *iterations) { +void artv_import_message(long *iterations, char **b64buf, size_t *b64size, char **plain, size_t *plain_size) { struct MetaData smi; long msgnum; long msglen; @@ -691,7 +700,10 @@ void artv_import_message(long *iterations) { char buf[SIZ]; char tempfile[PATH_MAX]; char *mbuf; - + size_t b64len = 0; + char *tbuf, *tbuf2; + size_t mlen; + memset(&smi, 0, sizeof(struct MetaData)); client_getln(buf, sizeof buf); msgnum = atol(buf); smi.meta_msgnum = msgnum; @@ -701,14 +713,63 @@ void artv_import_message(long *iterations) { CtdlLogPrintf(CTDL_INFO, "message #%ld\n", msgnum); /* decode base64 message text */ + while (client_getln(buf, sizeof buf) >= 0 && strcasecmp(buf, END_OF_MESSAGE)) { + if (CtdlThreadCheckStop()) + return; + + cprintdot(iterations); + + /** + * Grow the buffers if we need to + */ + mlen = strlen (buf); + if (b64len + mlen > *b64size) + { + tbuf = realloc (*b64buf, *b64size + SIZ); + tbuf2 = realloc (*plain, *plain_size + SIZ); + if (tbuf && tbuf2) + { + *b64buf = tbuf; + *plain = tbuf2; + *b64size += SIZ; + *plain_size += SIZ; + } + else + { + CtdlLogPrintf(CTDL_DEBUG, "ARTV import: realloc() failed.\n"); + cprintf("\nMemory allocation failure.\n"); + return; + } + } + strcat (*b64buf, buf); + b64len += mlen; + } + + /** + * Decode and store the message + * If this decode and store takes more than 5 seconds the sendcommand WD timer may expire. + * This is the reason for outputting a dot before and after. + */ + msglen = CtdlDecodeBase64(*plain, *b64buf, b64len); +// cprintdot(iterations); + CtdlLogPrintf(CTDL_DEBUG, "msglen = %ld\n", msglen); + cdb_store(CDB_MSGMAIN, &msgnum, sizeof(long), *plain, msglen); +// cprintdot(iterations); + PutMetaData(&smi); + CtdlLogPrintf(CTDL_INFO, "Imported message %ld\n", msgnum); + +/* CtdlMakeTempFileName(tempfile, sizeof tempfile); snprintf(buf, sizeof buf, "%s -d >%s", file_base64, tempfile); fp = popen(buf, "w"); - while (client_getln(buf, sizeof buf), strcasecmp(buf, END_OF_MESSAGE)) { - cprintf("."); - ++(*iterations); - if ((*iterations) % 64 == 0) - cprintf("\n"); + while (client_getln(buf, sizeof buf) >= 0 , strcasecmp(buf, END_OF_MESSAGE)) { + if (CtdlThreadCheckStop()) + { + pclose(fp); + unlink (tempfile); + return; + } + cprintdot(iterations); fprintf(fp, "%s\n", buf); } pclose(fp); @@ -730,6 +791,7 @@ void artv_import_message(long *iterations) { PutMetaData(&smi); CtdlLogPrintf(CTDL_INFO, "Imported message %ld\n", msgnum); +*/ } @@ -741,14 +803,39 @@ void artv_do_import(void) { char s_version[SIZ]; int version; long iterations; - + char *b64mes = NULL; + char *plain = NULL; + size_t b64size, plain_size; + unbuffer_output(); + /* Prepare buffers for base 64 decoding of messages. + */ + b64mes = malloc(SIZ); + if (b64mes == NULL) + { + cprintf("%d Malloc failed in import/export.\n", + ERROR + RESOURCE_BUSY); + return; + } + b64mes[0] = 0; + b64size=SIZ; + plain = malloc(SIZ); + if (plain == NULL) + { + cprintf("%d Malloc failed in import/export.\n", + ERROR + RESOURCE_BUSY); + free(b64mes); + return; + } + plain[0] = 0; + plain_size = SIZ; + cprintf("%d sock it to me\n", SEND_LISTING); abuf[0] = '\0'; unbuffer_output(); iterations = 0; - while (client_getln(buf, sizeof buf), strcmp(buf, "000")) { + while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) { if (CtdlThreadCheckStop()) break; // Should we break or return? @@ -762,10 +849,7 @@ void artv_do_import(void) { iterations = 0; } else { - cprintf("."); - iterations ++; - if (iterations % 64 == 0) - cprintf("\n"); + cprintdot(&iterations); } if (!strcasecmp(buf, "version")) { @@ -782,11 +866,19 @@ void artv_do_import(void) { else if (!strcasecmp(buf, "room")) artv_import_room(&iterations); else if (!strcasecmp(buf, "floor")) artv_import_floor(); else if (!strcasecmp(buf, "visit")) artv_import_visit(); - else if (!strcasecmp(buf, "message")) artv_import_message(&iterations); + else if (!strcasecmp(buf, "message")) + { + b64mes[0] = 0; + plain[0] = 0; + artv_import_message(&iterations, &b64mes, &b64size, &plain, &plain_size); + } else break; } + free (b64mes); + free (plain); + CtdlLogPrintf(CTDL_INFO, "Invalid keyword <%s>. Flushing input.\n", buf); - while (client_getln(buf, sizeof buf), strcmp(buf, "000")) ;; + while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) ;; rebuild_euid_index(); } diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 107b1d5cb..291d54fdd 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -744,7 +744,7 @@ void cmd_msgs(char *cmdbuf) template->cm_magic = CTDLMESSAGE_MAGIC; template->cm_anon_type = MES_NORMAL; - while(client_getln(buf, sizeof buf), strcmp(buf,"000")) { + while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) { extract_token(tfield, buf, 0, '|', sizeof tfield); extract_token(tvalue, buf, 1, '|', sizeof tvalue); for (i='A'; i<='Z'; ++i) if (msgkeys[i]!=NULL) { diff --git a/citadel/sysdep.c b/citadel/sysdep.c index acc3f9aa0..d634c5496 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -160,16 +160,15 @@ volatile int restart_server = 0; volatile int running_as_daemon = 0; static RETSIGTYPE signal_cleanup(int signum) { - CtdlLogPrintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum); #ifdef THREADS_USESIGNALS if (CT) - { - CtdlLogPrintf(CTDL_DEBUG, "Thread \"%s\" caught signal %d.\n", CT->name, signum); CT->signal = signum; - } else #endif + { + CtdlLogPrintf(CTDL_DEBUG, "Caught signal %d; shutting down.\n", signum); exit_signal = signum; + } } @@ -544,7 +543,7 @@ void unbuffer_output(void) { /* * client_write() ... Send binary data to the client. */ -void client_write(char *buf, int nbytes) +int client_write(char *buf, int nbytes) { int bytes_written = 0; int retval; @@ -565,7 +564,7 @@ void client_write(char *buf, int nbytes) memcpy(&Ctx->redirect_buffer[Ctx->redirect_len], buf, nbytes); Ctx->redirect_len += nbytes; Ctx->redirect_buffer[Ctx->redirect_len] = 0; - return; + return 0; } #ifndef HAVE_TCP_BUFFERING @@ -575,7 +574,7 @@ void client_write(char *buf, int nbytes) Ctx->buffer_len += nbytes; Ctx->output_buffer = realloc(Ctx->output_buffer, Ctx->buffer_len); memcpy(&Ctx->output_buffer[old_buffer_len], buf, nbytes); - return; + return 0; } #endif @@ -584,7 +583,7 @@ void client_write(char *buf, int nbytes) #ifdef HAVE_OPENSSL if (Ctx->redirect_ssl) { client_write_ssl(buf, nbytes); - return; + return 0; } #endif @@ -601,7 +600,7 @@ void client_write(char *buf, int nbytes) strerror(errno), errno); cit_backtrace(); Ctx->kill_me = 1; - return; + return -1; } } @@ -615,10 +614,11 @@ void client_write(char *buf, int nbytes) cit_backtrace(); // CtdlLogPrintf(CTDL_DEBUG, "Tried to send: %s", &buf[bytes_written]); Ctx->kill_me = 1; - return; + return -1; } bytes_written = bytes_written + retval; } + return 0; } @@ -670,6 +670,15 @@ int client_read_to(char *buf, int bytes, int timeout) retval = select( (fd)+1, &rfds, NULL, NULL, &tv); + if (retval < 0) + { + if (errno == EINTR) + { + CtdlLogPrintf(CTDL_DEBUG, "Interrupted select().\n"); + CC->kill_me = 1; + return (-1); + } + } if (FD_ISSET(fd, &rfds) == 0) { return(0); @@ -1162,8 +1171,9 @@ do_select: force_purge = 0; if (errno != EINTR) { CtdlLogPrintf(CTDL_EMERG, "Exiting (%s)\n", strerror(errno)); CtdlThreadStopAll(); - } else if (!CtdlThreadCheckStop()) { - CtdlLogPrintf(CTDL_DEBUG, "Interrupted select.\n"); + } else { + CtdlLogPrintf(CTDL_DEBUG, "Interrupted CtdlThreadSelect.\n"); + if (CtdlThreadCheckStop()) return(NULL); goto do_select; } } diff --git a/citadel/sysdep_decls.h b/citadel/sysdep_decls.h index a20c35cdb..c45c67f2d 100644 --- a/citadel/sysdep_decls.h +++ b/citadel/sysdep_decls.h @@ -83,7 +83,7 @@ void InitMyContext (struct CitContext *con); void buffer_output(void); void unbuffer_output(void); void flush_output(void); -void client_write (char *buf, int nbytes); +int client_write (char *buf, int nbytes); int client_read_to (char *buf, int bytes, int timeout); int client_read (char *buf, int bytes); int client_getln (char *buf, int maxbytes); diff --git a/citadel/threads.c b/citadel/threads.c index a1497d98c..a24e03289 100644 --- a/citadel/threads.c +++ b/citadel/threads.c @@ -13,6 +13,7 @@ #include #include #include +#include #if TIME_WITH_SYS_TIME # include @@ -329,14 +330,18 @@ void CtdlThreadStopAll(void) begin_critical_section(S_THREAD_LIST); this_thread = CtdlThreadList; + // Ask the GC thread to stop first so everything knows we are shutting down. + GC_thread->state = CTDL_THREAD_STOP_REQ; while(this_thread) { #ifdef THREADS_USESIGNALS - citthread_killl(this_thread->tid, SIGHUP); + if (!citthread_equal(this_thread->tid, GC_thread->tid)) + citthread_kill(this_thread->tid, SIGHUP); #endif ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_STOP_REQ); citthread_cond_signal(&this_thread->ThreadCond); citthread_cond_signal(&this_thread->SleepCond); + this_thread->stop_ticker = time(NULL); CtdlLogPrintf(CTDL_DEBUG, "Thread system stopping thread \"%s\" (0x%08lx).\n", this_thread->name, this_thread->tid); this_thread = this_thread->next; @@ -473,7 +478,10 @@ int CtdlThreadCheckStop(void) #ifdef THREADS_USESIGNALS if (CT->signal) + { CtdlLogPrintf(CTDL_DEBUG, "Thread \"%s\" caught signal %d.\n", CT->name, CT->signal); + CT->signal = 0; + } #endif if(state == CTDL_THREAD_STOP_REQ) { @@ -505,11 +513,13 @@ void CtdlThreadStop(CtdlThreadNode *thread) if (!(this_thread->thread_func)) return; // Don't stop garbage collector #ifdef THREADS_USESIGNALS - citthread_kill(this_thread->tid, SIGHUP); + if (!citthread_equal(this_thread->tid, GC_thread->tid)) + citthread_kill(this_thread->tid, SIGHUP); #endif ctdl_thread_internal_change_state (this_thread, CTDL_THREAD_STOP_REQ); citthread_cond_signal(&this_thread->ThreadCond); citthread_cond_signal(&this_thread->SleepCond); + this_thread->stop_ticker = time(NULL); } /* @@ -640,7 +650,7 @@ void CtdlThreadGC (void) if ((that_thread->state == CTDL_THREAD_STOP_REQ || that_thread->state == CTDL_THREAD_STOPPING) && (!citthread_equal(that_thread->tid, citthread_self()))) - that_thread->stop_ticker++; + CtdlLogPrintf(CTDL_DEBUG, "Waiting for thread %s (0x%08lx) to exit.\n", that_thread->name, that_thread->tid); else { /** @@ -650,7 +660,7 @@ void CtdlThreadGC (void) that_thread->stop_ticker = 0; } - if (that_thread->stop_ticker == 5) + if (that_thread->stop_ticker + 5 == time(NULL)) { CtdlLogPrintf(CTDL_DEBUG, "Thread System: The thread \"%s\" (0x%08lx) failed to self terminate within 5 ticks. It would be cancelled now.\n", that_thread->name, that_thread->tid); if ((that_thread->flags & CTDLTHREAD_WORKER) == 0) @@ -1120,7 +1130,7 @@ void ctdl_thread_internal_check_scheduled(void) if (ctdl_thread_internal_start_scheduled (that_thread)) { #ifdef WITH_THREADLOG - CtdlLogPrintf(CTDL_INFO, "Thread system, Started a scheduled thread \"%s\" (%ud).\n", + CtdlLogPrintf(CTDL_INFO, "Thread system, Started a scheduled thread \"%s\" (0x%08lx).\n", that_thread->name, that_thread->tid); #endif } @@ -1143,10 +1153,11 @@ void ctdl_thread_internal_check_scheduled(void) */ int CtdlThreadSelect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { - int ret; + int ret = 0; ctdl_thread_internal_change_state(CT, CTDL_THREAD_BLOCKED); - ret = select(n, readfds, writefds, exceptfds, timeout); + if (!CtdlThreadCheckStop()) + ret = select(n, readfds, writefds, exceptfds, timeout); /** * If the select returned <= 0 then it failed due to an error * or timeout so this thread could stop if asked to do so. @@ -1168,13 +1179,19 @@ int CtdlThreadSelect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds * idle and select has given it a task to do so it must not stop * In this condition we need to force it into the running state. * CtdlThreadGC will clear its ticker for us. + * + * FIXME: there is still a small hole here. It is possible for the sequence of locking + * to allow the state to get changed to STOP_REQ just after this code if the other thread + * has decided to change the state before this lock, it there fore has to wait till the lock + * completes but it will continue to change the state. We need something a bit better here. */ - if (GC_thread->state > CTDL_THREAD_STOP_REQ) + citthread_mutex_lock(&CT->ThreadMutex); /* To prevent race condition of a sleeping thread */ + if (GC_thread->state > CTDL_THREAD_STOP_REQ && CT->state <= CTDL_THREAD_STOP_REQ) { - citthread_mutex_lock(&CT->ThreadMutex); /* To prevent race condition of a sleeping thread */ + CtdlLogPrintf(CTDL_DEBUG, "Thread %s (0x%08lx) refused stop request.\n", CT->name, CT->tid); CT->state = CTDL_THREAD_RUNNING; - citthread_mutex_unlock(&CT->ThreadMutex); } + citthread_mutex_unlock(&CT->ThreadMutex); } return ret; @@ -1299,7 +1316,11 @@ void go_threading(void) CtdlThreadGC(); } +#ifdef THREADS_USESIGNALS + if (CtdlThreadGetCount() && CT->state > CTDL_THREAD_STOP_REQ) +#else if (CtdlThreadGetCount()) +#endif CtdlThreadSleep(1); } /* diff --git a/citadel/threads.h b/citadel/threads.h index c9e683cf5..65c5689fa 100644 --- a/citadel/threads.h +++ b/citadel/threads.h @@ -23,6 +23,8 @@ #include "server.h" #include "sysdep_decls.h" +// #define THREADS_USESIGNALS + /* * Thread stuff */ @@ -56,7 +58,7 @@ struct CtdlThreadNode{ void *user_args; /* Arguments passed to this threads work function */ long flags; /* Flags that describe this thread */ enum CtdlThreadState state; /* Flag to show state of this thread */ - int stop_ticker; /* A counter to determine how long it has taken for this thread to exit */ + time_t stop_ticker; /* A counter to determine how long it has taken for this thread to exit */ citthread_mutex_t ThreadMutex; /* A mutex to sync this thread to others if this thread allows (also used for sleeping) */ citthread_cond_t ThreadCond; /* A condition variable to sync this thread with others */ citthread_mutex_t SleepMutex; /* A mutex for sleeping */ -- 2.30.2