/* Asynchronous subprocess control for GNU Emacs.
-Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2012
- Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2013 Free Software
+Foundation, Inc.
This file is part of GNU Emacs.
#define PROCESS_INLINE EXTERN_INLINE
-#include <signal.h>
#include <stdio.h>
#include <errno.h>
-#include <setjmp.h>
#include <sys/types.h> /* Some typedefs are used in sys/file.h. */
#include <sys/file.h>
#include <sys/stat.h>
-#include <setjmp.h>
-
#include <unistd.h>
#include <fcntl.h>
#include <bsdtty.h>
#endif
+#ifdef USG5_4
+# include <sys/stream.h>
+# include <sys/stropts.h>
+#endif
+
#ifdef HAVE_RES_INIT
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <pty.h>
#endif
+#include <c-ctype.h>
+#include <sig2str.h>
+
#endif /* subprocesses */
#include "systime.h"
#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 */
"non-destructive" select. So we require either native select,
or emulation of select using FIONREAD. */
-#ifdef BROKEN_DATAGRAM_SOCKETS
-#undef DATAGRAM_SOCKETS
-#else
-#ifndef DATAGRAM_SOCKETS
-#if defined (HAVE_SELECT) || defined (FIONREAD)
-#if defined (HAVE_SENDTO) && defined (HAVE_RECVFROM) && defined (EMSGSIZE)
-#define DATAGRAM_SOCKETS
-#endif /* HAVE_SENDTO && HAVE_RECVFROM && EMSGSIZE */
-#endif /* HAVE_SELECT || FIONREAD */
-#endif /* DATAGRAM_SOCKETS */
-#endif /* BROKEN_DATAGRAM_SOCKETS */
+#ifndef BROKEN_DATAGRAM_SOCKETS
+# if defined HAVE_SELECT || defined USABLE_FIONREAD
+# if defined HAVE_SENDTO && defined HAVE_RECVFROM && defined EMSGSIZE
+# define DATAGRAM_SOCKETS
+# endif
+# endif
+#endif
#if defined HAVE_LOCAL_SOCKETS && defined DATAGRAM_SOCKETS
# define HAVE_SEQPACKET
#endif
static void create_process (Lisp_Object, char **, Lisp_Object);
-#ifdef SIGIO
+#ifdef USABLE_SIGIO
static int keyboard_bit_set (SELECT_TYPE *);
#endif
static void deactivate_process (Lisp_Object);
static void status_notify (struct Lisp_Process *);
static int read_process_output (Lisp_Object, int);
+static void handle_child_signal (int);
static void create_pty (Lisp_Object);
/* If we support a window system, turn on the code to poll periodically
to detect C-g. It isn't actually used when doing interrupt input. */
-#if defined (HAVE_WINDOW_SYSTEM) && !defined (USE_ASYNC_EVENTS)
+#ifdef HAVE_WINDOW_SYSTEM
#define POLL_FOR_INPUT
#endif
#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.
+
+ Some processes created by call-process are also put onto this list. */
static Lisp_Object deleted_pid_list;
-#endif
+
+void
+record_deleted_pid (pid_t pid)
+{
+ deleted_pid_list = Fcons (make_fixnum_or_float (pid),
+ /* GC treated elements set to nil. */
+ Fdelq (Qnil, deleted_pid_list));
+
+}
DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
doc: /* Delete PROCESS: kill it and forget about it immediately.
status_notify (p);
redisplay_preserve_echo_area (13);
}
- else if (p->infd >= 0)
+ else
{
-#ifdef SIGCHLD
- Lisp_Object symbol;
- pid_t pid = p->pid;
-
- /* No problem storing the pid here, as it is still in Vprocess_alist. */
- deleted_pid_list = Fcons (make_fixnum_or_float (pid),
- /* GC treated elements set to nil. */
- Fdelq (Qnil, deleted_pid_list));
- /* If the process has already signaled, remove it from the list. */
- if (p->raw_status_new)
- update_status (p);
- symbol = p->status;
- if (CONSP (p->status))
- symbol = XCAR (p->status);
- if (EQ (symbol, Qsignal) || EQ (symbol, Qexit))
- deleted_pid_list
- = Fdelete (make_fixnum_or_float (pid), deleted_pid_list);
- else
-#endif
+ if (p->alive)
+ record_kill_process (p);
+
+ if (p->infd >= 0)
{
- Fkill_process (process, Qnil);
- /* Do this now, since remove_process will make the
- SIGCHLD handler do nothing. */
- pset_status (p, Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil)));
+ /* Update P's status, since record_kill_process will make the
+ SIGCHLD handler update deleted_pid_list, not *P. */
+ Lisp_Object symbol;
+ if (p->raw_status_new)
+ update_status (p);
+ symbol = CONSP (p->status) ? XCAR (p->status) : p->status;
+ if (! (EQ (symbol, Qsignal) || EQ (symbol, Qexit)))
+ pset_status (p, list2 (Qsignal, make_number (SIGKILL)));
+
p->tick = ++process_tick;
status_notify (p);
redisplay_preserve_echo_area (13);
int inchannel, outchannel;
pid_t pid;
int sv[2];
-#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+#ifndef WINDOWSNT
int wait_child_setup[2];
#endif
- sigset_t procmask;
sigset_t blocked;
- struct sigaction sigint_action;
- struct sigaction sigquit_action;
- struct sigaction sigpipe_action;
-#ifdef AIX
- struct sigaction sighup_action;
-#endif
- /* Use volatile to protect variables from being clobbered by longjmp. */
+ /* Use volatile to protect variables from being clobbered by vfork. */
volatile int forkin, forkout;
volatile int pty_flag = 0;
+ volatile Lisp_Object lisp_pty_name = Qnil;
+ volatile Lisp_Object encoded_current_dir;
inchannel = outchannel = -1;
#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 = forkout = -1;
#endif /* not USG, or USG_SUBTTY_WORKS */
pty_flag = 1;
+ lisp_pty_name = build_string (pty_name);
}
else
#endif /* HAVE_PTYS */
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. */
XPROCESS (process)->pty_flag = pty_flag;
pset_status (XPROCESS (process), Qrun);
- /* Delay interrupts until we have a chance to store
- the new fork's pid in its process structure */
- sigemptyset (&blocked);
-#ifdef SIGCHLD
- sigaddset (&blocked, SIGCHLD);
-#endif
-#ifdef HAVE_WORKING_VFORK
- /* On many hosts (e.g. Solaris 2.4), if a vforked child calls `signal',
- this sets the parent's signal handlers as well as the child's.
- So delay all interrupts whose handlers the child might munge,
- and record the current handlers so they can be restored later. */
- sigaddset (&blocked, SIGINT ); sigaction (SIGINT , 0, &sigint_action );
- sigaddset (&blocked, SIGQUIT); sigaction (SIGQUIT, 0, &sigquit_action);
- sigaddset (&blocked, SIGPIPE); sigaction (SIGPIPE, 0, &sigpipe_action);
-#ifdef AIX
- sigaddset (&blocked, SIGHUP ); sigaction (SIGHUP , 0, &sighup_action );
-#endif
-#endif /* HAVE_WORKING_VFORK */
- pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
-
FD_SET (inchannel, &input_wait_mask);
FD_SET (inchannel, &non_keyboard_wait_mask);
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);
- BLOCK_INPUT;
+ encoded_current_dir = ENCODE_FILE (current_dir);
- {
- /* child_setup must clobber environ on systems with true vfork.
- Protect it from permanent change. */
- char **save_environ = environ;
- volatile Lisp_Object encoded_current_dir = ENCODE_FILE (current_dir);
+ block_input ();
+
+ /* Block SIGCHLD until we have a chance to store the new fork's
+ pid in its process structure. */
+ sigemptyset (&blocked);
+ sigaddset (&blocked, SIGCHLD);
+ pthread_sigmask (SIG_BLOCK, &blocked, 0);
#ifndef WINDOWSNT
- pid = vfork ();
- if (pid == 0)
+ pid = vfork ();
+ if (pid == 0)
#endif /* not WINDOWSNT */
- {
- int xforkin = forkin;
- int xforkout = forkout;
-
-#if 0 /* This was probably a mistake--it duplicates code later on,
- but fails to handle all the cases. */
- /* Make sure SIGCHLD is not blocked in the child. */
- sigsetmask (SIGEMPTYMASK);
-#endif
+ {
+ int xforkin = forkin;
+ int xforkout = forkout;
- /* Make the pty be the controlling terminal of the process. */
+ /* 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 ();
- /* Make the pty's terminal the controlling terminal. */
- if (pty_flag && xforkin >= 0)
- {
+ /* First, disconnect its current controlling terminal. */
+ /* We tried doing setsid only if pty_flag, but it caused
+ process_set_signal to fail on SGI when using a pipe. */
+ setsid ();
+ /* Make the pty's terminal the controlling terminal. */
+ if (pty_flag && xforkin >= 0)
+ {
#ifdef TIOCSCTTY
- /* We ignore the return value
- because faith@cs.unc.edu says that is necessary on Linux. */
- ioctl (xforkin, TIOCSCTTY, 0);
+ /* We ignore the return value
+ because faith@cs.unc.edu says that is necessary on Linux. */
+ 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)
- {
- struct termios t;
- tcgetattr (xforkin, &t);
- t.c_lflag = LDISC1;
- if (tcsetattr (xforkin, TCSANOW, &t) < 0)
- emacs_write (1, "create_process/tcsetattr LDISC1 failed\n", 39);
- }
+ if (pty_flag && xforkin >= 0)
+ {
+ struct termios t;
+ tcgetattr (xforkin, &t);
+ t.c_lflag = LDISC1;
+ if (tcsetattr (xforkin, TCSANOW, &t) < 0)
+ emacs_write (1, "create_process/tcsetattr LDISC1 failed\n", 39);
+ }
#else
#if defined (NTTYDISC) && defined (TIOCSETD)
- if (pty_flag && xforkin >= 0)
- {
- /* Use new line discipline. */
- int ldisc = NTTYDISC;
- ioctl (xforkin, TIOCSETD, &ldisc);
- }
+ if (pty_flag && xforkin >= 0)
+ {
+ /* Use new line discipline. */
+ int ldisc = NTTYDISC;
+ ioctl (xforkin, TIOCSETD, &ldisc);
+ }
#endif
#endif
#ifdef TIOCNOTTY
- /* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you
- can do TIOCSPGRP only to the process's controlling tty. */
- if (pty_flag)
- {
- /* I wonder: would just ioctl (0, TIOCNOTTY, 0) work here?
- I can't test it since I don't have 4.3. */
- int j = emacs_open ("/dev/tty", O_RDWR, 0);
- if (j >= 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
- }
+ /* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you
+ can do TIOCSPGRP only to the process's controlling tty. */
+ if (pty_flag)
+ {
+ /* I wonder: would just ioctl (0, TIOCNOTTY, 0) work here?
+ I can't test it since I don't have 4.3. */
+ int j = emacs_open ("/dev/tty", O_RDWR, 0);
+ if (j >= 0)
+ {
+ ioctl (j, TIOCNOTTY, 0);
+ emacs_close (j);
+ }
+ }
#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)
- {
+ if (pty_flag)
+ {
- /* I wonder if emacs_close (emacs_open (pty_name, ...))
- would work? */
- if (xforkin >= 0)
- emacs_close (xforkin);
- xforkout = xforkin = emacs_open (pty_name, O_RDWR, 0);
+ /* I wonder if emacs_close (emacs_open (pty_name, ...))
+ would work? */
+ if (xforkin >= 0)
+ emacs_close (xforkin);
+ xforkout = xforkin = emacs_open (pty_name, O_RDWR, 0);
- if (xforkin < 0)
- {
- emacs_write (1, "Couldn't open the pty terminal ", 31);
- emacs_write (1, pty_name, strlen (pty_name));
- emacs_write (1, "\n", 1);
- _exit (1);
- }
+ if (xforkin < 0)
+ {
+ emacs_write (1, "Couldn't open the pty terminal ", 31);
+ emacs_write (1, pty_name, strlen (pty_name));
+ emacs_write (1, "\n", 1);
+ _exit (1);
+ }
- }
+ }
#endif /* not DONT_REOPEN_PTY */
#ifdef SETUP_SLAVE_PTY
- if (pty_flag)
- {
- SETUP_SLAVE_PTY;
- }
+ if (pty_flag)
+ {
+ SETUP_SLAVE_PTY;
+ }
#endif /* SETUP_SLAVE_PTY */
#ifdef AIX
- /* On AIX, we've disabled SIGHUP above once we start a child on a pty.
- Now reenable it in the child, so it will die when we want it to. */
- if (pty_flag)
- signal (SIGHUP, SIG_DFL);
+ /* On AIX, we've disabled SIGHUP above once we start a child on a pty.
+ Now reenable it in the child, so it will die when we want it to. */
+ if (pty_flag)
+ signal (SIGHUP, SIG_DFL);
#endif
#endif /* HAVE_PTYS */
- signal (SIGINT, SIG_DFL);
- signal (SIGQUIT, SIG_DFL);
- /* GConf causes us to ignore SIGPIPE, make sure it is restored
- in the child. */
- signal (SIGPIPE, SIG_DFL);
+ signal (SIGINT, SIG_DFL);
+ signal (SIGQUIT, SIG_DFL);
+
+ /* Emacs ignores SIGPIPE, but the child should not. */
+ signal (SIGPIPE, SIG_DFL);
/* Stop blocking signals in the child. */
- pthread_sigmask (SIG_SETMASK, &procmask, 0);
+ pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
- if (pty_flag)
- child_setup_tty (xforkout);
+ if (pty_flag)
+ child_setup_tty (xforkout);
#ifdef WINDOWSNT
- pid = child_setup (xforkin, xforkout, xforkout,
- new_argv, 1, encoded_current_dir);
+ 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);
+ emacs_close (wait_child_setup[0]);
+ child_setup (xforkin, xforkout, xforkout,
+ new_argv, 1, encoded_current_dir);
#endif /* not WINDOWSNT */
- }
- environ = save_environ;
- }
+ }
+
+ /* Back in the parent process. */
- UNBLOCK_INPUT;
+ XPROCESS (process)->pid = pid;
+ if (0 <= pid)
+ XPROCESS (process)->alive = 1;
+
+ /* Stop blocking signals in the parent. */
+ pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+ unblock_input ();
- /* This runs in the Emacs process. */
if (pid < 0)
{
if (forkin >= 0)
else
{
/* vfork succeeded. */
- XPROCESS (process)->pid = pid;
#ifdef WINDOWSNT
register_child (pid, inchannel);
if (forkin != forkout && forkout >= 0)
emacs_close (forkout);
-#ifdef HAVE_PTYS
- if (pty_flag)
- pset_tty_name (XPROCESS (process), build_string (pty_name));
- else
-#endif
- pset_tty_name (XPROCESS (process), Qnil);
+ 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
- on successful execvp or the _exit call in child_setup. */
+ on successful execve or the _exit call in child_setup. */
{
char dummy;
#endif
}
- /* Restore the signal state whether vfork succeeded or not.
- (We will signal an error, below, if it failed.) */
-#ifdef HAVE_WORKING_VFORK
- /* Restore the parent's signal handlers. */
- sigaction (SIGINT, &sigint_action, 0);
- sigaction (SIGQUIT, &sigquit_action, 0);
- sigaction (SIGPIPE, &sigpipe_action, 0);
-#ifdef AIX
- sigaction (SIGHUP, &sighup_action, 0);
-#endif
-#endif /* HAVE_WORKING_VFORK */
- /* Stop blocking signals in the parent. */
- pthread_sigmask (SIG_SETMASK, &procmask, 0);
-
/* Now generate the error if vfork failed. */
if (pid < 0)
report_file_error ("Doing vfork", Qnil);
#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;
#ifdef HAVE_GETADDRINFO
if (res != &ai)
{
- BLOCK_INPUT;
+ block_input ();
freeaddrinfo (res);
- UNBLOCK_INPUT;
+ unblock_input ();
}
#endif
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)
{
Otherwise, do pending quit if requested. */
if (read_kbd >= 0)
QUIT;
-#ifdef SYNC_INPUT
- else
+ else if (pending_signals)
process_pending_signals ();
-#endif
/* Exit now if the cell we're waiting for became non-nil. */
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
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)
yielding EBADF here or at select() call above.
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. */
+ Cleanup occurs c/o status_notify after SIGCHLD. */
no_avail = 1; /* Cannot depend on values returned */
#else
emacs_abort ();
check_write = 0;
}
-#if 0 /* When polling is used, interrupt_input is 0,
- so get_input_pending should read the input.
- So this should not be needed. */
- /* If we are using polling for input,
- and we see input available, make it get read now.
- Otherwise it might not actually get read for a second.
- And on hpux, since we turn off polling in wait_reading_process_output,
- it might never get read at all if we don't spend much time
- outside of wait_reading_process_output. */
- if (read_kbd && interrupt_input
- && keyboard_bit_set (&Available)
- && input_polling_used ())
- kill (getpid (), SIGALRM);
-#endif
-
/* Check for keyboard input */
/* If there is any, return immediately
to give it higher priority than subprocesses */
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;
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
break;
-#ifdef SIGIO
+#ifdef USABLE_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,
if (read_kbd && interrupt_input
&& keyboard_bit_set (&Available) && ! noninteractive)
- kill (getpid (), SIGIO);
+ handle_input_available_signal (SIGIO);
#endif
if (! wait_proc)
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
Therefore, if we get an error reading and errno =
EIO, just continue, because the child process has
exited and should clean itself up soon (e.g. when we
- get a SIGCHLD).
-
- However, it has been known to happen that the SIGCHLD
- got lost. So raise the signal again just in case.
- It can't hurt. */
+ get a SIGCHLD). */
else if (nread == -1 && errno == EIO)
{
struct Lisp_Process *p = XPROCESS (proc);
p->tick = ++process_tick;
pset_status (p, Qfailed);
}
- else
- kill (getpid (), SIGCHLD);
}
#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) && !SERIALCONN_P (proc))
;
-#endif
else
{
/* Preserve status of processes already terminated. */
}
/* If no filter, write into buffer if it isn't dead. */
- else if (!NILP (p->buffer) && !NILP (BVAR (XBUFFER (p->buffer), name)))
+ else if (!NILP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer)))
{
Lisp_Object old_read_only;
ptrdiff_t old_begv, old_zv;
\f
/* Sending data to subprocess */
-static jmp_buf send_process_frame;
-static Lisp_Object process_sent_to;
-
-static _Noreturn void
-handle_pipe_signal (int sig)
-{
- sigunblock (sigmask (SIGPIPE));
- _longjmp (send_process_frame, 1);
-}
-
-static void
-deliver_pipe_signal (int sig)
-{
- handle_on_main_thread (sig, handle_pipe_signal);
-}
-
/* In send_process, when a write fails temporarily,
wait_reading_process_output is called. It may execute user code,
e.g. timers, that attempts to write new data to the same process.
This function can evaluate Lisp code and can garbage collect. */
static void
-send_process (volatile Lisp_Object proc, const char *volatile buf,
- volatile ptrdiff_t len, volatile Lisp_Object object)
+send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
+ Lisp_Object object)
{
- /* Use volatile to protect variables from being clobbered by longjmp. */
struct Lisp_Process *p = XPROCESS (proc);
ssize_t rv;
struct coding_system *coding;
- void (*volatile old_sigpipe) (int);
if (p->raw_status_new)
update_status (p);
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))
+ write_queue_push (p, object, buf, len, 0);
- /* 2000-09-21: Emacs 20.7, sparc-sun-solaris-2.6, GCC 2.95.2,
- CFLAGS="-g -O": The value of the parameter `proc' is clobbered
- when returning with longjmp despite being declared volatile. */
- if (!_setjmp (send_process_frame))
+ do /* while !NILP (p->write_queue) */
{
- p = XPROCESS (proc); /* Repair any setjmp clobbering. */
- process_sent_to = proc;
-
- /* 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))
- write_queue_push (p, object, buf, len, 0);
+ ptrdiff_t cur_len = -1;
+ const char *cur_buf;
+ Lisp_Object cur_object;
- do /* while !NILP (p->write_queue) */
+ /* If write_queue is empty, ignore it. */
+ if (!write_queue_pop (p, &cur_object, &cur_buf, &cur_len))
{
- ptrdiff_t cur_len = -1;
- const char *cur_buf;
- Lisp_Object cur_object;
+ cur_len = len;
+ cur_buf = buf;
+ cur_object = object;
+ }
- /* If write_queue is empty, ignore it. */
- if (!write_queue_pop (p, &cur_object, &cur_buf, &cur_len))
+ while (cur_len > 0)
+ {
+ /* Send this batch, using one or more write calls. */
+ ptrdiff_t written = 0;
+ int outfd = p->outfd;
+#ifdef DATAGRAM_SOCKETS
+ if (DATAGRAM_CHAN_P (outfd))
{
- cur_len = len;
- cur_buf = buf;
- cur_object = object;
+ rv = sendto (outfd, cur_buf, cur_len,
+ 0, datagram_address[outfd].sa,
+ datagram_address[outfd].len);
+ if (0 <= rv)
+ written = rv;
+ else if (errno == EMSGSIZE)
+ report_file_error ("sending datagram", Fcons (proc, Qnil));
}
-
- while (cur_len > 0)
- {
- /* Send this batch, using one or more write calls. */
- ptrdiff_t written = 0;
- int outfd = p->outfd;
- old_sigpipe = signal (SIGPIPE, deliver_pipe_signal);
-#ifdef DATAGRAM_SOCKETS
- if (DATAGRAM_CHAN_P (outfd))
- {
- rv = sendto (outfd, cur_buf, cur_len,
- 0, datagram_address[outfd].sa,
- datagram_address[outfd].len);
- if (0 <= rv)
- written = rv;
- else if (errno == EMSGSIZE)
- {
- signal (SIGPIPE, old_sigpipe);
- report_file_error ("sending datagram",
- Fcons (proc, Qnil));
- }
- }
- else
+ else
#endif
- {
+ {
#ifdef HAVE_GNUTLS
- if (p->gnutls_p)
- written = emacs_gnutls_write (p, cur_buf, cur_len);
- else
+ if (p->gnutls_p)
+ written = emacs_gnutls_write (p, cur_buf, cur_len);
+ else
#endif
- written = emacs_write (outfd, cur_buf, cur_len);
- rv = (written ? 0 : -1);
+ written = emacs_write (outfd, cur_buf, cur_len);
+ rv = (written ? 0 : -1);
#ifdef ADAPTIVE_READ_BUFFERING
- if (p->read_output_delay > 0
- && p->adaptive_read_buffering == 1)
- {
- p->read_output_delay = 0;
- process_output_delay_count--;
- p->read_output_skip = 0;
- }
-#endif
+ if (p->read_output_delay > 0
+ && p->adaptive_read_buffering == 1)
+ {
+ p->read_output_delay = 0;
+ process_output_delay_count--;
+ p->read_output_skip = 0;
}
- signal (SIGPIPE, old_sigpipe);
+#endif
+ }
- if (rv < 0)
- {
- if (0
+ if (rv < 0)
+ {
+ if (errno == EAGAIN
#ifdef EWOULDBLOCK
- || errno == EWOULDBLOCK
-#endif
-#ifdef EAGAIN
- || errno == EAGAIN
+ || errno == EWOULDBLOCK
#endif
- )
- /* Buffer is full. Wait, accepting input;
- that may allow the program
- to finish doing output and read more. */
- {
+ )
+ /* Buffer is full. Wait, accepting input;
+ that may allow the program
+ to finish doing output and read more. */
+ {
#ifdef BROKEN_PTY_READ_AFTER_EAGAIN
- /* A gross hack to work around a bug in FreeBSD.
- In the following sequence, read(2) returns
- bogus data:
-
- write(2) 1022 bytes
- write(2) 954 bytes, get EAGAIN
- read(2) 1024 bytes in process_read_output
- read(2) 11 bytes in process_read_output
-
- That is, read(2) returns more bytes than have
- ever been written successfully. The 1033 bytes
- read are the 1022 bytes written successfully
- after processing (for example with CRs added if
- the terminal is set up that way which it is
- here). The same bytes will be seen again in a
- later read(2), without the CRs. */
-
- if (errno == EAGAIN)
- {
- int flags = FWRITE;
- ioctl (p->outfd, TIOCFLUSH, &flags);
- }
+ /* A gross hack to work around a bug in FreeBSD.
+ In the following sequence, read(2) returns
+ bogus data:
+
+ write(2) 1022 bytes
+ write(2) 954 bytes, get EAGAIN
+ read(2) 1024 bytes in process_read_output
+ read(2) 11 bytes in process_read_output
+
+ That is, read(2) returns more bytes than have
+ ever been written successfully. The 1033 bytes
+ read are the 1022 bytes written successfully
+ after processing (for example with CRs added if
+ the terminal is set up that way which it is
+ here). The same bytes will be seen again in a
+ later read(2), without the CRs. */
+
+ if (errno == EAGAIN)
+ {
+ int flags = FWRITE;
+ ioctl (p->outfd, TIOCFLUSH, &flags);
+ }
#endif /* BROKEN_PTY_READ_AFTER_EAGAIN */
- /* Put what we should have written in wait_queue. */
- write_queue_push (p, cur_object, cur_buf, cur_len, 1);
- wait_reading_process_output (0, 20 * 1000 * 1000,
- 0, 0, Qnil, NULL, 0);
- /* Reread queue, to see what is left. */
- break;
- }
- else
- /* This is a real error. */
- report_file_error ("writing to process", Fcons (proc, Qnil));
+ /* Put what we should have written in wait_queue. */
+ write_queue_push (p, cur_object, cur_buf, cur_len, 1);
+ wait_reading_process_output (0, 20 * 1000 * 1000,
+ 0, 0, Qnil, NULL, 0);
+ /* Reread queue, to see what is left. */
+ break;
+ }
+ else if (errno == EPIPE)
+ {
+ p->raw_status_new = 0;
+ pset_status (p, list2 (Qexit, make_number (256)));
+ p->tick = ++process_tick;
+ deactivate_process (proc);
+ error ("process %s no longer connected to pipe; closed it",
+ SDATA (p->name));
}
- cur_buf += written;
- cur_len -= written;
+ else
+ /* This is a real error. */
+ report_file_error ("writing to process", Fcons (proc, Qnil));
}
+ cur_buf += written;
+ cur_len -= written;
}
- while (!NILP (p->write_queue));
- }
- else
- {
- signal (SIGPIPE, old_sigpipe);
- proc = process_sent_to;
- p = XPROCESS (proc);
- p->raw_status_new = 0;
- pset_status (p, Fcons (Qexit, Fcons (make_number (256), Qnil)));
- p->tick = ++process_tick;
- deactivate_process (proc);
- error ("SIGPIPE raised on process %s; closed it", SDATA (p->name));
}
+ while (!NILP (p->write_queue));
}
DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region,
Output from processes can arrive in between bunches. */)
(Lisp_Object process, Lisp_Object start, Lisp_Object end)
{
- Lisp_Object proc;
- ptrdiff_t start1, end1;
+ Lisp_Object proc = get_process (process);
+ ptrdiff_t start_byte, end_byte;
- proc = get_process (process);
validate_region (&start, &end);
+ start_byte = CHAR_TO_BYTE (XINT (start));
+ end_byte = CHAR_TO_BYTE (XINT (end));
+
if (XINT (start) < GPT && XINT (end) > GPT)
- move_gap (XINT (start));
+ move_gap_both (XINT (start), start_byte);
- start1 = CHAR_TO_BYTE (XINT (start));
- end1 = CHAR_TO_BYTE (XINT (end));
- send_process (proc, (char *) BYTE_POS_ADDR (start1), end1 - start1,
- Fcurrent_buffer ());
+ send_process (proc, (char *) BYTE_POS_ADDR (start_byte),
+ end_byte - start_byte, Fcurrent_buffer ());
return Qnil;
}
If we can, we try to signal PROCESS by sending control characters
down the pty. This allows us to signal inferiors who have changed
- their uid, for which killpg would return an EPERM error. */
+ their uid, for which kill would return an EPERM error. */
static void
process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
if (!NILP (current_group))
{
if (ioctl (p->infd, TIOCSIGSEND, signo) == -1)
- EMACS_KILLPG (gid, signo);
+ kill (-gid, signo);
}
else
{
kill (gid, signo);
}
#else /* ! defined (TIOCSIGSEND) */
- EMACS_KILLPG (gid, signo);
+ kill (-gid, signo);
#endif /* ! defined (TIOCSIGSEND) */
}
return process;
}
+/* Return the integer value of the signal whose abbreviation is ABBR,
+ or a negative number if there is no such signal. */
+static int
+abbr_to_signal (char const *name)
+{
+ int i, signo;
+ char sigbuf[20]; /* Large enough for all valid signal abbreviations. */
+
+ if (!strncmp (name, "SIG", 3) || !strncmp (name, "sig", 3))
+ name += 3;
+
+ for (i = 0; i < sizeof sigbuf; i++)
+ {
+ sigbuf[i] = c_toupper (name[i]);
+ if (! sigbuf[i])
+ return str2sig (sigbuf, &signo) == 0 ? signo : -1;
+ }
+
+ return -1;
+}
+
DEFUN ("signal-process", Fsignal_process, Ssignal_process,
2, 2, "sProcess (name or number): \nnSignal code: ",
doc: /* Send PROCESS the signal with code SIGCODE.
(Lisp_Object process, Lisp_Object sigcode)
{
pid_t pid;
+ int signo;
if (STRINGP (process))
{
error ("Cannot signal process %s", SDATA (XPROCESS (process)->name));
}
-#define parse_signal(NAME, VALUE) \
- else if (!xstrcasecmp (name, NAME)) \
- XSETINT (sigcode, VALUE)
-
if (INTEGERP (sigcode))
- CHECK_TYPE_RANGED_INTEGER (int, sigcode);
+ {
+ CHECK_TYPE_RANGED_INTEGER (int, sigcode);
+ signo = XINT (sigcode);
+ }
else
{
char *name;
CHECK_SYMBOL (sigcode);
name = SSDATA (SYMBOL_NAME (sigcode));
- if (!strncmp (name, "SIG", 3) || !strncmp (name, "sig", 3))
- name += 3;
-
- if (0)
- ;
-#ifdef SIGUSR1
- parse_signal ("usr1", SIGUSR1);
-#endif
-#ifdef SIGUSR2
- parse_signal ("usr2", SIGUSR2);
-#endif
-#ifdef SIGTERM
- parse_signal ("term", SIGTERM);
-#endif
-#ifdef SIGHUP
- parse_signal ("hup", SIGHUP);
-#endif
-#ifdef SIGINT
- parse_signal ("int", SIGINT);
-#endif
-#ifdef SIGQUIT
- parse_signal ("quit", SIGQUIT);
-#endif
-#ifdef SIGILL
- parse_signal ("ill", SIGILL);
-#endif
-#ifdef SIGABRT
- parse_signal ("abrt", SIGABRT);
-#endif
-#ifdef SIGEMT
- parse_signal ("emt", SIGEMT);
-#endif
-#ifdef SIGKILL
- parse_signal ("kill", SIGKILL);
-#endif
-#ifdef SIGFPE
- parse_signal ("fpe", SIGFPE);
-#endif
-#ifdef SIGBUS
- parse_signal ("bus", SIGBUS);
-#endif
-#ifdef SIGSEGV
- parse_signal ("segv", SIGSEGV);
-#endif
-#ifdef SIGSYS
- parse_signal ("sys", SIGSYS);
-#endif
-#ifdef SIGPIPE
- parse_signal ("pipe", SIGPIPE);
-#endif
-#ifdef SIGALRM
- parse_signal ("alrm", SIGALRM);
-#endif
-#ifdef SIGURG
- parse_signal ("urg", SIGURG);
-#endif
-#ifdef SIGSTOP
- parse_signal ("stop", SIGSTOP);
-#endif
-#ifdef SIGTSTP
- parse_signal ("tstp", SIGTSTP);
-#endif
-#ifdef SIGCONT
- parse_signal ("cont", SIGCONT);
-#endif
-#ifdef SIGCHLD
- parse_signal ("chld", SIGCHLD);
-#endif
-#ifdef SIGTTIN
- parse_signal ("ttin", SIGTTIN);
-#endif
-#ifdef SIGTTOU
- parse_signal ("ttou", SIGTTOU);
-#endif
-#ifdef SIGIO
- parse_signal ("io", SIGIO);
-#endif
-#ifdef SIGXCPU
- parse_signal ("xcpu", SIGXCPU);
-#endif
-#ifdef SIGXFSZ
- parse_signal ("xfsz", SIGXFSZ);
-#endif
-#ifdef SIGVTALRM
- parse_signal ("vtalrm", SIGVTALRM);
-#endif
-#ifdef SIGPROF
- parse_signal ("prof", SIGPROF);
-#endif
-#ifdef SIGWINCH
- parse_signal ("winch", SIGWINCH);
-#endif
-#ifdef SIGINFO
- parse_signal ("info", SIGINFO);
-#endif
- else
+ signo = abbr_to_signal (name);
+ if (signo < 0)
error ("Undefined signal name %s", name);
}
-#undef parse_signal
-
- return make_number (kill (pid, XINT (sigcode)));
+ return make_number (kill (pid, signo));
}
DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
if (!proc_encode_coding_system[new_outfd])
proc_encode_coding_system[new_outfd]
= xmalloc (sizeof (struct coding_system));
- memcpy (proc_encode_coding_system[new_outfd],
- proc_encode_coding_system[old_outfd],
- sizeof (struct coding_system));
+ *proc_encode_coding_system[new_outfd]
+ = *proc_encode_coding_system[old_outfd];
memset (proc_encode_coding_system[old_outfd], 0,
sizeof (struct coding_system));
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.
+/* The main Emacs thread records child processes in three places:
+
+ - Vprocess_alist, for asynchronous subprocesses, which are child
+ processes visible to Lisp.
+
+ - deleted_pid_list, for child processes invisible to Lisp,
+ typically because of delete-process. These are recorded so that
+ the processes can be reaped when they exit, so that the operating
+ system's process table is not cluttered by zombies.
+
+ - the local variable PID in Fcall_process, call_process_cleanup and
+ call_process_kill, for synchronous subprocesses.
+ record_unwind_protect is used to make sure this process is not
+ forgotten: if the user interrupts call-process and the child
+ process refuses to exit immediately even with two C-g's,
+ call_process_kill adds PID's contents to deleted_pid_list before
+ returning.
+
+ The main Emacs thread invokes waitpid only on child processes that
+ it creates and that have not been reaped. This avoid races on
+ platforms such as GTK, where other threads create their own
+ subprocesses which the main thread should not reap. For example,
+ if the main thread attempted to reap an already-reaped child, it
+ might inadvertently reap a GTK-created process that happened to
+ have the same process ID. */
+
+/* Handle a SIGCHLD signal by looking 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 */
-#ifdef SIGCHLD
-
-/* Record one child's changed status. Return true if a child was found. */
-static bool
-record_child_status_change (void)
+static void
+handle_child_signal (int sig)
{
- Lisp_Object proc;
- struct Lisp_Process *p;
- pid_t pid;
- int w;
Lisp_Object tail;
- do
- pid = waitpid (-1, &w, 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)
- return false;
-
/* Find the process that signaled us, and record its status. */
- /* The process can have been deleted by Fdelete_process. */
+ /* The process can have been deleted by Fdelete_process, or have
+ been started asynchronously by Fcall_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 true;
+ pid_t deleted_pid;
+ if (INTEGERP (xpid))
+ deleted_pid = XINT (xpid);
+ else
+ deleted_pid = XFLOAT_DATA (xpid);
+ if (child_status_changed (deleted_pid, 0, 0))
+ XSETCAR (tail, Qnil);
}
}
/* 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;
- }
-
- /* Change the status of the process that was found. */
- if (p)
- {
- int clear_desc_flag = 0;
+ Lisp_Object proc = XCDR (XCAR (tail));
+ struct Lisp_Process *p = XPROCESS (proc);
+ int status;
- p->tick = ++process_tick;
- p->raw_status = w;
- p->raw_status_new = 1;
+ if (p->alive && child_status_changed (p->pid, &status, WUNTRACED))
+ {
+ /* Change the status of the process that was found. */
+ p->tick = ++process_tick;
+ p->raw_status = status;
+ p->raw_status_new = 1;
- /* If process has terminated, stop waiting for its output. */
- if ((WIFSIGNALED (w) || WIFEXITED (w))
- && p->infd >= 0)
- clear_desc_flag = 1;
+ /* If process has terminated, stop waiting for its output. */
+ if (WIFSIGNALED (status) || WIFEXITED (status))
+ {
+ int clear_desc_flag = 0;
+ p->alive = 0;
+ if (p->infd >= 0)
+ clear_desc_flag = 1;
- /* 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);
+ /* 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);
+ }
+ }
}
-
- /* 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
- {
- synch_process_alive = 0;
-
- /* Report the status of the synchronous process. */
- if (WIFEXITED (w))
- synch_process_retcode = WEXITSTATUS (w);
- else if (WIFSIGNALED (w))
- synch_process_termsig = WTERMSIG (w);
-
- /* 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);
- }
-
- return true;
-}
-
-/* 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)
-{
- while (record_child_status_change () && CAN_HANDLE_MULTIPLE_CHILDREN)
- continue;
}
static void
deliver_child_signal (int sig)
{
- handle_on_main_thread (sig, handle_child_signal);
+ deliver_process_signal (sig, handle_child_signal);
}
-
-#endif /* SIGCHLD */
\f
static Lisp_Object
/* Avoid error if buffer is deleted
(probably that's why the process is dead, too) */
- if (NILP (BVAR (XBUFFER (buffer), name)))
+ if (!BUFFER_LIVE_P (XBUFFER (buffer)))
continue;
Fset_buffer (buffer);
# endif
-# ifdef SIGIO
+# ifdef USABLE_SIGIO
/* Return nonzero if *MASK has a bit set
that corresponds to one of the keyboard input descriptors. */
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
inhibit_sentinels = 0;
-#ifdef SIGCHLD
#ifndef CANNOT_DUMP
if (! noninteractive || initialized)
#endif
- signal (SIGCHLD, deliver_child_signal);
-#endif
+ {
+ struct sigaction action;
+ emacs_sigaction_init (&action, deliver_child_signal);
+ sigaction (SIGCHLD, &action, 0);
+ }
FD_ZERO (&input_wait_mask);
FD_ZERO (&non_keyboard_wait_mask);
#endif
Vprocess_alist = Qnil;
-#ifdef SIGCHLD
deleted_pid_list = Qnil;
-#endif
for (i = 0; i < MAXDESC; i++)
{
chan_process[i] = Qnil;
#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);
DEFSYM (Qlast_nonmenu_event, "last-nonmenu-event");
staticpro (&Vprocess_alist);
-#ifdef SIGCHLD
staticpro (&deleted_pid_list);
-#endif
#endif /* subprocesses */