aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2012-11-23 14:20:31 -0800
committerPaul Eggert2012-11-23 14:20:31 -0800
commit6d4e8f62e93b575a1da2cd2b4abeb9dce56e1e52 (patch)
tree2d3564ca26405db0e887bea037dcc175d85cc753 /src
parent002c019c34eeb1cad4ce8f5ae721b1cdf22f0946 (diff)
downloademacs-6d4e8f62e93b575a1da2cd2b4abeb9dce56e1e52.tar.gz
emacs-6d4e8f62e93b575a1da2cd2b4abeb9dce56e1e52.zip
Fix a race condition with glib (Bug#8855).
This is a backport from the trunk, consisting of: 2012-11-17 Eli Zaretskii <eliz@gnu.org> * nt/inc/sys/wait.h: New file, with prototype of waitpid and definitions of macros it needs. * nt/inc/ms-w32.h (wait): Don't define, 'wait' is not used anymore. (sys_wait): Remove prototype. * nt/config.nt (HAVE_SYS_WAIT_H): Define to 1. * src/w32proc.c (create_child): Don't clip the PID of the child process to fit into an Emacs integer, as this is no longer a restriction. (waitpid): Rename from sys_wait. Emulate a Posix 'waitpid' by reaping only the process specified by PID argument, if that is positive. Use PID instead of dead_child to know which process to reap. Wait for the child to die only if WNOHANG is not in OPTIONS. (sys_select): Don't set dead_child. * src/sysdep.c (wait_for_termination_1): Remove the WINDOWSNT portion, as it is no longer needed. * src/process.c (waitpid, WUNTRACED) [!WNOHANG]: Remove definitions, no longer needed. (record_child_status_change): Remove the setting of record_at_most_one_child for the !WNOHANG case. 2012-11-03 Paul Eggert <eggert@cs.ucla.edu> Fix a race condition that causes Emacs to mess up glib (Bug#8855). This is a backport from the trunk. The symptom is a diagnostic "GLib-WARNING **: In call to g_spawn_sync(), exit status of a child process was requested but SIGCHLD action was set to SIG_IGN and ECHILD was received by waitpid(), so exit status can't be returned." The diagnostic is partly wrong, as the SIGCHLD action is not set to SIG_IGN. The real bug is a race condition between Emacs and glib: Emacs does a waitpid (-1, ...) and reaps glib's subprocess by mistake, so that glib can't find it. Work around the bug by invoking waitpid only on subprocesses that Emacs itself creates. * src/process.c (create_process, record_child_status_change): Don't use special value -1 in pid field, as the caller now must know the pid rather than having the callee infer it. The inference was sometimes incorrect anyway, due to another race. (create_process): Set new 'alive' member if child is created. (process_status_retrieved): New function. (record_child_status_change): Use it. Accept negative 1st argument, which means to wait for the processes that Emacs already knows about. Move special-case code for DOS_NT (which lacks WNOHANG) here, from caller. Keep track of processes that have already been waited for, by testing and clearing new 'alive' member. (CAN_HANDLE_MULTIPLE_CHILDREN): Remove, as record_child_status_change now does this internally. (handle_child_signal): Let record_child_status_change do all the work, since we do not want to reap all exited child processes, only the child processes that Emacs itself created. * src/process.h (Lisp_Process): New boolean member 'alive'.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog57
-rw-r--r--src/process.c191
-rw-r--r--src/process.h3
-rw-r--r--src/sysdep.c7
-rw-r--r--src/w32proc.c127
5 files changed, 240 insertions, 145 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 88fbf7a99f2..655eb1595c0 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,60 @@
12012-11-23 Paul Eggert <eggert@cs.ucla.edu>
2
3 Fix a race condition with glib (Bug#8855).
4 This is a backport from the trunk, consisting of:
5
6 2012-11-17 Eli Zaretskii <eliz@gnu.org>
7
8 * w32proc.c (create_child): Don't clip the PID of the child
9 process to fit into an Emacs integer, as this is no longer a
10 restriction.
11 (waitpid): Rename from sys_wait. Emulate a Posix 'waitpid' by
12 reaping only the process specified by PID argument, if that is
13 positive. Use PID instead of dead_child to know which process to
14 reap. Wait for the child to die only if WNOHANG is not in
15 OPTIONS.
16 (sys_select): Don't set dead_child.
17
18 * sysdep.c (wait_for_termination_1): Remove the WINDOWSNT portion,
19 as it is no longer needed.
20
21 * process.c (waitpid, WUNTRACED) [!WNOHANG]: Remove definitions,
22 no longer needed.
23 (record_child_status_change): Remove the setting of
24 record_at_most_one_child for the !WNOHANG case.
25
26 2012-11-03 Paul Eggert <eggert@cs.ucla.edu>
27
28 Fix a race condition that causes Emacs to mess up glib (Bug#8855).
29 This is a backport from the trunk.
30 The symptom is a diagnostic "GLib-WARNING **: In call to
31 g_spawn_sync(), exit status of a child process was requested but
32 SIGCHLD action was set to SIG_IGN and ECHILD was received by
33 waitpid(), so exit status can't be returned." The diagnostic
34 is partly wrong, as the SIGCHLD action is not set to SIG_IGN.
35 The real bug is a race condition between Emacs and glib: Emacs
36 does a waitpid (-1, ...) and reaps glib's subprocess by mistake,
37 so that glib can't find it. Work around the bug by invoking
38 waitpid only on subprocesses that Emacs itself creates.
39 * process.c (create_process, record_child_status_change):
40 Don't use special value -1 in pid field, as the caller now must
41 know the pid rather than having the callee infer it. The
42 inference was sometimes incorrect anyway, due to another race.
43 (create_process): Set new 'alive' member if child is created.
44 (process_status_retrieved): New function.
45 (record_child_status_change): Use it.
46 Accept negative 1st argument, which means to wait for the
47 processes that Emacs already knows about. Move special-case code
48 for DOS_NT (which lacks WNOHANG) here, from caller. Keep track of
49 processes that have already been waited for, by testing and
50 clearing new 'alive' member.
51 (CAN_HANDLE_MULTIPLE_CHILDREN): Remove, as record_child_status_change
52 now does this internally.
53 (handle_child_signal): Let record_child_status_change do all
54 the work, since we do not want to reap all exited child processes,
55 only the child processes that Emacs itself created.
56 * process.h (Lisp_Process): New boolean member 'alive'.
57
12012-11-23 Eli Zaretskii <eliz@gnu.org> 582012-11-23 Eli Zaretskii <eliz@gnu.org>
2 59
3 * xdisp.c (set_cursor_from_row): Skip step 2 only if point is not 60 * xdisp.c (set_cursor_from_row): Skip step 2 only if point is not
diff --git a/src/process.c b/src/process.c
index 77e99ead01f..c095d13293b 100644
--- a/src/process.c
+++ b/src/process.c
@@ -130,14 +130,6 @@ extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
130 EMACS_TIME *, void *); 130 EMACS_TIME *, void *);
131#endif 131#endif
132 132
133#ifndef WNOHANG
134# undef waitpid
135# define waitpid(pid, status, options) wait (status)
136#endif
137#ifndef WUNTRACED
138# define WUNTRACED 0
139#endif
140
141/* Work around GCC 4.7.0 bug with strict overflow checking; see 133/* Work around GCC 4.7.0 bug with strict overflow checking; see
142 <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>. 134 <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>.
143 These lines can be removed once the GCC bug is fixed. */ 135 These lines can be removed once the GCC bug is fixed. */
@@ -795,9 +787,8 @@ get_process (register Lisp_Object name)
795#ifdef SIGCHLD 787#ifdef SIGCHLD
796/* Fdelete_process promises to immediately forget about the process, but in 788/* Fdelete_process promises to immediately forget about the process, but in
797 reality, Emacs needs to remember those processes until they have been 789 reality, Emacs needs to remember those processes until they have been
798 treated by the SIGCHLD handler; otherwise this handler would consider the 790 treated by the SIGCHLD handler and waitpid has been invoked on them;
799 process as being synchronous and say that the synchronous process is 791 otherwise they might fill up the kernel's process table. */
800 dead. */
801static Lisp_Object deleted_pid_list; 792static Lisp_Object deleted_pid_list;
802#endif 793#endif
803 794
@@ -1704,16 +1695,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
1704 if (inchannel > max_process_desc) 1695 if (inchannel > max_process_desc)
1705 max_process_desc = inchannel; 1696 max_process_desc = inchannel;
1706 1697
1707 /* Until we store the proper pid, enable the SIGCHLD handler 1698 /* This may signal an error. */
1708 to recognize an unknown pid as standing for this process.
1709 It is very important not to let this `marker' value stay
1710 in the table after this function has returned; if it does
1711 it might cause call-process to hang and subsequent asynchronous
1712 processes to get their return values scrambled. */
1713 XPROCESS (process)->pid = -1;
1714
1715 /* This must be called after the above line because it may signal an
1716 error. */
1717 setup_process_coding_systems (process); 1699 setup_process_coding_systems (process);
1718 1700
1719 encoded_current_dir = ENCODE_FILE (current_dir); 1701 encoded_current_dir = ENCODE_FILE (current_dir);
@@ -1880,6 +1862,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
1880#endif 1862#endif
1881 1863
1882 XPROCESS (process)->pid = pid; 1864 XPROCESS (process)->pid = pid;
1865 if (0 <= pid)
1866 XPROCESS (process)->alive = 1;
1883 1867
1884 /* Stop blocking signals in the parent. */ 1868 /* Stop blocking signals in the parent. */
1885#ifdef SIGCHLD 1869#ifdef SIGCHLD
@@ -6273,9 +6257,35 @@ process has been transmitted to the serial port. */)
6273 return process; 6257 return process;
6274} 6258}
6275 6259
6276/* On receipt of a signal that a child status has changed, loop asking 6260/* If the status of the process DESIRED has changed, return true and
6277 about children with changed statuses until the system says there 6261 set *STATUS to its exit status; otherwise, return false.
6278 are no more. 6262 If HAVE is nonnegative, assume that HAVE = waitpid (HAVE, STATUS, ...)
6263 has already been invoked, and do not invoke waitpid again. */
6264
6265static bool
6266process_status_retrieved (pid_t desired, pid_t have, int *status)
6267{
6268 if (have < 0)
6269 {
6270 /* Invoke waitpid only with a known process ID; do not invoke
6271 waitpid with a nonpositive argument. Otherwise, Emacs might
6272 reap an unwanted process by mistake. For example, invoking
6273 waitpid (-1, ...) can mess up glib by reaping glib's subprocesses,
6274 so that another thread running glib won't find them. */
6275 do
6276 have = waitpid (desired, status, WNOHANG | WUNTRACED);
6277 while (have < 0 && errno == EINTR);
6278 }
6279
6280 return have == desired;
6281}
6282
6283/* If PID is nonnegative, the child process PID with wait status W has
6284 changed its status; record this and return true.
6285
6286 If PID is negative, ignore W, and look for known child processes
6287 of Emacs whose status have changed. For each one found, record its new
6288 status.
6279 6289
6280 All we do is change the status; we do not run sentinels or print 6290 All we do is change the status; we do not run sentinels or print
6281 notifications. That is saved for the next time keyboard input is 6291 notifications. That is saved for the next time keyboard input is
@@ -6298,13 +6308,15 @@ process has been transmitted to the serial port. */)
6298 ** Malloc WARNING: This should never call malloc either directly or 6308 ** Malloc WARNING: This should never call malloc either directly or
6299 indirectly; if it does, that is a bug */ 6309 indirectly; if it does, that is a bug */
6300 6310
6301/* Record the changed status of the child process PID with wait status W. */
6302void 6311void
6303record_child_status_change (pid_t pid, int w) 6312record_child_status_change (pid_t pid, int w)
6304{ 6313{
6305#ifdef SIGCHLD 6314#ifdef SIGCHLD
6306 Lisp_Object proc; 6315
6307 struct Lisp_Process *p; 6316 /* On POSIXish hosts, record at most one child only if we already
6317 know one child that has exited. */
6318 bool record_at_most_one_child = 0 <= pid;
6319
6308 Lisp_Object tail; 6320 Lisp_Object tail;
6309 6321
6310 /* Find the process that signaled us, and record its status. */ 6322 /* Find the process that signaled us, and record its status. */
@@ -6312,68 +6324,69 @@ record_child_status_change (pid_t pid, int w)
6312 /* The process can have been deleted by Fdelete_process. */ 6324 /* The process can have been deleted by Fdelete_process. */
6313 for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) 6325 for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail))
6314 { 6326 {
6327 bool all_pids_are_fixnums
6328 = (MOST_NEGATIVE_FIXNUM <= TYPE_MINIMUM (pid_t)
6329 && TYPE_MAXIMUM (pid_t) <= MOST_POSITIVE_FIXNUM);
6315 Lisp_Object xpid = XCAR (tail); 6330 Lisp_Object xpid = XCAR (tail);
6316 if ((INTEGERP (xpid) && pid == XINT (xpid)) 6331 if (all_pids_are_fixnums ? INTEGERP (xpid) : NUMBERP (xpid))
6317 || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid)))
6318 { 6332 {
6319 XSETCAR (tail, Qnil); 6333 pid_t deleted_pid;
6320 return; 6334 if (INTEGERP (xpid))
6335 deleted_pid = XINT (xpid);
6336 else
6337 deleted_pid = XFLOAT_DATA (xpid);
6338 if (process_status_retrieved (deleted_pid, pid, &w))
6339 {
6340 XSETCAR (tail, Qnil);
6341 if (record_at_most_one_child)
6342 return;
6343 }
6321 } 6344 }
6322 } 6345 }
6323 6346
6324 /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */ 6347 /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */
6325 p = 0;
6326 for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) 6348 for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
6327 { 6349 {
6328 proc = XCDR (XCAR (tail)); 6350 Lisp_Object proc = XCDR (XCAR (tail));
6329 p = XPROCESS (proc); 6351 struct Lisp_Process *p = XPROCESS (proc);
6330 if (EQ (p->type, Qreal) && p->pid == pid) 6352 if (p->alive && process_status_retrieved (p->pid, pid, &w))
6331 break; 6353 {
6332 p = 0; 6354 /* Change the status of the process that was found. */
6333 } 6355 p->tick = ++process_tick;
6334 6356 p->raw_status = w;
6335 /* Look for an asynchronous process whose pid hasn't been filled 6357 p->raw_status_new = 1;
6336 in yet. */
6337 if (! p)
6338 for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
6339 {
6340 proc = XCDR (XCAR (tail));
6341 p = XPROCESS (proc);
6342 if (p->pid == -1)
6343 break;
6344 p = 0;
6345 }
6346 6358
6347 /* Change the status of the process that was found. */ 6359 /* If process has terminated, stop waiting for its output. */
6348 if (p) 6360 if (WIFSIGNALED (w) || WIFEXITED (w))
6349 { 6361 {
6350 int clear_desc_flag = 0; 6362 int clear_desc_flag = 0;
6363 p->alive = 0;
6364 if (p->infd >= 0)
6365 clear_desc_flag = 1;
6351 6366
6352 p->tick = ++process_tick; 6367 /* clear_desc_flag avoids a compiler bug in Microsoft C. */
6353 p->raw_status = w; 6368 if (clear_desc_flag)
6354 p->raw_status_new = 1; 6369 {
6370 FD_CLR (p->infd, &input_wait_mask);
6371 FD_CLR (p->infd, &non_keyboard_wait_mask);
6372 }
6373 }
6355 6374
6356 /* If process has terminated, stop waiting for its output. */ 6375 /* Tell wait_reading_process_output that it needs to wake up and
6357 if ((WIFSIGNALED (w) || WIFEXITED (w)) 6376 look around. */
6358 && p->infd >= 0) 6377 if (input_available_clear_time)
6359 clear_desc_flag = 1; 6378 *input_available_clear_time = make_emacs_time (0, 0);
6360 6379
6361 /* We use clear_desc_flag to avoid a compiler bug in Microsoft C. */ 6380 if (record_at_most_one_child)
6362 if (clear_desc_flag) 6381 return;
6363 {
6364 FD_CLR (p->infd, &input_wait_mask);
6365 FD_CLR (p->infd, &non_keyboard_wait_mask);
6366 } 6382 }
6367
6368 /* Tell wait_reading_process_output that it needs to wake up and
6369 look around. */
6370 if (input_available_clear_time)
6371 *input_available_clear_time = make_emacs_time (0, 0);
6372 } 6383 }
6373 /* There was no asynchronous process found for that pid: we have 6384
6374 a synchronous process. */ 6385 if (0 <= pid)
6375 else
6376 { 6386 {
6387 /* The caller successfully waited for a pid but no asynchronous
6388 process was found for it, so this is a synchronous process. */
6389
6377 synch_process_alive = 0; 6390 synch_process_alive = 0;
6378 6391
6379 /* Report the status of the synchronous process. */ 6392 /* Report the status of the synchronous process. */
@@ -6392,38 +6405,10 @@ record_child_status_change (pid_t pid, int w)
6392 6405
6393#ifdef SIGCHLD 6406#ifdef SIGCHLD
6394 6407
6395/* On some systems, the SIGCHLD handler must return right away. If
6396 any more processes want to signal us, we will get another signal.
6397 Otherwise, loop around to use up all the processes that have
6398 something to tell us. */
6399#if (defined WINDOWSNT \
6400 || (defined USG && !defined GNU_LINUX \
6401 && !(defined HPUX && defined WNOHANG)))
6402enum { CAN_HANDLE_MULTIPLE_CHILDREN = 0 };
6403#else
6404enum { CAN_HANDLE_MULTIPLE_CHILDREN = 1 };
6405#endif
6406
6407static void 6408static void
6408handle_child_signal (int sig) 6409handle_child_signal (int sig)
6409{ 6410{
6410 do 6411 record_child_status_change (-1, 0);
6411 {
6412 pid_t pid;
6413 int status;
6414
6415 do
6416 pid = waitpid (-1, &status, WNOHANG | WUNTRACED);
6417 while (pid < 0 && errno == EINTR);
6418
6419 /* PID == 0 means no processes found, PID == -1 means a real failure.
6420 Either way, we have done all our job. */
6421 if (pid <= 0)
6422 break;
6423
6424 record_child_status_change (pid, status);
6425 }
6426 while (CAN_HANDLE_MULTIPLE_CHILDREN);
6427} 6412}
6428 6413
6429static void 6414static void
diff --git a/src/process.h b/src/process.h
index ce3d2e702cc..74d1a124060 100644
--- a/src/process.h
+++ b/src/process.h
@@ -142,6 +142,9 @@ struct Lisp_Process
142 /* Flag to set coding-system of the process buffer from the 142 /* Flag to set coding-system of the process buffer from the
143 coding_system used to decode process output. */ 143 coding_system used to decode process output. */
144 unsigned int inherit_coding_system_flag : 1; 144 unsigned int inherit_coding_system_flag : 1;
145 /* Whether the process is alive, i.e., can be waited for. Running
146 processes can be waited for, but exited and fake processes cannot. */
147 unsigned int alive : 1;
145 /* Record the process status in the raw form in which it comes from `wait'. 148 /* Record the process status in the raw form in which it comes from `wait'.
146 This is to avoid consing in a signal handler. The `raw_status_new' 149 This is to avoid consing in a signal handler. The `raw_status_new'
147 flag indicates that `raw_status' contains a new status that still 150 flag indicates that `raw_status' contains a new status that still
diff --git a/src/sysdep.c b/src/sysdep.c
index 63eac5d9e09..bb81353847b 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -289,10 +289,6 @@ wait_for_termination_1 (pid_t pid, int interruptible)
289{ 289{
290 while (1) 290 while (1)
291 { 291 {
292#ifdef WINDOWSNT
293 wait (0);
294 break;
295#else /* not WINDOWSNT */
296 int status; 292 int status;
297 int wait_result = waitpid (pid, &status, 0); 293 int wait_result = waitpid (pid, &status, 0);
298 if (wait_result < 0) 294 if (wait_result < 0)
@@ -306,7 +302,8 @@ wait_for_termination_1 (pid_t pid, int interruptible)
306 break; 302 break;
307 } 303 }
308 304
309#endif /* not WINDOWSNT */ 305 /* Note: the MS-Windows emulation of waitpid calls QUIT
306 internally. */
310 if (interruptible) 307 if (interruptible)
311 QUIT; 308 QUIT;
312 } 309 }
diff --git a/src/w32proc.c b/src/w32proc.c
index e3c54fe5460..b4f2099f06a 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -783,7 +783,6 @@ alarm (int seconds)
783/* Child process management list. */ 783/* Child process management list. */
784int child_proc_count = 0; 784int child_proc_count = 0;
785child_process child_procs[ MAX_CHILDREN ]; 785child_process child_procs[ MAX_CHILDREN ];
786child_process *dead_child = NULL;
787 786
788static DWORD WINAPI reader_thread (void *arg); 787static DWORD WINAPI reader_thread (void *arg);
789 788
@@ -1036,9 +1035,6 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
1036 if (cp->pid < 0) 1035 if (cp->pid < 0)
1037 cp->pid = -cp->pid; 1036 cp->pid = -cp->pid;
1038 1037
1039 /* pid must fit in a Lisp_Int */
1040 cp->pid = cp->pid & INTMASK;
1041
1042 *pPid = cp->pid; 1038 *pPid = cp->pid;
1043 1039
1044 return TRUE; 1040 return TRUE;
@@ -1114,55 +1110,110 @@ reap_subprocess (child_process *cp)
1114 delete_child (cp); 1110 delete_child (cp);
1115} 1111}
1116 1112
1117/* Wait for any of our existing child processes to die 1113/* Wait for a child process specified by PID, or for any of our
1118 When it does, close its handle 1114 existing child processes (if PID is nonpositive) to die. When it
1119 Return the pid and fill in the status if non-NULL. */ 1115 does, close its handle. Return the pid of the process that died
1116 and fill in STATUS if non-NULL. */
1120 1117
1121int 1118pid_t
1122sys_wait (int *status) 1119waitpid (pid_t pid, int *status, int options)
1123{ 1120{
1124 DWORD active, retval; 1121 DWORD active, retval;
1125 int nh; 1122 int nh;
1126 int pid;
1127 child_process *cp, *cps[MAX_CHILDREN]; 1123 child_process *cp, *cps[MAX_CHILDREN];
1128 HANDLE wait_hnd[MAX_CHILDREN]; 1124 HANDLE wait_hnd[MAX_CHILDREN];
1125 DWORD timeout_ms;
1126 int dont_wait = (options & WNOHANG) != 0;
1129 1127
1130 nh = 0; 1128 nh = 0;
1131 if (dead_child != NULL) 1129 /* According to Posix:
1130
1131 PID = -1 means status is requested for any child process.
1132
1133 PID > 0 means status is requested for a single child process
1134 whose pid is PID.
1135
1136 PID = 0 means status is requested for any child process whose
1137 process group ID is equal to that of the calling process. But
1138 since Windows has only a limited support for process groups (only
1139 for console processes and only for the purposes of passing
1140 Ctrl-BREAK signal to them), and since we have no documented way
1141 of determining whether a given process belongs to our group, we
1142 treat 0 as -1.
1143
1144 PID < -1 means status is requested for any child process whose
1145 process group ID is equal to the absolute value of PID. Again,
1146 since we don't support process groups, we treat that as -1. */
1147 if (pid > 0)
1132 { 1148 {
1133 /* We want to wait for a specific child */ 1149 int our_child = 0;
1134 wait_hnd[nh] = dead_child->procinfo.hProcess; 1150
1135 cps[nh] = dead_child; 1151 /* We are requested to wait for a specific child. */
1136 if (!wait_hnd[nh]) emacs_abort (); 1152 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1137 nh++; 1153 {
1138 active = 0; 1154 /* Some child_procs might be sockets; ignore them. Also
1139 goto get_result; 1155 ignore subprocesses whose output is not yet completely
1156 read. */
1157 if (CHILD_ACTIVE (cp)
1158 && cp->procinfo.hProcess
1159 && cp->pid == pid)
1160 {
1161 our_child = 1;
1162 break;
1163 }
1164 }
1165 if (our_child)
1166 {
1167 if (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)
1168 {
1169 wait_hnd[nh] = cp->procinfo.hProcess;
1170 cps[nh] = cp;
1171 nh++;
1172 }
1173 else if (dont_wait)
1174 {
1175 /* PID specifies our subprocess, but its status is not
1176 yet available. */
1177 return 0;
1178 }
1179 }
1180 if (nh == 0)
1181 {
1182 /* No such child process, or nothing to wait for, so fail. */
1183 errno = ECHILD;
1184 return -1;
1185 }
1140 } 1186 }
1141 else 1187 else
1142 { 1188 {
1143 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) 1189 for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
1144 /* some child_procs might be sockets; ignore them */ 1190 {
1145 if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess 1191 if (CHILD_ACTIVE (cp)
1146 && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) 1192 && cp->procinfo.hProcess
1147 { 1193 && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0))
1148 wait_hnd[nh] = cp->procinfo.hProcess; 1194 {
1149 cps[nh] = cp; 1195 wait_hnd[nh] = cp->procinfo.hProcess;
1150 nh++; 1196 cps[nh] = cp;
1151 } 1197 nh++;
1198 }
1199 }
1200 if (nh == 0)
1201 {
1202 /* Nothing to wait on, so fail. */
1203 errno = ECHILD;
1204 return -1;
1205 }
1152 } 1206 }
1153 1207
1154 if (nh == 0) 1208 if (dont_wait)
1155 { 1209 timeout_ms = 0;
1156 /* Nothing to wait on, so fail */ 1210 else
1157 errno = ECHILD; 1211 timeout_ms = 1000; /* check for quit about once a second. */
1158 return -1;
1159 }
1160 1212
1161 do 1213 do
1162 { 1214 {
1163 /* Check for quit about once a second. */
1164 QUIT; 1215 QUIT;
1165 active = WaitForMultipleObjects (nh, wait_hnd, FALSE, 1000); 1216 active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms);
1166 } while (active == WAIT_TIMEOUT); 1217 } while (active == WAIT_TIMEOUT);
1167 1218
1168 if (active == WAIT_FAILED) 1219 if (active == WAIT_FAILED)
@@ -1192,8 +1243,10 @@ get_result:
1192 } 1243 }
1193 if (retval == STILL_ACTIVE) 1244 if (retval == STILL_ACTIVE)
1194 { 1245 {
1195 /* Should never happen */ 1246 /* Should never happen. */
1196 DebPrint (("Wait.WaitForMultipleObjects returned an active process\n")); 1247 DebPrint (("Wait.WaitForMultipleObjects returned an active process\n"));
1248 if (pid > 0 && dont_wait)
1249 return 0;
1197 errno = EINVAL; 1250 errno = EINVAL;
1198 return -1; 1251 return -1;
1199 } 1252 }
@@ -1207,6 +1260,8 @@ get_result:
1207 else 1260 else
1208 retval <<= 8; 1261 retval <<= 8;
1209 1262
1263 if (pid > 0 && active != 0)
1264 emacs_abort ();
1210 cp = cps[active]; 1265 cp = cps[active];
1211 pid = cp->pid; 1266 pid = cp->pid;
1212#ifdef FULL_DEBUG 1267#ifdef FULL_DEBUG
@@ -1995,9 +2050,7 @@ count_children:
1995 DebPrint (("select calling SIGCHLD handler for pid %d\n", 2050 DebPrint (("select calling SIGCHLD handler for pid %d\n",
1996 cp->pid)); 2051 cp->pid));
1997#endif 2052#endif
1998 dead_child = cp;
1999 sig_handlers[SIGCHLD] (SIGCHLD); 2053 sig_handlers[SIGCHLD] (SIGCHLD);
2000 dead_child = NULL;
2001 } 2054 }
2002 } 2055 }
2003 else if (fdindex[active] == -1) 2056 else if (fdindex[active] == -1)