#include "xgselect.h"
#endif
+#ifdef WINDOWSNT
+extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
+ EMACS_TIME *, void *);
+#endif
+
#ifndef WNOHANG
# undef waitpid
# define waitpid(pid, status, options) wait (status)
#ifndef NON_BLOCKING_CONNECT
#ifdef HAVE_SELECT
#if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
-#if defined (O_NONBLOCK) || defined (O_NDELAY)
+#if O_NONBLOCK || O_NDELAY
#if defined (EWOULDBLOCK) || defined (EINPROGRESS)
#define NON_BLOCKING_CONNECT
#endif /* EWOULDBLOCK || EINPROGRESS */
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
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)
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
+# if O_NONBLOCK
fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
# else
fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 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
#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
int wait_child_setup[2];
#endif
- sigset_t blocked, procmask;
- struct sigaction sigint_action;
- struct sigaction sigquit_action;
- struct sigaction sigpipe_action;
-#ifdef AIX
- struct sigaction sighup_action;
+#ifdef SIGCHLD
+ sigset_t blocked;
#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;
+#if HAVE_WORKING_VFORK
+ char **volatile save_environ;
+#endif
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
+#if 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);
forkin = forkout = -1;
#endif /* not USG, or USG_SUBTTY_WORKS */
pty_flag = 1;
+ lisp_pty_name = build_string (pty_name);
}
else
#endif /* HAVE_PTYS */
}
#endif
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (inchannel, F_SETFL, O_NDELAY);
fcntl (outchannel, F_SETFL, O_NDELAY);
#endif
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)
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 ();
+
+#ifdef SIGCHLD
+ /* 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);
+#endif
+
+#if HAVE_WORKING_VFORK
+ /* child_setup must clobber environ on systems with true vfork.
+ Protect it from permanent change. */
+ save_environ = environ;
+#endif
#ifndef WINDOWSNT
- pid = vfork ();
- if (pid == 0)
+ pid = vfork ();
+ if (pid == 0)
#endif /* not WINDOWSNT */
- {
- int xforkin = forkin;
- int xforkout = forkout;
+ {
+ 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. */
+ /* 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)
- {
+ /* 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 ();
+ /* 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);
- }
+ /* 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. */
+ /* 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);
+ setpgid (0, 0);
#else
- setpgrp (0, 0);
+ setpgrp (0, 0);
#endif
#endif
- }
+ }
#endif /* TIOCNOTTY */
#if !defined (DONT_REOPEN_PTY)
both HAVE_SETSID and TIOCSCTTY are 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);
+#ifdef SIGCHLD
/* Stop blocking signals in the child. */
- pthread_sigmask (SIG_SETMASK, &procmask, 0);
+ pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+#endif
- 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]);
+ emacs_close (wait_child_setup[0]);
#endif
- child_setup (xforkin, xforkout, xforkout,
- new_argv, 1, encoded_current_dir);
+ child_setup (xforkin, xforkout, xforkout,
+ new_argv, 1, encoded_current_dir);
#endif /* not WINDOWSNT */
- }
- environ = save_environ;
- }
+ }
+
+ /* Back in the parent process. */
- UNBLOCK_INPUT;
+#if HAVE_WORKING_VFORK
+ environ = save_environ;
+#endif
+
+ XPROCESS (process)->pid = pid;
+
+ /* Stop blocking signals in the parent. */
+#ifdef SIGCHLD
+ pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+#endif
+ 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)
/* Wait for child_setup to complete in case that vfork is
#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
+#if 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);
}
#endif /* HAVE_PTYS */
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (inchannel, F_SETFL, O_NDELAY);
fcntl (outchannel, F_SETFL, O_NDELAY);
#endif
{
/* 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)
+#if !O_NONBLOCK && !O_NDELAY
error ("Network servers not supported");
#else
is_server = 1;
#ifdef NON_BLOCKING_CONNECT
if (is_non_blocking_client)
{
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
ret = fcntl (s, F_SETFL, O_NONBLOCK);
#else
ret = fcntl (s, F_SETFL, O_NDELAY);
#ifdef HAVE_GETADDRINFO
if (res != &ai)
{
- BLOCK_INPUT;
+ block_input ();
freeaddrinfo (res);
- UNBLOCK_INPUT;
+ unblock_input ();
}
#endif
chan_process[inch] = proc;
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (inch, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (inch, F_SETFL, O_NDELAY);
#endif
#endif
chan_process[s] = proc;
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
fcntl (s, F_SETFL, O_NONBLOCK);
#else
-#ifdef O_NDELAY
+#if O_NDELAY
fcntl (s, F_SETFL, O_NDELAY);
#endif
#endif
-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;
process_output_skip = 0;
}
#endif
+
#if defined (USE_GTK) || defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
nfds = xg_select
#elif defined (HAVE_NS)
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 (read_kbd && interrupt_input
&& keyboard_bit_set (&Available) && ! noninteractive)
- kill (getpid (), SIGIO);
+ handle_input_available_signal (SIGIO);
#endif
if (! wait_proc)
#endif
/* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK,
and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */
-#ifdef O_NONBLOCK
+#if O_NONBLOCK
else if (nread == -1 && errno == EAGAIN)
;
#else
-#ifdef O_NDELAY
+#if O_NDELAY
else if (nread == -1 && errno == EAGAIN)
;
/* Note that we cannot distinguish between no input
pset_status (p, Qfailed);
}
else
- kill (getpid (), SIGCHLD);
+ handle_child_signal (SIGCHLD);
}
#endif /* HAVE_PTYS */
/* If we can detect process termination, don't consider the
\f
/* Sending data to subprocess */
-static sys_jmp_buf send_process_frame;
-static Lisp_Object process_sent_to;
-
-static _Noreturn void
-handle_pipe_signal (int sig)
-{
- sigset_t unblocked;
- sigemptyset (&unblocked);
- sigaddset (&unblocked, SIGPIPE);
- pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
- sys_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;
- struct sigaction old_sigpipe_action;
if (p->raw_status_new)
update_status (p);
pty_max_bytes--;
}
- /* 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 (!sys_setjmp (send_process_frame))
- {
- 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);
- /* 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);
+ do /* while !NILP (p->write_queue) */
+ {
+ 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;
- struct sigaction action;
- emacs_sigaction_init (&action, deliver_pipe_signal);
- sigaction (SIGPIPE, &action, &old_sigpipe_action);
-#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)
- {
- sigaction (SIGPIPE, &old_sigpipe_action, 0);
- 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;
}
- sigaction (SIGPIPE, &old_sigpipe_action, 0);
+#endif
+ }
- if (rv < 0)
- {
- if (0
+ if (rv < 0)
+ {
+ if (0
#ifdef EWOULDBLOCK
- || errno == EWOULDBLOCK
+ || errno == EWOULDBLOCK
#endif
#ifdef EAGAIN
- || errno == EAGAIN
+ || errno == EAGAIN
#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
- {
- sigaction (SIGPIPE, &old_sigpipe_action, 0);
- 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,
#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
** 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)
+/* 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;
- 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. */
|| (FLOATP (xpid) && pid == XFLOAT_DATA (xpid)))
{
XSETCAR (tail, Qnil);
- return true;
+ return;
}
}
if (input_available_clear_time)
*input_available_clear_time = make_emacs_time (0, 0);
}
-
- return true;
+#endif
}
+#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
static void
handle_child_signal (int sig)
{
- while (record_child_status_change () && CAN_HANDLE_MULTIPLE_CHILDREN)
- continue;
+ 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);
}
static void
deliver_child_signal (int sig)
{
- handle_on_main_thread (sig, handle_child_signal);
+ deliver_process_signal (sig, handle_child_signal);
}
#endif /* SIGCHLD */
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)
+#if O_NONBLOCK || O_NDELAY
ADD_SUBFEATURE (QCserver, Qt);
#endif