mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-07 12:20:39 -08:00
Avoid hangs in accept-process-output.
* lisp.h, process.c (wait_reading_process_input): Return int, not bool. All uses changed. * process.c (SELECT_CANT_DO_WRITE_MASK): Remove macro, replacing with ... (SELECT_CAN_DO_WRITE_MASK): ... new constant, with inverted sense. All uses changed. (status_notify): New arg WAIT_PROC. Return int, not void. All uses changed. Fixes: debbugs:17647
This commit is contained in:
parent
99961a049f
commit
05d282102d
3 changed files with 78 additions and 62 deletions
|
|
@ -1,3 +1,15 @@
|
|||
2014-06-13 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Avoid hangs in accept-process-output (Bug#17647).
|
||||
* lisp.h, process.c (wait_reading_process_input):
|
||||
Return int, not bool. All uses changed.
|
||||
* process.c (SELECT_CANT_DO_WRITE_MASK):
|
||||
Remove macro, replacing with ...
|
||||
(SELECT_CAN_DO_WRITE_MASK): ... new constant, with inverted sense.
|
||||
All uses changed.
|
||||
(status_notify): New arg WAIT_PROC. Return int, not void.
|
||||
All uses changed.
|
||||
|
||||
2014-06-13 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* menu.c (Fx_popup_menu): Don't call the frame's menu_show_hook if
|
||||
|
|
|
|||
|
|
@ -4178,10 +4178,8 @@ extern bool running_asynch_code;
|
|||
/* Defined in process.c. */
|
||||
extern Lisp_Object QCtype, Qlocal;
|
||||
extern void kill_buffer_processes (Lisp_Object);
|
||||
extern bool wait_reading_process_output (intmax_t, int, int, bool,
|
||||
Lisp_Object,
|
||||
struct Lisp_Process *,
|
||||
int);
|
||||
extern int wait_reading_process_output (intmax_t, int, int, bool, Lisp_Object,
|
||||
struct Lisp_Process *, int);
|
||||
/* Max value for the first argument of wait_reading_process_output. */
|
||||
#if __GNUC__ == 3 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 5)
|
||||
/* Work around a bug in GCC 3.4.2, known to be fixed in GCC 4.6.3.
|
||||
|
|
|
|||
122
src/process.c
122
src/process.c
|
|
@ -224,8 +224,9 @@ static EMACS_INT update_tick;
|
|||
/* Only W32 has this, it really means that select can't take write mask. */
|
||||
#ifdef BROKEN_NON_BLOCKING_CONNECT
|
||||
#undef NON_BLOCKING_CONNECT
|
||||
#define SELECT_CANT_DO_WRITE_MASK
|
||||
enum { SELECT_CAN_DO_WRITE_MASK = false };
|
||||
#else
|
||||
enum { SELECT_CAN_DO_WRITE_MASK = true };
|
||||
#ifndef NON_BLOCKING_CONNECT
|
||||
#ifdef HAVE_SELECT
|
||||
#if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX)
|
||||
|
|
@ -281,7 +282,7 @@ static void create_process (Lisp_Object, char **, Lisp_Object);
|
|||
static bool keyboard_bit_set (fd_set *);
|
||||
#endif
|
||||
static void deactivate_process (Lisp_Object);
|
||||
static void status_notify (struct Lisp_Process *);
|
||||
static int status_notify (struct Lisp_Process *, struct Lisp_Process *);
|
||||
static int read_process_output (Lisp_Object, int);
|
||||
static void handle_child_signal (int);
|
||||
static void create_pty (Lisp_Object);
|
||||
|
|
@ -860,7 +861,7 @@ nil, indicating the current buffer's process. */)
|
|||
{
|
||||
pset_status (p, list2 (Qexit, make_number (0)));
|
||||
p->tick = ++process_tick;
|
||||
status_notify (p);
|
||||
status_notify (p, NULL);
|
||||
redisplay_preserve_echo_area (13);
|
||||
}
|
||||
else
|
||||
|
|
@ -880,7 +881,7 @@ nil, indicating the current buffer's process. */)
|
|||
pset_status (p, list2 (Qsignal, make_number (SIGKILL)));
|
||||
|
||||
p->tick = ++process_tick;
|
||||
status_notify (p);
|
||||
status_notify (p, NULL);
|
||||
redisplay_preserve_echo_area (13);
|
||||
}
|
||||
}
|
||||
|
|
@ -3986,12 +3987,13 @@ is nil, from any process) before the timeout expired. */)
|
|||
nsecs = 0;
|
||||
|
||||
return
|
||||
(wait_reading_process_output (secs, nsecs, 0, 0,
|
||||
((wait_reading_process_output (secs, nsecs, 0, 0,
|
||||
Qnil,
|
||||
!NILP (process) ? XPROCESS (process) : NULL,
|
||||
NILP (just_this_one) ? 0 :
|
||||
!INTEGERP (just_this_one) ? 1 : -1)
|
||||
? Qt : Qnil);
|
||||
<= 0)
|
||||
? Qnil : Qt);
|
||||
}
|
||||
|
||||
/* Accept a connection for server process SERVER on CHANNEL. */
|
||||
|
|
@ -4262,10 +4264,11 @@ wait_reading_process_output_1 (void)
|
|||
(suspending output from other processes). A negative value
|
||||
means don't run any timers either.
|
||||
|
||||
Return true if we received input from WAIT_PROC, or from any
|
||||
process if WAIT_PROC is null. */
|
||||
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. */
|
||||
|
||||
bool
|
||||
int
|
||||
wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
||||
bool do_display,
|
||||
Lisp_Object wait_for_cell,
|
||||
|
|
@ -4280,8 +4283,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
int xerrno;
|
||||
Lisp_Object proc;
|
||||
struct timespec timeout, end_time;
|
||||
int wait_channel = -1;
|
||||
bool got_some_input = 0;
|
||||
int got_some_input = -1;
|
||||
ptrdiff_t count = SPECPDL_INDEX ();
|
||||
|
||||
FD_ZERO (&Available);
|
||||
|
|
@ -4292,10 +4294,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
&& EQ (XCAR (wait_proc->status), Qexit)))
|
||||
message1 ("Blocking call to accept-process-output with quit inhibited!!");
|
||||
|
||||
/* If wait_proc is a process to watch, set wait_channel accordingly. */
|
||||
if (wait_proc != NULL)
|
||||
wait_channel = wait_proc->infd;
|
||||
|
||||
record_unwind_protect_int (wait_reading_process_output_unwind,
|
||||
waiting_for_user_input_p);
|
||||
waiting_for_user_input_p = read_kbd;
|
||||
|
|
@ -4332,6 +4330,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
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)
|
||||
|
|
@ -4450,7 +4452,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
/* 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 ();
|
||||
status_notify (NULL);
|
||||
got_some_input = status_notify (NULL, wait_proc);
|
||||
if (do_display) redisplay_preserve_echo_area (13);
|
||||
}
|
||||
}
|
||||
|
|
@ -4472,18 +4474,23 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
while (wait_proc->infd >= 0)
|
||||
{
|
||||
int nread = read_process_output (proc, wait_proc->infd);
|
||||
|
||||
if (nread == 0)
|
||||
break;
|
||||
|
||||
if (nread > 0)
|
||||
got_some_input = read_some_bytes = 1;
|
||||
else if (nread == -1 && (errno == EIO || errno == EAGAIN))
|
||||
break;
|
||||
if (nread < 0)
|
||||
{
|
||||
if (errno == EIO || errno == EAGAIN)
|
||||
break;
|
||||
#ifdef EWOULDBLOCK
|
||||
else if (nread == -1 && EWOULDBLOCK == errno)
|
||||
break;
|
||||
if (errno == EWOULDBLOCK)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (got_some_input < nread)
|
||||
got_some_input = nread;
|
||||
if (nread == 0)
|
||||
break;
|
||||
read_some_bytes = true;
|
||||
}
|
||||
}
|
||||
if (read_some_bytes && do_display)
|
||||
redisplay_preserve_echo_area (10);
|
||||
|
|
@ -4514,12 +4521,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
else
|
||||
Available = input_wait_mask;
|
||||
Writeok = write_mask;
|
||||
#ifdef SELECT_CANT_DO_WRITE_MASK
|
||||
check_write = 0;
|
||||
#else
|
||||
check_write = 1;
|
||||
#endif
|
||||
check_delay = wait_channel >= 0 ? 0 : process_output_delay_count;
|
||||
check_delay = wait_proc ? 0 : process_output_delay_count;
|
||||
check_write = SELECT_CAN_DO_WRITE_MASK;
|
||||
}
|
||||
|
||||
/* If frame size has changed or the window is newly mapped,
|
||||
|
|
@ -4545,6 +4548,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
{
|
||||
nfds = read_kbd ? 0 : 1;
|
||||
no_avail = 1;
|
||||
FD_ZERO (&Available);
|
||||
}
|
||||
|
||||
if (!no_avail)
|
||||
|
|
@ -4554,7 +4558,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
/* 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
|
||||
specific wait_channel. It is not executed if
|
||||
specific process. It is not executed if
|
||||
Vprocess_adaptive_read_buffering is nil. */
|
||||
if (process_output_skip && check_delay > 0)
|
||||
{
|
||||
|
|
@ -4667,12 +4671,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
report_file_errno ("Failed select", Qnil, xerrno);
|
||||
}
|
||||
|
||||
if (no_avail)
|
||||
{
|
||||
FD_ZERO (&Available);
|
||||
check_write = 0;
|
||||
}
|
||||
|
||||
/* Check for keyboard input */
|
||||
/* If there is any, return immediately
|
||||
to give it higher priority than subprocesses */
|
||||
|
|
@ -4739,9 +4737,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
handle_input_available_signal (SIGIO);
|
||||
#endif
|
||||
|
||||
if (! wait_proc)
|
||||
got_some_input |= nfds > 0;
|
||||
|
||||
/* If checking input just got us a size-change event from X,
|
||||
obey it now if we should. */
|
||||
if (read_kbd || ! NILP (wait_for_cell))
|
||||
|
|
@ -4773,12 +4768,6 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
/* If waiting for this channel, arrange to return as
|
||||
soon as no more input to be processed. No more
|
||||
waiting. */
|
||||
if (wait_channel == channel)
|
||||
{
|
||||
wait_channel = -1;
|
||||
nsecs = -1;
|
||||
got_some_input = 1;
|
||||
}
|
||||
proc = chan_process[channel];
|
||||
if (NILP (proc))
|
||||
continue;
|
||||
|
|
@ -4794,6 +4783,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
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 (nread > 0)
|
||||
{
|
||||
/* Since read_process_output can run a filter,
|
||||
|
|
@ -5814,7 +5805,7 @@ process_send_signal (Lisp_Object process, int signo, Lisp_Object current_group,
|
|||
p->tick = ++process_tick;
|
||||
if (!nomsg)
|
||||
{
|
||||
status_notify (NULL);
|
||||
status_notify (NULL, NULL);
|
||||
redisplay_preserve_echo_area (13);
|
||||
}
|
||||
}
|
||||
|
|
@ -6337,14 +6328,20 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
|
|||
/* Report all recent events of a change in process status
|
||||
(either run the sentinel or output a message).
|
||||
This is usually done while Emacs is waiting for keyboard input
|
||||
but can be done at other times. */
|
||||
but can be done at other times.
|
||||
|
||||
static void
|
||||
status_notify (struct Lisp_Process *deleting_process)
|
||||
Return positive if any input was received from WAIT_PROC (or from
|
||||
any process if WAIT_PROC is null), zero if input was attempted but
|
||||
none received, and negative if we didn't even try. */
|
||||
|
||||
static int
|
||||
status_notify (struct Lisp_Process *deleting_process,
|
||||
struct Lisp_Process *wait_proc)
|
||||
{
|
||||
register Lisp_Object proc;
|
||||
Lisp_Object proc;
|
||||
Lisp_Object tail, msg;
|
||||
struct gcpro gcpro1, gcpro2;
|
||||
int got_some_input = -1;
|
||||
|
||||
tail = Qnil;
|
||||
msg = Qnil;
|
||||
|
|
@ -6374,8 +6371,14 @@ status_notify (struct Lisp_Process *deleting_process)
|
|||
/* Network or serial process not stopped: */
|
||||
&& ! EQ (p->command, Qt)
|
||||
&& p->infd >= 0
|
||||
&& p != deleting_process
|
||||
&& read_process_output (proc, p->infd) > 0);
|
||||
&& p != deleting_process)
|
||||
{
|
||||
int nread = read_process_output (proc, p->infd);
|
||||
if (got_some_input < nread)
|
||||
got_some_input = nread;
|
||||
if (nread <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the text to use for the message. */
|
||||
if (p->raw_status_new)
|
||||
|
|
@ -6407,6 +6410,7 @@ status_notify (struct Lisp_Process *deleting_process)
|
|||
|
||||
update_mode_lines = 24; /* In case buffers use %s in mode-line-format. */
|
||||
UNGCPRO;
|
||||
return got_some_input;
|
||||
}
|
||||
|
||||
DEFUN ("internal-default-process-sentinel", Finternal_default_process_sentinel,
|
||||
|
|
@ -6618,9 +6622,11 @@ extern int sys_select (int, fd_set *, fd_set *, fd_set *,
|
|||
DO_DISPLAY means redisplay should be done to show subprocess
|
||||
output that arrives.
|
||||
|
||||
Return true if we received input from any process. */
|
||||
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. */
|
||||
|
||||
bool
|
||||
int
|
||||
wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
||||
bool do_display,
|
||||
Lisp_Object wait_for_cell,
|
||||
|
|
@ -6808,7 +6814,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
|
|||
|
||||
start_polling ();
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* not subprocesses */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue