#include "xgselect.h"
#endif
-#ifndef WNOHANG
-# undef waitpid
-# define waitpid(pid, status, options) wait (status)
-#endif
-#ifndef WUNTRACED
-# define WUNTRACED 0
+#ifdef WINDOWSNT
+extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
+ EMACS_TIME *, void *);
#endif
/* Work around GCC 4.7.0 bug with strict overflow checking; see
#ifndef NON_BLOCKING_CONNECT
#ifdef HAVE_SELECT
#if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
-#if defined (O_NONBLOCK) || defined (O_NDELAY)
#if defined (EWOULDBLOCK) || defined (EINPROGRESS)
#define NON_BLOCKING_CONNECT
#endif /* EWOULDBLOCK || EINPROGRESS */
-#endif /* O_NONBLOCK || O_NDELAY */
#endif /* HAVE_GETPEERNAME || GNU_LINUX */
#endif /* HAVE_SELECT */
#endif /* NON_BLOCKING_CONNECT */
#define DATAGRAM_CONN_P(proc) (0)
#endif
-/* Maximum number of bytes to send to a pty without an eof. */
-static int pty_max_bytes;
-
/* These setters are used only in this file, so they can be private. */
-static inline void
+static void
pset_buffer (struct Lisp_Process *p, Lisp_Object val)
{
p->buffer = val;
}
-static inline void
+static void
pset_command (struct Lisp_Process *p, Lisp_Object val)
{
p->command = val;
}
-static inline void
+static void
pset_decode_coding_system (struct Lisp_Process *p, Lisp_Object val)
{
p->decode_coding_system = val;
}
-static inline void
+static void
pset_decoding_buf (struct Lisp_Process *p, Lisp_Object val)
{
p->decoding_buf = val;
}
-static inline void
+static void
pset_encode_coding_system (struct Lisp_Process *p, Lisp_Object val)
{
p->encode_coding_system = val;
}
-static inline void
+static void
pset_encoding_buf (struct Lisp_Process *p, Lisp_Object val)
{
p->encoding_buf = val;
}
-static inline void
+static void
pset_filter (struct Lisp_Process *p, Lisp_Object val)
{
p->filter = val;
}
-static inline void
+static void
pset_log (struct Lisp_Process *p, Lisp_Object val)
{
p->log = val;
}
-static inline void
+static void
pset_mark (struct Lisp_Process *p, Lisp_Object val)
{
p->mark = val;
}
-static inline void
+static void
pset_name (struct Lisp_Process *p, Lisp_Object val)
{
p->name = val;
}
-static inline void
+static void
pset_plist (struct Lisp_Process *p, Lisp_Object val)
{
p->plist = val;
}
-static inline void
+static void
pset_sentinel (struct Lisp_Process *p, Lisp_Object val)
{
p->sentinel = val;
}
-static inline void
+static void
pset_status (struct Lisp_Process *p, Lisp_Object val)
{
p->status = val;
}
-static inline void
+static void
pset_tty_name (struct Lisp_Process *p, Lisp_Object val)
{
p->tty_name = val;
}
-static inline void
+static void
pset_type (struct Lisp_Process *p, Lisp_Object val)
{
p->type = val;
}
-static inline void
+static void
pset_write_queue (struct Lisp_Process *p, Lisp_Object val)
{
p->write_queue = val;
if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
{
- char *signame;
+ char const *signame;
synchronize_system_messages_locale ();
signame = strsignal (code);
if (signame == 0)
#ifdef PTY_OPEN
PTY_OPEN;
#else /* no PTY_OPEN */
- {
- { /* 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;
- struct stat stb;
-
- if (stat (pty_name, &stb) < 0)
- {
- failed_count++;
- if (failed_count >= 3)
- return -1;
- }
- else
- failed_count = 0;
- }
-# ifdef O_NONBLOCK
- fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
-# else
- fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0);
-# endif
- }
+ fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
#endif /* no PTY_OPEN */
if (fd >= 0)
#else
sprintf (pty_name, "/dev/tty%c%x", c, i);
#endif /* no PTY_TTY_NAME_SPRINTF */
- if (access (pty_name, 6) != 0)
+ if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0)
{
emacs_close (fd);
# ifndef __sgi
#ifdef SIGCHLD
/* Fdelete_process promises to immediately forget about the process, but in
reality, Emacs needs to remember those processes until they have been
- treated by the SIGCHLD handler; otherwise this handler would consider the
- process as being synchronous and say that the synchronous process is
- dead. */
+ treated by the SIGCHLD handler and waitpid has been invoked on them;
+ otherwise they might fill up the kernel's process table. */
static Lisp_Object deleted_pid_list;
#endif
int inchannel, outchannel;
pid_t pid;
int sv[2];
-#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+#ifndef WINDOWSNT
int wait_child_setup[2];
#endif
#ifdef SIGCHLD
#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
/* On most USG systems it does not work to open the pty's tty here,
then close it and reopen it in the child. */
-#ifdef O_NOCTTY
/* Don't let this terminal become our controlling terminal
(in case we don't have one). */
forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
-#else
- forkout = forkin = emacs_open (pty_name, O_RDWR, 0);
-#endif
if (forkin < 0)
report_file_error ("Opening pty", Qnil);
#else
forkin = sv[0];
}
-#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+#ifndef WINDOWSNT
{
int tem;
}
#endif
-#ifdef O_NONBLOCK
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
-#else
-#ifdef O_NDELAY
- fcntl (inchannel, F_SETFL, O_NDELAY);
- fcntl (outchannel, F_SETFL, O_NDELAY);
-#endif
-#endif
/* Record this as an active process, with its channels.
As a result, child_setup will close Emacs's side of the pipes. */
if (inchannel > max_process_desc)
max_process_desc = inchannel;
- /* Until we store the proper pid, enable the SIGCHLD handler
- to recognize an unknown pid as standing for this process.
- It is very important not to let this `marker' value stay
- in the table after this function has returned; if it does
- it might cause call-process to hang and subsequent asynchronous
- processes to get their return values scrambled. */
- XPROCESS (process)->pid = -1;
-
- /* This must be called after the above line because it may signal an
- error. */
+ /* This may signal an error. */
setup_process_coding_systems (process);
encoded_current_dir = ENCODE_FILE (current_dir);
/* Make the pty be the controlling terminal of the process. */
#ifdef HAVE_PTYS
/* First, disconnect its current controlling terminal. */
-#ifdef HAVE_SETSID
/* We tried doing setsid only if pty_flag, but it caused
process_set_signal to fail on SGI when using a pipe. */
setsid ();
ioctl (xforkin, TIOCSCTTY, 0);
#endif
}
-#else /* not HAVE_SETSID */
-#ifdef USG
- /* It's very important to call setpgrp here and no time
- afterwards. Otherwise, we lose our controlling tty which
- is set when we open the pty. */
- setpgrp ();
-#endif /* USG */
-#endif /* not HAVE_SETSID */
#if defined (LDISC1)
if (pty_flag && xforkin >= 0)
{
ioctl (j, TIOCNOTTY, 0);
emacs_close (j);
}
-#ifndef USG
- /* In order to get a controlling terminal on some versions
- of BSD, it is necessary to put the process in pgrp 0
- before it opens the terminal. */
-#ifdef HAVE_SETPGID
- setpgid (0, 0);
-#else
- setpgrp (0, 0);
-#endif
-#endif
}
#endif /* TIOCNOTTY */
#if !defined (DONT_REOPEN_PTY)
/*** There is a suggestion that this ought to be a
- conditional on TIOCSPGRP,
- or !(defined (HAVE_SETSID) && defined (TIOCSCTTY)).
+ conditional on TIOCSPGRP, or !defined TIOCSCTTY.
Trying the latter gave the wrong results on Debian GNU/Linux 1.1;
that system does seem to need this code, even though
- both HAVE_SETSID and TIOCSCTTY are defined. */
+ both TIOCSCTTY is defined. */
/* Now close the pty (if we had it open) and reopen it.
This makes the pty the controlling terminal of the subprocess. */
if (pty_flag)
pid = child_setup (xforkin, xforkout, xforkout,
new_argv, 1, encoded_current_dir);
#else /* not WINDOWSNT */
-#ifdef FD_CLOEXEC
emacs_close (wait_child_setup[0]);
-#endif
child_setup (xforkin, xforkout, xforkout,
new_argv, 1, encoded_current_dir);
#endif /* not WINDOWSNT */
#endif
XPROCESS (process)->pid = pid;
+ if (0 <= pid)
+ XPROCESS (process)->alive = 1;
/* Stop blocking signals in the parent. */
#ifdef SIGCHLD
pset_tty_name (XPROCESS (process), lisp_pty_name);
-#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+#ifndef WINDOWSNT
/* Wait for child_setup to complete in case that vfork is
actually defined as fork. The descriptor wait_child_setup[1]
of a pipe is closed at the child side either by close-on-exec
#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
/* On most USG systems it does not work to open the pty's tty here,
then close it and reopen it in the child. */
-#ifdef O_NOCTTY
/* Don't let this terminal become our controlling terminal
(in case we don't have one). */
int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
-#else
- int forkout = emacs_open (pty_name, O_RDWR, 0);
-#endif
if (forkout < 0)
report_file_error ("Opening pty", Qnil);
#if defined (DONT_REOPEN_PTY)
}
#endif /* HAVE_PTYS */
-#ifdef O_NONBLOCK
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
-#else
-#ifdef O_NDELAY
- fcntl (inchannel, F_SETFL, O_NDELAY);
- fcntl (outchannel, F_SETFL, O_NDELAY);
-#endif
-#endif
/* Record this as an active process, with its channels.
As a result, child_setup will close Emacs's side of the pipes. */
{
/* Don't support network sockets when non-blocking mode is
not available, since a blocked Emacs is not useful. */
-#if !defined (O_NONBLOCK) && !defined (O_NDELAY)
- error ("Network servers not supported");
-#else
is_server = 1;
if (TYPE_RANGED_INTEGERP (int, tem))
backlog = XINT (tem);
-#endif
}
/* Make QCaddress an alias for :local (server) or :remote (client). */
#ifdef NON_BLOCKING_CONNECT
if (is_non_blocking_client)
{
-#ifdef O_NONBLOCK
ret = fcntl (s, F_SETFL, O_NONBLOCK);
-#else
- ret = fcntl (s, F_SETFL, O_NDELAY);
-#endif
if (ret < 0)
{
xerrno = errno;
chan_process[inch] = proc;
-#ifdef O_NONBLOCK
fcntl (inch, F_SETFL, O_NONBLOCK);
-#else
-#ifdef O_NDELAY
- fcntl (inch, F_SETFL, O_NDELAY);
-#endif
-#endif
p = XPROCESS (proc);
chan_process[s] = proc;
-#ifdef O_NONBLOCK
fcntl (s, F_SETFL, O_NONBLOCK);
-#else
-#ifdef O_NDELAY
- fcntl (s, F_SETFL, O_NDELAY);
-#endif
-#endif
p = XPROCESS (proc);
-1 meaning caller will actually read the input, so don't throw to
the quit handler, or
- DO_DISPLAY != 0 means redisplay should be done to show subprocess
+ DO_DISPLAY means redisplay should be done to show subprocess
output that arrives.
If WAIT_FOR_CELL is a cons cell, wait until its car is non-nil
int
wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
- int do_display,
+ bool do_display,
Lisp_Object wait_for_cell,
struct Lisp_Process *wait_proc, int just_wait_proc)
{
do
{
- int old_timers_run = timers_run;
+ unsigned old_timers_run = timers_run;
struct buffer *old_buffer = current_buffer;
Lisp_Object old_window = selected_window;
if (EMACS_TIME_LT (timer_delay, timeout))
{
timeout = timer_delay;
- timeout_reduced_for_timers = 1;
+ timeout_reduced_for_timers = 1;
}
}
else
total_nread += nread;
got_some_input = 1;
}
-#ifdef EIO
- else if (nread == -1 && EIO == errno)
- break;
-#endif
-#ifdef EAGAIN
- else if (nread == -1 && EAGAIN == errno)
+ else if (nread == -1 && (errno == EIO || errno == EAGAIN))
break;
-#endif
#ifdef EWOULDBLOCK
else if (nread == -1 && EWOULDBLOCK == errno)
break;
process_output_skip = 0;
}
#endif
+
#if defined (USE_GTK) || defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
nfds = xg_select
#elif defined (HAVE_NS)
if (read_kbd != 0)
{
- int old_timers_run = timers_run;
+ unsigned old_timers_run = timers_run;
struct buffer *old_buffer = current_buffer;
Lisp_Object old_window = selected_window;
int leave = 0;
else if (nread == -1 && errno == EWOULDBLOCK)
;
#endif
- /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK,
- and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */
-#ifdef O_NONBLOCK
- else if (nread == -1 && errno == EAGAIN)
- ;
-#else
-#ifdef O_NDELAY
else if (nread == -1 && errno == EAGAIN)
;
+#ifdef WINDOWSNT
+ /* FIXME: Is this special case still needed? */
/* Note that we cannot distinguish between no input
available now and a closed pipe.
With luck, a closed pipe will be accompanied by
subprocess termination and SIGCHLD. */
else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc))
;
-#endif /* O_NDELAY */
-#endif /* O_NONBLOCK */
+#endif
#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
buf = SSDATA (object);
}
- if (pty_max_bytes == 0)
- {
-#if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON)
- pty_max_bytes = fpathconf (p->outfd, _PC_MAX_CANON);
- if (pty_max_bytes < 0)
- pty_max_bytes = 250;
-#else
- pty_max_bytes = 250;
-#endif
- /* Deduct one, to leave space for the eof. */
- pty_max_bytes--;
- }
-
/* If there is already data in the write_queue, put the new data
in the back of queue. Otherwise, ignore it. */
if (!NILP (p->write_queue))
if (rv < 0)
{
- if (0
+ if (errno == EAGAIN
#ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
-#endif
-#ifdef EAGAIN
- || errno == EAGAIN
#endif
)
/* Buffer is full. Wait, accepting input;
return process;
}
\f
-/* On receipt of a signal that a child status has changed, loop asking
- about children with changed statuses until the system says there
- are no more.
+/* If the status of the process DESIRED has changed, return true and
+ set *STATUS to its exit status; otherwise, return false.
+ If HAVE is nonnegative, assume that HAVE = waitpid (HAVE, STATUS, ...)
+ has already been invoked, and do not invoke waitpid again. */
+
+static bool
+process_status_retrieved (pid_t desired, pid_t have, int *status)
+{
+ if (have < 0)
+ {
+ /* Invoke waitpid only with a known process ID; do not invoke
+ waitpid with a nonpositive argument. Otherwise, Emacs might
+ reap an unwanted process by mistake. For example, invoking
+ waitpid (-1, ...) can mess up glib by reaping glib's subprocesses,
+ so that another thread running glib won't find them. */
+ do
+ have = waitpid (desired, status, WNOHANG | WUNTRACED);
+ while (have < 0 && errno == EINTR);
+ }
+
+ return have == desired;
+}
+
+/* If PID is nonnegative, the child process PID with wait status W has
+ changed its status; record this and return true.
+
+ If PID is negative, ignore W, and look for known child processes
+ of Emacs whose status have changed. For each one found, record its new
+ status.
All we do is change the status; we do not run sentinels or print
notifications. That is saved for the next time keyboard input is
** Malloc WARNING: This should never call malloc either directly or
indirectly; if it does, that is a bug */
-/* Record the changed status of the child process PID with wait status W. */
void
record_child_status_change (pid_t pid, int w)
{
#ifdef SIGCHLD
- Lisp_Object proc;
- struct Lisp_Process *p;
+
+ /* Record at most one child only if we already know one child that
+ has exited. */
+ bool record_at_most_one_child = 0 <= pid;
+
Lisp_Object tail;
/* Find the process that signaled us, and record its status. */
/* The process can have been deleted by Fdelete_process. */
for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail))
{
+ bool all_pids_are_fixnums
+ = (MOST_NEGATIVE_FIXNUM <= TYPE_MINIMUM (pid_t)
+ && TYPE_MAXIMUM (pid_t) <= MOST_POSITIVE_FIXNUM);
Lisp_Object xpid = XCAR (tail);
- if ((INTEGERP (xpid) && pid == XINT (xpid))
- || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid)))
+ if (all_pids_are_fixnums ? INTEGERP (xpid) : NUMBERP (xpid))
{
- XSETCAR (tail, Qnil);
- return;
+ pid_t deleted_pid;
+ if (INTEGERP (xpid))
+ deleted_pid = XINT (xpid);
+ else
+ deleted_pid = XFLOAT_DATA (xpid);
+ if (process_status_retrieved (deleted_pid, pid, &w))
+ {
+ XSETCAR (tail, Qnil);
+ if (record_at_most_one_child)
+ return;
+ }
}
}
/* Otherwise, if it is asynchronous, it is in Vprocess_alist. */
- p = 0;
for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
{
- proc = XCDR (XCAR (tail));
- p = XPROCESS (proc);
- if (EQ (p->type, Qreal) && p->pid == pid)
- break;
- p = 0;
- }
-
- /* Look for an asynchronous process whose pid hasn't been filled
- in yet. */
- if (! p)
- for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
- {
- proc = XCDR (XCAR (tail));
- p = XPROCESS (proc);
- if (p->pid == -1)
- break;
- p = 0;
- }
+ Lisp_Object proc = XCDR (XCAR (tail));
+ struct Lisp_Process *p = XPROCESS (proc);
+ if (p->alive && process_status_retrieved (p->pid, pid, &w))
+ {
+ /* Change the status of the process that was found. */
+ p->tick = ++process_tick;
+ p->raw_status = w;
+ p->raw_status_new = 1;
- /* Change the status of the process that was found. */
- if (p)
- {
- int clear_desc_flag = 0;
+ /* If process has terminated, stop waiting for its output. */
+ if (WIFSIGNALED (w) || WIFEXITED (w))
+ {
+ int clear_desc_flag = 0;
+ p->alive = 0;
+ if (p->infd >= 0)
+ clear_desc_flag = 1;
- p->tick = ++process_tick;
- p->raw_status = w;
- p->raw_status_new = 1;
+ /* clear_desc_flag avoids a compiler bug in Microsoft C. */
+ if (clear_desc_flag)
+ {
+ FD_CLR (p->infd, &input_wait_mask);
+ FD_CLR (p->infd, &non_keyboard_wait_mask);
+ }
+ }
- /* If process has terminated, stop waiting for its output. */
- if ((WIFSIGNALED (w) || WIFEXITED (w))
- && p->infd >= 0)
- clear_desc_flag = 1;
+ /* Tell wait_reading_process_output that it needs to wake up and
+ look around. */
+ if (input_available_clear_time)
+ *input_available_clear_time = make_emacs_time (0, 0);
- /* We use clear_desc_flag to avoid a compiler bug in Microsoft C. */
- if (clear_desc_flag)
- {
- FD_CLR (p->infd, &input_wait_mask);
- FD_CLR (p->infd, &non_keyboard_wait_mask);
+ if (record_at_most_one_child)
+ return;
}
-
- /* Tell wait_reading_process_output that it needs to wake up and
- look around. */
- if (input_available_clear_time)
- *input_available_clear_time = make_emacs_time (0, 0);
}
- /* There was no asynchronous process found for that pid: we have
- a synchronous process. */
- else
+
+ if (0 <= pid)
{
+ /* The caller successfully waited for a pid but no asynchronous
+ process was found for it, so this is a synchronous process. */
+
synch_process_alive = 0;
/* Report the status of the synchronous process. */
#ifdef SIGCHLD
-/* On some systems, the SIGCHLD handler must return right away. If
- any more processes want to signal us, we will get another signal.
- Otherwise, loop around to use up all the processes that have
- something to tell us. */
-#if (defined WINDOWSNT \
- || (defined USG && !defined GNU_LINUX \
- && !(defined HPUX && defined WNOHANG)))
-enum { CAN_HANDLE_MULTIPLE_CHILDREN = 0 };
-#else
-enum { CAN_HANDLE_MULTIPLE_CHILDREN = 1 };
-#endif
-
static void
handle_child_signal (int sig)
{
- do
- {
- pid_t pid;
- int status;
-
- do
- pid = waitpid (-1, &status, WNOHANG | WUNTRACED);
- while (pid < 0 && errno == EINTR);
-
- /* PID == 0 means no processes found, PID == -1 means a real failure.
- Either way, we have done all our job. */
- if (pid <= 0)
- break;
-
- record_child_status_change (pid, status);
- }
- while (CAN_HANDLE_MULTIPLE_CHILDREN);
+ record_child_status_change (-1, 0);
}
static void
see full version for other parameters. We know that wait_proc will
always be NULL, since `subprocesses' isn't defined.
- DO_DISPLAY != 0 means redisplay should be done to show subprocess
+ DO_DISPLAY means redisplay should be done to show subprocess
output that arrives.
Return true if we received input from any process. */
int
wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
- int do_display,
+ bool do_display,
Lisp_Object wait_for_cell,
struct Lisp_Process *wait_proc, int just_wait_proc)
{
do
{
- int old_timers_run = timers_run;
+ unsigned old_timers_run = timers_run;
timer_delay = timer_check ();
if (timers_run != old_timers_run && do_display)
/* We must retry, since a timer may have requeued itself
#ifdef HAVE_GETSOCKNAME
ADD_SUBFEATURE (QCservice, Qt);
#endif
-#if defined (O_NONBLOCK) || defined (O_NDELAY)
ADD_SUBFEATURE (QCserver, Qt);
-#endif
for (sopt = socket_options; sopt->name; sopt++)
subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);