X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/9caab067d66a2de8520aab5c2b17205548631c4d..e9be0a138c07b93576c07c7fe7c94defee9adfc6:/src/process.c diff --git a/src/process.c b/src/process.c index 1c21064902..763d2fd504 100644 --- a/src/process.c +++ b/src/process.c @@ -1,6 +1,6 @@ /* Asynchronous subprocess control for GNU Emacs. -Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2013 Free Software +Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2014 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -21,8 +21,6 @@ along with GNU Emacs. If not, see . */ #include -#define PROCESS_INLINE EXTERN_INLINE - #include #include #include /* Some typedefs are used in sys/file.h. */ @@ -92,6 +90,7 @@ along with GNU Emacs. If not, see . */ #include #include +#include #endif /* subprocesses */ @@ -131,8 +130,8 @@ along with GNU Emacs. If not, see . */ #endif #ifdef WINDOWSNT -extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, - EMACS_TIME *, void *); +extern int sys_select (int, fd_set *, fd_set *, fd_set *, + struct timespec *, void *); #endif #ifndef SOCK_CLOEXEC @@ -260,7 +259,7 @@ static EMACS_INT update_tick; #endif #ifdef ADAPTIVE_READ_BUFFERING -#define READ_OUTPUT_DELAY_INCREMENT (EMACS_TIME_RESOLUTION / 100) +#define READ_OUTPUT_DELAY_INCREMENT (TIMESPEC_RESOLUTION / 100) #define READ_OUTPUT_DELAY_MAX (READ_OUTPUT_DELAY_INCREMENT * 5) #define READ_OUTPUT_DELAY_MAX_MAX (READ_OUTPUT_DELAY_INCREMENT * 7) @@ -279,7 +278,7 @@ static bool process_output_skip; static void create_process (Lisp_Object, char **, Lisp_Object); #ifdef USABLE_SIGIO -static bool keyboard_bit_set (SELECT_TYPE *); +static bool keyboard_bit_set (fd_set *); #endif static void deactivate_process (Lisp_Object); static void status_notify (struct Lisp_Process *); @@ -298,39 +297,39 @@ static void exec_sentinel (Lisp_Object proc, Lisp_Object reason); /* Mask of bits indicating the descriptors that we wait for input on. */ -static SELECT_TYPE input_wait_mask; +static fd_set input_wait_mask; /* Mask that excludes keyboard input descriptor(s). */ -static SELECT_TYPE non_keyboard_wait_mask; +static fd_set non_keyboard_wait_mask; /* Mask that excludes process input descriptor(s). */ -static SELECT_TYPE non_process_wait_mask; +static fd_set non_process_wait_mask; /* Mask for selecting for write. */ -static SELECT_TYPE write_mask; +static fd_set write_mask; #ifdef NON_BLOCKING_CONNECT /* Mask of bits indicating the descriptors that we wait for connect to complete on. Once they complete, they are removed from this mask and added to the input_wait_mask and non_keyboard_wait_mask. */ -static SELECT_TYPE connect_wait_mask; +static fd_set connect_wait_mask; /* Number of bits set in connect_wait_mask. */ 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 */ -static Lisp_Object chan_process[MAXDESC]; +static Lisp_Object chan_process[FD_SETSIZE]; /* Alist of elements (NAME . PROCESS) */ static Lisp_Object Vprocess_alist; @@ -341,18 +340,18 @@ static Lisp_Object Vprocess_alist; output from the process is to read at least one char. Always -1 on systems that support FIONREAD. */ -static int proc_buffered_char[MAXDESC]; +static int proc_buffered_char[FD_SETSIZE]; /* Table of `struct coding-system' for each process. */ -static struct coding_system *proc_decode_coding_system[MAXDESC]; -static struct coding_system *proc_encode_coding_system[MAXDESC]; +static struct coding_system *proc_decode_coding_system[FD_SETSIZE]; +static struct coding_system *proc_encode_coding_system[FD_SETSIZE]; #ifdef DATAGRAM_SOCKETS /* Table of `partner address' for datagram sockets. */ static struct sockaddr_and_len { struct sockaddr *sa; int len; -} datagram_address[MAXDESC]; +} datagram_address[FD_SETSIZE]; #define DATAGRAM_CHAN_P(chan) (datagram_address[chan].sa != 0) #define DATAGRAM_CONN_P(proc) (PROCESSP (proc) && datagram_address[XPROCESS (proc)->infd].sa != 0) #else @@ -360,6 +359,12 @@ static struct sockaddr_and_len { #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) @@ -451,7 +456,7 @@ static struct fd_callback_data #define FOR_READ 1 #define FOR_WRITE 2 int condition; /* mask of the defines above. */ -} fd_callback_info[MAXDESC]; +} fd_callback_info[FD_SETSIZE]; /* Add a file descriptor FD to be monitored for when read is possible. @@ -460,7 +465,7 @@ static struct fd_callback_data void add_read_fd (int fd, fd_callback func, void *data) { - eassert (fd < MAXDESC); + eassert (fd < FD_SETSIZE); add_keyboard_wait_descriptor (fd); fd_callback_info[fd].func = func; @@ -473,7 +478,7 @@ add_read_fd (int fd, fd_callback func, void *data) void delete_read_fd (int fd) { - eassert (fd < MAXDESC); + eassert (fd < FD_SETSIZE); delete_keyboard_wait_descriptor (fd); fd_callback_info[fd].condition &= ~FOR_READ; @@ -490,7 +495,7 @@ delete_read_fd (int fd) void add_write_fd (int fd, fd_callback func, void *data) { - eassert (fd < MAXDESC); + eassert (fd < FD_SETSIZE); FD_SET (fd, &write_mask); if (fd > max_input_desc) max_input_desc = fd; @@ -500,29 +505,35 @@ add_write_fd (int fd, fd_callback func, void *data) 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); + eassert (fd < FD_SETSIZE); FD_CLR (fd, &write_mask); fd_callback_info[fd].condition &= ~FOR_WRITE; if (fd_callback_info[fd].condition == 0) { 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); } } @@ -640,19 +651,16 @@ status_message (struct Lisp_Process *p) return Fcopy_sequence (Fsymbol_name (symbol)); } -#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 @@ -677,6 +685,15 @@ allocate_pty (void) 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 @@ -697,9 +714,9 @@ allocate_pty (void) return fd; } } +#endif /* HAVE_PTYS */ return -1; } -#endif /* HAVE_PTYS */ static Lisp_Object make_process (Lisp_Object name) @@ -719,6 +736,8 @@ 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; @@ -793,13 +812,14 @@ get_process (register Lisp_Object name) else obj = name; - /* Now obj should be either a buffer object or a process object. - */ + /* Now obj should be either a buffer object or a process object. */ if (BUFFERP (obj)) { + if (NILP (BVAR (XBUFFER (obj), name))) + error ("Attempt to get process for a dead buffer"); proc = Fget_buffer_process (obj); if (NILP (proc)) - error ("Buffer %s has no process", SDATA (BVAR (XBUFFER (obj), name))); + error ("Buffer %s has no process", SDATA (BVAR (XBUFFER (obj), name))); } else { @@ -815,13 +835,17 @@ get_process (register Lisp_Object name) 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)); @@ -841,7 +865,7 @@ nil, indicating the current buffer's process. */) 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); @@ -849,7 +873,7 @@ nil, indicating the current buffer's process. */) else { if (p->alive) - record_kill_process (p); + record_kill_process (p, Qnil); if (p->infd >= 0) { @@ -1115,15 +1139,18 @@ See `set-process-sentinel' for more info on sentinels. */) 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; @@ -1206,11 +1233,11 @@ list of keywords. */) 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); } @@ -1333,7 +1360,7 @@ Returns nil if format of ADDRESS is invalid. */) } 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); @@ -1341,7 +1368,7 @@ DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0, /* 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. @@ -1383,22 +1410,9 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) 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; } @@ -1516,10 +1530,11 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) tem = Qnil; GCPRO4 (name, program, buffer, current_dir); - openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK)); + openp (Vexec_path, program, Vexec_suffixes, &tem, + make_number (X_OK), false); 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 @@ -1542,7 +1557,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) /* 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 @@ -1590,7 +1605,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) 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)) @@ -1600,39 +1615,60 @@ start_process_unwind (Lisp_Object 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 + int vfork_errno; int forkin, forkout; bool pty_flag = 0; + char pty_name[PTY_NAME_SIZE]; Lisp_Object lisp_pty_name = Qnil; - Lisp_Object encoded_current_dir; 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. */ @@ -1641,6 +1677,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) 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 */ @@ -1648,24 +1685,18 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) lisp_pty_name = build_string (pty_name); } else -#endif /* HAVE_PTYS */ { - if (pipe2 (sv, O_CLOEXEC) != 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]; - if (pipe2 (sv, O_CLOEXEC) != 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 - if (pipe2 (wait_child_setup, O_CLOEXEC) != 0) + if (emacs_pipe (p->open_fd + READ_FROM_EXEC_MONITOR) != 0) report_file_error ("Creating pipe", Qnil); #endif @@ -1674,16 +1705,16 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) /* 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); @@ -1693,35 +1724,29 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) /* This may signal an error. */ setup_process_coding_systems (process); - encoded_current_dir = ENCODE_FILE (current_dir); - block_input (); block_child_signal (); #ifndef WINDOWSNT /* vfork, and prevent local vars from being clobbered by the vfork. */ { - Lisp_Object volatile encoded_current_dir_volatile = encoded_current_dir; + Lisp_Object volatile current_dir_volatile = current_dir; Lisp_Object volatile lisp_pty_name_volatile = lisp_pty_name; - Lisp_Object volatile process_volatile = process; - bool volatile pty_flag_volatile = pty_flag; char **volatile new_argv_volatile = new_argv; int volatile forkin_volatile = forkin; int volatile forkout_volatile = forkout; - int volatile wait_child_setup_0_volatile = wait_child_setup[0]; - int volatile wait_child_setup_1_volatile = wait_child_setup[1]; + struct Lisp_Process *p_volatile = p; pid = vfork (); - encoded_current_dir = encoded_current_dir_volatile; + current_dir = current_dir_volatile; lisp_pty_name = lisp_pty_name_volatile; - process = process_volatile; - pty_flag = pty_flag_volatile; new_argv = new_argv_volatile; forkin = forkin_volatile; forkout = forkout_volatile; - wait_child_setup[0] = wait_child_setup_0_volatile; - wait_child_setup[1] = wait_child_setup_1_volatile; + p = p_volatile; + + pty_flag = p->pty_flag; } if (pid == 0) @@ -1752,7 +1777,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) 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) @@ -1791,18 +1816,16 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) 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); } } @@ -1814,12 +1837,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) 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); @@ -1834,96 +1851,66 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) 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 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. */ @@ -1932,6 +1919,7 @@ create_pty (Lisp_Object process) 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 @@ -1939,47 +1927,43 @@ create_pty (Lisp_Object process) 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; } /* Convert an internal struct sockaddr to a lisp object (vector or string). The address family of sa is not included in the result. */ -static Lisp_Object +#ifndef WINDOWSNT +static +#endif +Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *sa, int len) { Lisp_Object address; @@ -2332,8 +2316,12 @@ set_socket_option (int s, Lisp_Object opt, Lisp_Object val) } 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); } @@ -2465,16 +2453,6 @@ usage: (serial-process-configure &rest ARGS) */) 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. @@ -2580,10 +2558,11 @@ usage: (make-serial-process &rest ARGS) */) 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) @@ -2606,7 +2585,7 @@ usage: (make-serial-process &rest ARGS) */) 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)) { @@ -3016,7 +2995,7 @@ usage: (make-network-process &rest ARGS) */) #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 @@ -3176,7 +3155,7 @@ usage: (make-network-process &rest ARGS) */) #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). @@ -3256,7 +3235,7 @@ usage: (make-network-process &rest ARGS) */) wait for completion is pselect(). */ int sc; socklen_t len; - SELECT_TYPE fdset; + fd_set fdset; retry_select: FD_ZERO (&fdset); FD_SET (s, &fdset); @@ -3267,18 +3246,17 @@ usage: (make-network-process &rest ARGS) */) 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 */ @@ -3347,12 +3325,6 @@ usage: (make-network-process &rest ARGS) */) } #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 @@ -3362,11 +3334,10 @@ usage: (make-network-process &rest ARGS) */) 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; @@ -3395,8 +3366,17 @@ usage: (make-network-process &rest ARGS) */) 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); @@ -3529,15 +3509,11 @@ usage: (make-network-process &rest ARGS) */) } -#if defined (HAVE_NET_IF_H) +#ifdef HAVE_NET_IF_H #ifdef SIOCGIFCONF -DEFUN ("network-interface-list", Fnetwork_interface_list, Snetwork_interface_list, 0, 0, 0, - doc: /* Return an alist of all network interfaces and their network address. -Each element is a cons, the car of which is a string containing the -interface name, and the cdr is the network address in internal -format; see the description of ADDRESS in `make-network-process'. */) - (void) +static Lisp_Object +network_interface_list (void) { struct ifconf ifconf; struct ifreq *ifreq; @@ -3545,10 +3521,13 @@ format; see the description of ADDRESS in `make-network-process'. */) ptrdiff_t buf_size = 512; int s; Lisp_Object res; + ptrdiff_t count; 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 { @@ -3557,16 +3536,14 @@ format; see the description of ADDRESS in `make-network-process'. */) 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) { @@ -3678,19 +3655,15 @@ static const struct ifflag_def ifflag_table[] = { { 0, 0 } }; -DEFUN ("network-interface-info", Fnetwork_interface_info, Snetwork_interface_info, 1, 1, 0, - doc: /* Return information about network interface named IFNAME. -The return value is a list (ADDR BCAST NETMASK HWADDR FLAGS), -where ADDR is the layer 3 address, BCAST is the layer 3 broadcast address, -NETMASK is the layer 3 network mask, HWADDR is the layer 2 address, and -FLAGS is the current flags of the interface. */) - (Lisp_Object ifname) +static Lisp_Object +network_interface_info (Lisp_Object ifname) { struct ifreq rq; Lisp_Object res = Qnil; 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; @@ -3705,6 +3678,8 @@ FLAGS is the current flags of the interface. */) 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) @@ -3750,7 +3725,9 @@ FLAGS is the current flags of the interface. */) any = 1; for (n = 0; n < 6; n++) - p->contents[n] = make_number (((unsigned char *)&rq.ifr_hwaddr.sa_data[0])[n]); + p->contents[n] = make_number (((unsigned char *) + &rq.ifr_hwaddr.sa_data[0]) + [n]); elt = Fcons (make_number (rq.ifr_hwaddr.sa_family), hwaddr); } #elif defined (HAVE_GETIFADDRS) && defined (LLADDR) @@ -3821,29 +3798,64 @@ FLAGS is the current flags of the interface. */) #endif res = Fcons (elt, res); - close (s); + return unbind_to (count, any ? res : Qnil); +} +#endif /* !SIOCGIFADDR && !SIOCGIFHWADDR && !SIOCGIFFLAGS */ +#endif /* defined (HAVE_NET_IF_H) */ + +DEFUN ("network-interface-list", Fnetwork_interface_list, + Snetwork_interface_list, 0, 0, 0, + doc: /* Return an alist of all network interfaces and their network address. +Each element is a cons, the car of which is a string containing the +interface name, and the cdr is the network address in internal +format; see the description of ADDRESS in `make-network-process'. - return any ? res : Qnil; +If the information is not available, return nil. */) + (void) +{ +#if (defined HAVE_NET_IF_H && defined SIOCGIFCONF) || defined WINDOWSNT + return network_interface_list (); +#else + return Qnil; +#endif } + +DEFUN ("network-interface-info", Fnetwork_interface_info, + Snetwork_interface_info, 1, 1, 0, + doc: /* Return information about network interface named IFNAME. +The return value is a list (ADDR BCAST NETMASK HWADDR FLAGS), +where ADDR is the layer 3 address, BCAST is the layer 3 broadcast address, +NETMASK is the layer 3 network mask, HWADDR is the layer 2 address, and +FLAGS is the current flags of the interface. + +Data that is unavailable is returned as nil. */) + (Lisp_Object ifname) +{ +#if ((defined HAVE_NET_IF_H \ + && (defined SIOCGIFADDR || defined SIOCGIFHWADDR \ + || defined SIOCGIFFLAGS)) \ + || defined WINDOWSNT) + return network_interface_info (ifname); +#else + return Qnil; #endif -#endif /* defined (HAVE_NET_IF_H) */ +} + /* Turn off input and output for process PROC. */ 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) { @@ -3854,14 +3866,14 @@ deactivate_process (Lisp_Object proc) } #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 @@ -3886,13 +3898,14 @@ deactivate_process (Lisp_Object proc) #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; } } } @@ -3954,9 +3967,9 @@ Return non-nil if we received any output before the timeout expired. */) { if (XFLOAT_DATA (seconds) > 0) { - EMACS_TIME t = EMACS_TIME_FROM_DOUBLE (XFLOAT_DATA (seconds)); - secs = min (EMACS_SECS (t), WAIT_READING_MAX); - nsecs = EMACS_NSECS (t); + struct timespec t = dtotimespec (XFLOAT_DATA (seconds)); + secs = min (t.tv_sec, WAIT_READING_MAX); + nsecs = t.tv_nsec; } } else @@ -3997,6 +4010,7 @@ server_accept_connection (Lisp_Object server, int channel) #endif } saddr; socklen_t len = sizeof saddr; + ptrdiff_t count; s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC); @@ -4019,6 +4033,9 @@ server_accept_connection (Lisp_Object server, int channel) return; } + count = SPECPDL_INDEX (); + record_unwind_protect_int (close_file_unwind, s); + connect_counter++; /* Setup a new process to handle the connection. */ @@ -4135,6 +4152,11 @@ server_accept_connection (Lisp_Object server, int channel) 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); @@ -4188,11 +4210,10 @@ server_accept_connection (Lisp_Object server, int channel) 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. */ @@ -4246,14 +4267,14 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, struct Lisp_Process *wait_proc, int just_wait_proc) { int channel, nfds; - SELECT_TYPE Available; - SELECT_TYPE Writeok; + fd_set Available; + fd_set Writeok; bool check_write; int check_delay; bool no_avail; int xerrno; Lisp_Object proc; - EMACS_TIME timeout, end_time; + struct timespec timeout, end_time; int wait_channel = -1; bool got_some_input = 0; ptrdiff_t count = SPECPDL_INDEX (); @@ -4270,8 +4291,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, 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) @@ -4286,8 +4307,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, compute the absolute time to return at. */ if (time_limit || nsecs > 0) { - timeout = make_emacs_time (time_limit, nsecs); - end_time = add_emacs_time (current_emacs_time (), timeout); + timeout = make_timespec (time_limit, nsecs); + end_time = timespec_add (current_timespec (), timeout); } while (1) @@ -4314,18 +4335,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, gobble output available now but don't wait at all. */ - timeout = make_emacs_time (0, 0); + timeout = make_timespec (0, 0); } else if (time_limit || nsecs > 0) { - EMACS_TIME now = current_emacs_time (); - if (EMACS_TIME_LE (end_time, now)) + struct timespec now = current_timespec (); + if (timespec_cmp (end_time, now) <= 0) break; - timeout = sub_emacs_time (end_time, now); + timeout = timespec_sub (end_time, now); } else { - timeout = make_emacs_time (100000, 0); + timeout = make_timespec (100000, 0); } /* Normally we run timers here. @@ -4335,7 +4356,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, if (NILP (wait_for_cell) && just_wait_proc >= 0) { - EMACS_TIME timer_delay; + struct timespec timer_delay; do { @@ -4370,9 +4391,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, /* A negative timeout means do not wait at all. */ if (nsecs >= 0) { - if (EMACS_TIME_VALID_P (timer_delay)) + if (timespec_valid_p (timer_delay)) { - if (EMACS_TIME_LT (timer_delay, timeout)) + if (timespec_cmp (timer_delay, timeout) < 0) { timeout = timer_delay; timeout_reduced_for_timers = 1; @@ -4401,8 +4422,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, timeout to get our attention. */ if (update_tick != process_tick) { - SELECT_TYPE Atemp; - SELECT_TYPE Ctemp; + fd_set Atemp; + fd_set Ctemp; if (kbd_on_hold_p ()) FD_ZERO (&Atemp); @@ -4410,7 +4431,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, Atemp = input_wait_mask; Ctemp = write_mask; - timeout = make_emacs_time (0, 0); + timeout = make_timespec (0, 0); if ((pselect (max (max_process_desc, max_input_desc) + 1, &Atemp, #ifdef NON_BLOCKING_CONNECT @@ -4532,8 +4553,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, Vprocess_adaptive_read_buffering is nil. */ if (process_output_skip && check_delay > 0) { - int nsecs = EMACS_NSECS (timeout); - if (EMACS_SECS (timeout) > 0 || nsecs > READ_OUTPUT_DELAY_MAX) + int nsecs = timeout.tv_nsec; + if (timeout.tv_sec > 0 || nsecs > READ_OUTPUT_DELAY_MAX) nsecs = READ_OUTPUT_DELAY_MAX; for (channel = 0; check_delay > 0 && channel <= max_process_desc; channel++) { @@ -4553,7 +4574,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, nsecs = XPROCESS (proc)->read_output_delay; } } - timeout = make_emacs_time (0, nsecs); + timeout = make_timespec (0, nsecs); process_output_skip = 0; } #endif @@ -4567,7 +4588,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, #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 @@ -4585,12 +4606,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, the gnutls library -- 2.12.14 has been confirmed to need it. See http://comments.gmane.org/gmane.emacs.devel/145074 */ - for (channel = 0; channel < MAXDESC; ++channel) + for (channel = 0; channel < FD_SETSIZE; ++channel) if (! NILP (chan_process[channel])) { struct Lisp_Process *p = XPROCESS (chan_process[channel]); - if (p && p->gnutls_p && p->infd + if (p && p->gnutls_p && p->gnutls_state && p->infd && ((emacs_gnutls_record_check_pending (p->gnutls_state)) > 0)) @@ -4604,6 +4625,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, { /* Check this specific channel. */ if (wait_proc->gnutls_p /* Check for valid process. */ + && wait_proc->gnutls_state /* Do we have pending data? */ && ((emacs_gnutls_record_check_pending (wait_proc->gnutls_state)) @@ -4634,22 +4656,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, 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) @@ -4876,7 +4885,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, #else { struct sockaddr pname; - int pnamelen = sizeof (pname); + socklen_t pnamelen = sizeof (pname); /* If connection failed, getpeername will fail. */ xerrno = 0; @@ -4998,7 +5007,7 @@ read_process_output (Lisp_Object proc, register int channel) proc_buffered_char[channel] = -1; } #ifdef HAVE_GNUTLS - if (p->gnutls_p) + if (p->gnutls_p && p->gnutls_state) nbytes = emacs_gnutls_read (p, chars + carryover + buffered, readmax - buffered); else @@ -5148,9 +5157,7 @@ read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars, 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 (make_lisp_proc (p), - Fcons (text, Qnil))), + list3 (outstream, make_lisp_proc (p), text), !NILP (Vdebug_on_error) ? Qnil : Qerror, read_process_output_error_handler); @@ -5207,15 +5214,10 @@ DEFUN ("internal-default-process-filter", Finternal_default_process_filter, bset_read_only (current_buffer, Qnil); - /* Insert new output into buffer - at the current end-of-output marker, - thus preserving logical ordering of input and output. */ + /* 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) - SET_PT_BOTH (clip_to_bounds (BEGV, - marker_position (p->mark), ZV), - clip_to_bounds (BEGV_BYTE, - marker_byte_position (p->mark), - ZV_BYTE)); + set_point_from_marker (p->mark); else SET_PT_BOTH (ZV, ZV_BYTE); before = PT; @@ -5246,7 +5248,7 @@ DEFUN ("internal-default-process-filter", Finternal_default_process_filter, else set_marker_both (p->mark, p->buffer, PT, PT_BYTE); - update_mode_lines++; + update_mode_lines = 23; /* Make sure opoint and the old restrictions float ahead of any new text just as point would. */ @@ -5320,7 +5322,7 @@ write_queue_push (struct Lisp_Process *p, Lisp_Object input_obj, 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 @@ -5493,17 +5495,17 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len, 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 { #ifdef HAVE_GNUTLS - if (p->gnutls_p) + if (p->gnutls_p && p->gnutls_state) 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 @@ -5570,7 +5572,7 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len, } 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; @@ -5796,10 +5798,9 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group, return; } - switch (signo) - { #ifdef SIGCONT - case SIGCONT: + if (signo == SIGCONT) + { p->raw_status_new = 0; pset_status (p, Qrun); p->tick = ++process_tick; @@ -5808,14 +5809,8 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group, 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 @@ -6038,13 +6033,16 @@ process has been transmitted to the serial port. */) (Lisp_Object process) { Lisp_Object proc; - struct coding_system *coding; + struct coding_system *coding = NULL; + int outfd; if (DATAGRAM_CONN_P (process)) return process; proc = get_process (process); - coding = proc_encode_coding_system[XPROCESS (proc)->outfd]; + outfd = XPROCESS (proc)->outfd; + if (outfd >= 0) + coding = proc_encode_coding_system[outfd]; /* Make sure the process is really alive. */ if (XPROCESS (proc)->raw_status_new) @@ -6052,7 +6050,7 @@ process has been transmitted to the serial port. */) if (! EQ (XPROCESS (proc)->status, Qrun)) error ("Process %s not running", SDATA (XPROCESS (proc)->name)); - if (CODING_REQUIRE_FLUSHING (coding)) + if (coding && CODING_REQUIRE_FLUSHING (coding)) { coding->mode |= CODING_MODE_LAST_BLOCK; send_process (proc, "", 0, Qnil); @@ -6064,42 +6062,45 @@ process has been transmitted to the serial port. */) { #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; + struct Lisp_Process *p = XPROCESS (proc); + int old_outfd = p->outfd; + int new_outfd; #ifdef HAVE_SHUTDOWN /* If this is a network connection, or socketpair is used for communication with the subprocess, call shutdown to cause EOF. (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 */ + if (EQ (p->type, Qnetwork) + || p->infd == old_outfd) + shutdown (old_outfd, 1); +#endif + close_process_fd (&p->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); + p->open_fd[WRITE_TO_SUBPROCESS] = new_outfd; + p->outfd = new_outfd; if (!proc_encode_coding_system[new_outfd]) proc_encode_coding_system[new_outfd] = xmalloc (sizeof (struct coding_system)); - *proc_encode_coding_system[new_outfd] - = *proc_encode_coding_system[old_outfd]; - memset (proc_encode_coding_system[old_outfd], 0, - sizeof (struct coding_system)); - - XPROCESS (proc)->outfd = new_outfd; + if (old_outfd >= 0) + { + *proc_encode_coding_system[new_outfd] + = *proc_encode_coding_system[old_outfd]; + memset (proc_encode_coding_system[old_outfd], 0, + sizeof (struct coding_system)); + } + else + setup_coding_system (p->encode_coding_system, + proc_encode_coding_system[new_outfd]); } return process; } @@ -6165,7 +6166,7 @@ static signal_handler_t volatile lib_child_handler; static void handle_child_signal (int sig) { - Lisp_Object tail; + Lisp_Object tail, proc; /* Find the process that signaled us, and record its status. */ @@ -6176,7 +6177,11 @@ handle_child_signal (int sig) 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; @@ -6185,14 +6190,17 @@ handle_child_signal (int sig) 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; @@ -6296,8 +6304,7 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason) 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); @@ -6348,13 +6355,10 @@ status_notify (struct Lisp_Process *deleting_process) 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) { @@ -6398,7 +6402,7 @@ status_notify (struct Lisp_Process *deleting_process) } } /* end for */ - update_mode_lines++; /* In case buffers use %s in mode-line-format. */ + update_mode_lines = 24; /* In case buffers use %s in mode-line-format. */ UNGCPRO; } @@ -6579,8 +6583,8 @@ keyboard_bit_set (fd_set *mask) #else /* not subprocesses */ /* Defined on msdos.c. */ -extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, - EMACS_TIME *, void *); +extern int sys_select (int, fd_set *, fd_set *, fd_set *, + struct timespec *, void *); /* Implementation of wait_reading_process_output, assuming that there are no subprocesses. Used only by the MS-DOS build. @@ -6619,7 +6623,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, struct Lisp_Process *wait_proc, int just_wait_proc) { register int nfds; - EMACS_TIME end_time, timeout; + struct timespec end_time, timeout; if (time_limit < 0) { @@ -6632,8 +6636,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, /* What does time_limit really mean? */ if (time_limit || nsecs > 0) { - timeout = make_emacs_time (time_limit, nsecs); - end_time = add_emacs_time (current_emacs_time (), timeout); + timeout = make_timespec (time_limit, nsecs); + end_time = timespec_add (current_timespec (), timeout); } /* Turn off periodic alarms (in case they are in use) @@ -6645,7 +6649,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, while (1) { bool timeout_reduced_for_timers = 0; - SELECT_TYPE waitchannels; + fd_set waitchannels; int xerrno; /* If calling from keyboard input, do not quit @@ -6666,18 +6670,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, gobble output available now but don't wait at all. */ - timeout = make_emacs_time (0, 0); + timeout = make_timespec (0, 0); } else if (time_limit || nsecs > 0) { - EMACS_TIME now = current_emacs_time (); - if (EMACS_TIME_LE (end_time, now)) + struct timespec now = current_timespec (); + if (timespec_cmp (end_time, now) <= 0) break; - timeout = sub_emacs_time (end_time, now); + timeout = timespec_sub (end_time, now); } else { - timeout = make_emacs_time (100000, 0); + timeout = make_timespec (100000, 0); } /* If our caller will not immediately handle keyboard events, @@ -6686,7 +6690,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, call timer_delay on their own.) */ if (NILP (wait_for_cell)) { - EMACS_TIME timer_delay; + struct timespec timer_delay; do { @@ -6706,9 +6710,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, && requeued_events_pending_p ()) break; - if (EMACS_TIME_VALID_P (timer_delay) && nsecs >= 0) + if (timespec_valid_p (timer_delay) && nsecs >= 0) { - if (EMACS_TIME_LT (timer_delay, timeout)) + if (timespec_cmp (timer_delay, timeout) < 0) { timeout = timer_delay; timeout_reduced_for_timers = 1; @@ -6761,7 +6765,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, 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 */ @@ -6827,16 +6831,9 @@ void 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 } @@ -6884,12 +6881,9 @@ 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; } @@ -6922,18 +6916,14 @@ kill_buffer_processes (Lisp_Object buffer) #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 */ @@ -7101,7 +7091,7 @@ init_process_emacs (void) 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 @@ -7123,7 +7113,7 @@ init_process_emacs (void) Vprocess_alist = Qnil; deleted_pid_list = Qnil; - for (i = 0; i < MAXDESC; i++) + for (i = 0; i < FD_SETSIZE; i++) { chan_process[i] = Qnil; proc_buffered_char[i] = -1; @@ -7351,14 +7341,8 @@ The variable takes effect when `start-process' is called. */); defsubr (&Sset_network_process_option); defsubr (&Smake_network_process); defsubr (&Sformat_network_address); -#if defined (HAVE_NET_IF_H) -#ifdef SIOCGIFCONF defsubr (&Snetwork_interface_list); -#endif -#if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS) defsubr (&Snetwork_interface_info); -#endif -#endif /* defined (HAVE_NET_IF_H) */ #ifdef DATAGRAM_SOCKETS defsubr (&Sprocess_datagram_address); defsubr (&Sset_process_datagram_address);