]> code.citadel.org Git - citadel.git/commitdiff
* new threaded client code for background keepalives
authorNathan Bryant <loanshark@uncensored.citadel.org>
Sat, 11 Mar 2000 04:09:03 +0000 (04:09 +0000)
committerNathan Bryant <loanshark@uncensored.citadel.org>
Sat, 11 Mar 2000 04:09:03 +0000 (04:09 +0000)
citadel/ChangeLog
citadel/Makefile.in
citadel/acconfig.h
citadel/commands.c
citadel/commands.h
citadel/configure.in
citadel/messages.c

index ee7185ab04081f1dceb93a0b4655c10ac1d51565..47825a45776bd8a7dd5555e6c1415ced45ca019c 100644 (file)
@@ -1,4 +1,7 @@
 $Log$
+Revision 1.482  2000/03/11 04:09:03  nbryant
+ * new threaded client code for background keepalives
+
 Revision 1.481  2000/03/10 21:40:04  ajc
 * Changes to message base and networker to support Internet-style message
   ID's instead of the conventional Citadel style.
@@ -1711,4 +1714,3 @@ 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 1555f2e02489fc06bddbf6d5e83828e35f5527ae..0bf427c4071030ec4f667d11c7b2d405ed42a9cd 100644 (file)
@@ -21,6 +21,7 @@ all: $(TARGETS)
 
 EXEEXT=@EXEEXT@
 SO=@SO@
+CX=@CX@
 SERV_ICQ=@SERV_ICQ@
 
 CLIENT_TARGETS=citadel$(EXEEXT) whobbs$(EXEEXT)
@@ -55,7 +56,10 @@ CURSES=@CURSES@
 NETLIBS=@NETLIBS@
 chkpwd_LIBS=@chkpwd_LIBS@
 LIBOBJS=@LIBOBJS@
+CL_LIBOBJS=@CL_LIBOBJS@
 PTHREAD_DEFS=@PTHREAD_DEFS@
+PTHREAD_LIBS=@PTHREAD_LIBS@
+CLIENT_PTLIBS=@CLIENT_PTLIBS@
 INSTALL=@INSTALL@
 INSTALL_DATA=@INSTALL_DATA@
 SHELL=/bin/sh
@@ -91,13 +95,13 @@ serv_modules: $(SERV_MODULES)
 #
 #
 
-citadel$(EXEEXT): ipc_c_tcp.o citadel.o rooms.o routines.o \
-       routines2.o messages.o client_icq.o \
-       commands.o client_chat.o serv_info.o tools.o $(LIBOBJS)
-       $(CC) ipc_c_tcp.o citadel.o rooms.o routines.o routines2.o \
-       messages.o client_icq.o \
-       commands.o client_chat.o serv_info.o tools.o $(LIBOBJS) $(LDFLAGS) \
-       -o citadel $(NETLIBS)
+citadel$(EXEEXT): ipc_c_tcp$(CX) citadel$(CX) rooms$(CX) routines$(CX) \
+       routines2$(CX) messages$(CX) client_icq$(CX) \
+       commands$(CX) client_chat$(CX) serv_info$(CX) tools$(CX) $(LIBOBJS)
+       $(CC) ipc_c_tcp$(CX) citadel$(CX) rooms$(CX) routines$(CX) \
+       routines2$(CX) messages$(CX) client_icq$(CX) \
+       commands$(CX) client_chat$(CX) serv_info$(CX) tools$(CX) \
+       $(LIBOBJS) $(LDFLAGS) -o citadel $(NETLIBS) $(CLIENT_PTLIBS)
 
 netpoll: netpoll.o config.o ipc_c_tcp.o tools.o $(LIBOBJS)
        $(CC) netpoll.o config.o ipc_c_tcp.o tools.o \
@@ -117,8 +121,8 @@ SERV_OBJS = citserver.ro user_ops.ro support.ro room_ops.ro file_ops.ro \
        $(AUTH) $(LIBOBJS:.o=.ro)
 
 citserver: $(SERV_OBJS)
