diff options
| author | Eli Zaretskii | 2013-02-15 11:41:31 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2013-02-15 11:41:31 +0200 |
| commit | ef862e206a28f6618048c8b28413fa8f9c135c61 (patch) | |
| tree | 268021369bcc27a23f840634815215bd6d0d6def /src | |
| parent | bcf7fe2aeff7e3aacbfae08ca6001f7615a06709 (diff) | |
| download | emacs-ef862e206a28f6618048c8b28413fa8f9c135c61.tar.gz emacs-ef862e206a28f6618048c8b28413fa8f9c135c61.zip | |
Allow deleted processes to be reaped by SIGCHLD handler on MS-Windows.
src/w32proc.c (new_child): Free up to 2 slots of dead processes at a
time. Improve diagnostics in DebPrint.
(reader_thread): If cp->char_avail is NULL, set the FILE_AT_EOF
flag, so that sys_select could have a chance of noticing that this
process is dead, and call a SIGCHLD handler for it. Improve
diagnostics in DebPrint.
(reap_subprocess): Reset the FILE_AT_EOF flag set by
reader_thread.
(sys_select): Watch a process whose procinfo.hProcess is non-NULL
even if its char_avail is NULL. Allows to reap subprocesses that
were forcibly deleted by delete-process. (Bug#13546)
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 12 | ||||
| -rw-r--r-- | src/w32proc.c | 42 |
2 files changed, 48 insertions, 6 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 47a55535870..f4bee9f0905 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,17 @@ | |||
| 1 | 2013-02-15 Eli Zaretskii <eliz@gnu.org> | 1 | 2013-02-15 Eli Zaretskii <eliz@gnu.org> |
| 2 | 2 | ||
| 3 | * w32proc.c (new_child): Free up to 2 slots of dead processes at a | ||
| 4 | time. Improve diagnostics in DebPrint. | ||
| 5 | (reader_thread): If cp->char_avail is NULL, set the FILE_AT_EOF | ||
| 6 | flag, so that sys_select could have a chance of noticing that this | ||
| 7 | process is dead, and call a SIGCHLD handler for it. Improve | ||
| 8 | diagnostics in DebPrint. | ||
| 9 | (reap_subprocess): Reset the FILE_AT_EOF flag set by | ||
| 10 | reader_thread. | ||
| 11 | (sys_select): Watch a process whose procinfo.hProcess is non-NULL | ||
| 12 | even if its char_avail is NULL. Allows to reap subprocesses that | ||
| 13 | were forcibly deleted by delete-process. (Bug#13546) | ||
| 14 | |||
| 3 | * w32.c (sys_socket, sys_bind, sys_connect, sys_gethostname) | 15 | * w32.c (sys_socket, sys_bind, sys_connect, sys_gethostname) |
| 4 | (sys_gethostbyname, sys_getservbyname, sys_getpeername) | 16 | (sys_gethostbyname, sys_getservbyname, sys_getpeername) |
| 5 | (sys_shutdown, sys_setsockopt, sys_listen, sys_getsockname) | 17 | (sys_shutdown, sys_setsockopt, sys_listen, sys_getsockname) |
diff --git a/src/w32proc.c b/src/w32proc.c index 1e72d41e16b..e9860a66468 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -799,6 +799,9 @@ new_child (void) | |||
| 799 | goto Initialize; | 799 | goto Initialize; |
| 800 | if (child_proc_count == MAX_CHILDREN) | 800 | if (child_proc_count == MAX_CHILDREN) |
| 801 | { | 801 | { |
| 802 | int i = 0; | ||
| 803 | child_process *dead_cp; | ||
| 804 | |||
| 802 | DebPrint (("new_child: No vacant slots, looking for dead processes\n")); | 805 | DebPrint (("new_child: No vacant slots, looking for dead processes\n")); |
| 803 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) | 806 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) |
| 804 | if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess) | 807 | if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess) |
| @@ -814,13 +817,23 @@ new_child (void) | |||
| 814 | if (status != STILL_ACTIVE | 817 | if (status != STILL_ACTIVE |
| 815 | || WaitForSingleObject (cp->procinfo.hProcess, 0) == WAIT_OBJECT_0) | 818 | || WaitForSingleObject (cp->procinfo.hProcess, 0) == WAIT_OBJECT_0) |
| 816 | { | 819 | { |
| 817 | DebPrint (("new_child: Freeing slot of dead process %d\n", | 820 | DebPrint (("new_child: Freeing slot of dead process %d, fd %d\n", |
| 818 | cp->procinfo.dwProcessId)); | 821 | cp->procinfo.dwProcessId, cp->fd)); |
| 819 | CloseHandle (cp->procinfo.hProcess); | 822 | CloseHandle (cp->procinfo.hProcess); |
| 820 | cp->procinfo.hProcess = NULL; | 823 | cp->procinfo.hProcess = NULL; |
| 821 | CloseHandle (cp->procinfo.hThread); | 824 | CloseHandle (cp->procinfo.hThread); |
| 822 | cp->procinfo.hThread = NULL; | 825 | cp->procinfo.hThread = NULL; |
| 823 | goto Initialize; | 826 | /* Free up to 2 dead slots at a time, so that if we |
| 827 | have a lot of them, they will eventually all be | ||
| 828 | freed when the tornado ends. */ | ||
| 829 | if (i == 0) | ||
| 830 | dead_cp = cp; | ||
| 831 | else | ||
| 832 | { | ||
| 833 | cp = dead_cp; | ||
| 834 | goto Initialize; | ||
| 835 | } | ||
| 836 | i++; | ||
| 824 | } | 837 | } |
| 825 | } | 838 | } |
| 826 | } | 839 | } |
| @@ -975,12 +988,24 @@ reader_thread (void *arg) | |||
| 975 | else | 988 | else |
| 976 | rc = _sys_read_ahead (cp->fd); | 989 | rc = _sys_read_ahead (cp->fd); |
| 977 | 990 | ||
| 991 | if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess && cp->fd >= 0) | ||
| 992 | { | ||
| 993 | /* Somebody already called delete_child on this child, since | ||
| 994 | only delete_child zeroes out cp->char_avail. This means | ||
| 995 | no one will read from cp->fd and will not set the | ||
| 996 | FILE_AT_EOF flag, therefore preventing sys_select from | ||
| 997 | noticing that the process died. Set the flag here | ||
| 998 | instead. */ | ||
| 999 | fd_info[cp->fd].flags |= FILE_AT_EOF; | ||
| 1000 | } | ||
| 1001 | |||
| 978 | /* The name char_avail is a misnomer - it really just means the | 1002 | /* The name char_avail is a misnomer - it really just means the |
| 979 | read-ahead has completed, whether successfully or not. */ | 1003 | read-ahead has completed, whether successfully or not. */ |
| 980 | if (!SetEvent (cp->char_avail)) | 1004 | if (!SetEvent (cp->char_avail)) |
| 981 | { | 1005 | { |
| 982 | DebPrint (("reader_thread.SetEvent failed with %lu for fd %ld\n", | 1006 | DebPrint (("reader_thread.SetEvent(0x%x) failed with %lu for fd %ld (PID %d)\n", |
| 983 | GetLastError (), cp->fd)); | 1007 | (DWORD_PTR)cp->char_avail, GetLastError (), |
| 1008 | cp->fd, cp->pid)); | ||
| 984 | return 1; | 1009 | return 1; |
| 985 | } | 1010 | } |
| 986 | 1011 | ||
| @@ -1141,6 +1166,11 @@ reap_subprocess (child_process *cp) | |||
| 1141 | register_child has not been called. */ | 1166 | register_child has not been called. */ |
| 1142 | if (cp->fd == -1) | 1167 | if (cp->fd == -1) |
| 1143 | delete_child (cp); | 1168 | delete_child (cp); |
| 1169 | else | ||
| 1170 | { | ||
| 1171 | /* Reset the flag set by reader_thread. */ | ||
| 1172 | fd_info[cp->fd].flags &= ~FILE_AT_EOF; | ||
| 1173 | } | ||
| 1144 | } | 1174 | } |
| 1145 | 1175 | ||
| 1146 | /* Wait for any of our existing child processes to die | 1176 | /* Wait for any of our existing child processes to die |
| @@ -1925,7 +1955,7 @@ count_children: | |||
| 1925 | /* Some child_procs might be sockets; ignore them. Also some | 1955 | /* Some child_procs might be sockets; ignore them. Also some |
| 1926 | children may have died already, but we haven't finished reading | 1956 | children may have died already, but we haven't finished reading |
| 1927 | the process output; ignore them too. */ | 1957 | the process output; ignore them too. */ |
| 1928 | if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess | 1958 | if ((CHILD_ACTIVE (cp) || cp->procinfo.hProcess) |
| 1929 | && (cp->fd < 0 | 1959 | && (cp->fd < 0 |
| 1930 | || (fd_info[cp->fd].flags & FILE_SEND_SIGCHLD) == 0 | 1960 | || (fd_info[cp->fd].flags & FILE_SEND_SIGCHLD) == 0 |
| 1931 | || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0) | 1961 | || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0) |