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