diff options
| author | Paul Eggert | 2012-11-24 00:24:11 -0800 |
|---|---|---|
| committer | Paul Eggert | 2012-11-24 00:24:11 -0800 |
| commit | d4547511735190a81449727a89dc90f6ef1d99a3 (patch) | |
| tree | 21a30d3770b340cfbd67df4875d3c9a1d782bc20 /src | |
| parent | 0c5ef1333558423f0eb0f14934fffb1b4bce0946 (diff) | |
| download | emacs-d4547511735190a81449727a89dc90f6ef1d99a3.tar.gz emacs-d4547511735190a81449727a89dc90f6ef1d99a3.zip | |
Revert recent change for Bug#8855.
As reported by Harald Hanche-Olsen in
<http://lists.gnu.org/archive/html/emacs-devel/2012-11/msg00445.html>
the change introduces a further bug, of creating lots of zombie
processes in some cases. Further work is needed to come up with a
better fix for Bug#8855.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 9 | ||||
| -rw-r--r-- | src/process.c | 191 | ||||
| -rw-r--r-- | src/process.h | 3 | ||||
| -rw-r--r-- | src/sysdep.c | 7 | ||||
| -rw-r--r-- | src/w32proc.c | 127 |
5 files changed, 154 insertions, 183 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 6c9893b2f4f..99abda8a884 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2012-11-24 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Revert recent change for Bug#8855. | ||
| 4 | As reported by Harald Hanche-Olsen in | ||
| 5 | <http://lists.gnu.org/archive/html/emacs-devel/2012-11/msg00445.html> | ||
| 6 | the change introduces a further bug, of creating lots of zombie | ||
| 7 | processes in some cases. Further work is needed to come up with a | ||
| 8 | better fix for Bug#8855. | ||
| 9 | |||
| 1 | 2012-11-24 Eli Zaretskii <eliz@gnu.org> | 10 | 2012-11-24 Eli Zaretskii <eliz@gnu.org> |
| 2 | 11 | ||
| 3 | * xdisp.c (draw_glyphs): Don't draw in mouse face if mouse | 12 | * xdisp.c (draw_glyphs): Don't draw in mouse face if mouse |
diff --git a/src/process.c b/src/process.c index c095d13293b..77e99ead01f 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -130,6 +130,14 @@ 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 | |||
| 133 | /* Work around GCC 4.7.0 bug with strict overflow checking; see | 141 | /* Work around GCC 4.7.0 bug with strict overflow checking; see |
| 134 | <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>. | 142 | <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>. |
| 135 | These lines can be removed once the GCC bug is fixed. */ | 143 | These lines can be removed once the GCC bug is fixed. */ |
| @@ -787,8 +795,9 @@ get_process (register Lisp_Object name) | |||
| 787 | #ifdef SIGCHLD | 795 | #ifdef SIGCHLD |
| 788 | /* Fdelete_process promises to immediately forget about the process, but in | 796 | /* Fdelete_process promises to immediately forget about the process, but in |
| 789 | reality, Emacs needs to remember those processes until they have been | 797 | reality, Emacs needs to remember those processes until they have been |
| 790 | treated by the SIGCHLD handler and waitpid has been invoked on them; | 798 | treated by the SIGCHLD handler; otherwise this handler would consider the |
| 791 | otherwise they might fill up the kernel's process table. */ | 799 | process as being synchronous and say that the synchronous process is |
| 800 | dead. */ | ||
| 792 | static Lisp_Object deleted_pid_list; | 801 | static Lisp_Object deleted_pid_list; |
| 793 | #endif | 802 | #endif |
| 794 | 803 | ||
| @@ -1695,7 +1704,16 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1695 | if (inchannel > max_process_desc) | 1704 | if (inchannel > max_process_desc) |
| 1696 | max_process_desc = inchannel; | 1705 | max_process_desc = inchannel; |
| 1697 | 1706 | ||
| 1698 | /* This may signal an error. */ | 1707 | /* Until we store the proper pid, enable the SIGCHLD handler |
| 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. */ | ||
| 1699 | setup_process_coding_systems (process); | 1717 | setup_process_coding_systems (process); |
| 1700 | 1718 | ||
| 1701 | encoded_current_dir = ENCODE_FILE (current_dir); | 1719 | encoded_current_dir = ENCODE_FILE (current_dir); |
| @@ -1862,8 +1880,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1862 | #endif | 1880 | #endif |
| 1863 | 1881 | ||
| 1864 | XPROCESS (process)->pid = pid; | 1882 | XPROCESS (process)->pid = pid; |
| 1865 | if (0 <= pid) | ||
| 1866 | XPROCESS (process)->alive = 1; | ||
| 1867 | 1883 | ||
| 1868 | /* Stop blocking signals in the parent. */ | 1884 | /* Stop blocking signals in the parent. */ |
| 1869 | #ifdef SIGCHLD | 1885 | #ifdef SIGCHLD |
| @@ -6257,35 +6273,9 @@ process has been transmitted to the serial port. */) | |||
| 6257 | return process; | 6273 | return process; |
| 6258 | } | 6274 | } |
| 6259 | 6275 | ||
| 6260 | /* If the status of the process DESIRED has changed, return true and | 6276 | /* On receipt of a signal that a child status has changed, loop asking |
| 6261 | set *STATUS to its exit status; otherwise, return false. | 6277 | about children with changed statuses until the system says there |
| 6262 | If HAVE is nonnegative, assume that HAVE = waitpid (HAVE, STATUS, ...) | 6278 | are no more. |
| 6263 | has already been invoked, and do not invoke waitpid again. */ | ||
| 6264 | |||
| 6265 | static bool | ||
| 6266 | process_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. | ||
| 6289 | 6279 | ||
| 6290 | All we do is change the status; we do not run sentinels or print | 6280 | All we do is change the status; we do not run sentinels or print |
| 6291 | notifications. That is saved for the next time keyboard input is | 6281 | notifications. That is saved for the next time keyboard input is |
| @@ -6308,15 +6298,13 @@ process_status_retrieved (pid_t desired, pid_t have, int *status) | |||
| 6308 | ** Malloc WARNING: This should never call malloc either directly or | 6298 | ** Malloc WARNING: This should never call malloc either directly or |
| 6309 | indirectly; if it does, that is a bug */ | 6299 | indirectly; if it does, that is a bug */ |
| 6310 | 6300 | ||
| 6301 | /* Record the changed status of the child process PID with wait status W. */ | ||
| 6311 | void | 6302 | void |
| 6312 | record_child_status_change (pid_t pid, int w) | 6303 | record_child_status_change (pid_t pid, int w) |
| 6313 | { | 6304 | { |
| 6314 | #ifdef SIGCHLD | 6305 | #ifdef SIGCHLD |
| 6315 | 6306 | Lisp_Object proc; | |
| 6316 | /* On POSIXish hosts, record at most one child only if we already | 6307 | struct Lisp_Process *p; |
| 6317 | know one child that has exited. */ | ||
| 6318 | bool record_at_most_one_child = 0 <= pid; | ||
| 6319 | |||
| 6320 | Lisp_Object tail; | 6308 | Lisp_Object tail; |
| 6321 | 6309 | ||
| 6322 | /* Find the process that signaled us, and record its status. */ | 6310 | /* Find the process that signaled us, and record its status. */ |
| @@ -6324,69 +6312,68 @@ record_child_status_change (pid_t pid, int w) | |||
| 6324 | /* The process can have been deleted by Fdelete_process. */ | 6312 | /* The process can have been deleted by Fdelete_process. */ |
| 6325 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) | 6313 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) |
| 6326 | { | 6314 | { |
| 6327 | bool all_pids_are_fixnums | ||
| 6328 | = (MOST_NEGATIVE_FIXNUM <= TYPE_MINIMUM (pid_t) | ||
| 6329 | && TYPE_MAXIMUM (pid_t) <= MOST_POSITIVE_FIXNUM); | ||
| 6330 | Lisp_Object xpid = XCAR (tail); | 6315 | Lisp_Object xpid = XCAR (tail); |
| 6331 | if (all_pids_are_fixnums ? INTEGERP (xpid) : NUMBERP (xpid)) | 6316 | if ((INTEGERP (xpid) && pid == XINT (xpid)) |
| 6317 | || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid))) | ||
| 6332 | { | 6318 | { |
| 6333 | pid_t deleted_pid; | 6319 | XSETCAR (tail, Qnil); |
| 6334 | if (INTEGERP (xpid)) | 6320 | return; |
| 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 | } | ||
| 6344 | } | 6321 | } |
| 6345 | } | 6322 | } |
| 6346 | 6323 | ||
| 6347 | /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */ | 6324 | /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */ |
| 6325 | p = 0; | ||
| 6348 | for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) | 6326 | for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) |
| 6349 | { | 6327 | { |
| 6350 | Lisp_Object proc = XCDR (XCAR (tail)); | 6328 | proc = XCDR (XCAR (tail)); |
| 6351 | struct Lisp_Process *p = XPROCESS (proc); | 6329 | p = XPROCESS (proc); |
| 6352 | if (p->alive && process_status_retrieved (p->pid, pid, &w)) | 6330 | if (EQ (p->type, Qreal) && p->pid == pid) |
| 6353 | { | 6331 | break; |
| 6354 | /* Change the status of the process that was found. */ | 6332 | p = 0; |
| 6355 | p->tick = ++process_tick; | 6333 | } |
| 6356 | p->raw_status = w; | ||
| 6357 | p->raw_status_new = 1; | ||
| 6358 | 6334 | ||
| 6359 | /* If process has terminated, stop waiting for its output. */ | 6335 | /* Look for an asynchronous process whose pid hasn't been filled |
| 6360 | if (WIFSIGNALED (w) || WIFEXITED (w)) | 6336 | in yet. */ |
| 6361 | { | 6337 | if (! p) |
| 6362 | int clear_desc_flag = 0; | 6338 | for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) |
| 6363 | p->alive = 0; | 6339 | { |
| 6364 | if (p->infd >= 0) | 6340 | proc = XCDR (XCAR (tail)); |
| 6365 | clear_desc_flag = 1; | 6341 | p = XPROCESS (proc); |
| 6342 | if (p->pid == -1) | ||
| 6343 | break; | ||
| 6344 | p = 0; | ||
| 6345 | } | ||
| 6366 | 6346 | ||
| 6367 | /* clear_desc_flag avoids a compiler bug in Microsoft C. */ | 6347 | /* Change the status of the process that was found. */ |
| 6368 | if (clear_desc_flag) | 6348 | if (p) |
| 6369 | { | 6349 | { |
| 6370 | FD_CLR (p->infd, &input_wait_mask); | 6350 | int clear_desc_flag = 0; |
| 6371 | FD_CLR (p->infd, &non_keyboard_wait_mask); | ||
| 6372 | } | ||
| 6373 | } | ||
| 6374 | 6351 | ||
| 6375 | /* Tell wait_reading_process_output that it needs to wake up and | 6352 | p->tick = ++process_tick; |
| 6376 | look around. */ | 6353 | p->raw_status = w; |
| 6377 | if (input_available_clear_time) | 6354 | p->raw_status_new = 1; |
| 6378 | *input_available_clear_time = make_emacs_time (0, 0); | 6355 | |
| 6356 | /* If process has terminated, stop waiting for its output. */ | ||
| 6357 | if ((WIFSIGNALED (w) || WIFEXITED (w)) | ||
| 6358 | && p->infd >= 0) | ||
| 6359 | clear_desc_flag = 1; | ||
| 6379 | 6360 | ||
| 6380 | if (record_at_most_one_child) | 6361 | /* We use clear_desc_flag to avoid a compiler bug in Microsoft C. */ |
| 6381 | return; | 6362 | if (clear_desc_flag) |
| 6363 | { | ||
| 6364 | FD_CLR (p->infd, &input_wait_mask); | ||
| 6365 | FD_CLR (p->infd, &non_keyboard_wait_mask); | ||
| 6382 | } | 6366 | } |
| 6383 | } | ||
| 6384 | 6367 | ||
| 6385 | if (0 <= pid) | 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 | } | ||
| 6373 | /* There was no asynchronous process found for that pid: we have | ||
| 6374 | a synchronous process. */ | ||
| 6375 | else | ||
| 6386 | { | 6376 | { |
| 6387 | /* The caller successfully waited for a pid but no asynchronous | ||
| 6388 | process was found for it, so this is a synchronous process. */ | ||
| 6389 | |||
| 6390 | synch_process_alive = 0; | 6377 | synch_process_alive = 0; |
| 6391 | 6378 | ||
| 6392 | /* Report the status of the synchronous process. */ | 6379 | /* Report the status of the synchronous process. */ |
| @@ -6405,10 +6392,38 @@ record_child_status_change (pid_t pid, int w) | |||
| 6405 | 6392 | ||
| 6406 | #ifdef SIGCHLD | 6393 | #ifdef SIGCHLD |
| 6407 | 6394 | ||
| 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))) | ||
| 6402 | enum { CAN_HANDLE_MULTIPLE_CHILDREN = 0 }; | ||
| 6403 | #else | ||
| 6404 | enum { CAN_HANDLE_MULTIPLE_CHILDREN = 1 }; | ||
| 6405 | #endif | ||
| 6406 | |||
| 6408 | static void | 6407 | static void |
| 6409 | handle_child_signal (int sig) | 6408 | handle_child_signal (int sig) |
| 6410 | { | 6409 | { |
| 6411 | record_child_status_change (-1, 0); | 6410 | do |
| 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); | ||
| 6412 | } | 6427 | } |
| 6413 | 6428 | ||
| 6414 | static void | 6429 | static void |
diff --git a/src/process.h b/src/process.h index 74d1a124060..ce3d2e702cc 100644 --- a/src/process.h +++ b/src/process.h | |||
| @@ -142,9 +142,6 @@ 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; | ||
| 148 | /* Record the process status in the raw form in which it comes from `wait'. | 145 | /* Record the process status in the raw form in which it comes from `wait'. |
| 149 | This is to avoid consing in a signal handler. The `raw_status_new' | 146 | This is to avoid consing in a signal handler. The `raw_status_new' |
| 150 | flag indicates that `raw_status' contains a new status that still | 147 | flag indicates that `raw_status' contains a new status that still |
diff --git a/src/sysdep.c b/src/sysdep.c index bb81353847b..63eac5d9e09 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -289,6 +289,10 @@ 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 */ | ||
| 292 | int status; | 296 | int status; |
| 293 | int wait_result = waitpid (pid, &status, 0); | 297 | int wait_result = waitpid (pid, &status, 0); |
| 294 | if (wait_result < 0) | 298 | if (wait_result < 0) |
| @@ -302,8 +306,7 @@ wait_for_termination_1 (pid_t pid, int interruptible) | |||
| 302 | break; | 306 | break; |
| 303 | } | 307 | } |
| 304 | 308 | ||
| 305 | /* Note: the MS-Windows emulation of waitpid calls QUIT | 309 | #endif /* not WINDOWSNT */ |
| 306 | internally. */ | ||
| 307 | if (interruptible) | 310 | if (interruptible) |
| 308 | QUIT; | 311 | QUIT; |
| 309 | } | 312 | } |
diff --git a/src/w32proc.c b/src/w32proc.c index b4f2099f06a..e3c54fe5460 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -783,6 +783,7 @@ alarm (int seconds) | |||
| 783 | /* Child process management list. */ | 783 | /* Child process management list. */ |
| 784 | int child_proc_count = 0; | 784 | int child_proc_count = 0; |
| 785 | child_process child_procs[ MAX_CHILDREN ]; | 785 | child_process child_procs[ MAX_CHILDREN ]; |
| 786 | child_process *dead_child = NULL; | ||
| 786 | 787 | ||
| 787 | static DWORD WINAPI reader_thread (void *arg); | 788 | static DWORD WINAPI reader_thread (void *arg); |
| 788 | 789 | ||
| @@ -1035,6 +1036,9 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, | |||
| 1035 | if (cp->pid < 0) | 1036 | if (cp->pid < 0) |
| 1036 | cp->pid = -cp->pid; | 1037 | cp->pid = -cp->pid; |
| 1037 | 1038 | ||
| 1039 | /* pid must fit in a Lisp_Int */ | ||
| 1040 | cp->pid = cp->pid & INTMASK; | ||
| 1041 | |||
| 1038 | *pPid = cp->pid; | 1042 | *pPid = cp->pid; |
| 1039 | 1043 | ||
| 1040 | return TRUE; | 1044 | return TRUE; |
| @@ -1110,110 +1114,55 @@ reap_subprocess (child_process *cp) | |||
| 1110 | delete_child (cp); | 1114 | delete_child (cp); |
| 1111 | } | 1115 | } |
| 1112 | 1116 | ||
| 1113 | /* Wait for a child process specified by PID, or for any of our | 1117 | /* Wait for any of our existing child processes to die |
| 1114 | existing child processes (if PID is nonpositive) to die. When it | 1118 | When it does, close its handle |
| 1115 | does, close its handle. Return the pid of the process that died | 1119 | Return the pid and fill in the status if non-NULL. */ |
| 1116 | and fill in STATUS if non-NULL. */ | ||
| 1117 | 1120 | ||
| 1118 | pid_t | 1121 | int |
| 1119 | waitpid (pid_t pid, int *status, int options) | 1122 | sys_wait (int *status) |
| 1120 | { | 1123 | { |
| 1121 | DWORD active, retval; | 1124 | DWORD active, retval; |
| 1122 | int nh; | 1125 | int nh; |
| 1126 | int pid; | ||
| 1123 | child_process *cp, *cps[MAX_CHILDREN]; | 1127 | child_process *cp, *cps[MAX_CHILDREN]; |
| 1124 | HANDLE wait_hnd[MAX_CHILDREN]; | 1128 | HANDLE wait_hnd[MAX_CHILDREN]; |
| 1125 | DWORD timeout_ms; | ||
| 1126 | int dont_wait = (options & WNOHANG) != 0; | ||
| 1127 | 1129 | ||
| 1128 | nh = 0; | 1130 | nh = 0; |
| 1129 | /* According to Posix: | 1131 | if (dead_child != NULL) |
| 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) | ||
| 1148 | { | 1132 | { |
| 1149 | int our_child = 0; | 1133 | /* We want to wait for a specific child */ |
| 1150 | 1134 | wait_hnd[nh] = dead_child->procinfo.hProcess; | |
| 1151 | /* We are requested to wait for a specific child. */ | 1135 | cps[nh] = dead_child; |
| 1152 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) | 1136 | if (!wait_hnd[nh]) emacs_abort (); |
| 1153 | { | 1137 | nh++; |
| 1154 | /* Some child_procs might be sockets; ignore them. Also | 1138 | active = 0; |
| 1155 | ignore subprocesses whose output is not yet completely | 1139 | goto get_result; |
| 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 | } | ||
| 1186 | } | 1140 | } |
| 1187 | else | 1141 | else |
| 1188 | { | 1142 | { |
| 1189 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) | 1143 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) |
| 1190 | { | 1144 | /* some child_procs might be sockets; ignore them */ |
| 1191 | if (CHILD_ACTIVE (cp) | 1145 | if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess |
| 1192 | && cp->procinfo.hProcess | 1146 | && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) |
| 1193 | && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) | 1147 | { |
| 1194 | { | 1148 | wait_hnd[nh] = cp->procinfo.hProcess; |
| 1195 | wait_hnd[nh] = cp->procinfo.hProcess; | 1149 | cps[nh] = cp; |
| 1196 | cps[nh] = cp; | 1150 | nh++; |
| 1197 | nh++; | 1151 | } |
| 1198 | } | ||
| 1199 | } | ||
| 1200 | if (nh == 0) | ||
| 1201 | { | ||
| 1202 | /* Nothing to wait on, so fail. */ | ||
| 1203 | errno = ECHILD; | ||
| 1204 | return -1; | ||
| 1205 | } | ||
| 1206 | } | 1152 | } |
| 1207 | 1153 | ||
| 1208 | if (dont_wait) | 1154 | if (nh == 0) |
| 1209 | timeout_ms = 0; | 1155 | { |
| 1210 | else | 1156 | /* Nothing to wait on, so fail */ |
| 1211 | timeout_ms = 1000; /* check for quit about once a second. */ | 1157 | errno = ECHILD; |
| 1158 | return -1; | ||
| 1159 | } | ||
| 1212 | 1160 | ||
| 1213 | do | 1161 | do |
| 1214 | { | 1162 | { |
| 1163 | /* Check for quit about once a second. */ | ||
| 1215 | QUIT; | 1164 | QUIT; |
| 1216 | active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms); | 1165 | active = WaitForMultipleObjects (nh, wait_hnd, FALSE, 1000); |
| 1217 | } while (active == WAIT_TIMEOUT); | 1166 | } while (active == WAIT_TIMEOUT); |
| 1218 | 1167 | ||
| 1219 | if (active == WAIT_FAILED) | 1168 | if (active == WAIT_FAILED) |
| @@ -1243,10 +1192,8 @@ get_result: | |||
| 1243 | } | 1192 | } |
| 1244 | if (retval == STILL_ACTIVE) | 1193 | if (retval == STILL_ACTIVE) |
| 1245 | { | 1194 | { |
| 1246 | /* Should never happen. */ | 1195 | /* Should never happen */ |
| 1247 | DebPrint (("Wait.WaitForMultipleObjects returned an active process\n")); | 1196 | DebPrint (("Wait.WaitForMultipleObjects returned an active process\n")); |
| 1248 | if (pid > 0 && dont_wait) | ||
| 1249 | return 0; | ||
| 1250 | errno = EINVAL; | 1197 | errno = EINVAL; |
| 1251 | return -1; | 1198 | return -1; |
| 1252 | } | 1199 | } |
| @@ -1260,8 +1207,6 @@ get_result: | |||
| 1260 | else | 1207 | else |
| 1261 | retval <<= 8; | 1208 | retval <<= 8; |
| 1262 | 1209 | ||
| 1263 | if (pid > 0 && active != 0) | ||
| 1264 | emacs_abort (); | ||
| 1265 | cp = cps[active]; | 1210 | cp = cps[active]; |
| 1266 | pid = cp->pid; | 1211 | pid = cp->pid; |
| 1267 | #ifdef FULL_DEBUG | 1212 | #ifdef FULL_DEBUG |
| @@ -2050,7 +1995,9 @@ count_children: | |||
| 2050 | DebPrint (("select calling SIGCHLD handler for pid %d\n", | 1995 | DebPrint (("select calling SIGCHLD handler for pid %d\n", |
| 2051 | cp->pid)); | 1996 | cp->pid)); |
| 2052 | #endif | 1997 | #endif |
| 1998 | dead_child = cp; | ||
| 2053 | sig_handlers[SIGCHLD] (SIGCHLD); | 1999 | sig_handlers[SIGCHLD] (SIGCHLD); |
| 2000 | dead_child = NULL; | ||
| 2054 | } | 2001 | } |
| 2055 | } | 2002 | } |
| 2056 | else if (fdindex[active] == -1) | 2003 | else if (fdindex[active] == -1) |