-       $(CC) $(SERV_OBJS) $(LDFLAGS) $(SERVER_LDFLAGS) $(LIBS) $(NETLIBS) \
-       $(GDBM) $(RESOLV) -o citserver
+       $(CC) $(SERV_OBJS) $(LDFLAGS) $(SERVER_LDFLAGS) $(PTHREAD_LIBS) \
+       $(LIBS) $(NETLIBS) $(GDBM) $(RESOLV) -o citserver
 
 .c.ro:
        $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) $(PTHREAD_DEFS) -c $< -o $@
index 6b52e2f41a4c504350871c5168375e48c8039eec..d2d1d1527715d181a0a07f07afeeaa52a690ad26 100644 (file)
@@ -18,3 +18,6 @@
 
 /* define this if you have the pthread_cancel() function */
 #undef HAVE_PTHREAD_CANCEL
+
+/* define this if you want to enable the multithreaded client */
+#undef THREADED_CLIENT
index 4a69b1aecc97ec0b1cc777518d8ce393ff820237..af29a10dfc2ab577e6f1286cd5824e5b5efc5c68 100644 (file)
@@ -26,6 +26,9 @@
 #include <sys/select.h>
 #endif
 
+#ifdef THREADED_CLIENT
+#include <pthread.h>
+#endif
 
 #include <signal.h>
 #include <errno.h>
@@ -122,20 +125,9 @@ void set_keepalives(int s)
 /* 
  * This loop handles the "keepalive" messages sent to the server when idling.
  */
