Fix up ARTV import so that imports actually work.
authorDave West <davew@uncensored.citadel.org>
Sat, 29 Mar 2008 01:15:32 +0000 (01:15 +0000)
committerDave West <davew@uncensored.citadel.org>
Sat, 29 Mar 2008 01:15:32 +0000 (01:15 +0000)
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
citadel/control.c
citadel/modules/bio/serv_bio.c
citadel/modules/chat/serv_chat.c
citadel/modules/network/serv_network.c
citadel/modules/vandelay/serv_vandelay.c
citadel/msgbase.c
citadel/sysdep.c
citadel/sysdep_decls.h
citadel/threads.c
citadel/threads.h

index f334f5cfd8d94f26426431794251aa848bf2a34a..bf23951560ba3a933500bcfe8b4cad5c6d27a50c 100644 (file)
@@ -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);
        }
 
index 2522c7f3acd8a3a1d29c359da2efbdffa8431220..ea0865d49fd5db46243e0427d70ff76783a466b9 100644 (file)
@@ -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,
index 276e7d9811baebb88c87c05b36891335f0b257dd..d6cbb7537928f60447adf92e67857a3344377ba6 100644 (file)
@@ -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);
                }
index 9a517f0ceb45c9f2858d705dd578cdc5aadae6f0..afc03dbb4358cd6dd4c33b283e1e1132f884e425 100644 (file)
@@ -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))
index deb9f8cbb9bc488f09184ae48c032df2d9ea2fa4..eb2a7c8f0c5b3bf1d212c9ac5c0e5ca30c06c024 100644 (file)
@@ -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);
index 42878cceaacc7846bb4d82eeb6baf680839d5e94..c55329ea4fac1c145a6c6605be609271e0a2b90e 100644 (file)
@@ -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();
 }
 
index 107b1d5cb2a9fa32f73f34aea6d27c433d4d4fda..291d54fdda6245be56812a34f4fd6018940f003c 100644 (file)
@@ -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) {
index acc3f9aa09f436c335177b0b8d45292dff619b80..d634c5496a01a21dfac30edc6be95564ef9fd9ef 100644 (file)
@@ -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;
                        }
                }
index a20c35cdb46cef5ed904ed29cc2ac8ec078ad68a..c45c67f2de77fdd4f07bfebbf10405bddc3efed2 100644 (file)
@@ -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);
index a1497d98c35907ce25c6198f95a1ec9e407cb146..a24e03289e74121b826d57856c09d63a2d17649c 100644 (file)
@@ -13,6 +13,7 @@
 #include <sys/socket.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <signal.h>
 
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
@@ -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);
        }
        /*
index c9e683cf524e2adcf98c67222449347262ea0ee5..65c5689fac86c639e3e7a23458a6244a0a5dad85 100644 (file)
@@ -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 */