240 lines
5.9 KiB
C
240 lines
5.9 KiB
C
/* This file is part of the Project Athena Zephyr Notification System.
|
|
* It is one of the source files comprising zwgc, the Zephyr WindowGram
|
|
* client.
|
|
*
|
|
* Created by: Marc Horowitz <marc@athena.mit.edu>
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
|
|
* For copying and distribution information, see the file
|
|
* "mit-copyright.h".
|
|
*/
|
|
|
|
#include <sysdep.h>
|
|
|
|
#if (!defined(lint) && !defined(SABER))
|
|
static const char rcsid_mux_c[] = "$Id$";
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Module containing code to wait on multiple file descriptors: */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
#include <zephyr/zephyr.h>
|
|
#include "main.h"
|
|
#include "mux.h"
|
|
#include "error.h"
|
|
#include "zwgc.h"
|
|
#include "pointer.h"
|
|
#ifdef CMU_ZWGCPLUS
|
|
#include "plus.h"
|
|
#endif
|
|
|
|
#ifdef _AIX
|
|
#include <sys/select.h>
|
|
#endif
|
|
|
|
/*
|
|
* mux_end_loop_p - Setting this to true during a mux_loop causes the mux_loop
|
|
* to be exited.
|
|
*/
|
|
|
|
int mux_end_loop_p;
|
|
|
|
/*
|
|
* have_tty - is defined to be true if there is a controlling tty for this
|
|
* process. When we can no longer access the controlling tty,
|
|
* the process will die.
|
|
*/
|
|
|
|
static int have_tty = 0;
|
|
|
|
/*
|
|
* max_source - the maximum file descriptor that a handler was ever
|
|
* registered for:
|
|
*/
|
|
|
|
static int max_source = -1;
|
|
|
|
/*
|
|
* Which file descriptors we're waiting on for input & the accompanying
|
|
* input handlers & their arguments:
|
|
*/
|
|
|
|
static fd_set input_sources;
|
|
static void (*input_handler[MAX_SOURCES])(void *);
|
|
static pointer input_handler_arg[MAX_SOURCES];
|
|
|
|
static int check_tty(void);
|
|
|
|
/*
|
|
* void mux_init()
|
|
* Requires: mux_init has never been called before
|
|
* Effects: Initializes the mux module. Must be called before
|
|
* any other mux call.
|
|
*/
|
|
|
|
void
|
|
mux_init(void)
|
|
{
|
|
int i;
|
|
|
|
FD_ZERO(&input_sources);
|
|
|
|
for (i=0; i<MAX_SOURCES; i++)
|
|
input_handler[i] = NULL;
|
|
|
|
have_tty = check_tty();
|
|
}
|
|
|
|
/*
|
|
* void mux_add_input_source(int descriptor; void (*handler)(); pointer arg)
|
|
* Requires: 0<=descriptor<MAX_SOURCES, mux_init has been called
|
|
* Modifies: Removes the previous input handler if any for descriptor
|
|
* Effects: Registers handler as the input handler for file descriptor
|
|
* descriptor. When mux_loop() is running and input is
|
|
* available on descriptor, handler will be called with
|
|
* argument arg.
|
|
*/
|
|
|
|
void
|
|
mux_add_input_source(int descriptor,
|
|
void (*handler)(void *),
|
|
pointer arg)
|
|
{
|
|
#ifdef DEBUG
|
|
if(descriptor < 0 || descriptor >= MAX_SOURCES)
|
|
abort(); /* <<<>>> */
|
|
#endif
|
|
|
|
input_handler[descriptor] = handler;
|
|
input_handler_arg[descriptor] = arg;
|
|
FD_SET(descriptor, &input_sources);
|
|
if(descriptor > max_source)
|
|
max_source = descriptor;
|
|
}
|
|
|
|
/*
|
|
* void mux_loop()
|
|
* Requires: mux_init has been called.
|
|
* Effects: Loops until mux_end_loop_p becomes true. (Sets
|
|
* mux_end_loop_p false to start). Whenever input is
|
|
* available on an input source which has a registered
|
|
* handler (see mux_add_input_source), that handler is
|
|
* called with its argument. It is guaranteed that if
|
|
* input is available on a source, its respective input
|
|
* handler, if any, will eventually be called. No other
|
|
* ordering guarantees are made. When some signal handler
|
|
* or input handler eventually sets mux_end_loop_p to
|
|
* true, we return.
|
|
*/
|
|
|
|
void
|
|
mux_loop(void)
|
|
{
|
|
int i, nfds;
|
|
fd_set inputs, outputs;
|
|
struct timeval tv, *tvp;
|
|
|
|
mux_end_loop_p = 0;
|
|
|
|
for (;;) {
|
|
/*
|
|
* Exit if mux_end_loop_p has been set to true by a handler:
|
|
*/
|
|
if (mux_end_loop_p)
|
|
break;
|
|
tvp = NULL;
|
|
tv.tv_sec = 0;
|
|
if (have_tty) {
|
|
#ifdef CMU_ZWGCPLUS
|
|
tv.tv_sec = plus_timequeue_events();
|
|
if (tv.tv_sec > 10) tv.tv_sec = 10;
|
|
#else
|
|
tv.tv_sec = 10;
|
|
#endif
|
|
tv.tv_usec = 0;
|
|
#ifdef CMU_ZWGCPLUS
|
|
} else {
|
|
tv.tv_sec = plus_timequeue_events();
|
|
tv.tv_usec = 0;
|
|
#endif
|
|
}
|
|
if (tv.tv_sec)
|
|
tvp = &tv;
|
|
|
|
/*
|
|
* Do a select on all the file descriptors we care about to
|
|
* wait until at least one of them has input available:
|
|
*/
|
|
inputs = input_sources;
|
|
FD_ZERO(&outputs);
|
|
|
|
#ifdef HAVE_ARES
|
|
nfds = ares_fds(achannel, &inputs, &outputs);
|
|
if (nfds < max_source + 1)
|
|
nfds = max_source + 1;
|
|
tvp = ares_timeout(achannel, tvp, &tv);
|
|
#else
|
|
nfds = max_source + 1;
|
|
#endif
|
|
|
|
i = select(nfds, &inputs, &outputs, NULL, tvp);
|
|
|
|
if (i == -1) {
|
|
if (errno == EINTR)
|
|
continue; /* on a signal restart checking mux_loop_end_p */
|
|
else
|
|
FATAL_TRAP( errno, "while selecting" );
|
|
}
|
|
else if (i == 0) {
|
|
if (have_tty && !check_tty()) {
|
|
mux_end_loop_p = 1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_ARES
|
|
ares_process(achannel, &inputs, &outputs);
|
|
#endif
|
|
|
|
/*
|
|
* Call all input handlers whose corresponding file descriptors have
|
|
* input:
|
|
*/
|
|
for(i=0; i<=max_source; i++)
|
|
if (FD_ISSET(i, &inputs) && input_handler[i]) {
|
|
#ifdef DEBUG
|
|
if (zwgc_debug)
|
|
fprintf(stderr,
|
|
"mux_loop...activity on fd %d, calling %lx(%lx)\n",
|
|
i, (unsigned long)input_handler[i],
|
|
(unsigned long)input_handler_arg[i]);
|
|
#endif
|
|
input_handler[i](input_handler_arg[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
check_tty(void)
|
|
{
|
|
register int result;
|
|
int pgrp;
|
|
int tty = open("/dev/tty", O_RDONLY|O_NDELAY);
|
|
|
|
if (tty < 0) return 0;
|
|
|
|
#if defined(_POSIX_VERSION)
|
|
result = ( ((pgrp = tcgetpgrp(tty)) < 0) ? 0 : 1 );
|
|
#else
|
|
result = ( (ioctl(tty, TIOCGPGRP, &pgrp) < 0) ? 0 : 1 );
|
|
#endif
|
|
|
|
close(tty);
|
|
return(result);
|
|
}
|