$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.
Fri Jul 10 1998 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
* Initial CVS import
-
EXEEXT=@EXEEXT@
SO=@SO@
+CX=@CX@
SERV_ICQ=@SERV_ICQ@
CLIENT_TARGETS=citadel$(EXEEXT) whobbs$(EXEEXT)
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
#
#
-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 \
$(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 $@
/* 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
#include <sys/select.h>
#endif
+#ifdef THREADED_CLIENT
+#include <pthread.h>
+#endif
#include <signal.h>
#include <errno.h>
/*
* 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");
}
}
+/* 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 */
*/
do {
do_keepalive();
+
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = S_KEEPALIVE;
}
strcpy(string, "");
gl_string = string;
+ async_ka_start();
GLA:a = inkey();
a = (a & 127);
if ((a == 8) && (strlen(string) == 0))
if ((a == 13) || (a == 10)) {
putc(13, stdout);
putc(10, stdout);
+ async_ka_end();
return;
}
if (a < 32)
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];
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)])
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"
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.
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
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)
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)
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);
finished = 0;
prev = (appending ? 13 : (-1));
strcpy(wordbuf,"");
+ async_ka_start();
do {
a=inkey();
if (a==10) a=13;
}
}
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);