#endif
#ifdef HAVE_RES_INIT
-#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#endif
#include <c-ctype.h>
#include <sig2str.h>
+#include <verify.h>
#endif /* subprocesses */
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
-#if defined (USE_GTK) || defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
+#ifdef HAVE_GLIB
#include "xgselect.h"
+#ifndef WINDOWSNT
+#include <glib.h>
+#endif
#endif
#ifdef WINDOWSNT
EMACS_TIME *, void *);
#endif
+#ifndef SOCK_CLOEXEC
+# define SOCK_CLOEXEC 0
+#endif
+
+#ifndef HAVE_ACCEPT4
+
+/* Emulate GNU/Linux accept4 and socket well enough for this module. */
+
+static int
+close_on_exec (int fd)
+{
+ if (0 <= fd)
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+ return fd;
+}
+
+static int
+accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+ return close_on_exec (accept (sockfd, addr, addrlen));
+}
+
+static int
+process_socket (int domain, int type, int protocol)
+{
+ return close_on_exec (socket (domain, type, protocol));
+}
+# undef socket
+# define socket(domain, type, protocol) process_socket (domain, type, protocol)
+#endif
+
/* Work around GCC 4.7.0 bug with strict overflow checking; see
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>.
These lines can be removed once the GCC bug is fixed. */
static Lisp_Object QCserver, QCnowait, QCnoquery, QCstop;
static Lisp_Object QCsentinel, QClog, QCoptions, QCplist;
static Lisp_Object Qlast_nonmenu_event;
+static Lisp_Object Qinternal_default_process_sentinel;
+static Lisp_Object Qinternal_default_process_filter;
#define NETCONN_P(p) (EQ (XPROCESS (p)->type, Qnetwork))
#define NETCONN1_P(p) (EQ (p->type, Qnetwork))
static int num_pending_connects;
#endif /* NON_BLOCKING_CONNECT */
-/* The largest descriptor currently in use for a process object. */
+/* The largest descriptor currently in use for a process object; -1 if none. */
static int max_process_desc;
-/* The largest descriptor currently in use for input. */
+/* The largest descriptor currently in use for input; -1 if none. */
static int max_input_desc;
/* Indexed by descriptor, gives the process (if any) for that descriptor */
#define DATAGRAM_CONN_P(proc) (0)
#endif
+/* FOR_EACH_PROCESS (LIST_VAR, PROC_VAR) followed by a statement is
+ a `for' loop which iterates over processes from Vprocess_alist. */
+
+#define FOR_EACH_PROCESS(list_var, proc_var) \
+ FOR_EACH_ALIST_VALUE (Vprocess_alist, list_var, proc_var)
+
/* These setters are used only in this file, so they can be private. */
static void
pset_buffer (struct Lisp_Process *p, Lisp_Object val)
static void
pset_filter (struct Lisp_Process *p, Lisp_Object val)
{
- p->filter = val;
+ p->filter = NILP (val) ? Qinternal_default_process_filter : val;
}
static void
pset_log (struct Lisp_Process *p, Lisp_Object val)
static void
pset_sentinel (struct Lisp_Process *p, Lisp_Object val)
{
- p->sentinel = val;
+ p->sentinel = NILP (val) ? Qinternal_default_process_sentinel : val;
}
static void
pset_status (struct Lisp_Process *p, Lisp_Object val)
fd_callback_info[fd].condition |= FOR_WRITE;
}
+/* FD is no longer an input descriptor; update max_input_desc accordingly. */
+
+static void
+delete_input_desc (int fd)
+{
+ if (fd == max_input_desc)
+ {
+ do
+ fd--;
+ while (0 <= fd && ! (FD_ISSET (fd, &input_wait_mask)
+ || FD_ISSET (fd, &write_mask)));
+
+ max_input_desc = fd;
+ }
+}
+
/* Stop monitoring file descriptor FD for when write is possible. */
void
delete_write_fd (int fd)
{
- int lim = max_input_desc;
-
eassert (fd < MAXDESC);
FD_CLR (fd, &write_mask);
fd_callback_info[fd].condition &= ~FOR_WRITE;
{
fd_callback_info[fd].func = 0;
fd_callback_info[fd].data = 0;
-
- if (fd == max_input_desc)
- for (fd = lim; fd >= 0; fd--)
- if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
- {
- max_input_desc = fd;
- break;
- }
-
+ delete_input_desc (fd);
}
}
return Fcopy_sequence (Fsymbol_name (symbol));
}
\f
-#ifdef HAVE_PTYS
-
-/* The file name of the pty opened by allocate_pty. */
-static char pty_name[24];
+enum { PTY_NAME_SIZE = 24 };
/* Open an available pty, returning a file descriptor.
- Return -1 on failure.
- The file name of the terminal corresponding to the pty
- is left in the variable pty_name. */
+ Store into PTY_NAME the file name of the terminal corresponding to the pty.
+ Return -1 on failure. */
static int
-allocate_pty (void)
+allocate_pty (char pty_name[PTY_NAME_SIZE])
{
+#ifdef HAVE_PTYS
int fd;
#ifdef PTY_ITERATION
if (fd >= 0)
{
+#ifdef PTY_OPEN
+ /* Set FD's close-on-exec flag. This is needed even if
+ PT_OPEN calls posix_openpt with O_CLOEXEC, since POSIX
+ doesn't require support for that combination.
+ Multithreaded platforms where posix_openpt ignores
+ O_CLOEXEC (or where PTY_OPEN doesn't call posix_openpt)
+ have a race condition between the PTY_OPEN and here. */
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+#endif
/* check to make certain that both sides are available
this avoids a nasty yet stupid bug in rlogins */
#ifdef PTY_TTY_NAME_SPRINTF
return fd;
}
}
+#endif /* HAVE_PTYS */
return -1;
}
-#endif /* HAVE_PTYS */
\f
static Lisp_Object
make_process (Lisp_Object name)
non-Lisp data, so do it only for slots which should not be zero. */
p->infd = -1;
p->outfd = -1;
+ for (i = 0; i < PROCESS_OPEN_FDS; i++)
+ p->open_fd[i] = -1;
#ifdef HAVE_GNUTLS
p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
}
name = name1;
pset_name (p, name);
+ pset_sentinel (p, Qinternal_default_process_sentinel);
+ pset_filter (p, Qinternal_default_process_filter);
XSETPROCESS (val, p);
Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
return val;
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. */
+ Some processes created by call-process are also put onto this list.
+
+ Members of this list are (process-ID . filename) pairs. The
+ process-ID is a number; the filename, if a string, is a file that
+ needs to be removed after the process exits. */
static Lisp_Object deleted_pid_list;
void
-record_deleted_pid (pid_t pid)
+record_deleted_pid (pid_t pid, Lisp_Object filename)
{
- deleted_pid_list = Fcons (make_fixnum_or_float (pid),
+ deleted_pid_list = Fcons (Fcons (make_fixnum_or_float (pid), filename),
/* GC treated elements set to nil. */
Fdelq (Qnil, deleted_pid_list));
p->raw_status_new = 0;
if (NETCONN1_P (p) || SERIALCONN1_P (p))
{
- pset_status (p, Fcons (Qexit, Fcons (make_number (0), Qnil)));
+ pset_status (p, list2 (Qexit, make_number (0)));
p->tick = ++process_tick;
status_notify (p);
redisplay_preserve_echo_area (13);
else
{
if (p->alive)
- record_kill_process (p);
+ record_kill_process (p, Qnil);
if (p->infd >= 0)
{
DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter,
2, 2, 0,
- doc: /* Give PROCESS the filter function FILTER; nil means no filter.
+ doc: /* Give PROCESS the filter function FILTER; nil means default.
A value of t means stop accepting output from the process.
-When a process has a filter, its buffer is not used for output.
+When a process has a non-default filter, its buffer is not used for output.
Instead, each time it does output, the entire string of output is
passed to the filter.
(debug)
(set-process-filter process ...) */
+ if (NILP (filter))
+ filter = Qinternal_default_process_filter;
+
if (p->infd >= 0)
{
if (EQ (filter, Qt) && !EQ (p->status, Qlisten))
DEFUN ("process-filter", Fprocess_filter, Sprocess_filter,
1, 1, 0,
- doc: /* Returns the filter function of PROCESS; nil if none.
+ doc: /* Return the filter function of PROCESS.
See `set-process-filter' for more info on filter functions. */)
(register Lisp_Object process)
{
DEFUN ("set-process-sentinel", Fset_process_sentinel, Sset_process_sentinel,
2, 2, 0,
- doc: /* Give PROCESS the sentinel SENTINEL; nil for none.
+ doc: /* Give PROCESS the sentinel SENTINEL; nil for default.
The sentinel is called as a function when the process changes state.
It gets two arguments: the process, and a string describing the change. */)
(register Lisp_Object process, Lisp_Object sentinel)
CHECK_PROCESS (process);
p = XPROCESS (process);
+ if (NILP (sentinel))
+ sentinel = Qinternal_default_process_sentinel;
+
pset_sentinel (p, sentinel);
if (NETCONN1_P (p) || SERIALCONN1_P (p))
pset_childp (p, Fplist_put (p->childp, QCsentinel, sentinel));
DEFUN ("process-sentinel", Fprocess_sentinel, Sprocess_sentinel,
1, 1, 0,
- doc: /* Return the sentinel of PROCESS; nil if none.
+ doc: /* Return the sentinel of PROCESS.
See `set-process-sentinel' for more info on sentinels. */)
(register Lisp_Object process)
{
DEFUN ("set-process-window-size", Fset_process_window_size,
Sset_process_window_size, 3, 3, 0,
doc: /* Tell PROCESS that it has logical window size HEIGHT and WIDTH. */)
- (register Lisp_Object process, Lisp_Object height, Lisp_Object width)
+ (Lisp_Object process, Lisp_Object height, Lisp_Object width)
{
CHECK_PROCESS (process);
- CHECK_RANGED_INTEGER (height, 0, INT_MAX);
- CHECK_RANGED_INTEGER (width, 0, INT_MAX);
+
+ /* All known platforms store window sizes as 'unsigned short'. */
+ CHECK_RANGED_INTEGER (height, 0, USHRT_MAX);
+ CHECK_RANGED_INTEGER (width, 0, USHRT_MAX);
if (XPROCESS (process)->infd < 0
- || set_window_size (XPROCESS (process)->infd,
- XINT (height), XINT (width)) <= 0)
+ || (set_window_size (XPROCESS (process)->infd,
+ XINT (height), XINT (width))
+ < 0))
return Qnil;
else
return Qt;
if ((!NETCONN_P (process) && !SERIALCONN_P (process)) || EQ (key, Qt))
return contact;
if (NILP (key) && NETCONN_P (process))
- return Fcons (Fplist_get (contact, QChost),
- Fcons (Fplist_get (contact, QCservice), Qnil));
+ return list2 (Fplist_get (contact, QChost),
+ Fplist_get (contact, QCservice));
if (NILP (key) && SERIALCONN_P (process))
- return Fcons (Fplist_get (contact, QCport),
- Fcons (Fplist_get (contact, QCspeed), Qnil));
+ return list2 (Fplist_get (contact, QCport),
+ Fplist_get (contact, QCspeed));
return Fplist_get (contact, key);
}
}
DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
- doc: /* Return a list of all processes. */)
+ doc: /* Return a list of all processes that are Emacs sub-processes. */)
(void)
{
return Fmapcar (Qcdr, Vprocess_alist);
\f
/* Starting asynchronous inferior processes. */
-static Lisp_Object start_process_unwind (Lisp_Object proc);
+static void start_process_unwind (Lisp_Object proc);
DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
doc: /* Start a program in a subprocess. Return the process object for it.
function. The argument list is protected by the caller, so all
we really have to worry about is buffer. */
{
- struct gcpro gcpro1, gcpro2;
-
- current_dir = BVAR (current_buffer, directory);
-
- GCPRO2 (buffer, current_dir);
-
- current_dir = Funhandled_file_name_directory (current_dir);
- if (NILP (current_dir))
- /* If the file name handler says that current_dir is unreachable, use
- a sensible default. */
- current_dir = build_string ("~/");
- current_dir = expand_and_dir_to_file (current_dir, Qnil);
- if (NILP (Ffile_accessible_directory_p (current_dir)))
- report_file_error ("Setting current directory",
- Fcons (BVAR (current_buffer, directory), Qnil));
-
+ struct gcpro gcpro1;
+ GCPRO1 (buffer);
+ current_dir = encode_current_directory ();
UNGCPRO;
}
pset_plist (XPROCESS (proc), Qnil);
pset_type (XPROCESS (proc), Qreal);
pset_buffer (XPROCESS (proc), buffer);
- pset_sentinel (XPROCESS (proc), Qnil);
- pset_filter (XPROCESS (proc), Qnil);
+ pset_sentinel (XPROCESS (proc), Qinternal_default_process_sentinel);
+ pset_filter (XPROCESS (proc), Qinternal_default_process_filter);
pset_command (XPROCESS (proc), Flist (nargs - 2, args + 2));
#ifdef HAVE_GNUTLS
openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK));
UNGCPRO;
if (NILP (tem))
- report_file_error ("Searching for program", Fcons (program, Qnil));
+ report_file_error ("Searching for program", program);
tem = Fexpand_file_name (tem, Qnil);
}
else
/* Encode the file name and put it in NEW_ARGV.
That's where the child will use it to execute the program. */
- tem = Fcons (ENCODE_FILE (tem), Qnil);
+ tem = list1 (ENCODE_FILE (tem));
/* Here we encode arguments by the coding system used for sending
data to the process. We don't support using different coding
PROC doesn't have its pid set, then we know someone has signaled
an error and the process wasn't started successfully, so we should
remove it from the process list. */
-static Lisp_Object
+static void
start_process_unwind (Lisp_Object proc)
{
if (!PROCESSP (proc))
-2 is used for a pty with no process, eg for gdb. */
if (XPROCESS (proc)->pid <= 0 && XPROCESS (proc)->pid != -2)
remove_process (proc);
-
- return Qnil;
}
+/* If *FD_ADDR is nonnegative, close it, and mark it as closed. */
+
static void
-create_process_1 (struct atimer *timer)
+close_process_fd (int *fd_addr)
{
- /* Nothing to do. */
+ int fd = *fd_addr;
+ if (0 <= fd)
+ {
+ *fd_addr = -1;
+ emacs_close (fd);
+ }
}
+/* Indexes of file descriptors in open_fds. */
+enum
+ {
+ /* The pipe from Emacs to its subprocess. */
+ SUBPROCESS_STDIN,
+ WRITE_TO_SUBPROCESS,
+
+ /* The main pipe from the subprocess to Emacs. */
+ READ_FROM_SUBPROCESS,
+ SUBPROCESS_STDOUT,
+
+ /* The pipe from the subprocess to Emacs that is closed when the
+ subprocess execs. */
+ READ_FROM_EXEC_MONITOR,
+ EXEC_MONITOR_OUTPUT
+ };
+
+verify (PROCESS_OPEN_FDS == EXEC_MONITOR_OUTPUT + 1);
static void
create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
{
+ struct Lisp_Process *p = XPROCESS (process);
int inchannel, outchannel;
pid_t pid;
- int sv[2];
-#ifndef WINDOWSNT
- int wait_child_setup[2];
-#endif
- sigset_t blocked;
- /* Use volatile to protect variables from being clobbered by vfork. */
- volatile int forkin, forkout;
- volatile bool pty_flag = 0;
- volatile Lisp_Object lisp_pty_name = Qnil;
- volatile Lisp_Object encoded_current_dir;
+ int vfork_errno;
+ int forkin, forkout;
+ bool pty_flag = 0;
+ char pty_name[PTY_NAME_SIZE];
+ Lisp_Object lisp_pty_name = Qnil;
inchannel = outchannel = -1;
-#ifdef HAVE_PTYS
if (!NILP (Vprocess_connection_type))
- outchannel = inchannel = allocate_pty ();
+ outchannel = inchannel = allocate_pty (pty_name);
if (inchannel >= 0)
{
+ p->open_fd[READ_FROM_SUBPROCESS] = inchannel;
#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. */
forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
if (forkin < 0)
report_file_error ("Opening pty", Qnil);
+ p->open_fd[SUBPROCESS_STDIN] = forkin;
#else
forkin = forkout = -1;
#endif /* not USG, or USG_SUBTTY_WORKS */
lisp_pty_name = build_string (pty_name);
}
else
-#endif /* HAVE_PTYS */
{
- int tem;
- tem = pipe (sv);
- if (tem < 0)
+ if (emacs_pipe (p->open_fd + SUBPROCESS_STDIN) != 0
+ || emacs_pipe (p->open_fd + READ_FROM_SUBPROCESS) != 0)
report_file_error ("Creating pipe", Qnil);
- inchannel = sv[0];
- forkout = sv[1];
- tem = pipe (sv);
- if (tem < 0)
- {
- emacs_close (inchannel);
- emacs_close (forkout);
- report_file_error ("Creating pipe", Qnil);
- }
- outchannel = sv[1];
- forkin = sv[0];
+ forkin = p->open_fd[SUBPROCESS_STDIN];
+ outchannel = p->open_fd[WRITE_TO_SUBPROCESS];
+ inchannel = p->open_fd[READ_FROM_SUBPROCESS];
+ forkout = p->open_fd[SUBPROCESS_STDOUT];
}
#ifndef WINDOWSNT
- {
- int tem;
-
- tem = pipe (wait_child_setup);
- if (tem < 0)
- report_file_error ("Creating pipe", Qnil);
- tem = fcntl (wait_child_setup[1], F_GETFD, 0);
- if (tem >= 0)
- tem = fcntl (wait_child_setup[1], F_SETFD, tem | FD_CLOEXEC);
- if (tem < 0)
- {
- emacs_close (wait_child_setup[0]);
- emacs_close (wait_child_setup[1]);
- report_file_error ("Setting file descriptor flags", Qnil);
- }
- }
+ if (emacs_pipe (p->open_fd + READ_FROM_EXEC_MONITOR) != 0)
+ report_file_error ("Creating pipe", Qnil);
#endif
fcntl (inchannel, F_SETFL, O_NONBLOCK);
fcntl (outchannel, F_SETFL, O_NONBLOCK);
- /* Record this as an active process, with its channels.
- As a result, child_setup will close Emacs's side of the pipes. */
+ /* Record this as an active process, with its channels. */
chan_process[inchannel] = process;
- XPROCESS (process)->infd = inchannel;
- XPROCESS (process)->outfd = outchannel;
+ p->infd = inchannel;
+ p->outfd = outchannel;
/* Previously we recorded the tty descriptor used in the subprocess.
It was only used for getting the foreground tty process, so now
we just reopen the device (see emacs_get_tty_pgrp) as this is
more portable (see USG_SUBTTY_WORKS above). */
- XPROCESS (process)->pty_flag = pty_flag;
- pset_status (XPROCESS (process), Qrun);
+ p->pty_flag = pty_flag;
+ pset_status (p, Qrun);
FD_SET (inchannel, &input_wait_mask);
FD_SET (inchannel, &non_keyboard_wait_mask);
/* This may signal an error. */
setup_process_coding_systems (process);
- 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);
+ block_child_signal ();
#ifndef WINDOWSNT
- pid = vfork ();
+ /* vfork, and prevent local vars from being clobbered by the vfork. */
+ {
+ Lisp_Object volatile current_dir_volatile = current_dir;
+ Lisp_Object volatile lisp_pty_name_volatile = lisp_pty_name;
+ char **volatile new_argv_volatile = new_argv;
+ int volatile forkin_volatile = forkin;
+ int volatile forkout_volatile = forkout;
+ struct Lisp_Process *p_volatile = p;
+
+ pid = vfork ();
+
+ current_dir = current_dir_volatile;
+ lisp_pty_name = lisp_pty_name_volatile;
+ new_argv = new_argv_volatile;
+ forkin = forkin_volatile;
+ forkout = forkout_volatile;
+ p = p_volatile;
+
+ pty_flag = p->pty_flag;
+ }
+
if (pid == 0)
#endif /* not WINDOWSNT */
{
tcgetattr (xforkin, &t);
t.c_lflag = LDISC1;
if (tcsetattr (xforkin, TCSANOW, &t) < 0)
- emacs_write (1, "create_process/tcsetattr LDISC1 failed\n", 39);
+ emacs_perror ("create_process/tcsetattr LDISC1");
}
#else
#if defined (NTTYDISC) && defined (TIOCSETD)
if (pty_flag)
{
- /* I wonder if emacs_close (emacs_open (pty_name, ...))
+ /* I wonder if emacs_close (emacs_open (SSDATA (lisp_pty_name), ...))
would work? */
if (xforkin >= 0)
emacs_close (xforkin);
- xforkout = xforkin = emacs_open (pty_name, O_RDWR, 0);
+ xforkout = xforkin = emacs_open (SSDATA (lisp_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);
+ emacs_perror (SSDATA (lisp_pty_name));
+ _exit (EXIT_CANCELED);
}
}
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);
-#endif
#endif /* HAVE_PTYS */
signal (SIGINT, SIG_DFL);
/* Emacs ignores SIGPIPE, but the child should not. */
signal (SIGPIPE, SIG_DFL);
- /* Stop blocking signals in the child. */
- pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+ /* Stop blocking SIGCHLD in the child. */
+ unblock_child_signal ();
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, current_dir);
#else /* not WINDOWSNT */
- emacs_close (wait_child_setup[0]);
- child_setup (xforkin, xforkout, xforkout,
- new_argv, 1, encoded_current_dir);
+ child_setup (xforkin, xforkout, xforkout, new_argv, 1, current_dir);
#endif /* not WINDOWSNT */
}
/* Back in the parent process. */
- XPROCESS (process)->pid = pid;
+ vfork_errno = errno;
+ p->pid = pid;
if (pid >= 0)
- XPROCESS (process)->alive = 1;
+ p->alive = 1;
- /* Stop blocking signals in the parent. */
- pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+ /* Stop blocking in the parent. */
+ unblock_child_signal ();
unblock_input ();
if (pid < 0)
- {
- if (forkin >= 0)
- emacs_close (forkin);
- if (forkin != forkout && forkout >= 0)
- emacs_close (forkout);
- }
+ report_file_errno ("Doing vfork", Qnil, vfork_errno);
else
{
/* vfork succeeded. */
+ /* Close the pipe ends that the child uses, or the child's pty. */
+ close_process_fd (&p->open_fd[SUBPROCESS_STDIN]);
+ close_process_fd (&p->open_fd[SUBPROCESS_STDOUT]);
+
#ifdef WINDOWSNT
register_child (pid, inchannel);
#endif /* WINDOWSNT */
- /* If the subfork execv fails, and it exits,
- this close hangs. I don't know why.
- So have an interrupt jar it loose. */
- {
- struct atimer *timer;
- EMACS_TIME offset = make_emacs_time (1, 0);
-
- stop_polling ();
- timer = start_atimer (ATIMER_RELATIVE, offset, create_process_1, 0);
-
- if (forkin >= 0)
- emacs_close (forkin);
-
- cancel_atimer (timer);
- start_polling ();
- }
-
- if (forkin != forkout && forkout >= 0)
- emacs_close (forkout);
-
- pset_tty_name (XPROCESS (process), lisp_pty_name);
+ pset_tty_name (p, lisp_pty_name);
#ifndef WINDOWSNT
/* Wait for child_setup to complete in case that vfork is
- actually defined as fork. The descriptor wait_child_setup[1]
+ actually defined as fork. The descriptor
+ XPROCESS (proc)->open_fd[EXEC_MONITOR_OUTPUT]
of a pipe is closed at the child side either by close-on-exec
on successful execve or the _exit call in child_setup. */
{
char dummy;
- emacs_close (wait_child_setup[1]);
- emacs_read (wait_child_setup[0], &dummy, 1);
- emacs_close (wait_child_setup[0]);
+ close_process_fd (&p->open_fd[EXEC_MONITOR_OUTPUT]);
+ emacs_read (p->open_fd[READ_FROM_EXEC_MONITOR], &dummy, 1);
+ close_process_fd (&p->open_fd[READ_FROM_EXEC_MONITOR]);
}
#endif
}
-
- /* Now generate the error if vfork failed. */
- if (pid < 0)
- report_file_error ("Doing vfork", Qnil);
}
-void
+static void
create_pty (Lisp_Object process)
{
- int inchannel, outchannel;
- bool pty_flag = 0;
-
- inchannel = outchannel = -1;
-
-#ifdef HAVE_PTYS
- if (!NILP (Vprocess_connection_type))
- outchannel = inchannel = allocate_pty ();
+ struct Lisp_Process *p = XPROCESS (process);
+ char pty_name[PTY_NAME_SIZE];
+ int pty_fd = NILP (Vprocess_connection_type) ? -1 : allocate_pty (pty_name);
- if (inchannel >= 0)
+ if (pty_fd >= 0)
{
+ p->open_fd[SUBPROCESS_STDIN] = pty_fd;
#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. */
int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
if (forkout < 0)
report_file_error ("Opening pty", Qnil);
+ p->open_fd[WRITE_TO_SUBPROCESS] = forkout;
#if defined (DONT_REOPEN_PTY)
/* In the case that vfork is defined as fork, the parent process
(Emacs) may send some data before the child process completes
child_setup_tty (forkout);
#endif /* DONT_REOPEN_PTY */
#endif /* not USG, or USG_SUBTTY_WORKS */
- pty_flag = 1;
- }
-#endif /* HAVE_PTYS */
- fcntl (inchannel, F_SETFL, O_NONBLOCK);
- fcntl (outchannel, F_SETFL, O_NONBLOCK);
+ fcntl (pty_fd, F_SETFL, O_NONBLOCK);
- /* Record this as an active process, with its channels.
- As a result, child_setup will close Emacs's side of the pipes. */
- chan_process[inchannel] = process;
- XPROCESS (process)->infd = inchannel;
- XPROCESS (process)->outfd = outchannel;
+ /* Record this as an active process, with its channels.
+ As a result, child_setup will close Emacs's side of the pipes. */
+ chan_process[pty_fd] = process;
+ p->infd = pty_fd;
+ p->outfd = pty_fd;
- /* Previously we recorded the tty descriptor used in the subprocess.
- It was only used for getting the foreground tty process, so now
- we just reopen the device (see emacs_get_tty_pgrp) as this is
- more portable (see USG_SUBTTY_WORKS above). */
+ /* Previously we recorded the tty descriptor used in the subprocess.
+ It was only used for getting the foreground tty process, so now
+ we just reopen the device (see emacs_get_tty_pgrp) as this is
+ more portable (see USG_SUBTTY_WORKS above). */
- XPROCESS (process)->pty_flag = pty_flag;
- pset_status (XPROCESS (process), Qrun);
- setup_process_coding_systems (process);
+ p->pty_flag = 1;
+ pset_status (p, Qrun);
+ setup_process_coding_systems (process);
- FD_SET (inchannel, &input_wait_mask);
- FD_SET (inchannel, &non_keyboard_wait_mask);
- if (inchannel > max_process_desc)
- max_process_desc = inchannel;
+ FD_SET (pty_fd, &input_wait_mask);
+ FD_SET (pty_fd, &non_keyboard_wait_mask);
+ if (pty_fd > max_process_desc)
+ max_process_desc = pty_fd;
- XPROCESS (process)->pid = -2;
-#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 (p, build_string (pty_name));
+ }
+
+ p->pid = -2;
}
\f
}
if (ret < 0)
- report_file_error ("Cannot set network option",
- Fcons (opt, Fcons (val, Qnil)));
+ {
+ int setsockopt_errno = errno;
+ report_file_errno ("Cannot set network option", list2 (opt, val),
+ setsockopt_errno);
+ }
+
return (1 << sopt->optbit);
}
return Qnil;
}
-/* Used by make-serial-process to recover from errors. */
-static Lisp_Object
-make_serial_process_unwind (Lisp_Object proc)
-{
- if (!PROCESSP (proc))
- emacs_abort ();
- remove_process (proc);
- return Qnil;
-}
-
DEFUN ("make-serial-process", Fmake_serial_process, Smake_serial_process,
0, MANY, 0,
doc: /* Create and return a serial port process.
struct gcpro gcpro1;
Lisp_Object name, buffer;
Lisp_Object tem, val;
- ptrdiff_t specpdl_count = -1;
+ ptrdiff_t specpdl_count;
if (nargs == 0)
return Qnil;
CHECK_STRING (name);
proc = make_process (name);
specpdl_count = SPECPDL_INDEX ();
- record_unwind_protect (make_serial_process_unwind, proc);
+ record_unwind_protect (remove_process, proc);
p = XPROCESS (proc);
- fd = serial_open (SSDATA (port));
+ fd = serial_open (port);
+ p->open_fd[SUBPROCESS_STDIN] = fd;
p->infd = fd;
p->outfd = fd;
if (fd > max_process_desc)
p->kill_without_query = 1;
if (tem = Fplist_get (contact, QCstop), !NILP (tem))
pset_command (p, Qt);
- p->pty_flag = 0;
+ eassert (! p->pty_flag);
if (!EQ (p->command, Qt))
{
#ifdef POLL_FOR_INPUT
if (socktype != SOCK_DGRAM)
{
- record_unwind_protect (unwind_stop_other_atimers, Qnil);
+ record_unwind_protect_void (run_all_atimers);
bind_polling_period (10);
}
#endif
retry_connect:
#endif
- s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol);
+ s = socket (lres->ai_family, lres->ai_socktype | SOCK_CLOEXEC,
+ lres->ai_protocol);
if (s < 0)
{
xerrno = errno;
#endif
/* Make us close S if quit. */
- record_unwind_protect (close_file_unwind, make_number (s));
+ record_unwind_protect_int (close_file_unwind, s);
/* Parse network options in the arg list.
We simply ignore anything which isn't a known option (including other keywords).
if (errno == EINTR)
goto retry_select;
else
- report_file_error ("select failed", Qnil);
+ report_file_error ("Failed select", Qnil);
}
eassert (sc > 0);
len = sizeof xerrno;
eassert (FD_ISSET (s, &fdset));
- if (getsockopt (s, SOL_SOCKET, SO_ERROR, &xerrno, &len) == -1)
- report_file_error ("getsockopt failed", Qnil);
+ if (getsockopt (s, SOL_SOCKET, SO_ERROR, &xerrno, &len) < 0)
+ report_file_error ("Failed getsockopt", Qnil);
if (xerrno)
- errno = xerrno, report_file_error ("error during connect", Qnil);
- else
- break;
+ report_file_errno ("Failed connect", Qnil, xerrno);
+ break;
}
#endif /* !WINDOWSNT */
}
#endif
- /* Discard the unwind protect for closing S, if any. */
- specpdl_ptr = specpdl + count1;
-
- /* Unwind bind_polling_period and request_sigio. */
- unbind_to (count, Qnil);
-
if (s < 0)
{
/* If non-blocking got this far - and failed - assume non-blocking is
if (is_non_blocking_client)
return Qnil;
- errno = xerrno;
- if (is_server)
- report_file_error ("make server process failed", contact);
- else
- report_file_error ("make client process failed", contact);
+ report_file_errno ((is_server
+ ? "make server process failed"
+ : "make client process failed"),
+ contact, xerrno);
}
inch = s;
if ((tem = Fplist_get (contact, QCstop), !NILP (tem)))
pset_command (p, Qt);
p->pid = 0;
+
+ p->open_fd[SUBPROCESS_STDIN] = inch;
p->infd = inch;
p->outfd = outch;
+
+ /* Discard the unwind protect for closing S, if any. */
+ specpdl_ptr = specpdl + count1;
+
+ /* Unwind bind_polling_period and request_sigio. */
+ unbind_to (count, Qnil);
+
if (is_server && socktype != SOCK_DGRAM)
pset_status (p, Qlisten);
ptrdiff_t buf_size = 512;
int s;
Lisp_Object res;
+ ptrdiff_t count;
- s = socket (AF_INET, SOCK_STREAM, 0);
+ s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (s < 0)
return Qnil;
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_int (close_file_unwind, s);
do
{
ifconf.ifc_len = buf_size;
if (ioctl (s, SIOCGIFCONF, &ifconf))
{
- close (s);
+ emacs_close (s);
xfree (buf);
return Qnil;
}
}
while (ifconf.ifc_len == buf_size);
- close (s);
-
- res = Qnil;
+ res = unbind_to (count, Qnil);
ifreq = ifconf.ifc_req;
while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len)
{
Lisp_Object elt;
int s;
bool any = 0;
+ ptrdiff_t count;
#if (! (defined SIOCGIFHWADDR && defined HAVE_STRUCT_IFREQ_IFR_HWADDR) \
&& defined HAVE_GETIFADDRS && defined LLADDR)
struct ifaddrs *ifap;
error ("interface name too long");
strcpy (rq.ifr_name, SSDATA (ifname));
- s = socket (AF_INET, SOCK_STREAM, 0);
+ s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (s < 0)
return Qnil;
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_int (close_file_unwind, s);
elt = Qnil;
#if defined (SIOCGIFFLAGS) && defined (HAVE_STRUCT_IFREQ_IFR_FLAGS)
#endif
res = Fcons (elt, res);
- close (s);
-
- return any ? res : Qnil;
+ return unbind_to (count, any ? res : Qnil);
}
#endif
#endif /* defined (HAVE_NET_IF_H) */
static void
deactivate_process (Lisp_Object proc)
{
- register int inchannel, outchannel;
- register struct Lisp_Process *p = XPROCESS (proc);
+ int inchannel;
+ struct Lisp_Process *p = XPROCESS (proc);
+ int i;
#ifdef HAVE_GNUTLS
/* Delete GnuTLS structures in PROC, if any. */
emacs_gnutls_deinit (proc);
#endif /* HAVE_GNUTLS */
- inchannel = p->infd;
- outchannel = p->outfd;
-
#ifdef ADAPTIVE_READ_BUFFERING
if (p->read_output_delay > 0)
{
}
#endif
+ /* Beware SIGCHLD hereabouts. */
+
+ for (i = 0; i < PROCESS_OPEN_FDS; i++)
+ close_process_fd (&p->open_fd[i]);
+
+ inchannel = p->infd;
if (inchannel >= 0)
{
- /* Beware SIGCHLD hereabouts. */
- flush_pending_output (inchannel);
- emacs_close (inchannel);
- if (outchannel >= 0 && outchannel != inchannel)
- emacs_close (outchannel);
-
p->infd = -1;
p->outfd = -1;
#ifdef DATAGRAM_SOCKETS
#endif
if (inchannel == max_process_desc)
{
- int i;
/* We just closed the highest-numbered process input descriptor,
so recompute the highest-numbered one now. */
- max_process_desc = 0;
- for (i = 0; i < MAXDESC; i++)
- if (!NILP (chan_process[i]))
- max_process_desc = i;
+ int i = inchannel;
+ do
+ i--;
+ while (0 <= i && NILP (chan_process[i]));
+
+ max_process_desc = i;
}
}
}
#endif
} saddr;
socklen_t len = sizeof saddr;
+ ptrdiff_t count;
- s = accept (channel, &saddr.sa, &len);
+ s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC);
if (s < 0)
{
return;
}
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_int (close_file_unwind, s);
+
connect_counter++;
/* Setup a new process to handle the connection. */
process name of the server process concatenated with the caller
identification. */
- if (!NILP (ps->filter) && !EQ (ps->filter, Qt))
+ if (!(EQ (ps->filter, Qinternal_default_process_filter)
+ || EQ (ps->filter, Qt)))
buffer = Qnil;
else
{
pset_filter (p, ps->filter);
pset_command (p, Qnil);
p->pid = 0;
+
+ /* Discard the unwind protect for closing S. */
+ specpdl_ptr = specpdl + count;
+
+ p->open_fd[SUBPROCESS_STDIN] = s;
p->infd = s;
p->outfd = s;
pset_status (p, Qrun);
/* Setup coding system for new process based on server process.
This seems to be the proper thing to do, as the coding system
of the new process should reflect the settings at the time the
- server socket was opened; not the current settings. */
+ server socket was opened; not the current settings. */
pset_decode_coding_system (p, ps->decode_coding_system);
pset_encode_coding_system (p, ps->encode_coding_system);
(STRINGP (host) ? host : build_string ("-")),
build_string ("\n")));
- if (!NILP (p->sentinel))
- exec_sentinel (proc,
- concat3 (build_string ("open from "),
- (STRINGP (host) ? host : build_string ("-")),
- build_string ("\n")));
+ exec_sentinel (proc,
+ concat3 (build_string ("open from "),
+ (STRINGP (host) ? host : build_string ("-")),
+ build_string ("\n")));
}
/* This variable is different from waiting_for_input in keyboard.c.
when not inside wait_reading_process_output. */
static int waiting_for_user_input_p;
-static Lisp_Object
-wait_reading_process_output_unwind (Lisp_Object data)
+static void
+wait_reading_process_output_unwind (int data)
{
- waiting_for_user_input_p = XINT (data);
- return Qnil;
+ waiting_for_user_input_p = data;
}
/* This is here so breakpoints can be put on it. */
if (wait_proc != NULL)
wait_channel = wait_proc->infd;
- record_unwind_protect (wait_reading_process_output_unwind,
- make_number (waiting_for_user_input_p));
+ record_unwind_protect_int (wait_reading_process_output_unwind,
+ waiting_for_user_input_p);
waiting_for_user_input_p = read_kbd;
if (time_limit < 0)
time_limit = 0;
nsecs = -1;
}
- else if (time_limit > TYPE_MAXIMUM (time_t))
+ else if (TYPE_MAXIMUM (time_t) < time_limit)
time_limit = TYPE_MAXIMUM (time_t);
/* Since we may need to wait several times,
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
break;
- /* Compute time from now till when time limit is up */
- /* Exit if already run out */
+ /* Compute time from now till when time limit is up. */
+ /* Exit if already run out. */
if (nsecs < 0)
{
/* A negative timeout means
&& ! EQ (wait_proc->status, Qrun)
&& ! EQ (wait_proc->status, Qconnect))
{
- int nread, total_nread = 0;
+ bool read_some_bytes = 0;
clear_waiting_for_input ();
XSETPROCESS (proc, wait_proc);
/* Read data from the process, until we exhaust it. */
while (wait_proc->infd >= 0)
{
- nread = read_process_output (proc, wait_proc->infd);
+ int nread = read_process_output (proc, wait_proc->infd);
if (nread == 0)
break;
if (nread > 0)
- {
- total_nread += nread;
- got_some_input = 1;
- }
+ got_some_input = read_some_bytes = 1;
else if (nread == -1 && (errno == EIO || errno == EAGAIN))
break;
#ifdef EWOULDBLOCK
break;
#endif
}
- if (total_nread > 0 && do_display)
+ if (read_some_bytes && do_display)
redisplay_preserve_echo_area (10);
break;
}
#endif
-#if defined (USE_GTK) || defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
- nfds = xg_select
-#elif defined (HAVE_NS)
- nfds = ns_select
+#if defined (HAVE_NS)
+ nfds = ns_select
+#elif defined (HAVE_GLIB)
+ nfds = xg_select
#else
nfds = pselect
#endif
(max (max_process_desc, max_input_desc) + 1,
&Available,
- (check_write ? &Writeok : (SELECT_TYPE *)0),
+ (check_write ? &Writeok : 0),
NULL, &timeout, NULL);
#ifdef HAVE_GNUTLS
if (xerrno == EINTR)
no_avail = 1;
else if (xerrno == EBADF)
- {
-#ifdef AIX
- /* AIX doesn't handle PTY closure the same way BSD does. On AIX,
- the child's closure of the pts gives the parent a SIGHUP, and
- the ptc file descriptor is automatically closed,
- 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 SIGCHLD. */
- no_avail = 1; /* Cannot depend on values returned */
-#else
- emacs_abort ();
-#endif
- }
+ emacs_abort ();
else
- error ("select error: %s", emacs_strerror (xerrno));
+ report_file_errno ("Failed select", Qnil, xerrno);
}
if (no_avail)
}
}
#endif /* NON_BLOCKING_CONNECT */
- } /* end for each file descriptor */
- } /* end while exit conditions not met */
+ } /* End for each file descriptor. */
+ } /* End while exit conditions not met. */
unbind_to (count, Qnil);
return Qt;
}
+static void
+read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars,
+ ssize_t nbytes,
+ struct coding_system *coding);
+
/* Read pending output from the process channel,
starting with our buffered-ahead character if we have one.
Yield number of decoded characters read.
{
register ssize_t nbytes;
char *chars;
- register Lisp_Object outstream;
register struct Lisp_Process *p = XPROCESS (proc);
- register ptrdiff_t opoint;
struct coding_system *coding = proc_decode_coding_system[channel];
int carryover = p->decoding_carryover;
int readmax = 4096;
friends don't expect current-buffer to be changed from under them. */
record_unwind_current_buffer ();
- /* Read and dispose of the process output. */
- outstream = p->filter;
- if (!NILP (outstream))
- {
- Lisp_Object text;
- bool outer_running_asynch_code = running_asynch_code;
- int waiting = waiting_for_user_input_p;
+ read_and_dispose_of_process_output (p, chars, nbytes, coding);
+
+ /* Handling the process output should not deactivate the mark. */
+ Vdeactivate_mark = odeactivate;
+
+ unbind_to (count, Qnil);
+ return nbytes;
+}
- /* No need to gcpro these, because all we do with them later
- is test them for EQness, and none of them should be a string. */
+static void
+read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars,
+ ssize_t nbytes,
+ struct coding_system *coding)
+{
+ Lisp_Object outstream = p->filter;
+ Lisp_Object text;
+ bool outer_running_asynch_code = running_asynch_code;
+ int waiting = waiting_for_user_input_p;
+
+ /* No need to gcpro these, because all we do with them later
+ is test them for EQness, and none of them should be a string. */
#if 0
- Lisp_Object obuffer, okeymap;
- XSETBUFFER (obuffer, current_buffer);
- okeymap = BVAR (current_buffer, keymap);
+ Lisp_Object obuffer, okeymap;
+ XSETBUFFER (obuffer, current_buffer);
+ okeymap = BVAR (current_buffer, keymap);
#endif
- /* We inhibit quit here instead of just catching it so that
- hitting ^G when a filter happens to be running won't screw
- it up. */
- specbind (Qinhibit_quit, Qt);
- specbind (Qlast_nonmenu_event, Qt);
-
- /* In case we get recursively called,
- and we already saved the match data nonrecursively,
- save the same match data in safely recursive fashion. */
- if (outer_running_asynch_code)
- {
- Lisp_Object tem;
- /* Don't clobber the CURRENT match data, either! */
- tem = Fmatch_data (Qnil, Qnil, Qnil);
- restore_search_regs ();
- record_unwind_save_match_data ();
- Fset_match_data (tem, Qt);
- }
+ /* We inhibit quit here instead of just catching it so that
+ hitting ^G when a filter happens to be running won't screw
+ it up. */
+ specbind (Qinhibit_quit, Qt);
+ specbind (Qlast_nonmenu_event, Qt);
- /* For speed, if a search happens within this code,
- save the match data in a special nonrecursive fashion. */
- running_asynch_code = 1;
+ /* In case we get recursively called,
+ and we already saved the match data nonrecursively,
+ save the same match data in safely recursive fashion. */
+ if (outer_running_asynch_code)
+ {
+ Lisp_Object tem;
+ /* Don't clobber the CURRENT match data, either! */
+ tem = Fmatch_data (Qnil, Qnil, Qnil);
+ restore_search_regs ();
+ record_unwind_save_match_data ();
+ Fset_match_data (tem, Qt);
+ }
- decode_coding_c_string (coding, (unsigned char *) chars, nbytes, Qt);
- text = coding->dst_object;
- Vlast_coding_system_used = CODING_ID_NAME (coding->id);
- /* A new coding system might be found. */
- if (!EQ (p->decode_coding_system, Vlast_coding_system_used))
- {
- pset_decode_coding_system (p, Vlast_coding_system_used);
+ /* For speed, if a search happens within this code,
+ save the match data in a special nonrecursive fashion. */
+ running_asynch_code = 1;
- /* Don't call setup_coding_system for
- proc_decode_coding_system[channel] here. It is done in
- detect_coding called via decode_coding above. */
+ decode_coding_c_string (coding, (unsigned char *) chars, nbytes, Qt);
+ text = coding->dst_object;
+ Vlast_coding_system_used = CODING_ID_NAME (coding->id);
+ /* A new coding system might be found. */
+ if (!EQ (p->decode_coding_system, Vlast_coding_system_used))
+ {
+ pset_decode_coding_system (p, Vlast_coding_system_used);
- /* If a coding system for encoding is not yet decided, we set
- it as the same as coding-system for decoding.
+ /* Don't call setup_coding_system for
+ proc_decode_coding_system[channel] here. It is done in
+ detect_coding called via decode_coding above. */
- But, before doing that we must check if
- proc_encode_coding_system[p->outfd] surely points to a
- valid memory because p->outfd will be changed once EOF is
- sent to the process. */
- if (NILP (p->encode_coding_system)
- && proc_encode_coding_system[p->outfd])
- {
- pset_encode_coding_system
- (p, coding_inherit_eol_type (Vlast_coding_system_used, Qnil));
- setup_coding_system (p->encode_coding_system,
- proc_encode_coding_system[p->outfd]);
- }
- }
+ /* If a coding system for encoding is not yet decided, we set
+ it as the same as coding-system for decoding.
- if (coding->carryover_bytes > 0)
+ But, before doing that we must check if
+ proc_encode_coding_system[p->outfd] surely points to a
+ valid memory because p->outfd will be changed once EOF is
+ sent to the process. */
+ if (NILP (p->encode_coding_system)
+ && proc_encode_coding_system[p->outfd])
{
- if (SCHARS (p->decoding_buf) < coding->carryover_bytes)
- pset_decoding_buf (p, make_uninit_string (coding->carryover_bytes));
- memcpy (SDATA (p->decoding_buf), coding->carryover,
- coding->carryover_bytes);
- p->decoding_carryover = coding->carryover_bytes;
+ pset_encode_coding_system
+ (p, coding_inherit_eol_type (Vlast_coding_system_used, Qnil));
+ setup_coding_system (p->encode_coding_system,
+ proc_encode_coding_system[p->outfd]);
}
- if (SBYTES (text) > 0)
- /* FIXME: It's wrong to wrap or not based on debug-on-error, and
- sometimes it's simply wrong to wrap (e.g. when called from
- accept-process-output). */
- internal_condition_case_1 (read_process_output_call,
- Fcons (outstream,
- Fcons (proc, Fcons (text, Qnil))),
- !NILP (Vdebug_on_error) ? Qnil : Qerror,
- read_process_output_error_handler);
-
- /* If we saved the match data nonrecursively, restore it now. */
- restore_search_regs ();
- running_asynch_code = outer_running_asynch_code;
+ }
+
+ if (coding->carryover_bytes > 0)
+ {
+ if (SCHARS (p->decoding_buf) < coding->carryover_bytes)
+ pset_decoding_buf (p, make_uninit_string (coding->carryover_bytes));
+ memcpy (SDATA (p->decoding_buf), coding->carryover,
+ coding->carryover_bytes);
+ p->decoding_carryover = coding->carryover_bytes;
+ }
+ if (SBYTES (text) > 0)
+ /* FIXME: It's wrong to wrap or not based on debug-on-error, and
+ sometimes it's simply wrong to wrap (e.g. when called from
+ accept-process-output). */
+ internal_condition_case_1 (read_process_output_call,
+ list3 (outstream, make_lisp_proc (p), text),
+ !NILP (Vdebug_on_error) ? Qnil : Qerror,
+ read_process_output_error_handler);
+
+ /* If we saved the match data nonrecursively, restore it now. */
+ restore_search_regs ();
+ running_asynch_code = outer_running_asynch_code;
- /* Restore waiting_for_user_input_p as it was
- when we were called, in case the filter clobbered it. */
- waiting_for_user_input_p = waiting;
+ /* Restore waiting_for_user_input_p as it was
+ when we were called, in case the filter clobbered it. */
+ waiting_for_user_input_p = waiting;
#if 0 /* Call record_asynch_buffer_change unconditionally,
because we might have changed minor modes or other things
that affect key bindings. */
- if (! EQ (Fcurrent_buffer (), obuffer)
- || ! EQ (current_buffer->keymap, okeymap))
-#endif
- /* But do it only if the caller is actually going to read events.
- Otherwise there's no need to make him wake up, and it could
- cause trouble (for example it would make sit_for return). */
- if (waiting_for_user_input_p == -1)
- record_asynch_buffer_change ();
- }
+ if (! EQ (Fcurrent_buffer (), obuffer)
+ || ! EQ (current_buffer->keymap, okeymap))
+#endif
+ /* But do it only if the caller is actually going to read events.
+ Otherwise there's no need to make him wake up, and it could
+ cause trouble (for example it would make sit_for return). */
+ if (waiting_for_user_input_p == -1)
+ record_asynch_buffer_change ();
+}
- /* If no filter, write into buffer if it isn't dead. */
- else if (!NILP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer)))
+DEFUN ("internal-default-process-filter", Finternal_default_process_filter,
+ Sinternal_default_process_filter, 2, 2, 0,
+ doc: /* Function used as default process filter. */)
+ (Lisp_Object proc, Lisp_Object text)
+{
+ struct Lisp_Process *p;
+ ptrdiff_t opoint;
+
+ CHECK_PROCESS (proc);
+ p = XPROCESS (proc);
+ CHECK_STRING (text);
+
+ if (!NILP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer)))
{
Lisp_Object old_read_only;
ptrdiff_t old_begv, old_zv;
ptrdiff_t old_begv_byte, old_zv_byte;
ptrdiff_t before, before_byte;
ptrdiff_t opoint_byte;
- Lisp_Object text;
struct buffer *b;
Fset_buffer (p->buffer);
if (! (BEGV <= PT && PT <= ZV))
Fwiden ();
- decode_coding_c_string (coding, (unsigned char *) chars, nbytes, Qt);
- text = coding->dst_object;
- Vlast_coding_system_used = CODING_ID_NAME (coding->id);
- /* A new coding system might be found. See the comment in the
- similar code in the previous `if' block. */
- if (!EQ (p->decode_coding_system, Vlast_coding_system_used))
- {
- pset_decode_coding_system (p, Vlast_coding_system_used);
- if (NILP (p->encode_coding_system)
- && proc_encode_coding_system[p->outfd])
- {
- pset_encode_coding_system
- (p, coding_inherit_eol_type (Vlast_coding_system_used, Qnil));
- setup_coding_system (p->encode_coding_system,
- proc_encode_coding_system[p->outfd]);
- }
- }
- if (coding->carryover_bytes > 0)
- {
- if (SCHARS (p->decoding_buf) < coding->carryover_bytes)
- pset_decoding_buf (p, make_uninit_string (coding->carryover_bytes));
- memcpy (SDATA (p->decoding_buf), coding->carryover,
- coding->carryover_bytes);
- p->decoding_carryover = coding->carryover_bytes;
- }
/* Adjust the multibyteness of TEXT to that of the buffer. */
if (NILP (BVAR (current_buffer, enable_multibyte_characters))
!= ! STRING_MULTIBYTE (text))
if (old_begv != BEGV || old_zv != ZV)
Fnarrow_to_region (make_number (old_begv), make_number (old_zv));
-
bset_read_only (current_buffer, old_read_only);
SET_PT_BOTH (opoint, opoint_byte);
}
- /* Handling the process output should not deactivate the mark. */
- Vdeactivate_mark = odeactivate;
-
- unbind_to (count, Qnil);
- return nbytes;
+ return Qnil;
}
\f
-/* Sending data to subprocess */
+/* Sending data to subprocess. */
/* In send_process, when a write fails temporarily,
wait_reading_process_output is called. It may execute user code,
if (front)
pset_write_queue (p, Fcons (entry, p->write_queue));
else
- pset_write_queue (p, nconc2 (p->write_queue, Fcons (entry, Qnil)));
+ pset_write_queue (p, nconc2 (p->write_queue, list1 (entry)));
}
/* Remove the first element in the write_queue of process P, put its
if (rv >= 0)
written = rv;
else if (errno == EMSGSIZE)
- report_file_error ("sending datagram", Fcons (proc, Qnil));
+ report_file_error ("Sending datagram", proc);
}
else
#endif
written = emacs_gnutls_write (p, cur_buf, cur_len);
else
#endif
- written = emacs_write (outfd, cur_buf, cur_len);
+ written = emacs_write_sig (outfd, cur_buf, cur_len);
rv = (written ? 0 : -1);
#ifdef ADAPTIVE_READ_BUFFERING
if (p->read_output_delay > 0
}
else
/* This is a real error. */
- report_file_error ("writing to process", Fcons (proc, Qnil));
+ report_file_error ("Writing to process", proc);
}
cur_buf += written;
cur_len -= written;
return;
}
- switch (signo)
- {
#ifdef SIGCONT
- case SIGCONT:
+ if (signo == SIGCONT)
+ {
p->raw_status_new = 0;
pset_status (p, Qrun);
p->tick = ++process_tick;
status_notify (NULL);
redisplay_preserve_echo_area (13);
}
- break;
-#endif /* ! defined (SIGCONT) */
- case SIGINT:
- case SIGQUIT:
- case SIGKILL:
- flush_pending_output (p->infd);
- break;
}
+#endif
/* If we don't have process groups, send the signal to the immediate
subprocess. That isn't really right, but it's better than any
{
#ifndef WINDOWSNT
if (tcdrain (XPROCESS (proc)->outfd) != 0)
- error ("tcdrain() failed: %s", emacs_strerror (errno));
+ report_file_error ("Failed tcdrain", Qnil);
#endif /* not WINDOWSNT */
/* Do nothing on Windows because writes are blocking. */
}
else
{
- int old_outfd, new_outfd;
+ int old_outfd = XPROCESS (proc)->outfd;
+ int new_outfd;
#ifdef HAVE_SHUTDOWN
/* If this is a network connection, or socketpair is used
(In some old system, shutdown to socketpair doesn't work.
Then we just can't win.) */
if (EQ (XPROCESS (proc)->type, Qnetwork)
- || XPROCESS (proc)->outfd == XPROCESS (proc)->infd)
- shutdown (XPROCESS (proc)->outfd, 1);
- /* In case of socketpair, outfd == infd, so don't close it. */
- if (XPROCESS (proc)->outfd != XPROCESS (proc)->infd)
- emacs_close (XPROCESS (proc)->outfd);
-#else /* not HAVE_SHUTDOWN */
- emacs_close (XPROCESS (proc)->outfd);
-#endif /* not HAVE_SHUTDOWN */
+ || XPROCESS (proc)->infd == old_outfd)
+ shutdown (old_outfd, 1);
+#endif
+ close_process_fd (&XPROCESS (proc)->open_fd[WRITE_TO_SUBPROCESS]);
new_outfd = emacs_open (NULL_DEVICE, O_WRONLY, 0);
if (new_outfd < 0)
- emacs_abort ();
- old_outfd = XPROCESS (proc)->outfd;
+ report_file_error ("Opening null device", Qnil);
+ XPROCESS (proc)->open_fd[WRITE_TO_SUBPROCESS] = new_outfd;
+ XPROCESS (proc)->outfd = new_outfd;
if (!proc_encode_coding_system[new_outfd])
proc_encode_coding_system[new_outfd]
= *proc_encode_coding_system[old_outfd];
memset (proc_encode_coding_system[old_outfd], 0,
sizeof (struct coding_system));
-
- XPROCESS (proc)->outfd = new_outfd;
}
return process;
}
might inadvertently reap a GTK-created process that happened to
have the same process ID. */
+/* LIB_CHILD_HANDLER is a SIGCHLD handler that Emacs calls while doing
+ its own SIGCHLD handling. On POSIXish systems, glib needs this to
+ keep track of its own children. GNUstep is similar. */
+
+static void dummy_handler (int sig) {}
+static signal_handler_t volatile lib_child_handler;
+
/* Handle a SIGCHLD signal by looking for known child processes of
Emacs whose status have changed. For each one found, record its
new status.
static void
handle_child_signal (int sig)
{
- Lisp_Object tail;
+ Lisp_Object tail, proc;
/* Find the process that signaled us, and record its status. */
bool all_pids_are_fixnums
= (MOST_NEGATIVE_FIXNUM <= TYPE_MINIMUM (pid_t)
&& TYPE_MAXIMUM (pid_t) <= MOST_POSITIVE_FIXNUM);
- Lisp_Object xpid = XCAR (tail);
+ Lisp_Object head = XCAR (tail);
+ Lisp_Object xpid;
+ if (! CONSP (head))
+ continue;
+ xpid = XCAR (head);
if (all_pids_are_fixnums ? INTEGERP (xpid) : NUMBERP (xpid))
{
pid_t deleted_pid;
else
deleted_pid = XFLOAT_DATA (xpid);
if (child_status_changed (deleted_pid, 0, 0))
- XSETCAR (tail, Qnil);
+ {
+ if (STRINGP (XCDR (head)))
+ unlink (SSDATA (XCDR (head)));
+ XSETCAR (tail, Qnil);
+ }
}
}
/* Otherwise, if it is asynchronous, it is in Vprocess_alist. */
- for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+ FOR_EACH_PROCESS (tail, proc)
{
- Lisp_Object proc = XCDR (XCAR (tail));
struct Lisp_Process *p = XPROCESS (proc);
int status;
- if (p->alive && child_status_changed (p->pid, &status, WUNTRACED))
+ if (p->alive
+ && child_status_changed (p->pid, &status, WUNTRACED | WCONTINUED))
{
/* Change the status of the process that was found. */
p->tick = ++process_tick;
}
}
}
+
+ lib_child_handler (sig);
+#ifdef NS_IMPL_GNUSTEP
+ /* NSTask in GNUStep sets its child handler each time it is called.
+ So we must re-set ours. */
+ catch_child_signal();
+#endif
}
static void
}
\f
-static Lisp_Object
-exec_sentinel_unwind (Lisp_Object data)
-{
- pset_sentinel (XPROCESS (XCAR (data)), XCDR (data));
- return Qnil;
-}
-
static Lisp_Object
exec_sentinel_error_handler (Lisp_Object error_val)
{
record_unwind_current_buffer ();
sentinel = p->sentinel;
- if (NILP (sentinel))
- return;
- /* Zilch the sentinel while it's running, to avoid recursive invocations;
- assure that it gets restored no matter how the sentinel exits. */
- pset_sentinel (p, Qnil);
- record_unwind_protect (exec_sentinel_unwind, Fcons (proc, sentinel));
/* Inhibit quit so that random quits don't screw up a running filter. */
specbind (Qinhibit_quit, Qt);
specbind (Qlast_nonmenu_event, Qt); /* Why? --Stef */
running_asynch_code = 1;
internal_condition_case_1 (read_process_output_call,
- Fcons (sentinel,
- Fcons (proc, Fcons (reason, Qnil))),
+ list3 (sentinel, proc, reason),
!NILP (Vdebug_on_error) ? Qnil : Qerror,
exec_sentinel_error_handler);
static void
status_notify (struct Lisp_Process *deleting_process)
{
- register Lisp_Object proc, buffer;
+ register Lisp_Object proc;
Lisp_Object tail, msg;
struct gcpro gcpro1, gcpro2;
that we run, we get called again to handle their status changes. */
update_tick = process_tick;
- for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+ FOR_EACH_PROCESS (tail, proc)
{
Lisp_Object symbol;
- register struct Lisp_Process *p;
-
- proc = Fcdr (XCAR (tail));
- p = XPROCESS (proc);
+ register struct Lisp_Process *p = XPROCESS (proc);
if (p->tick != p->update_tick)
{
&& p != deleting_process
&& read_process_output (proc, p->infd) > 0);
- buffer = p->buffer;
-
/* Get the text to use for the message. */
if (p->raw_status_new)
update_status (p);
}
/* The actions above may have further incremented p->tick.
- So set p->update_tick again
- so that an error in the sentinel will not cause
- this code to be run again. */
+ So set p->update_tick again so that an error in the sentinel will
+ not cause this code to be run again. */
p->update_tick = p->tick;
/* Now output the message suitably. */
- if (!NILP (p->sentinel))
- exec_sentinel (proc, msg);
- /* Don't bother with a message in the buffer
- when a process becomes runnable. */
- else if (!EQ (symbol, Qrun) && !NILP (buffer))
- {
- Lisp_Object tem;
- struct buffer *old = current_buffer;
- ptrdiff_t opoint, opoint_byte;
- ptrdiff_t before, before_byte;
-
- /* Avoid error if buffer is deleted
- (probably that's why the process is dead, too) */
- if (!BUFFER_LIVE_P (XBUFFER (buffer)))
- continue;
- Fset_buffer (buffer);
-
- opoint = PT;
- opoint_byte = PT_BYTE;
- /* Insert new output into buffer
- at the current end-of-output marker,
- thus preserving logical ordering of input and output. */
- if (XMARKER (p->mark)->buffer)
- Fgoto_char (p->mark);
- else
- SET_PT_BOTH (ZV, ZV_BYTE);
-
- before = PT;
- before_byte = PT_BYTE;
-
- tem = BVAR (current_buffer, read_only);
- bset_read_only (current_buffer, Qnil);
- insert_string ("\nProcess ");
- { /* FIXME: temporary kludge */
- Lisp_Object tem2 = p->name; Finsert (1, &tem2); }
- insert_string (" ");
- Finsert (1, &msg);
- bset_read_only (current_buffer, tem);
- set_marker_both (p->mark, p->buffer, PT, PT_BYTE);
-
- if (opoint >= before)
- SET_PT_BOTH (opoint + (PT - before),
- opoint_byte + (PT_BYTE - before_byte));
- else
- SET_PT_BOTH (opoint, opoint_byte);
-
- set_buffer_internal (old);
- }
+ exec_sentinel (proc, msg);
}
} /* end for */
- update_mode_lines++; /* in case buffers use %s in mode-line-format */
+ update_mode_lines++; /* In case buffers use %s in mode-line-format. */
UNGCPRO;
}
+DEFUN ("internal-default-process-sentinel", Finternal_default_process_sentinel,
+ Sinternal_default_process_sentinel, 2, 2, 0,
+ doc: /* Function used as default sentinel for processes. */)
+ (Lisp_Object proc, Lisp_Object msg)
+{
+ Lisp_Object buffer, symbol;
+ struct Lisp_Process *p;
+ CHECK_PROCESS (proc);
+ p = XPROCESS (proc);
+ buffer = p->buffer;
+ symbol = p->status;
+ if (CONSP (symbol))
+ symbol = XCAR (symbol);
+
+ if (!EQ (symbol, Qrun) && !NILP (buffer))
+ {
+ Lisp_Object tem;
+ struct buffer *old = current_buffer;
+ ptrdiff_t opoint, opoint_byte;
+ ptrdiff_t before, before_byte;
+
+ /* Avoid error if buffer is deleted
+ (probably that's why the process is dead, too). */
+ if (!BUFFER_LIVE_P (XBUFFER (buffer)))
+ return Qnil;
+ Fset_buffer (buffer);
+
+ if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
+ msg = (code_convert_string_norecord
+ (msg, Vlocale_coding_system, 1));
+
+ opoint = PT;
+ opoint_byte = PT_BYTE;
+ /* Insert new output into buffer
+ at the current end-of-output marker,
+ thus preserving logical ordering of input and output. */
+ if (XMARKER (p->mark)->buffer)
+ Fgoto_char (p->mark);
+ else
+ SET_PT_BOTH (ZV, ZV_BYTE);
+
+ before = PT;
+ before_byte = PT_BYTE;
+
+ tem = BVAR (current_buffer, read_only);
+ bset_read_only (current_buffer, Qnil);
+ insert_string ("\nProcess ");
+ { /* FIXME: temporary kludge. */
+ Lisp_Object tem2 = p->name; Finsert (1, &tem2); }
+ insert_string (" ");
+ Finsert (1, &msg);
+ bset_read_only (current_buffer, tem);
+ set_marker_both (p->mark, p->buffer, PT, PT_BYTE);
+
+ if (opoint >= before)
+ SET_PT_BOTH (opoint + (PT - before),
+ opoint_byte + (PT_BYTE - before_byte));
+ else
+ SET_PT_BOTH (opoint, opoint_byte);
+
+ set_buffer_internal (old);
+ }
+ return Qnil;
+}
+
\f
DEFUN ("set-process-coding-system", Fset_process_coding_system,
Sset_process_coding_system, 1, 3, 0,
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
break;
- /* Compute time from now till when time limit is up */
- /* Exit if already run out */
+ /* Compute time from now till when time limit is up. */
+ /* Exit if already run out. */
if (nsecs < 0)
{
/* A negative timeout means
gobble output available now
- but don't wait at all. */
+ but don't wait at all. */
timeout = make_emacs_time (0, 0);
}
if (xerrno == EINTR)
FD_ZERO (&waitchannels);
else
- error ("select error: %s", emacs_strerror (xerrno));
+ report_file_errno ("Failed select", Qnil, xerrno);
}
/* Check for keyboard input */
delete_keyboard_wait_descriptor (int desc)
{
#ifdef subprocesses
- int fd;
- int lim = max_input_desc;
-
FD_CLR (desc, &input_wait_mask);
FD_CLR (desc, &non_process_wait_mask);
-
- if (desc == max_input_desc)
- for (fd = 0; fd < lim; fd++)
- if (FD_ISSET (fd, &input_wait_mask) || FD_ISSET (fd, &write_mask))
- max_input_desc = fd;
+ delete_input_desc (desc);
#endif
}
if (!proc_decode_coding_system[inch])
proc_decode_coding_system[inch] = xmalloc (sizeof (struct coding_system));
coding_system = p->decode_coding_system;
- if (! NILP (p->filter))
- ;
- else if (BUFFERP (p->buffer))
+ if (EQ (p->filter, Qinternal_default_process_filter)
+ && BUFFERP (p->buffer))
{
if (NILP (BVAR (XBUFFER (p->buffer), enable_multibyte_characters)))
coding_system = raw_text_coding_system (coding_system);
#endif
}
-/* Close all descriptors currently in use for communication
- with subprocess. This is used in a newly-forked subprocess
- to get rid of irrelevant descriptors. */
-
-void
-close_process_descs (void)
-{
-#ifndef DOS_NT
- int i;
- for (i = 0; i < MAXDESC; i++)
- {
- Lisp_Object process;
- process = chan_process[i];
- if (!NILP (process))
- {
- int in = XPROCESS (process)->infd;
- int out = XPROCESS (process)->outfd;
- if (in >= 0)
- emacs_close (in);
- if (out >= 0 && in != out)
- emacs_close (out);
- }
- }
-#endif
-}
-
DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
doc: /* Return the (or a) process associated with BUFFER.
BUFFER may be a buffer or the name of one. */)
buf = Fget_buffer (buffer);
if (NILP (buf)) return Qnil;
- for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
- {
- proc = Fcdr (XCAR (tail));
- if (PROCESSP (proc) && EQ (XPROCESS (proc)->buffer, buf))
- return proc;
- }
+ FOR_EACH_PROCESS (tail, proc)
+ if (EQ (XPROCESS (proc)->buffer, buf))
+ return proc;
#endif /* subprocesses */
return Qnil;
}
#ifdef subprocesses
Lisp_Object tail, proc;
- for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
- {
- proc = XCDR (XCAR (tail));
- if (PROCESSP (proc)
- && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
- {
- if (NETCONN_P (proc) || SERIALCONN_P (proc))
- Fdelete_process (proc);
- else if (XPROCESS (proc)->infd >= 0)
- process_send_signal (proc, SIGHUP, Qnil, 1);
- }
- }
+ FOR_EACH_PROCESS (tail, proc)
+ if (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer))
+ {
+ if (NETCONN_P (proc) || SERIALCONN_P (proc))
+ Fdelete_process (proc);
+ else if (XPROCESS (proc)->infd >= 0)
+ process_send_signal (proc, SIGHUP, Qnil, 1);
+ }
#else /* subprocesses */
/* Since we have no subprocesses, this does nothing. */
#endif /* subprocesses */
DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p,
Swaiting_for_user_input_p, 0, 0, 0,
- doc: /* Returns non-nil if Emacs is waiting for input from the user.
+ doc: /* Return non-nil if Emacs is waiting for input from the user.
This is intended for use by asynchronous process output filters and sentinels. */)
(void)
{
return system_process_attributes (pid);
}
+/* Arrange to catch SIGCHLD if this hasn't already been arranged.
+ Invoke this after init_process_emacs, and after glib and/or GNUstep
+ futz with the SIGCHLD handler, but before Emacs forks any children.
+ This function's caller should block SIGCHLD. */
+
+#ifndef NS_IMPL_GNUSTEP
+static
+#endif
+void
+catch_child_signal (void)
+{
+ struct sigaction action, old_action;
+ emacs_sigaction_init (&action, deliver_child_signal);
+ block_child_signal ();
+ sigaction (SIGCHLD, &action, &old_action);
+ eassert (! (old_action.sa_flags & SA_SIGINFO));
+
+ if (old_action.sa_handler != deliver_child_signal)
+ lib_child_handler
+ = (old_action.sa_handler == SIG_DFL || old_action.sa_handler == SIG_IGN
+ ? dummy_handler
+ : old_action.sa_handler);
+ unblock_child_signal ();
+}
+
\f
/* This is not called "init_process" because that is the name of a
Mach system call, so it would cause problems on Darwin systems. */
if (! noninteractive || initialized)
#endif
{
- struct sigaction action;
- emacs_sigaction_init (&action, deliver_child_signal);
- sigaction (SIGCHLD, &action, 0);
+#if defined HAVE_GLIB && !defined WINDOWSNT
+ /* Tickle glib's child-handling code. Ask glib to wait for Emacs itself;
+ this should always fail, but is enough to initialize glib's
+ private SIGCHLD handler, allowing catch_child_signal to copy
+ it into lib_child_handler. */
+ g_source_unref (g_child_watch_source_new (getpid ()));
+#endif
+ catch_child_signal ();
}
FD_ZERO (&input_wait_mask);
FD_ZERO (&non_keyboard_wait_mask);
FD_ZERO (&non_process_wait_mask);
FD_ZERO (&write_mask);
- max_process_desc = 0;
+ max_process_desc = max_input_desc = -1;
memset (fd_callback_info, 0, sizeof (fd_callback_info));
#ifdef NON_BLOCKING_CONNECT
DEFSYM (Qcutime, "cutime");
DEFSYM (Qcstime, "cstime");
DEFSYM (Qctime, "ctime");
+ DEFSYM (Qinternal_default_process_sentinel,
+ "internal-default-process-sentinel");
+ DEFSYM (Qinternal_default_process_filter,
+ "internal-default-process-filter");
DEFSYM (Qpri, "pri");
DEFSYM (Qnice, "nice");
DEFSYM (Qthcount, "thcount");
defsubr (&Ssignal_process);
defsubr (&Swaiting_for_user_input_p);
defsubr (&Sprocess_type);
+ defsubr (&Sinternal_default_process_sentinel);
+ defsubr (&Sinternal_default_process_filter);
defsubr (&Sset_process_coding_system);
defsubr (&Sprocess_coding_system);
defsubr (&Sset_process_filter_multibyte);