]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/mux.c
import 3.0.1
[1ts-debian.git] / zephyr / zwgc / mux.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It is one of the source files comprising zwgc, the Zephyr WindowGram
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id: mux.c 2328 2009-03-22 17:34:39Z kcr $
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #include <sysdep.h>
15
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_mux_c[] = "$Id: mux.c 2328 2009-03-22 17:34:39Z kcr $";
18 #endif
19
20 /****************************************************************************/
21 /*                                                                          */
22 /*        Module containing code to wait on multiple file descriptors:      */
23 /*                                                                          */
24 /****************************************************************************/
25
26 #include <zephyr/zephyr.h>
27 #include "main.h"
28 #include "mux.h"
29 #include "error.h"
30 #include "zwgc.h"
31 #include "pointer.h"
32 #ifdef CMU_ZWGCPLUS
33 #include "plus.h"
34 #endif
35
36 #ifdef _AIX
37 #include <sys/select.h>
38 #endif
39
40 /*
41  * mux_end_loop_p - Setting this to true during a mux_loop causes the mux_loop
42  *                  to be exited.
43  */
44
45 int mux_end_loop_p;
46
47 /*
48  * have_tty - is defined to be true if there is a controlling tty for this
49  *            process.  When we can no longer access the controlling tty,
50  *            the process will die.
51  */
52
53 static int have_tty = 0;
54
55 /*
56  * max_source - the maximum file descriptor that a handler was ever
57  *              registered for:
58  */
59
60 static int max_source = -1;
61
62 /*
63  * Which file descriptors we're waiting on for input & the accompanying
64  * input handlers & their arguments:
65  */
66
67 static fd_set input_sources;
68 static void (*input_handler[MAX_SOURCES])(void *);
69 static pointer input_handler_arg[MAX_SOURCES];
70
71 static int check_tty(void);
72
73 /*
74  *    void mux_init()
75  *        Requires: mux_init has never been called before
76  *        Effects: Initializes the mux module.  Must be called before
77  *                 any other mux call.
78  */
79
80 void
81 mux_init(void)
82 {
83     int i;
84
85     FD_ZERO(&input_sources);
86     
87     for (i=0; i<MAX_SOURCES; i++)
88       input_handler[i] = NULL;
89
90     have_tty = check_tty();
91 }
92
93 /*
94  *    void mux_add_input_source(int descriptor; void (*handler)(); pointer arg)
95  *        Requires: 0<=descriptor<MAX_SOURCES, mux_init has been called
96  *        Modifies: Removes the previous input handler if any for descriptor
97  *        Effects: Registers handler as the input handler for file descriptor
98  *                 descriptor.  When mux_loop() is running and input is
99  *                 available on descriptor, handler will be called with
100  *                 argument arg.
101  */
102
103 void
104 mux_add_input_source(int descriptor,
105                           void (*handler)(void *),
106                           pointer arg)
107 {
108 #ifdef DEBUG
109     if(descriptor < 0 || descriptor >= MAX_SOURCES)
110       abort(); /* <<<>>> */
111 #endif
112     
113     input_handler[descriptor] = handler;
114     input_handler_arg[descriptor] = arg;
115     FD_SET(descriptor, &input_sources);
116     if(descriptor > max_source)
117       max_source = descriptor;
118 }
119
120 /*
121  *    void mux_loop()
122  *        Requires: mux_init has been called.
123  *        Effects: Loops until mux_end_loop_p becomes true.  (Sets
124  *                 mux_end_loop_p false to start).  Whenever input is
125  *                 available on an input source which has a registered
126  *                 handler (see mux_add_input_source), that handler is
127  *                 called with its argument.  It is guaranteed that if
128  *                 input is available on a source, its respective input
129  *                 handler, if any, will eventually be called.  No other
130  *                 ordering guarantees are made.  When some signal handler
131  *                 or input handler eventually sets mux_end_loop_p to
132  *                 true, we return.
133  */
134
135 void
136 mux_loop(void)
137 {
138     int i, nfds;
139     fd_set inputs, outputs;
140     struct timeval tv, *tvp;
141
142     mux_end_loop_p = 0;
143
144     for (;;) {
145         /*
146          * Exit if mux_end_loop_p has been set to true by a handler:
147          */
148         if (mux_end_loop_p)
149           break;
150         tvp = NULL;
151         tv.tv_sec = 0;
152         if (have_tty) {
153 #ifdef CMU_ZWGCPLUS
154             tv.tv_sec = plus_timequeue_events();
155            if (tv.tv_sec > 10) tv.tv_sec = 10;
156 #else
157             tv.tv_sec = 10;
158 #endif
159             tv.tv_usec = 0;
160 #ifdef CMU_ZWGCPLUS
161         } else {
162            tv.tv_sec = plus_timequeue_events();
163            tv.tv_usec = 0;
164 #endif
165         }
166         if (tv.tv_sec)
167          tvp = &tv;
168
169         /*
170          * Do a select on all the file descriptors we care about to
171          * wait until at least one of them has input available:
172          */
173         inputs = input_sources;
174         FD_ZERO(&outputs);
175
176 #ifdef HAVE_ARES
177         nfds = ares_fds(achannel, &inputs, &outputs);
178         if (nfds < max_source + 1)
179             nfds = max_source + 1;
180         tvp = ares_timeout(achannel, tvp, &tv);
181 #else
182         nfds = max_source + 1;
183 #endif
184
185         i = select(nfds, &inputs, &outputs, NULL, tvp);
186
187         if (i == -1) {
188             if (errno == EINTR)
189                 continue;    /* on a signal restart checking mux_loop_end_p */
190             else
191                 FATAL_TRAP( errno, "while selecting" );
192         }
193         else if (i == 0) {
194             if (have_tty && !check_tty()) {
195                 mux_end_loop_p = 1;
196                 continue;
197             }
198         }
199
200 #ifdef HAVE_ARES
201         ares_process(achannel, &inputs, &outputs);
202 #endif
203
204         /*
205          * Call all input handlers whose corresponding file descriptors have
206          * input:
207          */
208         for(i=0; i<=max_source; i++)
209           if (FD_ISSET(i, &inputs) && input_handler[i]) {
210 #ifdef DEBUG
211               if (zwgc_debug)
212                 fprintf(stderr,
213                         "mux_loop...activity on fd %d, calling %x(%x)\n",
214                         i,input_handler[i],input_handler_arg[i]);
215 #endif
216               input_handler[i](input_handler_arg[i]);
217           }
218     }
219 }
220
221 static int
222 check_tty(void)
223 {
224     register int result;
225     int pgrp;
226     int tty = open("/dev/tty", O_RDONLY|O_NDELAY);
227
228     if (tty < 0) return 0;
229
230 #if defined(_POSIX_VERSION)
231     result = ( ((pgrp = tcgetpgrp(tty)) < 0)      ? 0 : 1 );
232 #else
233     result = ( (ioctl(tty, TIOCGPGRP, &pgrp) < 0) ? 0 : 1 );
234 #endif
235
236     close(tty);
237     return(result);
238 }