(char-db-feature-domains): Delete `jis/alt' because it has been
[chise/xemacs-chise.git] / 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 /* Mask of bits indicating the descriptors that we wait for input on.
45    These work as follows:
46
47    input_wait_mask == mask of all file descriptors we select() on,
48                       including TTY/stream console descriptors,
49                       process descriptors, and the signal event pipe.
50                       Only used in event-tty.c; event-Xt.c uses
51                       XtAppAddInput(), and the call to select() is down in
52                       the guts of Xt.
53
54    non_fake_input_wait_mask == same as input_wait_mask but minus the
55                                signal event pipe.  Also only used in
56                                event-tty.c.
57
58    process_only_mask == only the process descriptors.
59
60    tty_only_mask == only the TTY/stream console descriptors.
61    */
62 SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
63 SELECT_TYPE process_only_mask, tty_only_mask;
64
65 /* This is used to terminate the select(), when an event came in
66    through a signal (e.g. window-change or C-g on controlling TTY). */
67 int signal_event_pipe[2];
68
69 int signal_event_pipe_initialized;
70
71 int fake_event_occurred;
72
73 int
74 read_event_from_tty_or_stream_desc (Lisp_Event *event,
75                                     struct console *con, int fd)
76 {
77   unsigned char ch;
78   int nread;
79   Lisp_Object console;
80
81   XSETCONSOLE (console, con);
82
83   nread = read (fd, &ch, 1);
84   if (nread <= 0)
85     {
86       /* deleting the console might not be safe right now ... */
87       enqueue_magic_eval_event (io_error_delete_console, console);
88       /* but we definitely need to unselect it to avoid infinite
89          loops reading EOF's */
90       Fconsole_disable_input (console);
91     }
92   else
93     {
94       character_to_event (ch, event, con, 1, 1);
95       event->channel = console;
96       return 1;
97     }
98   return 0;
99 }
100
101 void
102 signal_fake_event (void)
103 {
104   char byte = 0;
105   /* We do the write always.  Formerly I tried to "optimize" this
106      by setting a flag indicating whether we're blocking and only
107      doing the write in that case, but there is a race condition
108      if the signal occurs after we've checked for the signal
109      occurrence (which could occur in many places throughout
110      an iteration of the command loop, e.g. in status_notify()),
111      but before we set the blocking flag.
112
113      This should be OK as long as write() is reentrant, which
114      I'm fairly sure it is since it's a system call. */
115
116   if (signal_event_pipe_initialized)
117     /* In case a signal comes through while we're dumping */
118     {
119       int old_errno = errno;
120       write (signal_event_pipe[1], &byte, 1);
121       errno = old_errno;
122     }
123 }
124
125 void
126 drain_signal_event_pipe (void)
127 {
128   char chars[128];
129   /* The input end of the pipe has been set to non-blocking. */
130   while (read (signal_event_pipe[0], chars, sizeof (chars)) > 0)
131     ;
132 }
133
134 int
135 event_stream_unixoid_select_console (struct console *con)
136 {
137   int infd;
138
139   if (CONSOLE_STREAM_P (con))
140     infd = fileno (CONSOLE_STREAM_DATA (con)->in);
141   else
142     {
143       assert (CONSOLE_TTY_P (con));
144       infd = CONSOLE_TTY_DATA (con)->infd;
145     }
146
147   assert (infd >= 0);
148
149   FD_SET (infd, &input_wait_mask);
150   FD_SET (infd, &non_fake_input_wait_mask);
151   FD_SET (infd, &tty_only_mask);
152   return infd;
153 }
154
155 int
156 event_stream_unixoid_unselect_console (struct console *con)
157 {
158   int infd;
159
160   if (CONSOLE_STREAM_P (con))
161     infd = fileno (CONSOLE_STREAM_DATA (con)->in);
162   else
163     {
164       assert (CONSOLE_TTY_P (con));
165       infd = CONSOLE_TTY_DATA (con)->infd;
166     }
167
168   assert (infd >= 0);
169
170   FD_CLR (infd, &input_wait_mask);
171   FD_CLR (infd, &non_fake_input_wait_mask);
172   FD_CLR (infd, &tty_only_mask);
173   return infd;
174 }
175
176 static int
177 get_process_infd (Lisp_Process *p)
178 {
179   Lisp_Object instr, outstr;
180   get_process_streams (p, &instr, &outstr);
181   assert (!NILP (instr));
182   return filedesc_stream_fd (XLSTREAM (instr));
183 }
184
185 int
186 event_stream_unixoid_select_process (Lisp_Process *proc)
187 {
188   int infd = get_process_infd (proc);
189
190   FD_SET (infd, &input_wait_mask);
191   FD_SET (infd, &non_fake_input_wait_mask);
192   FD_SET (infd, &process_only_mask);
193   return infd;
194 }
195
196 int
197 event_stream_unixoid_unselect_process (Lisp_Process *proc)
198 {
199   int infd = get_process_infd (proc);
200
201   FD_CLR (infd, &input_wait_mask);
202   FD_CLR (infd, &non_fake_input_wait_mask);
203   FD_CLR (infd, &process_only_mask);
204   return infd;
205 }
206
207 int
208 poll_fds_for_input (SELECT_TYPE mask)
209 {
210   EMACS_TIME sometime;
211   EMACS_SELECT_TIME select_time;
212   SELECT_TYPE temp_mask;
213   int retval;
214
215   while (1)
216     {
217       EMACS_SET_SECS_USECS (sometime, 0, 0);
218       EMACS_TIME_TO_SELECT_TIME (sometime, select_time);
219       temp_mask = mask;
220       /* To effect a poll, tell select() to block for zero seconds. */
221       retval = select (MAXDESC, &temp_mask, 0, 0, &select_time);
222       if (retval >= 0)
223         return retval;
224       if (errno != EINTR)
225         {
226           /* Something went seriously wrong; don't ABORT since maybe
227              the TTY just died at the wrong time. */
228           stderr_out ("xemacs: select failed: errno = %d\n", errno);
229           return 0;
230         }
231       /* else, we got interrupted by a signal, so try again. */
232     }
233
234   RETURN_NOT_REACHED(0) /* not reached */
235 }
236 \f
237 /****************************************************************************/
238 /*     Unixoid (file descriptors based) process I/O streams routines        */
239 /****************************************************************************/
240
241 USID
242 event_stream_unixoid_create_stream_pair (void* inhandle, void* outhandle,
243                                          Lisp_Object* instream,
244                                          Lisp_Object* outstream,
245                                          int flags)
246 {
247   int infd, outfd;
248   /* Decode inhandle and outhandle. Their meaning depends on
249      the process implementation being used. */
250 #if defined (HAVE_WIN32_PROCESSES)
251   /* We're passed in Windows handles. Open new fds for them */
252   if ((HANDLE)inhandle != INVALID_HANDLE_VALUE)
253     {
254       infd = open_osfhandle ((HANDLE)inhandle, 0);
255       if (infd < 0)
256         return USID_ERROR;
257     }
258   else
259     infd = -1;
260
261   if ((HANDLE)outhandle != INVALID_HANDLE_VALUE)
262     {
263       outfd = open_osfhandle ((HANDLE)outhandle, 0);
264       if (outfd < 0)
265         {
266           if (infd >= 0)
267             close (infd);
268           return USID_ERROR;
269         }
270     }
271   else
272     outfd = -1;
273
274   flags = 0;
275 #elif defined (HAVE_UNIX_PROCESSES)
276   /* We are passed plain old file descs */
277   infd  = (int)inhandle;
278   outfd = (int)outhandle;
279 #else
280 # error Which processes do you have?
281 #endif
282
283   *instream = (infd >= 0
284                ? make_filedesc_input_stream (infd, 0, -1, 0)
285                : Qnil);
286
287   *outstream = (outfd >= 0
288                 ? make_filedesc_output_stream (outfd, 0, -1, LSTR_BLOCKED_OK)
289                 : Qnil);
290
291 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
292   /* FLAGS is process->pty_flag for UNIX_PROCESSES */
293   if ((flags & STREAM_PTY_FLUSHING) && outfd >= 0)
294     {
295       Bufbyte eof_char = get_eof_char (outfd);
296       int pty_max_bytes = get_pty_max_bytes (outfd);
297       filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
298     }
299 #endif
300
301   return FD_TO_USID (infd);
302 }
303
304 USID
305 event_stream_unixoid_delete_stream_pair (Lisp_Object instream,
306                                          Lisp_Object outstream)
307 {
308   int in = (NILP(instream) ? -1
309             : filedesc_stream_fd (XLSTREAM (instream)));
310   int out = (NILP(outstream) ? -1
311              : filedesc_stream_fd (XLSTREAM (outstream)));
312
313   if (in >= 0)
314     close (in);
315   if (out != in && out >= 0)
316     close (out);
317
318   return FD_TO_USID (in);
319 }
320
321 \f
322 void
323 init_event_unixoid (void)
324 {
325   /* Do this first; the init_event_*_late() functions
326      pay attention to it. */
327   if (pipe (signal_event_pipe) < 0)
328     {
329       perror ("XEmacs: can't open pipe");
330       exit (-1);
331     }
332   signal_event_pipe_initialized = 1;
333
334   /* Set it non-blocking so we can drain its output. */
335   set_descriptor_non_blocking (signal_event_pipe[0]);
336
337   /* Also set the write descriptor non-blocking so we don't
338      hang in case a long time passes between times when
339      we drain the pipe. */
340   set_descriptor_non_blocking (signal_event_pipe[1]);
341
342   /* WARNING: In order for the signal-event pipe to work correctly
343      and not cause lockups, the following need to be followed:
344
345      1) event_pending_p() must ignore input on the signal-event pipe.
346      2) As soon as next_event() notices input on the signal-event
347      pipe, it must drain it. */
348   FD_ZERO (&input_wait_mask);
349   FD_ZERO (&non_fake_input_wait_mask);
350   FD_ZERO (&process_only_mask);
351   FD_ZERO (&tty_only_mask);
352
353   FD_SET (signal_event_pipe[0], &input_wait_mask);
354 }