XEmacs 21.2-b1
[chise/xemacs-chise.git.1] / src / event-unixoid.c
1 /* Code shared between all event loops that use select() and have a
2    different input descriptor for each device.
3    Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
4    Copyright (C) 1995 Board of Trustees, University of Illinois.
5    Copyright (C) 1995 Sun Microsystems, Inc.
6    Copyright (C) 1995, 1996 Ben Wing.
7
8 This file is part of XEmacs.
9
10 XEmacs is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2, or (at your option) any
13 later version.
14
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with XEmacs; see the file COPYING.  If not, write to
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA.  */
24
25 /* Synched up with: Not in FSF. */
26
27 /* This file has been Mule-ized. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "console-stream.h"
33 #include "console-tty.h"
34 #include "device.h"
35 #include "events.h"
36 #include "lstream.h"
37 #include "process.h"
38
39 #include "sysdep.h"
40 #include "sysfile.h"
41 #include "sysproc.h"            /* select stuff */
42 #include "systime.h"
43
44 #ifdef HAVE_GPM
45 #include "gpmevent.h"
46 #endif
47
48 /* Mask of bits indicating the descriptors that we wait for input on.
49    These work as follows:
50
51    input_wait_mask == mask of all file descriptors we select() on,
52                       including TTY/stream console descriptors,
53                       process descriptors, and the signal event pipe.
54                       Only used in event-tty.c; event-Xt.c uses
55                       XtAppAddInput(), and the call to select() is down in
56                       the guts of Xt.
57
58    non_fake_input_wait_mask == same as input_wait_mask but minus the
59                                signal event pipe.  Also only used in
60                                event-tty.c.
61
62    process_only_mask == only the process descriptors.
63
64    tty_only_mask == only the TTY/stream console descriptors.
65    */
66 SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
67 SELECT_TYPE process_only_mask, tty_only_mask;
68
69 /* This is used to terminate the select(), when an event came in
70    through a signal (e.g. window-change or C-g on controlling TTY). */
71 int signal_event_pipe[2];
72
73 int signal_event_pipe_initialized;
74
75 int fake_event_occurred;
76
77 int
78 read_event_from_tty_or_stream_desc (struct Lisp_Event *event,
79                                     struct console *con, int fd)
80 {
81   unsigned char ch;
82   int nread;
83   Lisp_Object console;
84
85   XSETCONSOLE (console, con);
86
87 #ifdef HAVE_GPM
88   if (fd == CONSOLE_TTY_MOUSE_FD (con)) {
89     return handle_gpm_read (event,con,fd);
90   }
91 #endif
92
93   nread = read (fd, &ch, 1);
94   if (nread <= 0)
95     {
96       /* deleting the console might not be safe right now ... */
97       enqueue_magic_eval_event (io_error_delete_console, console);
98       /* but we definitely need to unselect it to avoid infinite
99          loops reading EOF's */
100       Fconsole_disable_input (console);
101     }
102   else
103     {
104       character_to_event (ch, event, con, 1, 1);
105       event->channel = console;
106       return 1;
107     }
108   return 0;
109 }
110
111 void
112 signal_fake_event (void)
113 {
114   char byte = 0;
115   /* We do the write always.  Formerly I tried to "optimize" this
116      by setting a flag indicating whether we're blocking and only
117      doing the write in that case, but there is a race condition
118      if the signal occurs after we've checked for the signal
119      occurrence (which could occur in many places throughout
120      an iteration of the command loop, e.g. in status_notify()),
121      but before we set the blocking flag.
122
123      This should be OK as long as write() is reentrant, which
124      I'm fairly sure it is since it's a system call. */
125
126   if (signal_event_pipe_initialized)
127     /* In case a signal comes through while we're dumping */
128     {
129       int old_errno = errno;
130       write (signal_event_pipe[1], &byte, 1);
131       errno = old_errno;
132     }
133 }
134
135 void
136 drain_signal_event_pipe (void)
137 {
138   char chars[128];
139   /* The input end of the pipe has been set to non-blocking. */
140   while (read (signal_event_pipe[0], chars, sizeof (chars)) > 0)
141     ;
142 }
143
144 int
145 event_stream_unixoid_select_console (struct console *con)
146 {
147   int infd;
148
149   if (CONSOLE_STREAM_P (con))
150     infd = fileno (CONSOLE_STREAM_DATA (con)->infd);
151   else
152     {
153       assert (CONSOLE_TTY_P (con));
154       infd = CONSOLE_TTY_DATA (con)->infd;
155     }
156
157   assert (infd >= 0);
158
159   FD_SET (infd, &input_wait_mask);
160   FD_SET (infd, &non_fake_input_wait_mask);
161   FD_SET (infd, &tty_only_mask);
162   return infd;
163 }
164
165 int
166 event_stream_unixoid_unselect_console (struct console *con)
167 {
168   int infd;
169
170   if (CONSOLE_STREAM_P (con))
171     infd = fileno (CONSOLE_STREAM_DATA (con)->infd);
172   else
173     {
174       assert (CONSOLE_TTY_P (con));
175       infd = CONSOLE_TTY_DATA (con)->infd;
176     }
177
178   assert (infd >= 0);
179
180   FD_CLR (infd, &input_wait_mask);
181   FD_CLR (infd, &non_fake_input_wait_mask);
182   FD_CLR (infd, &tty_only_mask);
183   return infd;
184 }
185
186 static int
187 get_process_infd (struct Lisp_Process *p)
188 {
189   Lisp_Object instr, outstr;
190   get_process_streams (p, &instr, &outstr);
191   assert (!NILP (instr));
192   return filedesc_stream_fd (XLSTREAM (instr));
193 }
194
195 int
196 event_stream_unixoid_select_process (struct Lisp_Process *proc)
197 {
198   int infd = get_process_infd (proc);
199
200   FD_SET (infd, &input_wait_mask);
201   FD_SET (infd, &non_fake_input_wait_mask);
202   FD_SET (infd, &process_only_mask);
203   return infd;
204 }
205
206 int
207 event_stream_unixoid_unselect_process (struct Lisp_Process *proc)
208 {
209   int infd = get_process_infd (proc);
210
211   FD_CLR (infd, &input_wait_mask);
212   FD_CLR (infd, &non_fake_input_wait_mask);
213   FD_CLR (infd, &process_only_mask);
214   return infd;
215 }
216
217 int
218 poll_fds_for_input (SELECT_TYPE mask)
219 {
220   EMACS_TIME sometime;
221   EMACS_SELECT_TIME select_time;
222   SELECT_TYPE temp_mask;
223   int retval;
224
225   while (1)
226     {
227       EMACS_SET_SECS_USECS (sometime, 0, 0);
228       EMACS_TIME_TO_SELECT_TIME (sometime, select_time);
229       temp_mask = mask;
230       /* To effect a poll, tell select() to block for zero seconds. */
231       retval = select (MAXDESC, &temp_mask, 0, 0, &select_time);
232       if (retval >= 0)
233         return retval;
234       if (errno != EINTR)
235         {
236           /* Something went seriously wrong; don't abort since maybe
237              the TTY just died at the wrong time. */
238           fprintf (stderr, "xemacs: select failed: errno = %d\n", errno);
239           return 0;
240         }
241       /* else, we got interrupted by a signal, so try again. */
242     }
243
244   RETURN_NOT_REACHED(0) /* not reached */
245 }
246 \f
247 /****************************************************************************/
248 /*     Unixoid (file descriptors based) process I/O streams routines        */
249 /****************************************************************************/
250
251 USID
252 event_stream_unixoid_create_stream_pair (void* inhandle, void* outhandle,
253                                          Lisp_Object* instream,
254                                          Lisp_Object* outstream,
255                                          int flags)
256 {
257   int infd, outfd;
258   /* Decode inhandle and outhandle. Their meaning depends on
259      the process implementation being used. */
260 #if defined (HAVE_WIN32_PROCESSES)
261   /* We're passed in Windows handles. Open new fds for them */
262   if ((HANDLE)inhandle != INVALID_HANDLE_VALUE)
263     {
264       infd = open_osfhandle ((HANDLE)inhandle, 0);
265       if (infd < 0)
266         return USID_ERROR;
267     }
268   else
269     infd = -1;
270
271   if ((HANDLE)outhandle != INVALID_HANDLE_VALUE)
272     {
273       outfd = open_osfhandle ((HANDLE)outhandle, 0);
274       if (outfd < 0)
275         {
276           if (infd >= 0)
277             close (infd);
278           return USID_ERROR;
279         }
280     }
281   else
282     outfd = -1;
283
284   flags = 0;
285 #elif defined (HAVE_UNIX_PROCESSES)
286   /* We are passed plain old file descs */
287   infd  = (int)inhandle;
288   outfd = (int)outhandle;
289 #else
290 # error Which processes do you have?
291 #endif
292
293   *instream = (infd >= 0
294                ? make_filedesc_input_stream (infd, 0, -1, 0)
295                : Qnil);
296
297   *outstream = (outfd >= 0
298                 ? make_filedesc_output_stream (outfd, 0, -1, LSTR_BLOCKED_OK)
299                 : Qnil);
300
301 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
302   /* FLAGS is process->pty_flag for UNIX_PROCESSES */
303   if ((flags & STREAM_PTY_FLUSHING) && outfd >= 0)
304     {
305       Bufbyte eof_char = get_eof_char (outfd);
306       int pty_max_bytes = get_pty_max_bytes (outfd);
307       filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
308     }
309 #endif
310
311   return FD_TO_USID (infd);
312 }
313
314 USID
315 event_stream_unixoid_delete_stream_pair (Lisp_Object instream,
316                                          Lisp_Object outstream)
317 {
318   int in = (NILP(instream) ? -1
319             : filedesc_stream_fd (XLSTREAM (instream)));
320   int out = (NILP(outstream) ? -1
321              : filedesc_stream_fd (XLSTREAM (outstream)));
322
323   if (in >= 0)
324     close (in);
325   if (out != in && out >= 0)
326     close (out);
327
328   return FD_TO_USID (in);
329 }
330
331 \f
332 void
333 init_event_unixoid (void)
334 {
335   /* Do this first; the init_event_*_late() functions
336      pay attention to it. */
337   if (pipe (signal_event_pipe) < 0)
338     {
339       perror ("XEmacs: can't open pipe");
340       exit (-1);
341     }
342   signal_event_pipe_initialized = 1;
343
344   /* Set it non-blocking so we can drain its output. */
345   set_descriptor_non_blocking (signal_event_pipe[0]);
346
347   /* Also set the write descriptor non-blocking so we don't
348      hang in case a long time passes between times when
349      we drain the pipe. */
350   set_descriptor_non_blocking (signal_event_pipe[1]);
351
352   /* WARNING: In order for the signal-event pipe to work correctly
353      and not cause lockups, the following need to be followed:
354
355      1) event_pending_p() must ignore input on the signal-event pipe.
356      2) As soon as next_event() notices input on the signal-event
357      pipe, it must drain it. */
358   FD_ZERO (&input_wait_mask);
359   FD_ZERO (&non_fake_input_wait_mask);
360   FD_ZERO (&process_only_mask);
361   FD_ZERO (&tty_only_mask);
362
363   FD_SET (signal_event_pipe[0], &input_wait_mask);
364 }