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