#include "config.h"
+/* This file is split into two parts by the following preprocessor
+ conditional. The 'then' clause contains all of the support for
+ asynchronous subprocesses. The 'else' clause contains stub
+ versions of some of the asynchronous subprocess routines that are
+ often called elsewhere in Emacs, so we don't have to #ifdef the
+ sections that call them. */
+
+\f
#ifdef subprocesses
-/* The entire file is within this conditional */
#include <stdio.h>
#include <errno.h>
#include <bsdtty.h>
#endif
-#ifdef HPUX
-#undef TIOCGPGRP
-#endif
-
#ifdef IRIS
#include <sys/sysmacros.h> /* for "minor" */
#endif /* not IRIS */
#include "systime.h"
-
-#if defined (HPUX) && defined (HAVE_PTYS)
-#include <sys/ptyio.h>
-#endif
-
-#ifdef AIX
-#include <sys/pty.h>
-#include <unistd.h>
-#endif
-
-#ifdef SYSV_PTYS
-#include <sys/tty.h>
-#ifdef titan
-#include <sys/ttyhw.h>
-#include <sys/stream.h>
-#endif
-#include <sys/pty.h>
-#endif
-
-#ifdef XENIX
-#undef TIOCGETC /* Avoid confusing some conditionals that test this. */
-#endif
-
-#ifdef BROKEN_TIOCGETC
-#undef TIOCGETC
-#endif
+#include "systerm.h"
#include "lisp.h"
#include "window.h"
#include "termhooks.h"
#include "termopts.h"
#include "commands.h"
-
-extern int screen_garbaged;
+#include "dispextern.h"
Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
/* Qexit is declared and initialized in eval.c. */
}
\f
#ifdef HAVE_PTYS
-static pty_process;
+static int pty_process;
/* Open an available pty, returning a file descriptor.
Return -1 on failure.
register c, i;
int fd;
+ /* Some systems name their pseudoterminals so that there are gaps in
+ the usual sequence - for example, on HP9000/S700 systems, there
+ are no pseudoterminals with names ending in 'f'. So we wait for
+ three failures in a row before deciding that we've reached the
+ end of the ptys. */
+ int failed_count = 0;
+
#ifdef PTY_ITERATION
PTY_ITERATION
#else
#endif /* not HPUX */
#endif /* no PTY_NAME_SPRINTF */
-#ifndef IRIS
- if (stat (pty_name, &stb) < 0)
+#ifdef IRIS
+ /* Unusual IRIS code */
+ *ptyv = open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
+ if (fd < 0)
+ return -1;
+ if (fstat (fd, &stb) < 0)
return -1;
+#else
+ if (stat (pty_name, &stb) < 0)
+ {
+ failed_count++;
+ if (failed_count >= 3)
+ return -1;
+ }
+ else
+ failed_count = 0;
#ifdef O_NONBLOCK
fd = open (pty_name, O_RDWR | O_NONBLOCK, 0);
#else
fd = open (pty_name, O_RDWR | O_NDELAY, 0);
#endif
-#else /* Unusual IRIS code */
- *ptyv = open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
- if (fd < 0)
- return -1;
- if (fstat (fd, &stb) < 0)
- return -1;
#endif /* IRIS */
if (fd >= 0)
#endif
int pty_flag = 0;
Lisp_Object current_dir;
- char **env;
extern char **environ;
- env = environ;
-
inchannel = outchannel = -1;
#ifdef HAVE_PTYS
child_setup_tty (xforkout);
child_setup (xforkin, xforkout, xforkout,
- new_argv, env, 1, current_dir);
+ new_argv, 1, current_dir);
}
environ = save_environ;
}
seconds = 0;
}
+ if (NILP (proc))
+ XFASTINT (proc) = 0;
+
return
- (wait_reading_process_input (seconds, useconds,
- (NILP (proc)
- ? XPROCESS (get_process (proc)) : 0), 0)
+ (wait_reading_process_input (seconds, useconds, proc, 0)
? Qt : Qnil);
}
zero for no limit, or
-1 means gobble data immediately available but don't wait for any.
- read_kbd is:
+ read_kbd is a lisp value:
0 to ignore keyboard input, or
1 to return when input is available, or
-1 means caller will actually read the input, so don't throw to
the quit handler, or
- a pointer to a struct Lisp_Process, meaning wait until something
- arrives from that process. The return value is true iff we read
- some input from that process.
+ a process object, meaning wait until something arrives from that
+ process. The return value is true iff we read some input from
+ that process.
do_display != 0 means redisplay should be done to show subprocess
output that arrives.
Otherwise, return true iff we recieved input from any process. */
wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
- int time_limit, microsecs, read_kbd, do_display;
+ int time_limit, microsecs;
+ Lisp_Object read_kbd;
+ int do_display;
{
register int channel, nfds, m;
static SELECT_TYPE Available;
FD_ZERO (&Available);
- /* Detect when read_kbd is really the address of a Lisp_Process. */
- if (read_kbd > 10 || read_kbd < -1)
+ /* If read_kbd is a process to watch, set wait_proc and wait_channel
+ accordingly. */
+ if (XTYPE (read_kbd) == Lisp_Process)
{
- wait_proc = (struct Lisp_Process *) read_kbd;
+ wait_proc = XPROCESS (read_kbd);
wait_channel = XFASTINT (wait_proc->infd);
- read_kbd = 0;
+ XFASTINT (read_kbd) = 0;
}
- waiting_for_user_input_p = read_kbd;
+ waiting_for_user_input_p = XINT (read_kbd);
/* Since we may need to wait several times,
compute the absolute time to return at. */
EMACS_ADD_TIME (end_time, end_time, timeout);
}
- /* Turn off periodic alarms (in case they are in use)
- because the select emulator uses alarms. */
- stop_polling ();
-
while (1)
{
/* If calling from keyboard input, do not quit
since we want to return C-g as an input character.
Otherwise, do pending quit if requested. */
- if (read_kbd >= 0)
+ if (XINT (read_kbd) >= 0)
QUIT;
/* If status of something has changed, and no input is available,
/* Cause C-g and alarm signals to take immediate action,
and cause input available signals to zero out timeout */
- if (read_kbd < 0)
+ if (XINT (read_kbd) < 0)
set_waiting_for_input (&timeout);
/* Wait till there is something to do */
Available = input_wait_mask;
- if (!read_kbd)
+ if (! XINT (read_kbd))
FD_CLR (0, &Available);
- /* If a screen has been newly mapped and needs updating,
- reprocess its display stuff. */
- if (screen_garbaged)
+ /* If frame size has changed or the window is newly mapped,
+ redisplay now, before we start to wait. There is a race
+ condition here; if a SIGIO arrives between now and the select
+ and indicates that a frame is trashed, we lose. */
+ if (frame_garbaged)
redisplay_preserve_echo_area ();
- if (read_kbd && detect_input_pending ())
+ if (XINT (read_kbd) && detect_input_pending ())
nfds = 0;
else
-#ifdef AIX
- nfds = select (MAXDESC, &Available, 0, 0, &timeout);
-#else
-#ifdef HPUX
- nfds = select (MAXDESC, &Available, 0, 0, &timeout);
-#else
nfds = select (MAXDESC, &Available, 0, 0, &timeout);
-#endif
-#endif
+
xerrno = errno;
/* Make C-g and alarm signals set flags again */
/* If we woke up due to SIGWINCH, actually change size now. */
do_pending_window_change ();
- if (time_limit && nfds == 0) /* timeout elapsed */
+ if (time_limit && nfds == 0) /* timeout elapsed */
break;
if (nfds < 0)
{
So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF
in m-ibmrt-aix.h), and here we just ignore the select error.
Cleanup occurs c/o status_notify after SIGCLD. */
- FD_ZERO (&Available); /* Cannot depend on values returned */
+ FD_ZERO (&Available); /* Cannot depend on values returned */
#else
abort ();
#endif
/* If there is any, return immediately
to give it higher priority than subprocesses */
- if (read_kbd && detect_input_pending ())
+ if (XINT (read_kbd) && detect_input_pending ())
break;
+#ifdef SIGIO
/* If we think we have keyboard input waiting, but didn't get SIGIO
go read it. This can happen with X on BSD after logging out.
In that case, there really is no input and no SIGIO,
but select says there is input. */
/*
- if (read_kbd && interrupt_input && (Available & fileno (stdin)))
- */
- if (read_kbd && interrupt_input && (FD_ISSET (fileno (stdin), &Available)))
+ if (XINT (read_kbd) && interrupt_input && (Available & fileno (stdin)))
+ */
+ if (XINT (read_kbd) && interrupt_input && (FD_ISSET (fileno (stdin), &Available)))
kill (0, SIGIO);
+#endif
#ifdef vipc
/* Check for connection from other process */
if (! wait_proc)
got_some_input |= nfds > 0;
+ /* If checking input just got us a size-change event from X,
+ obey it now if we should. */
+ if (XINT (read_kbd))
+ do_pending_window_change ();
+
/* Check for data from a process or a command channel */
for (channel = FIRST_PROC_DESC; channel < MAXDESC; channel++)
{
}
continue;
}
-#endif /* vipc */
+#endif /* vipc */
/* Read data from the process, starting with our
buffered-ahead character if we have one. */
subprocess termination and SIGCHLD. */
else if (nread == 0 && !NETCONN_P (proc))
;
-#endif /* O_NDELAY */
-#endif /* O_NONBLOCK */
-#endif /* EWOULDBLOCK */
+#endif /* O_NDELAY */
+#endif /* O_NONBLOCK */
+#endif /* EWOULDBLOCK */
#ifdef HAVE_PTYS
/* On some OSs with ptys, when the process on one end of
a pty exits, the other end gets an error reading with
get a SIGCHLD). */
else if (nread == -1 && errno == EIO)
;
-#endif /* HAVE_PTYS */
-/* If we can detect process termination, don't consider the process
- gone just because its pipe is closed. */
+#endif /* HAVE_PTYS */
+ /* If we can detect process termination, don't consider the process
+ gone just because its pipe is closed. */
#ifdef SIGCHLD
else if (nread == 0 && !NETCONN_P (proc))
;
= Fcons (Qexit, Fcons (make_number (256), Qnil));
}
}
- } /* end for each file descriptor */
- } /* end while exit conditions not met */
+ } /* end for each file descriptor */
+ } /* end while exit conditions not met */
- /* Resume periodic signals to poll for input, if necessary. */
- start_polling ();
+ /* If calling from keyboard input, do not quit
+ since we want to return C-g as an input character.
+ Otherwise, do pending quit if requested. */
+ if (XINT (read_kbd) >= 0)
+ {
+ /* Prevent input_pending from remaining set if we quit. */
+ clear_input_pending ();
+ QUIT;
+ }
return got_some_input;
}
while (len > 0)
{
int this = len;
+ SIGTYPE (*old_sigpipe)();
+
/* Don't send more than 500 bytes at a time. */
if (this > 500)
this = 500;
- signal (SIGPIPE, send_process_trap);
+ old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap);
rv = write (XFASTINT (XPROCESS (proc)->outfd), buf, this);
- signal (SIGPIPE, SIG_DFL);
+ signal (SIGPIPE, old_sigpipe);
if (rv < 0)
{
if (0
/* Allow input from processes between bursts of sending.
Otherwise things may get stopped up. */
if (len > 0)
- wait_reading_process_input (-1, 0, 0, 0);
+ {
+ Lisp_Object zero;
+
+ XFASTINT (zero) = 0;
+ wait_reading_process_input (-1, 0, zero, 0);
+ }
}
#endif
else
proc_buffered_char[i] = -1;
}
}
-#ifdef 0
+#if 0
DEFUN ("process-connection", Fprocess_connection, Sprocess_connection, 0, 1, 0,
"Return the connection type of `PROCESS'. This can be nil (pipe),\n\
t or pty (pty) or stream (socket connection).")
/* defsubr (&Sprocess_connection); */
}
-#endif /* subprocesses */
+\f
+#else /* not subprocesses */
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include "lisp.h"
+#include "systime.h"
+#include "termopts.h"
+
+extern int frame_garbaged;
+
+
+/* As described above, except assuming that there are no subprocesses:
+
+ Wait for timeout to elapse and/or keyboard input to be available.
+
+ time_limit is:
+ timeout in seconds, or
+ zero for no limit, or
+ -1 means gobble data immediately available but don't wait for any.
+
+ read_kbd is a Lisp_Object:
+ 0 to ignore keyboard input, or
+ 1 to return when input is available, or
+ -1 means caller will actually read the input, so don't throw to
+ the quit handler.
+ We know that read_kbd will never be a Lisp_Process, since
+ `subprocesses' isn't defined.
+
+ do_display != 0 means redisplay should be done to show subprocess
+ output that arrives. This version of the function ignores it.
+
+ Return true iff we recieved input from any process. */
+
+int
+wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
+ int time_limit, microsecs;
+ Lisp_Object read_kbd;
+ int do_display;
+{
+ EMACS_TIME end_time, timeout, *timeout_p;
+ int waitchannels;
+
+ /* What does time_limit really mean? */
+ if (time_limit || microsecs)
+ {
+ /* It's not infinite. */
+ timeout_p = &timeout;
+
+ if (time_limit == -1)
+ /* In fact, it's zero. */
+ EMACS_SET_SECS_USECS (timeout, 0, 0);
+ else
+ EMACS_SET_SECS_USECS (timeout, time_limit, microsecs);
+
+ /* How far in the future is that? */
+ EMACS_GET_TIME (end_time);
+ EMACS_ADD_TIME (end_time, end_time, timeout);
+ }
+ else
+ /* It's infinite. */
+ timeout_p = 0;
+
+ /* Turn off periodic alarms (in case they are in use)
+ because the select emulator uses alarms. */
+ stop_polling ();
+
+ for (;;)
+ {
+ int nfds;
+
+ waitchannels = XINT (read_kbd) ? 1 : 0;
+
+ /* If calling from keyboard input, do not quit
+ since we want to return C-g as an input character.
+ Otherwise, do pending quit if requested. */
+ if (XINT (read_kbd) >= 0)
+ QUIT;
+
+ if (timeout_p)
+ {
+ EMACS_GET_TIME (*timeout_p);
+ EMACS_SUB_TIME (*timeout_p, end_time, *timeout_p);
+ if (EMACS_TIME_NEG_P (*timeout_p))
+ break;
+ }
+
+ /* Cause C-g and alarm signals to take immediate action,
+ and cause input available signals to zero out timeout. */
+ if (XINT (read_kbd) < 0)
+ set_waiting_for_input (&timeout);
+
+ /* If a frame has been newly mapped and needs updating,
+ reprocess its display stuff. */
+ if (frame_garbaged)
+ redisplay_preserve_echo_area ();
+
+ if (XINT (read_kbd) && detect_input_pending ())
+ nfds = 0;
+ else
+ nfds = select (1, &waitchannels, 0, 0, timeout_p);
+
+ /* Make C-g and alarm signals set flags again */
+ clear_waiting_for_input ();
+
+ /* If we woke up due to SIGWINCH, actually change size now. */
+ do_pending_window_change ();
+
+ if (nfds == -1)
+ {
+ /* If the system call was interrupted, then go around the
+ loop again. */
+ if (errno == EINTR)
+ waitchannels = 0;
+ }
+#ifdef sun
+ else if (nfds > 0 && (waitchannels & 1) && interrupt_input)
+ /* System sometimes fails to deliver SIGIO. */
+ kill (getpid (), SIGIO);
+#endif
+ if (XINT (read_kbd) && interrupt_input && (waitchannels & 1))
+ kill (0, SIGIO);
+
+ /* If we have timed out (nfds == 0) or found some input (nfds > 0),
+ we should exit. */
+ if (nfds >= 0)
+ break;
+ }
+
+ return 0;
+}
+
+
+DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
+ "Return the (or, a) process associated with BUFFER.\n\
+This copy of Emacs has not been built to support subprocesses, so this\n\
+function always returns nil.")
+ (name)
+ register Lisp_Object name;
+{
+ return Qnil;
+}
+
+/* Kill all processes associated with `buffer'.
+ If `buffer' is nil, kill all processes.
+ Since we have no subprocesses, this does nothing. */
+
+kill_buffer_processes (buffer)
+ Lisp_Object buffer;
+{
+}
+
+init_process ()
+{
+}
+
+syms_of_process ()
+{
+ defsubr (&Sget_buffer_process);
+}
+
+\f
+#endif /* not subprocesses */