-void do_keepalive(void)
-{
-       char buf[256];
-       static time_t idlet = 0;
-       time_t now;
-
-       time(&now);
-       if ((now - idlet) < ((long) S_KEEPALIVE))
-               return;
-       time(&idlet);
 
-       /* Do a space-backspace to keep telnet sessions from idling out */
-       printf(" %c", 8);
-       fflush(stdout);
+static void really_do_keepalive(void) {
+       char buf[256];
 
        if (keepalives_enabled != KA_NO) {
                serv_puts("NOOP");
@@ -155,6 +147,90 @@ void do_keepalive(void)
        }
 }
 
+/* threaded nonblocking keepalive stuff starts here. I'm going for a simple
+   encapsulated interface; in theory there should be no need to touch these
+   globals outside of the async_ka_* functions. */
+
+#ifdef THREADED_CLIENT
+static pthread_t ka_thr_handle;
+static int ka_thr_active = 0;
+static pthread_mutex_t ka_thr_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int async_ka_enabled = 0;
+
+static void *ka_thread(void *arg)
+{
+       really_do_keepalive();
+       pthread_detach(ka_thr_handle);
+       ka_thr_active = 0;
+       return NULL;
+}
+
+/* start up a thread to handle a keepalive in the background */
+static void async_ka_exec(void)
+{
+       if (ka_thr_active)
+               return;
+
+       pthread_mutex_lock(&ka_thr_mutex);
+
+       if (!ka_thr_active) {
+               ka_thr_active = 1;
+               if (pthread_create(&ka_thr_handle, NULL, ka_thread, NULL)) {
+                       perror("pthread_create");
+                       exit(1);
+               }
+       }
+       pthread_mutex_unlock(&ka_thr_mutex);
+}
+#endif /* THREADED_CLIENT */
+
+static void do_keepalive(void)
+{
+       static time_t idlet = 0;
+       time_t now;
+
+       time(&now);
+       if ((now - idlet) < ((long) S_KEEPALIVE))
+               return;
+       time(&idlet);
+
+       /* Do a space-backspace to keep telnet sessions from idling out */
+       printf(" %c", 8);
+       fflush(stdout);
+
+#ifdef THREADED_CLIENT
+       if (async_ka_enabled)
+               async_ka_exec();
+       else
+#endif
+               really_do_keepalive();
+}
+
+
+/* Now the actual async-keepalve API that we expose to higher levels:
+   async_ka_start() and async_ka_end(). These do nothing when we don't have
+   threading enabled, so we avoid sprinkling ifdef's throughout the code. */
+
+/* wait for a background keepalive to complete. this must be done before
+   attempting any further server requests! */
+void async_ka_end(void)
+{
+#ifdef THREADED_CLIENT
+       if (ka_thr_active)
+               pthread_join(ka_thr_handle, NULL);
+
+       async_ka_enabled--;
+#endif
+}
+
+/* tell do_keepalive() that keepalives are asynchronous. */
+void async_ka_start(void)
+{
+#ifdef THREADED_CLIENT
+       async_ka_enabled++;
+#endif
+}
+
 
 int inkey(void)
 {                              /* get a character from the keyboard, with   */
@@ -175,6 +251,7 @@ int inkey(void)
                 */
                do {
                        do_keepalive();
+
                        FD_ZERO(&rfds);
                        FD_SET(0, &rfds);
                        tv.tv_sec = S_KEEPALIVE;
@@ -265,6 +342,7 @@ void getline(char *string, int lim)
        }
        strcpy(string, "");
        gl_string = string;
+       async_ka_start();
       GLA:a = inkey();
        a = (a & 127);
        if ((a == 8) && (strlen(string) == 0))
@@ -281,6 +359,7 @@ void getline(char *string, int lim)
        if ((a == 13) || (a == 10)) {
                putc(13, stdout);
                putc(10, stdout);
+               async_ka_end();
                return;
        }
        if (a < 32)
index b1335ad0ec5455583b23290b9bb31ad894959a4d..2411b04091ae35e6627af9b22cc1ac3de0a4d3ae 100644 (file)
@@ -48,6 +48,8 @@ int yesno(void);
 int yesno_d(int d);
 void keyopt(char *);
 char keymenu(char *menuprompt, char *menustring);
+void async_ka_start(void);
+void async_ka_end(void);
 
 extern int num_urls;
 extern char urls[MAXURLS][256];
index 58e45f1e3b429964fbc1afe5cf20812668a60360..7b2e8963f60e7fbbd2fe6d744b91540723c6f3b5 100644 (file)
@@ -12,10 +12,12 @@ fi
 AC_ARG_ENABLE(autologin, [  --disable-autologin     disable autologin (default is enabled if possible)])
 AC_ARG_ENABLE(chkpwd, [  --disable-chkpwd        don't build 'chkpwd'])
 
-AC_ARG_ENABLE(icq, [  --enable-icq            include server ICQ support], [
+AC_ARG_ENABLE(icq,             [  --enable-icq            include server ICQ support], [
        if test "x$enableval" = xyes; then
                SERV_ICQ='modules/serv_icq$(SO)'
        fi])
+AC_ARG_ENABLE(threaded-client, [  --disable-threaded-client
+                         disable multithreaded client])
 
 AC_ARG_WITH(pam, [  --with-pam              use PAM if present (see PAM.txt before you try this)])
 AC_ARG_WITH(kthread, [  --with-kthread          use kernel threads (on FreeBSD) (not recommended yet)])
@@ -45,21 +47,21 @@ case "$host" in
        alpha*-dec-osf*)
                test -z "$CC" && CC=cc
                PTHREAD_DEFS=-pthread
-               SERVER_LDFLAGS=-pthread
+               PTHREAD_LIBS=-pthread
                check_pthread=no
        ;;
        dnl FreeBSD is similar to Digital UNIX:
        *-*-freebsd*)
                if test "$with_kthread" = yes; then
-                       SERVER_LDFLAGS=-kthread
+                       PTHREAD_LIBS=-kthread
                else
-                       SERVER_LDFLAGS=-pthread
+                       PTHREAD_LIBS=-pthread
                fi
                check_pthread=no
                PTHREAD_DEFS=-D_THREAD_SAFE
        ;;
        *-*-openbsd*)
-               SERVER_LDFLAGS=-pthread
+               PTHREAD_LIBS=-pthread
                check_pthread=no
                PTHREAD_DEFS=-pthread
                LINK_SHARED="ld -x -Bshareable"
@@ -169,8 +171,10 @@ LIBS=$save_LIBS
 dnl Check for libpthread(s) if we're not using Digital UNIX or FreeBSD. (On
 dnl which the -pthread flag takes care of this.)
 if test "$check_pthread" != no; then
-       AC_CHECK_LIB(pthread, pthread_create)
-       AC_CHECK_LIB(pthreads, pthread_create)
+       AC_CHECK_LIB(pthread, pthread_create,
+               PTHREAD_LIBS="-lpthread $PTHREAD_LIBS")
+       AC_CHECK_LIB(pthreads, pthread_create,
+               PTHREAD_LIBS="-lpthreads $PTHREAD_LIBS")
 fi
 
 dnl Checks for header files.
@@ -221,6 +225,8 @@ dnl Now check for pthreads -- set up variables so that the compiler will be run
 dnl with proper flags for pthread programs
 save_LDFLAGS=$LDFLAGS
 LDFLAGS="$LDFLAGS $SERVER_LDFLAGS"
+save_LIBS=$LIBS
+LIBS="$PTHREAD_LIBS $LIBS"
 
 dnl On some platforms, AC_CHECK_FUNC[S] doesn't work for pthreads programs;
 dnl we need to include pthread.h
@@ -258,10 +264,22 @@ AC_CACHE_CHECK([for pthread_create], ac_cv_func_pthread_create,
 ac_cv_func_pthread_create=yes, ac_cv_func_pthread_create=no)])
 if test "$ac_cv_func_pthread_create" = yes; then
        TARGETS="client server utils serv_modules"
