/* Asynchronous subprocess control for GNU Emacs.
-Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2015 Free Software
+Copyright (C) 1985-1988, 1993-1996, 1998-1999, 2001-2016 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "coding.h"
#include "process.h"
#include "frame.h"
-#include "termhooks.h"
#include "termopts.h"
-#include "commands.h"
#include "keyboard.h"
#include "blockinput.h"
-#include "dispextern.h"
-#include "composite.h"
#include "atimer.h"
#include "sysselect.h"
#include "syssignal.h"
# define HAVE_SEQPACKET
#endif
-#if !defined (ADAPTIVE_READ_BUFFERING) && !defined (NO_ADAPTIVE_READ_BUFFERING)
-#define ADAPTIVE_READ_BUFFERING
-#endif
-
-#ifdef ADAPTIVE_READ_BUFFERING
#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)
static bool process_output_skip;
-#else
-#define process_output_delay_count 0
-#endif
-
static void create_process (Lisp_Object, char **, Lisp_Object);
#ifdef USABLE_SIGIO
static bool keyboard_bit_set (fd_set *);
if (fd >= 0)
{
-#ifdef PTY_OPEN
+#ifdef PTY_TTY_NAME_SPRINTF
+ PTY_TTY_NAME_SPRINTF
+#else
+ sprintf (pty_name, "/dev/tty%c%x", c, i);
+#endif /* no PTY_TTY_NAME_SPRINTF */
+
/* 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.
+ Do this after PTY_TTY_NAME_SPRINTF, which on some platforms
+ doesn't work if the close-on-exec flag is set (Bug#20555).
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
- PTY_TTY_NAME_SPRINTF
-#else
- sprintf (pty_name, "/dev/tty%c%x", c, i);
-#endif /* no PTY_TTY_NAME_SPRINTF */
+
+ /* Check to make certain that both sides are available.
+ This avoids a nasty yet stupid bug in rlogins. */
if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0)
{
emacs_close (fd);
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. */)
+ doc: /* Tell PROCESS that it has logical window size WIDTH by HEIGHT.
+Value is t if PROCESS was successfully told about the window size,
+nil otherwise. */)
(Lisp_Object process, Lisp_Object height, Lisp_Object width)
{
CHECK_PROCESS (process);
Lisp_Object buffer, name, command, program, proc, contact, current_dir, tem;
Lisp_Object xstderr, stderrproc;
ptrdiff_t count = SPECPDL_INDEX ();
- struct gcpro gcpro1;
USE_SAFE_ALLOCA;
if (nargs == 0)
/* Save arguments for process-contact and clone-process. */
contact = Flist (nargs, args);
- GCPRO1 (contact);
buffer = Fplist_get (contact, QCbuffer);
if (!NILP (buffer))
/* Make sure that the child will be able to chdir to the current
buffer's current directory, or its unhandled equivalent. We
can't just have the child check for an error when it does the
- chdir, since it's in a vfork.
-
- We have to GCPRO around this because Fexpand_file_name and
- Funhandled_file_name_directory might call a file name handling
- function. The argument list is protected by the caller, so all
- we really have to worry about is buffer. */
- {
- struct gcpro gcpro1;
- GCPRO1 (buffer);
- current_dir = encode_current_directory ();
- UNGCPRO;
- }
+ chdir, since it's in a vfork. */
+ current_dir = encode_current_directory ();
name = Fplist_get (contact, QCname);
CHECK_STRING (name);
}
else if (!NILP (xstderr))
{
- struct gcpro gcpro1, gcpro2;
CHECK_STRING (program);
- GCPRO2 (buffer, current_dir);
stderrproc = CALLN (Fmake_pipe_process,
QCname,
concat2 (name, build_string (" stderr")),
QCbuffer,
Fget_buffer_create (xstderr));
- UNGCPRO;
}
proc = make_process (name);
pset_gnutls_cred_type (XPROCESS (proc), Qnil);
#endif
-#ifdef ADAPTIVE_READ_BUFFERING
XPROCESS (proc)->adaptive_read_buffering
= (NILP (Vprocess_adaptive_read_buffering) ? 0
: EQ (Vprocess_adaptive_read_buffering, Qt) ? 1 : 2);
-#endif
/* Make the process marker point into the process buffer (if any). */
if (BUFFERP (buffer))
/* Qt denotes we have not yet called Ffind_operation_coding_system. */
Lisp_Object coding_systems = Qt;
Lisp_Object val, *args2;
- struct gcpro gcpro1, gcpro2;
tem = Fplist_get (contact, QCcoding);
if (!NILP (tem))
args2[i++] = buffer;
for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
args2[i++] = XCAR (tem2);
- GCPRO2 (proc, current_dir);
if (!NILP (program))
coding_systems = Ffind_operation_coding_system (nargs2, args2);
- UNGCPRO;
if (CONSP (coding_systems))
val = XCAR (coding_systems);
else if (CONSP (Vdefault_process_coding_system))
args2[i++] = buffer;
for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
args2[i++] = XCAR (tem2);
- GCPRO2 (proc, current_dir);
if (!NILP (program))
coding_systems = Ffind_operation_coding_system (nargs2, args2);
- UNGCPRO;
}
if (CONSP (coding_systems))
val = XCDR (coding_systems);
&& !(SCHARS (program) > 1
&& IS_DEVICE_SEP (SREF (program, 1))))
{
- struct gcpro gcpro1, gcpro2;
-
tem = Qnil;
- GCPRO2 (buffer, current_dir);
openp (Vexec_path, program, Vexec_suffixes, &tem,
make_number (X_OK), false);
- UNGCPRO;
if (NILP (tem))
report_file_error ("Searching for program", program);
tem = Fexpand_file_name (tem, Qnil);
tem = remove_slash_colon (tem);
Lisp_Object arg_encoding = Qnil;
- struct gcpro gcpro1;
- GCPRO1 (tem);
/* Encode the file name and put it in NEW_ARGV.
That's where the child will use it to execute the program. */
new_argc++;
}
- UNGCPRO;
-
/* Now that everything is encoded we can collect the strings into
NEW_ARGV. */
char **new_argv;
else
create_pty (proc);
- UNGCPRO;
SAFE_FREE ();
return unbind_to (count, proc);
}
#ifndef WINDOWSNT
/* 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;
- int volatile forkerr_volatile = forkerr;
- 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;
- forkerr = forkerr_volatile;
- p = p_volatile;
-
- pty_flag = p->pty_flag;
- }
+ 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;
+ int volatile forkerr_volatile = forkerr;
+ 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;
+ forkerr = forkerr_volatile;
+ p = p_volatile;
+
+ pty_flag = p->pty_flag;
if (pid == 0)
#endif /* not WINDOWSNT */
{
- int xforkin = forkin;
- int xforkout = forkout;
- int xforkerr = forkerr;
-
/* Make the pty be the controlling terminal of the process. */
#ifdef HAVE_PTYS
/* First, disconnect its current controlling terminal. */
process_set_signal to fail on SGI when using a pipe. */
setsid ();
/* Make the pty's terminal the controlling terminal. */
- if (pty_flag && xforkin >= 0)
+ if (pty_flag && forkin >= 0)
{
#ifdef TIOCSCTTY
/* We ignore the return value
because faith@cs.unc.edu says that is necessary on Linux. */
- ioctl (xforkin, TIOCSCTTY, 0);
+ ioctl (forkin, TIOCSCTTY, 0);
#endif
}
#if defined (LDISC1)
- if (pty_flag && xforkin >= 0)
+ if (pty_flag && forkin >= 0)
{
struct termios t;
- tcgetattr (xforkin, &t);
+ tcgetattr (forkin, &t);
t.c_lflag = LDISC1;
- if (tcsetattr (xforkin, TCSANOW, &t) < 0)
+ if (tcsetattr (forkin, TCSANOW, &t) < 0)
emacs_perror ("create_process/tcsetattr LDISC1");
}
#else
#if defined (NTTYDISC) && defined (TIOCSETD)
- if (pty_flag && xforkin >= 0)
+ if (pty_flag && forkin >= 0)
{
/* Use new line discipline. */
int ldisc = NTTYDISC;
- ioctl (xforkin, TIOCSETD, &ldisc);
+ ioctl (forkin, TIOCSETD, &ldisc);
}
#endif
#endif
/* I wonder if emacs_close (emacs_open (SSDATA (lisp_pty_name), ...))
would work? */
- if (xforkin >= 0)
- emacs_close (xforkin);
- xforkout = xforkin = emacs_open (SSDATA (lisp_pty_name), O_RDWR, 0);
+ if (forkin >= 0)
+ emacs_close (forkin);
+ forkout = forkin = emacs_open (SSDATA (lisp_pty_name), O_RDWR, 0);
- if (xforkin < 0)
+ if (forkin < 0)
{
emacs_perror (SSDATA (lisp_pty_name));
_exit (EXIT_CANCELED);
unblock_child_signal (&oldset);
if (pty_flag)
- child_setup_tty (xforkout);
+ child_setup_tty (forkout);
- if (xforkerr < 0)
- xforkerr = xforkout;
+ if (forkerr < 0)
+ forkerr = forkout;
#ifdef WINDOWSNT
- pid = child_setup (xforkin, xforkout, xforkerr, new_argv, 1, current_dir);
+ pid = child_setup (forkin, forkout, forkerr, new_argv, 1, current_dir);
#else /* not WINDOWSNT */
- child_setup (xforkin, xforkout, xforkerr, new_argv, 1, current_dir);
+ child_setup (forkin, forkout, forkerr, new_argv, 1, current_dir);
#endif /* not WINDOWSNT */
}
{
Lisp_Object proc, contact;
struct Lisp_Process *p;
- struct gcpro gcpro1;
Lisp_Object name, buffer;
Lisp_Object tem;
ptrdiff_t specpdl_count;
return Qnil;
contact = Flist (nargs, args);
- GCPRO1 (contact);
name = Fplist_get (contact, QCname);
CHECK_STRING (name);
FD_SET (inchannel, &input_wait_mask);
FD_SET (inchannel, &non_keyboard_wait_mask);
}
-#ifdef ADAPTIVE_READ_BUFFERING
p->adaptive_read_buffering
= (NILP (Vprocess_adaptive_read_buffering) ? 0
: EQ (Vprocess_adaptive_read_buffering, Qt) ? 1 : 2);
-#endif
/* Make the process marker point into the process buffer (if any). */
if (BUFFERP (buffer))
specpdl_ptr = specpdl + specpdl_count;
- UNGCPRO;
return proc;
}
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr;
- len = sizeof (sin6->sin6_addr) + 1;
+ len = sizeof (sin6->sin6_addr) / 2 + 1;
hostport = XINT (p->contents[--len]);
sin6->sin6_port = htons (hostport);
for (i = 0; i < len; i++)
\(serial-process-configure :process "/dev/ttyS0" :speed 1200)
\(serial-process-configure
- :buffer "COM1" :stopbits 1 :parity 'odd :flowcontrol 'hw)
+ :buffer "COM1" :stopbits 1 :parity \\='odd :flowcontrol \\='hw)
\(serial-process-configure :port "\\\\.\\COM13" :bytesize 7)
struct Lisp_Process *p;
Lisp_Object contact = Qnil;
Lisp_Object proc = Qnil;
- struct gcpro gcpro1;
contact = Flist (nargs, args);
- GCPRO1 (contact);
proc = Fplist_get (contact, QCprocess);
if (NILP (proc))
error ("Not a serial process");
if (NILP (Fplist_get (p->childp, QCspeed)))
- {
- UNGCPRO;
- return Qnil;
- }
+ return Qnil;
serial_configure (p, contact);
-
- UNGCPRO;
return Qnil;
}
\(make-serial-process :port "COM1" :speed 115200 :stopbits 2)
-\(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity 'odd)
+\(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity \\='odd)
\(make-serial-process :port "/dev/tty.BlueConsole-SPP-1" :speed nil)
int fd = -1;
Lisp_Object proc, contact, port;
struct Lisp_Process *p;
- struct gcpro gcpro1;
Lisp_Object name, buffer;
Lisp_Object tem, val;
ptrdiff_t specpdl_count;
return Qnil;
contact = Flist (nargs, args);
- GCPRO1 (contact);
port = Fplist_get (contact, QCport);
if (NILP (port))
specpdl_ptr = specpdl + specpdl_count;
- UNGCPRO;
return proc;
}
int ret = 0;
int xerrno = 0;
int s = -1, outch, inch;
- struct gcpro gcpro1;
ptrdiff_t count = SPECPDL_INDEX ();
ptrdiff_t count1;
Lisp_Object colon_address; /* Either QClocal or QCremote. */
/* Save arguments for process-contact and clone-process. */
contact = Flist (nargs, args);
- GCPRO1 (contact);
#ifdef WINDOWSNT
/* Ensure socket support is loaded if available. */
{
/* Setup coding systems for communicating with the network stream. */
- struct gcpro gcpro1;
/* Qt denotes we have not yet called Ffind_operation_coding_system. */
Lisp_Object coding_systems = Qt;
Lisp_Object val;
if (NILP (host) || NILP (service))
coding_systems = Qnil;
else
- {
- GCPRO1 (proc);
- coding_systems = CALLN (Ffind_operation_coding_system,
- Qopen_network_stream, name, buffer,
- host, service);
- UNGCPRO;
- }
+ coding_systems = CALLN (Ffind_operation_coding_system,
+ Qopen_network_stream, name, buffer,
+ host, service);
if (CONSP (coding_systems))
val = XCAR (coding_systems);
else if (CONSP (Vdefault_process_coding_system))
if (NILP (host) || NILP (service))
coding_systems = Qnil;
else
- {
- GCPRO1 (proc);
- coding_systems = CALLN (Ffind_operation_coding_system,
- Qopen_network_stream, name, buffer,
- host, service);
- UNGCPRO;
- }
+ coding_systems = CALLN (Ffind_operation_coding_system,
+ Qopen_network_stream, name, buffer,
+ host, service);
}
if (CONSP (coding_systems))
val = XCDR (coding_systems);
p->inherit_coding_system_flag
= !(!NILP (tem) || NILP (buffer) || !inherit_process_coding_system);
- UNGCPRO;
return proc;
}
#endif
}
-/* If program file NAME starts with /: for quoting a magic
- name, remove that, preserving the multibyteness of NAME. */
-
-Lisp_Object
-remove_slash_colon (Lisp_Object name)
-{
- return
- ((SBYTES (name) > 2 && SREF (name, 0) == '/' && SREF (name, 1) == ':')
- ? make_specified_string (SSDATA (name) + 2, SCHARS (name) - 2,
- SBYTES (name) - 2, STRING_MULTIBYTE (name))
- : name);
-}
-
/* Turn off input and output for process PROC. */
static void
emacs_gnutls_deinit (proc);
#endif /* HAVE_GNUTLS */
-#ifdef ADAPTIVE_READ_BUFFERING
if (p->read_output_delay > 0)
{
if (--process_output_delay_count < 0)
p->read_output_delay = 0;
p->read_output_skip = 0;
}
-#endif
/* Beware SIGCHLD hereabouts. */
bool no_avail;
int xerrno;
Lisp_Object proc;
- struct timespec timeout, end_time;
- int got_some_input = -1;
+ struct timespec timeout, end_time, timer_delay;
+ struct timespec got_output_end_time = invalid_timespec ();
+ enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
+ int got_some_output = -1;
ptrdiff_t count = SPECPDL_INDEX ();
+ /* Close to the current time if known, an invalid timespec otherwise. */
+ struct timespec now = invalid_timespec ();
+
FD_ZERO (&Available);
FD_ZERO (&Writeok);
waiting_for_user_input_p);
waiting_for_user_input_p = read_kbd;
- if (time_limit < 0)
- {
- time_limit = 0;
- nsecs = -1;
- }
- else if (TYPE_MAXIMUM (time_t) < time_limit)
+ if (TYPE_MAXIMUM (time_t) < time_limit)
time_limit = TYPE_MAXIMUM (time_t);
- /* Since we may need to wait several times,
- compute the absolute time to return at. */
- if (time_limit || nsecs > 0)
+ if (time_limit < 0 || nsecs < 0)
+ wait = MINIMUM;
+ else if (time_limit > 0 || nsecs > 0)
{
- timeout = make_timespec (time_limit, nsecs);
- end_time = timespec_add (current_timespec (), timeout);
+ wait = TIMEOUT;
+ now = current_timespec ();
+ end_time = timespec_add (now, make_timespec (time_limit, nsecs));
}
+ else
+ wait = INFINITY;
while (1)
{
- bool timeout_reduced_for_timers = false;
+ bool process_skipped = false;
/* If calling from keyboard input, do not quit
since we want to return C-g as an input character.
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
break;
- /* After reading input, vacuum up any leftovers without waiting. */
- if (0 <= got_some_input)
- nsecs = -1;
-
/* Compute time from now till when time limit is up. */
/* Exit if already run out. */
- if (nsecs < 0)
+ if (wait == TIMEOUT)
{
- /* A negative timeout means
- gobble output available now
- but don't wait at all. */
-
- timeout = make_timespec (0, 0);
- }
- else if (time_limit || nsecs > 0)
- {
- struct timespec now = current_timespec ();
+ if (!timespec_valid_p (now))
+ now = current_timespec ();
if (timespec_cmp (end_time, now) <= 0)
break;
timeout = timespec_sub (end_time, now);
}
else
- {
- timeout = make_timespec (100000, 0);
- }
+ timeout = make_timespec (wait < TIMEOUT ? 0 : 100000, 0);
/* Normally we run timers here.
But not if wait_for_cell; in those cases,
if (NILP (wait_for_cell)
&& just_wait_proc >= 0)
{
- struct timespec timer_delay;
-
do
{
unsigned old_timers_run = timers_run;
&& requeued_events_pending_p ())
break;
- /* A negative timeout means do not wait at all. */
- if (nsecs >= 0)
- {
- if (timespec_valid_p (timer_delay))
- {
- if (timespec_cmp (timer_delay, timeout) < 0)
- {
- timeout = timer_delay;
- timeout_reduced_for_timers = true;
- }
- }
- else
- {
- /* This is so a breakpoint can be put here. */
- wait_reading_process_output_1 ();
- }
- }
- }
+ /* This is so a breakpoint can be put here. */
+ if (!timespec_valid_p (timer_delay))
+ wait_reading_process_output_1 ();
+ }
/* Cause C-g and alarm signals to take immediate action,
and cause input available signals to zero out timeout.
/* It's okay for us to do this and then continue with
the loop, since timeout has already been zeroed out. */
clear_waiting_for_input ();
- got_some_input = status_notify (NULL, wait_proc);
+ got_some_output = status_notify (NULL, wait_proc);
if (do_display) redisplay_preserve_echo_area (13);
}
}
}
else
{
- if (got_some_input < nread)
- got_some_input = nread;
+ if (got_some_output < nread)
+ got_some_output = nread;
if (nread == 0)
break;
read_some_bytes = true;
no_avail = 1;
FD_ZERO (&Available);
}
-
- if (!no_avail)
+ else
{
-
-#ifdef ADAPTIVE_READ_BUFFERING
/* Set the timeout for adaptive read buffering if any
process has non-zero read_output_skip and non-zero
read_output_delay, and we are not reading output for a
Vprocess_adaptive_read_buffering is nil. */
if (process_output_skip && check_delay > 0)
{
- int nsecs = timeout.tv_nsec;
- if (timeout.tv_sec > 0 || nsecs > READ_OUTPUT_DELAY_MAX)
- nsecs = READ_OUTPUT_DELAY_MAX;
+ int adaptive_nsecs = timeout.tv_nsec;
+ if (timeout.tv_sec > 0 || adaptive_nsecs > READ_OUTPUT_DELAY_MAX)
+ adaptive_nsecs = READ_OUTPUT_DELAY_MAX;
for (channel = 0; check_delay > 0 && channel <= max_process_desc; channel++)
{
proc = chan_process[channel];
if (!XPROCESS (proc)->read_output_skip)
continue;
FD_CLR (channel, &Available);
+ process_skipped = true;
XPROCESS (proc)->read_output_skip = 0;
- if (XPROCESS (proc)->read_output_delay < nsecs)
- nsecs = XPROCESS (proc)->read_output_delay;
+ if (XPROCESS (proc)->read_output_delay < adaptive_nsecs)
+ adaptive_nsecs = XPROCESS (proc)->read_output_delay;
}
}
- timeout = make_timespec (0, nsecs);
+ timeout = make_timespec (0, adaptive_nsecs);
process_output_skip = 0;
}
-#endif
+
+ /* If we've got some output and haven't limited our timeout
+ with adaptive read buffering, limit it. */
+ if (got_some_output > 0 && !process_skipped
+ && (timeout.tv_sec
+ || timeout.tv_nsec > READ_OUTPUT_DELAY_INCREMENT))
+ timeout = make_timespec (0, READ_OUTPUT_DELAY_INCREMENT);
+
+
+ if (NILP (wait_for_cell) && just_wait_proc >= 0
+ && timespec_valid_p (timer_delay)
+ && timespec_cmp (timer_delay, timeout) < 0)
+ {
+ if (!timespec_valid_p (now))
+ now = current_timespec ();
+ struct timespec timeout_abs = timespec_add (now, timeout);
+ if (!timespec_valid_p (got_output_end_time)
+ || timespec_cmp (timeout_abs, got_output_end_time) < 0)
+ got_output_end_time = timeout_abs;
+ timeout = timer_delay;
+ }
+ else
+ got_output_end_time = invalid_timespec ();
+
+ /* NOW can become inaccurate if time can pass during pselect. */
+ if (timeout.tv_sec > 0 || timeout.tv_nsec > 0)
+ now = invalid_timespec ();
#if defined (HAVE_NS)
nfds = ns_select
data is available in the buffers manually. */
if (nfds == 0)
{
+ fd_set tls_available;
+ int set = 0;
+
+ FD_ZERO (&tls_available);
if (! wait_proc)
{
/* We're not waiting on a specific process, so loop
{
nfds++;
eassert (p->infd == channel);
- FD_SET (p->infd, &Available);
+ FD_SET (p->infd, &tls_available);
+ set++;
}
}
}
nfds = 1;
eassert (0 <= wait_proc->infd);
/* Set to Available. */
- FD_SET (wait_proc->infd, &Available);
+ FD_SET (wait_proc->infd, &tls_available);
+ set++;
}
}
+ if (set)
+ Available = tls_available;
}
#endif
}
/* If we woke up due to SIGWINCH, actually change size now. */
do_pending_window_change (0);
- if ((time_limit || nsecs) && nfds == 0 && ! timeout_reduced_for_timers)
- /* We waited the full specified time, so return now. */
- break;
+ if (nfds == 0)
+ {
+ /* Exit the main loop if we've passed the requested timeout,
+ or aren't skipping processes and got some output and
+ haven't lowered our timeout due to timers or SIGIO and
+ have waited a long amount of time due to repeated
+ timers. */
+ if (wait < TIMEOUT)
+ break;
+ struct timespec cmp_time
+ = (wait == TIMEOUT
+ ? end_time
+ : (!process_skipped && got_some_output > 0
+ && (timeout.tv_sec > 0 || timeout.tv_nsec > 0))
+ ? got_output_end_time
+ : invalid_timespec ());
+ if (timespec_valid_p (cmp_time))
+ {
+ now = current_timespec ();
+ if (timespec_cmp (cmp_time, now) <= 0)
+ break;
+ }
+ }
+
if (nfds < 0)
{
if (xerrno == EINTR)
buffered-ahead character if we have one. */
nread = read_process_output (proc, channel);
- if ((!wait_proc || wait_proc == XPROCESS (proc)) && got_some_input < nread)
- got_some_input = nread;
+ if ((!wait_proc || wait_proc == XPROCESS (proc))
+ && got_some_output < nread)
+ got_some_output = nread;
if (nread > 0)
{
+ /* Vacuum up any leftovers without waiting. */
+ if (wait_proc == XPROCESS (proc))
+ wait = MINIMUM;
/* Since read_process_output can run a filter,
which can call accept-process-output,
don't try to read from any other processes
QUIT;
}
- return got_some_input;
+ return got_some_output;
}
\f
/* Given a list (FUNCTION ARGS...), apply FUNCTION to the ARGS. */
#endif
nbytes = emacs_read (channel, chars + carryover + buffered,
readmax - buffered);
-#ifdef ADAPTIVE_READ_BUFFERING
if (nbytes > 0 && p->adaptive_read_buffering)
{
int delay = p->read_output_delay;
process_output_skip = 1;
}
}
-#endif
nbytes += buffered;
nbytes += buffered && nbytes <= 0;
}
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);
#endif
written = emacs_write_sig (outfd, cur_buf, cur_len);
rv = (written ? 0 : -1);
-#ifdef ADAPTIVE_READ_BUFFERING
if (p->read_output_delay > 0
&& p->adaptive_read_buffering == 1)
{
process_output_delay_count--;
p->read_output_skip = 0;
}
-#endif
}
if (rv < 0)
{
Lisp_Object process_number
= string_to_number (SSDATA (process), 10, 1);
- if (INTEGERP (process_number) || FLOATP (process_number))
+ if (NUMBERP (process_number))
tem = process_number;
}
process = tem;
if (inhibit_sentinels)
return;
- /* 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. */
odeactivate = Vdeactivate_mark;
#if 0
Lisp_Object obuffer, okeymap;
{
Lisp_Object proc;
Lisp_Object tail, msg;
- struct gcpro gcpro1, gcpro2;
- int got_some_input = -1;
+ int got_some_output = -1;
tail = Qnil;
msg = Qnil;
- /* We need to gcpro tail; if read_process_output calls a filter
- which deletes a process and removes the cons to which tail points
- from Vprocess_alist, and then causes a GC, tail is an unprotected
- reference. */
- GCPRO2 (tail, msg);
/* Set this now, so that if new processes are created by sentinels
that we run, we get called again to handle their status changes. */
&& p != deleting_process)
{
int nread = read_process_output (proc, p->infd);
- if (got_some_input < nread)
- got_some_input = nread;
+ if ((!wait_proc || wait_proc == XPROCESS (proc))
+ && got_some_output < nread)
+ got_some_output = nread;
if (nread <= 0)
break;
}
p->update_tick = p->tick;
/* Now output the message suitably. */
exec_sentinel (proc, msg);
+ if (BUFFERP (p->buffer))
+ /* In case it uses %s in mode-line-format. */
+ bset_update_mode_line (XBUFFER (p->buffer));
}
} /* end for */
- update_mode_lines = 24; /* In case buffers use %s in mode-line-format. */
- UNGCPRO;
- return got_some_input;
+ return got_some_output;
}
DEFUN ("internal-default-process-sentinel", Finternal_default_process_sentinel,
DO_DISPLAY means redisplay should be done to show subprocess
output that arrives.
- Return positive if we received input from WAIT_PROC (or from any
- process if WAIT_PROC is null), zero if we attempted to receive
- input but got none, and negative if we didn't even try. */
+ Return -1 signifying we got no output and did not try. */
int
wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
{
register int nfds;
struct timespec end_time, timeout;
+ enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
- if (time_limit < 0)
- {
- time_limit = 0;
- nsecs = -1;
- }
- else if (TYPE_MAXIMUM (time_t) < time_limit)
+ if (TYPE_MAXIMUM (time_t) < time_limit)
time_limit = TYPE_MAXIMUM (time_t);
- /* What does time_limit really mean? */
- if (time_limit || nsecs > 0)
+ if (time_limit < 0 || nsecs < 0)
+ wait = MINIMUM;
+ else if (time_limit > 0 || nsecs > 0)
{
- timeout = make_timespec (time_limit, nsecs);
- end_time = timespec_add (current_timespec (), timeout);
+ wait = TIMEOUT;
+ end_time = timespec_add (current_timespec (),
+ make_timespec (time_limit, nsecs));
}
+ else
+ wait = INFINITY;
/* Turn off periodic alarms (in case they are in use)
and then turn off any other atimers,
/* 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. */
-
- timeout = make_timespec (0, 0);
- }
- else if (time_limit || nsecs > 0)
+ if (wait == TIMEOUT)
{
struct timespec now = current_timespec ();
if (timespec_cmp (end_time, now) <= 0)
timeout = timespec_sub (end_time, now);
}
else
- {
- timeout = make_timespec (100000, 0);
- }
+ timeout = make_timespec (wait < TIMEOUT ? 0 : 100000, 0);
/* If our caller will not immediately handle keyboard events,
run timer events directly.
&& requeued_events_pending_p ())
break;
- if (timespec_valid_p (timer_delay) && nsecs >= 0)
+ if (timespec_valid_p (timer_delay))
{
if (timespec_cmp (timer_delay, timeout) < 0)
{
/* If we woke up due to SIGWINCH, actually change size now. */
do_pending_window_change (0);
- if ((time_limit || nsecs) && nfds == 0 && ! timeout_reduced_for_timers)
+ if (wait < INFINITY && nfds == 0 && ! timeout_reduced_for_timers)
/* We waited the full specified time, so return now. */
break;
#endif /* HAVE_TIMERFD */
+/* If program file NAME starts with /: for quoting a magic
+ name, remove that, preserving the multibyteness of NAME. */
+
+Lisp_Object
+remove_slash_colon (Lisp_Object name)
+{
+ return
+ ((SBYTES (name) > 2 && SREF (name, 0) == '/' && SREF (name, 1) == ':')
+ ? make_specified_string (SSDATA (name) + 2, SCHARS (name) - 2,
+ SBYTES (name) - 2, STRING_MULTIBYTE (name))
+ : name);
+}
+
/* Add DESC to the set of keyboard input descriptors. */
void
}
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. */)
+ doc: /* Return the (or a) live process associated with BUFFER.
+BUFFER may be a buffer or the name of one.
+Return nil if all processes associated with BUFFER have been
+deleted or killed. */)
(register Lisp_Object buffer)
{
#ifdef subprocesses
Value is an alist where each element is a cons cell of the form
- \(KEY . VALUE)
+ (KEY . VALUE)
If this functionality is unsupported, the value is nil.
num_pending_connects = 0;
#endif
-#ifdef ADAPTIVE_READ_BUFFERING
process_output_delay_count = 0;
process_output_skip = 0;
-#endif
/* Don't do this, it caused infinite select loops. The display
method should call add_keyboard_wait_descriptor on stdin if it
DEFSYM (QClog, ":log");
DEFSYM (QCnoquery, ":noquery");
DEFSYM (QCstop, ":stop");
- DEFSYM (QCoptions, ":options");
DEFSYM (QCplist, ":plist");
DEFSYM (QCcommand, ":command");
DEFSYM (QCconnection_type, ":connection-type");
The value takes effect when `start-process' is called. */);
Vprocess_connection_type = Qt;
-#ifdef ADAPTIVE_READ_BUFFERING
DEFVAR_LISP ("process-adaptive-read-buffering", Vprocess_adaptive_read_buffering,
doc: /* If non-nil, improve receive buffering by delaying after short reads.
On some systems, when Emacs reads the output from a subprocess, the output data
non-nil value means that the delay is not reset on write.
The variable takes effect when `start-process' is called. */);
Vprocess_adaptive_read_buffering = Qt;
-#endif
defsubr (&Sprocessp);
defsubr (&Sget_process);
defsubr (&Sset_process_filter_multibyte);
defsubr (&Sprocess_filter_multibyte_p);
-#endif /* subprocesses */
-
- defsubr (&Sget_buffer_process);
- defsubr (&Sprocess_inherit_coding_system_flag);
- defsubr (&Slist_system_processes);
- defsubr (&Sprocess_attributes);
-
{
Lisp_Object subfeatures = Qnil;
const struct socket_options *sopt;
Fprovide (intern_c_string ("make-network-process"), subfeatures);
}
+#endif /* subprocesses */
+
+ defsubr (&Sget_buffer_process);
+ defsubr (&Sprocess_inherit_coding_system_flag);
+ defsubr (&Slist_system_processes);
+ defsubr (&Sprocess_attributes);
}