+       if test "x$enable_threaded_client" != xno; then
+               AC_DEFINE(THREADED_CLIENT)
+               CLIENT_PTLIBS=$PTHREAD_LIBS
+               CL_LIBOBJS='$(LIBOBJS:.o=.ro)'
+               CX=.ro
+       fi
+fi
+
+if test "x$CX" != x.ro; then
+       CL_LIBOBJS='$(LIBOBJS)'
+       CX=.o
 fi
 
 dnl Now restore the old ldflags so we don't pass the wrong stuff to makefile
 LDFLAGS=$save_LDFLAGS
+LIBS=$save_LIBS
 
 AC_REPLACE_FUNCS(snprintf getutline)
 
@@ -280,5 +298,9 @@ AC_SUBST(SERV_ICQ)
 AC_SUBST(PICFLAGS)
 AC_SUBST(LINK_SHARED)
 AC_SUBST(PTHREAD_DEFS)
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(CLIENT_PTLIBS)
+AC_SUBST(CL_LIBOBJS)
+AC_SUBST(CX)
 AC_CONFIG_HEADER(sysdep.h)
 AC_OUTPUT(Makefile weekly)
index 42a048bae8d88fd9fee599449929d3dc9b7f1272..54824cb07f5779cf4c39ab78be216811d611f23c 100644 (file)
@@ -195,15 +195,6 @@ void citedit(FILE *fp)
        struct cittext *textlist = NULL;
        struct cittext *ptr;
        char wordbuf[MAXWORDBUF];
-       char buf[256];
-       time_t last_server_msg,now;
-
-       /*
-        * we're going to keep track of the last time we talked to
-        * the server, so we can periodically send keep-alive messages
-        * out so it doesn't time out.
-        */
-       time(&last_server_msg);
 
        /* first, load the text into the buffer */
        fseek(fp, 0L, 0);
@@ -239,6 +230,7 @@ void citedit(FILE *fp)
        finished = 0;
        prev = (appending ? 13 : (-1));
        strcpy(wordbuf,"");
+       async_ka_start();
        do {
                a=inkey();
                if (a==10) a=13;
@@ -302,16 +294,8 @@ void citedit(FILE *fp)
                                }
                        }
                prev = a;
-
-               /* this check implements the server keep-alive */
-               time(&now);
-               if ( (now - last_server_msg) > S_KEEPALIVE ) {
-                       serv_puts("NOOP");
-                       serv_gets(buf);
-                       last_server_msg = now;
-                       }
-
                } while (finished==0);
+       async_ka_end();
 
        /* write the buffer back to disk */
        fseek(fp, 0L, 0);