aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2012-12-03 13:42:12 -0800
committerPaul Eggert2012-12-03 13:42:12 -0800
commitbb5f74ee84398a56435baa2ef15e12d8a35e5e03 (patch)
tree4bb59aacd4d69b873154ce576e51fe8efe345150
parentbc9dbce6ee527ded152682c98f5f82e42c33dde9 (diff)
downloademacs-bb5f74ee84398a56435baa2ef15e12d8a35e5e03.tar.gz
emacs-bb5f74ee84398a56435baa2ef15e12d8a35e5e03.zip
Don't let call-process be a zombie factory.
Fixing this bug required some cleanup of the signal-handling code. As a side effect, this change also fixes a longstanding rare race condition whereby Emacs could mistakenly kill unrelated processes, and it fixes a bug where a second C-g does not kill a recalcitrant synchronous process in GNU/Linux and similar platforms. The patch should also fix the last vestiges of Bug#9488, a bug which has mostly been fixed on the trunk by other changes. * callproc.c, process.h (synch_process_alive, synch_process_death) (synch_process_termsig, sync_process_retcode): Remove. All uses removed, to simplify analysis and so that less consing is done inside critical sections. * callproc.c (call_process_exited): Remove. All uses replaced with !synch_process_pid. * callproc.c (synch_process_pid, synch_process_fd): New static vars. These take the role of what used to be in unwind-protect arg. All uses changed. (block_child_signal, unblock_child_signal): New functions, to avoid races that could kill innocent-victim processes. (call_process_kill, call_process_cleanup, Fcall_process): Use them. (call_process_kill): Record killed processes as deleted, so that zombies do not clutter up the system. Do this inside a critical section, to avoid a race that would allow the clutter. (call_process_cleanup): Fix code so that the second C-g works again on common platforms such as GNU/Linux. (Fcall_process): Create the child process in a critical section, to fix a race condition. If creating an asynchronous process, record it as deleted so that zombies do not clutter up the system. Do unwind-protect for WINDOWSNT too, as that's simpler in the light of these changes. Omit unnecessary call to emacs_close before failure, as the unwind-protect code does that. * callproc.c (call_process_cleanup): * w32proc.c (waitpid): Simplify now that synch_process_alive is gone. * process.c (record_deleted_pid): New function, containing code refactored out of Fdelete_process. (Fdelete_process): Use it. (process_status_retrieved): Remove. All callers changed to use child_status_change. (record_child_status_change): Remove, folding its contents into ... (handle_child_signal): ... this signal handler. Now, this function is purely a handler for SIGCHLD, and is not called after a synchronous waitpid returns; the synchronous code is moved to wait_for_termination. There is no need to worry about reaping more than one child now. * sysdep.c (get_child_status, child_status_changed): New functions. (wait_for_termination): Now takes int * status and bool interruptible arguments, too. Do not record child status change; that's now the caller's responsibility. All callers changed. Reimplement in terms of get_child_status. (wait_for_termination_1, interruptible_wait_for_termination): Remove. All callers changed to use wait_for_termination. * syswait.h: Include <stdbool.h>, for bool. (record_child_status_change, interruptible_wait_for_termination): Remove decls. (record_deleted_pid, child_status_changed): New decls. (wait_for_termination): Adjust to API changes noted above. Fixes: debbugs:12980
-rw-r--r--src/ChangeLog57
-rw-r--r--src/callproc.c238
-rw-r--r--src/process.c136
-rw-r--r--src/process.h17
-rw-r--r--src/sysdep.c80
-rw-r--r--src/syswait.h7
-rw-r--r--src/w32proc.c28
7 files changed, 296 insertions, 267 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 019caf306b7..1a91eb0f1a3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,62 @@
12012-12-03 Paul Eggert <eggert@cs.ucla.edu> 12012-12-03 Paul Eggert <eggert@cs.ucla.edu>
2 2
3 Don't let call-process be a zombie factory (Bug#12980).
4 Fixing this bug required some cleanup of the signal-handling code.
5 As a side effect, this change also fixes a longstanding rare race
6 condition whereby Emacs could mistakenly kill unrelated processes,
7 and it fixes a bug where a second C-g does not kill a recalcitrant
8 synchronous process in GNU/Linux and similar platforms.
9 The patch should also fix the last vestiges of Bug#9488,
10 a bug which has mostly been fixed on the trunk by other changes.
11 * callproc.c, process.h (synch_process_alive, synch_process_death)
12 (synch_process_termsig, sync_process_retcode):
13 Remove. All uses removed, to simplify analysis and so that
14 less consing is done inside critical sections.
15 * callproc.c (call_process_exited): Remove. All uses replaced
16 with !synch_process_pid.
17 * callproc.c (synch_process_pid, synch_process_fd): New static vars.
18 These take the role of what used to be in unwind-protect arg.
19 All uses changed.
20 (block_child_signal, unblock_child_signal):
21 New functions, to avoid races that could kill innocent-victim processes.
22 (call_process_kill, call_process_cleanup, Fcall_process): Use them.
23 (call_process_kill): Record killed processes as deleted, so that
24 zombies do not clutter up the system. Do this inside a critical
25 section, to avoid a race that would allow the clutter.
26 (call_process_cleanup): Fix code so that the second C-g works again
27 on common platforms such as GNU/Linux.
28 (Fcall_process): Create the child process in a critical section,
29 to fix a race condition. If creating an asynchronous process,
30 record it as deleted so that zombies do not clutter up the system.
31 Do unwind-protect for WINDOWSNT too, as that's simpler in the
32 light of these changes. Omit unnecessary call to emacs_close
33 before failure, as the unwind-protect code does that.
34 * callproc.c (call_process_cleanup):
35 * w32proc.c (waitpid): Simplify now that synch_process_alive is gone.
36 * process.c (record_deleted_pid): New function, containing
37 code refactored out of Fdelete_process.
38 (Fdelete_process): Use it.
39 (process_status_retrieved): Remove. All callers changed to use
40 child_status_change.
41 (record_child_status_change): Remove, folding its contents into ...
42 (handle_child_signal): ... this signal handler. Now, this
43 function is purely a handler for SIGCHLD, and is not called after
44 a synchronous waitpid returns; the synchronous code is moved to
45 wait_for_termination. There is no need to worry about reaping
46 more than one child now.
47 * sysdep.c (get_child_status, child_status_changed): New functions.
48 (wait_for_termination): Now takes int * status and bool
49 interruptible arguments, too. Do not record child status change;
50 that's now the caller's responsibility. All callers changed.
51 Reimplement in terms of get_child_status.
52 (wait_for_termination_1, interruptible_wait_for_termination):
53 Remove. All callers changed to use wait_for_termination.
54 * syswait.h: Include <stdbool.h>, for bool.
55 (record_child_status_change, interruptible_wait_for_termination):
56 Remove decls.
57 (record_deleted_pid, child_status_changed): New decls.
58 (wait_for_termination): Adjust to API changes noted above.
59
3 * bytecode.c, lisp.h (Qbytecode): Remove. 60 * bytecode.c, lisp.h (Qbytecode): Remove.
4 No longer needed after 2012-11-20 interactive-p changes. 61 No longer needed after 2012-11-20 interactive-p changes.
5 62
diff --git a/src/callproc.c b/src/callproc.c
index 0242755eb5f..21c52d09e6b 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -67,88 +67,110 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
67/* Pattern used by call-process-region to make temp files. */ 67/* Pattern used by call-process-region to make temp files. */
68static Lisp_Object Vtemp_file_name_pattern; 68static Lisp_Object Vtemp_file_name_pattern;
69 69
70/* True if we are about to fork off a synchronous process or if we 70/* The next two variables are valid only while record-unwind-protect
71 are waiting for it. */ 71 is in place during call-process for a synchronous subprocess. At
72bool synch_process_alive; 72 other times, their contents are irrelevant. Doing this via static
73 73 C variables is more convenient than putting them into the arguments
74/* Nonzero => this is a string explaining death of synchronous subprocess. */ 74 of record-unwind-protect, as they need to be updated at randomish
75const char *synch_process_death; 75 times in the code, and Lisp cannot always store these values as
76 Emacs integers. It's safe to use static variables here, as the
77 code is never invoked reentrantly. */
78
79/* If nonzero, a process-ID that has not been reaped. */
80static pid_t synch_process_pid;
81
82/* If nonnegative, a file descriptor that has not been closed. */
83static int synch_process_fd;
84
85/* Block SIGCHLD. */
76 86
77/* Nonzero => this is the signal number that terminated the subprocess. */ 87static void
78int synch_process_termsig; 88block_child_signal (void)
89{
90#ifdef SIGCHLD
91 sigset_t blocked;
92 sigemptyset (&blocked);
93 sigaddset (&blocked, SIGCHLD);
94 pthread_sigmask (SIG_BLOCK, &blocked, 0);
95#endif
96}
79 97
80/* If synch_process_death is zero, 98/* Unblock SIGCHLD. */
81 this is exit code of synchronous subprocess. */
82int synch_process_retcode;
83 99
84 100static void
85/* Clean up when exiting Fcall_process. 101unblock_child_signal (void)
86 On MSDOS, delete the temporary file on any kind of termination. 102{
87 On Unix, kill the process and any children on termination by signal. */ 103#ifdef SIGCHLD
104 pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
105#endif
106}
88 107
89/* True if this is termination due to exit. */ 108/* Clean up when exiting call_process_cleanup. */
90static bool call_process_exited;
91 109
92static Lisp_Object 110static Lisp_Object
93call_process_kill (Lisp_Object fdpid) 111call_process_kill (Lisp_Object ignored)
94{ 112{
95 int fd; 113 if (0 <= synch_process_fd)
96 pid_t pid; 114 emacs_close (synch_process_fd);
97 CONS_TO_INTEGER (Fcar (fdpid), int, fd); 115
98 CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid); 116 /* If PID is reapable, kill it and record it as a deleted process.
99 emacs_close (fd); 117 Do this in a critical section. Unless PID is wedged it will be
100 EMACS_KILLPG (pid, SIGKILL); 118 reaped on receipt of the first SIGCHLD after the critical section. */
101 synch_process_alive = 0; 119 if (synch_process_pid)
120 {
121 block_child_signal ();
122 record_deleted_pid (synch_process_pid);
123 EMACS_KILLPG (synch_process_pid, SIGKILL);
124 unblock_child_signal ();
125 }
126
102 return Qnil; 127 return Qnil;
103} 128}
104 129
130/* Clean up when exiting Fcall_process.
131 On MSDOS, delete the temporary file on any kind of termination.
132 On Unix, kill the process and any children on termination by signal. */
133
105static Lisp_Object 134static Lisp_Object
106call_process_cleanup (Lisp_Object arg) 135call_process_cleanup (Lisp_Object arg)
107{ 136{
108 Lisp_Object fdpid = Fcdr (arg); 137#ifdef MSDOS
109 int fd; 138 Lisp_Object buffer = Fcar (arg);
110#if defined (MSDOS) 139 Lisp_Object file = Fcdr (arg);
111 Lisp_Object file;
112#else 140#else
113 pid_t pid; 141 Lisp_Object buffer = arg;
114#endif 142#endif
115 143
116 Fset_buffer (Fcar (arg)); 144 Fset_buffer (buffer);
117 CONS_TO_INTEGER (Fcar (fdpid), int, fd);
118
119#if defined (MSDOS)
120 /* for MSDOS fdpid is really (fd . tempfile) */
121 file = Fcdr (fdpid);
122 /* FD is -1 and FILE is "" when we didn't actually create a
123 temporary file in call-process. */
124 if (fd >= 0)
125 emacs_close (fd);
126 if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0'))
127 unlink (SDATA (file));
128#else /* not MSDOS */
129 CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid);
130 145
131 if (call_process_exited) 146#ifndef MSDOS
132 { 147 /* If the process still exists, kill its process group. */
133 emacs_close (fd); 148 if (synch_process_pid)
134 return Qnil;
135 }
136
137 if (EMACS_KILLPG (pid, SIGINT) == 0)
138 { 149 {
139 ptrdiff_t count = SPECPDL_INDEX (); 150 ptrdiff_t count = SPECPDL_INDEX ();
140 record_unwind_protect (call_process_kill, fdpid); 151 EMACS_KILLPG (synch_process_pid, SIGINT);
152 record_unwind_protect (call_process_kill, make_number (0));
141 message1 ("Waiting for process to die...(type C-g again to kill it instantly)"); 153 message1 ("Waiting for process to die...(type C-g again to kill it instantly)");
142 immediate_quit = 1; 154 immediate_quit = 1;
143 QUIT; 155 QUIT;
144 wait_for_termination (pid); 156 wait_for_termination (synch_process_pid, 0, 1);
157 synch_process_pid = 0;
145 immediate_quit = 0; 158 immediate_quit = 0;
146 specpdl_ptr = specpdl + count; /* Discard the unwind protect. */ 159 specpdl_ptr = specpdl + count; /* Discard the unwind protect. */
147 message1 ("Waiting for process to die...done"); 160 message1 ("Waiting for process to die...done");
148 } 161 }
149 synch_process_alive = 0; 162#endif
150 emacs_close (fd); 163
151#endif /* not MSDOS */ 164 if (0 <= synch_process_fd)
165 emacs_close (synch_process_fd);
166
167#ifdef MSDOS
168 /* FILE is "" when we didn't actually create a temporary file in
169 call-process. */
170 if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0'))
171 unlink (SDATA (file));
172#endif
173
152 return Qnil; 174 return Qnil;
153} 175}
154 176
@@ -181,9 +203,10 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.
181usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) 203usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
182 (ptrdiff_t nargs, Lisp_Object *args) 204 (ptrdiff_t nargs, Lisp_Object *args)
183{ 205{
184 Lisp_Object infile, buffer, current_dir, path, cleanup_info_tail; 206 Lisp_Object infile, buffer, current_dir, path;
185 bool display_p; 207 bool display_p;
186 int fd0, fd1, filefd; 208 int fd0, fd1, filefd;
209 int status;
187 ptrdiff_t count = SPECPDL_INDEX (); 210 ptrdiff_t count = SPECPDL_INDEX ();
188 USE_SAFE_ALLOCA; 211 USE_SAFE_ALLOCA;
189 212
@@ -199,7 +222,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
199#else 222#else
200 pid_t pid; 223 pid_t pid;
201#endif 224#endif
202 int vfork_errno; 225 int child_errno;
203 int fd_output = -1; 226 int fd_output = -1;
204 struct coding_system process_coding; /* coding-system of process output */ 227 struct coding_system process_coding; /* coding-system of process output */
205 struct coding_system argument_coding; /* coding-system of arguments */ 228 struct coding_system argument_coding; /* coding-system of arguments */
@@ -493,16 +516,6 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
493 if (fd_output >= 0) 516 if (fd_output >= 0)
494 fd1 = fd_output; 517 fd1 = fd_output;
495 518
496 /* Record that we're about to create a synchronous process. */
497 synch_process_alive = 1;
498
499 /* These vars record information from process termination.
500 Clear them now before process can possibly terminate,
501 to avoid timing error if process terminates soon. */
502 synch_process_death = 0;
503 synch_process_retcode = 0;
504 synch_process_termsig = 0;
505
506 if (NILP (error_file)) 519 if (NILP (error_file))
507 fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0); 520 fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0);
508 else if (STRINGP (error_file)) 521 else if (STRINGP (error_file))
@@ -535,23 +548,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
535 548
536#ifdef MSDOS /* MW, July 1993 */ 549#ifdef MSDOS /* MW, July 1993 */
537 /* Note that on MSDOS `child_setup' actually returns the child process 550 /* Note that on MSDOS `child_setup' actually returns the child process
538 exit status, not its PID, so we assign it to `synch_process_retcode' 551 exit status, not its PID, so assign it to status below. */
539 below. */
540 pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir); 552 pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir);
541 553 child_errno = errno;
542 /* Record that the synchronous process exited and note its
543 termination status. */
544 synch_process_alive = 0;
545 synch_process_retcode = pid;
546 if (synch_process_retcode < 0) /* means it couldn't be exec'ed */
547 {
548 synchronize_system_messages_locale ();
549 synch_process_death = strerror (errno);
550 }
551 554
552 emacs_close (outfilefd); 555 emacs_close (outfilefd);
553 if (fd_error != outfilefd) 556 if (fd_error != outfilefd)
554 emacs_close (fd_error); 557 emacs_close (fd_error);
558 if (pid < 0)
559 {
560 synchronize_system_messages_locale ();
561 return
562 code_convert_string_norecord (build_string (strerror (child_errno)),
563 Vlocale_coding_system, 0);
564 }
565 status = pid;
555 fd1 = -1; /* No harm in closing that one! */ 566 fd1 = -1; /* No harm in closing that one! */
556 if (tempfile) 567 if (tempfile)
557 { 568 {
@@ -569,12 +580,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
569 else 580 else
570 fd0 = -1; /* We are not going to read from tempfile. */ 581 fd0 = -1; /* We are not going to read from tempfile. */
571#else /* not MSDOS */ 582#else /* not MSDOS */
583
584 /* Do the unwind-protect now, even though the pid is not known, so
585 that no storage allocation is done in the critical section.
586 The actual PID will be filled in during the critical section. */
587 synch_process_pid = 0;
588 synch_process_fd = fd0;
589 record_unwind_protect (call_process_cleanup, Fcurrent_buffer ());
590
591 block_input ();
592 block_child_signal ();
593
572#ifdef WINDOWSNT 594#ifdef WINDOWSNT
573 pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); 595 pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir);
574#else /* not WINDOWSNT */ 596#else /* not WINDOWSNT */
575 597
576 block_input ();
577
578 /* vfork, and prevent local vars from being clobbered by the vfork. */ 598 /* vfork, and prevent local vars from being clobbered by the vfork. */
579 { 599 {
580 Lisp_Object volatile buffer_volatile = buffer; 600 Lisp_Object volatile buffer_volatile = buffer;
@@ -593,6 +613,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
593 char **volatile new_argv_volatile = new_argv; 613 char **volatile new_argv_volatile = new_argv;
594 614
595 pid = vfork (); 615 pid = vfork ();
616 child_errno = errno;
596 617
597 buffer = buffer_volatile; 618 buffer = buffer_volatile;
598 coding_systems = coding_systems_volatile; 619 coding_systems = coding_systems_volatile;
@@ -612,6 +633,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
612 633
613 if (pid == 0) 634 if (pid == 0)
614 { 635 {
636 unblock_child_signal ();
637
615 if (fd0 >= 0) 638 if (fd0 >= 0)
616 emacs_close (fd0); 639 emacs_close (fd0);
617 640
@@ -623,11 +646,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
623 child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); 646 child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir);
624 } 647 }
625 648
626 vfork_errno = errno;
627 unblock_input ();
628
629#endif /* not WINDOWSNT */ 649#endif /* not WINDOWSNT */
630 650
651 child_errno = errno;
652
653 if (0 < pid)
654 {
655 if (INTEGERP (buffer))
656 record_deleted_pid (pid);
657 else
658 synch_process_pid = pid;
659 }
660
661 unblock_child_signal ();
662 unblock_input ();
663
631 /* The MSDOS case did this already. */ 664 /* The MSDOS case did this already. */
632 if (fd_error >= 0) 665 if (fd_error >= 0)
633 emacs_close (fd_error); 666 emacs_close (fd_error);
@@ -644,9 +677,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
644 677
645 if (pid < 0) 678 if (pid < 0)
646 { 679 {
647 if (fd0 >= 0) 680 errno = child_errno;
648 emacs_close (fd0);
649 errno = vfork_errno;
650 report_file_error ("Doing vfork", Qnil); 681 report_file_error ("Doing vfork", Qnil);
651 } 682 }
652 683
@@ -657,19 +688,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
657 return Qnil; 688 return Qnil;
658 } 689 }
659 690
660 /* Enable sending signal if user quits below. */
661 call_process_exited = 0;
662
663#if defined (MSDOS) 691#if defined (MSDOS)
664 /* MSDOS needs different cleanup information. */ 692 /* MSDOS needs different cleanup information. */
665 cleanup_info_tail = build_string (tempfile ? tempfile : "");
666#else
667 cleanup_info_tail = INTEGER_TO_CONS (pid);
668#endif /* not MSDOS */
669 record_unwind_protect (call_process_cleanup, 693 record_unwind_protect (call_process_cleanup,
670 Fcons (Fcurrent_buffer (), 694 Fcons (Fcurrent_buffer (),
671 Fcons (INTEGER_TO_CONS (fd0), 695 build_string (tempfile ? tempfile : "")));
672 cleanup_info_tail))); 696#endif
673 697
674 if (BUFFERP (buffer)) 698 if (BUFFERP (buffer))
675 Fset_buffer (buffer); 699 Fset_buffer (buffer);
@@ -856,38 +880,34 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
856 880
857#ifndef MSDOS 881#ifndef MSDOS
858 /* Wait for it to terminate, unless it already has. */ 882 /* Wait for it to terminate, unless it already has. */
859 if (output_to_buffer) 883 wait_for_termination (pid, &status, !output_to_buffer);
860 wait_for_termination (pid);
861 else
862 interruptible_wait_for_termination (pid);
863#endif 884#endif
864 885
865 immediate_quit = 0; 886 immediate_quit = 0;
866 887
867 /* Don't kill any children that the subprocess may have left behind 888 /* Don't kill any children that the subprocess may have left behind
868 when exiting. */ 889 when exiting. */
869 call_process_exited = 1; 890 synch_process_pid = 0;
870 891
871 SAFE_FREE (); 892 SAFE_FREE ();
872 unbind_to (count, Qnil); 893 unbind_to (count, Qnil);
873 894
874 if (synch_process_termsig) 895 if (WIFSIGNALED (status))
875 { 896 {
876 const char *signame; 897 const char *signame;
877 898
878 synchronize_system_messages_locale (); 899 synchronize_system_messages_locale ();
879 signame = strsignal (synch_process_termsig); 900 signame = strsignal (WTERMSIG (status));
880 901
881 if (signame == 0) 902 if (signame == 0)
882 signame = "unknown"; 903 signame = "unknown";
883 904
884 synch_process_death = signame; 905 return code_convert_string_norecord (build_string (signame),
906 Vlocale_coding_system, 0);
885 } 907 }
886 908
887 if (synch_process_death) 909 eassert (WIFEXITED (status));
888 return code_convert_string_norecord (build_string (synch_process_death), 910 return make_number (WEXITSTATUS (status));
889 Vlocale_coding_system, 0);
890 return make_number (synch_process_retcode);
891} 911}
892 912
893static Lisp_Object 913static Lisp_Object
diff --git a/src/process.c b/src/process.c
index c6139c9f929..27009882c99 100644
--- a/src/process.c
+++ b/src/process.c
@@ -777,10 +777,23 @@ get_process (register Lisp_Object name)
777/* Fdelete_process promises to immediately forget about the process, but in 777/* Fdelete_process promises to immediately forget about the process, but in
778 reality, Emacs needs to remember those processes until they have been 778 reality, Emacs needs to remember those processes until they have been
779 treated by the SIGCHLD handler and waitpid has been invoked on them; 779 treated by the SIGCHLD handler and waitpid has been invoked on them;
780 otherwise they might fill up the kernel's process table. */ 780 otherwise they might fill up the kernel's process table.
781
782 Some processes created by call-process are also put onto this list. */
781static Lisp_Object deleted_pid_list; 783static Lisp_Object deleted_pid_list;
782#endif 784#endif
783 785
786void
787record_deleted_pid (pid_t pid)
788{
789#ifdef SIGCHLD
790 deleted_pid_list = Fcons (make_fixnum_or_float (pid),
791 /* GC treated elements set to nil. */
792 Fdelq (Qnil, deleted_pid_list));
793
794#endif
795}
796
784DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0, 797DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
785 doc: /* Delete PROCESS: kill it and forget about it immediately. 798 doc: /* Delete PROCESS: kill it and forget about it immediately.
786PROCESS may be a process, a buffer, the name of a process or buffer, or 799PROCESS may be a process, a buffer, the name of a process or buffer, or
@@ -807,9 +820,7 @@ nil, indicating the current buffer's process. */)
807 pid_t pid = p->pid; 820 pid_t pid = p->pid;
808 821
809 /* No problem storing the pid here, as it is still in Vprocess_alist. */ 822 /* No problem storing the pid here, as it is still in Vprocess_alist. */
810 deleted_pid_list = Fcons (make_fixnum_or_float (pid), 823 record_deleted_pid (pid);
811 /* GC treated elements set to nil. */
812 Fdelq (Qnil, deleted_pid_list));
813 /* If the process has already signaled, remove it from the list. */ 824 /* If the process has already signaled, remove it from the list. */
814 if (p->raw_status_new) 825 if (p->raw_status_new)
815 update_status (p); 826 update_status (p);
@@ -6147,35 +6158,37 @@ process has been transmitted to the serial port. */)
6147 return process; 6158 return process;
6148} 6159}
6149 6160
6150/* If the status of the process DESIRED has changed, return true and 6161#ifdef SIGCHLD
6151 set *STATUS to its exit status; otherwise, return false.
6152 If HAVE is nonnegative, assume that HAVE = waitpid (HAVE, STATUS, ...)
6153 has already been invoked, and do not invoke waitpid again. */
6154 6162
6155static bool 6163/* The main Emacs thread records child processes in three places:
6156process_status_retrieved (pid_t desired, pid_t have, int *status)
6157{
6158 if (have < 0)
6159 {
6160 /* Invoke waitpid only with a known process ID; do not invoke
6161 waitpid with a nonpositive argument. Otherwise, Emacs might
6162 reap an unwanted process by mistake. For example, invoking
6163 waitpid (-1, ...) can mess up glib by reaping glib's subprocesses,
6164 so that another thread running glib won't find them. */
6165 do
6166 have = waitpid (desired, status, WNOHANG | WUNTRACED);
6167 while (have < 0 && errno == EINTR);
6168 }
6169 6164
6170 return have == desired; 6165 - Vprocess_alist, for asynchronous subprocesses, which are child
6171} 6166 processes visible to Lisp.
6167
6168 - deleted_pid_list, for child processes invisible to Lisp,
6169 typically because of delete-process. These are recorded so that
6170 the processes can be reaped when they exit, so that the operating
6171 system's process table is not cluttered by zombies.
6172 6172
6173/* If PID is nonnegative, the child process PID with wait status W has 6173 - the local variable PID in Fcall_process, call_process_cleanup and
6174 changed its status; record this and return true. 6174 call_process_kill, for synchronous subprocesses.
6175 record_unwind_protect is used to make sure this process is not
6176 forgotten: if the user interrupts call-process and the child
6177 process refuses to exit immediately even with two C-g's,
6178 call_process_kill adds PID's contents to deleted_pid_list before
6179 returning.
6175 6180
6176 If PID is negative, ignore W, and look for known child processes 6181 The main Emacs thread invokes waitpid only on child processes that
6177 of Emacs whose status have changed. For each one found, record its new 6182 it creates and that have not been reaped. This avoid races on
6178 status. 6183 platforms such as GTK, where other threads create their own
6184 subprocesses which the main thread should not reap. For example,
6185 if the main thread attempted to reap an already-reaped child, it
6186 might inadvertently reap a GTK-created process that happened to
6187 have the same process ID. */
6188
6189/* Handle a SIGCHLD signal by looking for known child processes of
6190 Emacs whose status have changed. For each one found, record its
6191 new status.
6179 6192
6180 All we do is change the status; we do not run sentinels or print 6193 All we do is change the status; we do not run sentinels or print
6181 notifications. That is saved for the next time keyboard input is 6194 notifications. That is saved for the next time keyboard input is
@@ -6198,20 +6211,15 @@ process_status_retrieved (pid_t desired, pid_t have, int *status)
6198 ** Malloc WARNING: This should never call malloc either directly or 6211 ** Malloc WARNING: This should never call malloc either directly or
6199 indirectly; if it does, that is a bug */ 6212 indirectly; if it does, that is a bug */
6200 6213
6201void 6214static void
6202record_child_status_change (pid_t pid, int w) 6215handle_child_signal (int sig)
6203{ 6216{
6204#ifdef SIGCHLD
6205
6206 /* Record at most one child only if we already know one child that
6207 has exited. */
6208 bool record_at_most_one_child = 0 <= pid;
6209
6210 Lisp_Object tail; 6217 Lisp_Object tail;
6211 6218
6212 /* Find the process that signaled us, and record its status. */ 6219 /* Find the process that signaled us, and record its status. */
6213 6220
6214 /* The process can have been deleted by Fdelete_process. */ 6221 /* The process can have been deleted by Fdelete_process, or have
6222 been started asynchronously by Fcall_process. */
6215 for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) 6223 for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail))
6216 { 6224 {
6217 bool all_pids_are_fixnums 6225 bool all_pids_are_fixnums
@@ -6225,12 +6233,8 @@ record_child_status_change (pid_t pid, int w)
6225 deleted_pid = XINT (xpid); 6233 deleted_pid = XINT (xpid);
6226 else 6234 else
6227 deleted_pid = XFLOAT_DATA (xpid); 6235 deleted_pid = XFLOAT_DATA (xpid);
6228 if (process_status_retrieved (deleted_pid, pid, &w)) 6236 if (child_status_changed (deleted_pid, 0, 0))
6229 { 6237 XSETCAR (tail, Qnil);
6230 XSETCAR (tail, Qnil);
6231 if (record_at_most_one_child)
6232 return;
6233 }
6234 } 6238 }
6235 } 6239 }
6236 6240
@@ -6239,15 +6243,17 @@ record_child_status_change (pid_t pid, int w)
6239 { 6243 {
6240 Lisp_Object proc = XCDR (XCAR (tail)); 6244 Lisp_Object proc = XCDR (XCAR (tail));
6241 struct Lisp_Process *p = XPROCESS (proc); 6245 struct Lisp_Process *p = XPROCESS (proc);
6242 if (p->alive && process_status_retrieved (p->pid, pid, &w)) 6246 int status;
6247
6248 if (p->alive && child_status_changed (p->pid, &status, WUNTRACED))
6243 { 6249 {
6244 /* Change the status of the process that was found. */ 6250 /* Change the status of the process that was found. */
6245 p->tick = ++process_tick; 6251 p->tick = ++process_tick;
6246 p->raw_status = w; 6252 p->raw_status = status;
6247 p->raw_status_new = 1; 6253 p->raw_status_new = 1;
6248 6254
6249 /* If process has terminated, stop waiting for its output. */ 6255 /* If process has terminated, stop waiting for its output. */
6250 if (WIFSIGNALED (w) || WIFEXITED (w)) 6256 if (WIFSIGNALED (status) || WIFEXITED (status))
6251 { 6257 {
6252 int clear_desc_flag = 0; 6258 int clear_desc_flag = 0;
6253 p->alive = 0; 6259 p->alive = 0;
@@ -6261,44 +6267,8 @@ record_child_status_change (pid_t pid, int w)
6261 FD_CLR (p->infd, &non_keyboard_wait_mask); 6267 FD_CLR (p->infd, &non_keyboard_wait_mask);
6262 } 6268 }
6263 } 6269 }
6264
6265 /* Tell wait_reading_process_output that it needs to wake up and
6266 look around. */
6267 if (input_available_clear_time)
6268 *input_available_clear_time = make_emacs_time (0, 0);
6269
6270 if (record_at_most_one_child)
6271 return;
6272 } 6270 }
6273 } 6271 }
6274
6275 if (0 <= pid)
6276 {
6277 /* The caller successfully waited for a pid but no asynchronous
6278 process was found for it, so this is a synchronous process. */
6279
6280 synch_process_alive = 0;
6281
6282 /* Report the status of the synchronous process. */
6283 if (WIFEXITED (w))
6284 synch_process_retcode = WEXITSTATUS (w);
6285 else if (WIFSIGNALED (w))
6286 synch_process_termsig = WTERMSIG (w);
6287
6288 /* Tell wait_reading_process_output that it needs to wake up and
6289 look around. */
6290 if (input_available_clear_time)
6291 *input_available_clear_time = make_emacs_time (0, 0);
6292 }
6293#endif
6294}
6295
6296#ifdef SIGCHLD
6297
6298static void
6299handle_child_signal (int sig)
6300{
6301 record_child_status_change (-1, 0);
6302} 6272}
6303 6273
6304static void 6274static void
diff --git a/src/process.h b/src/process.h
index 74d1a124060..4fa22747ca9 100644
--- a/src/process.h
+++ b/src/process.h
@@ -185,23 +185,6 @@ pset_gnutls_cred_type (struct Lisp_Process *p, Lisp_Object val)
185} 185}
186#endif 186#endif
187 187
188/* True if we are about to fork off a synchronous process or if we
189 are waiting for it. */
190extern bool synch_process_alive;
191
192/* Communicate exit status of sync process to from sigchld_handler
193 to Fcall_process. */
194
195/* Nonzero => this is a string explaining death of synchronous subprocess. */
196extern const char *synch_process_death;
197
198/* Nonzero => this is the signal number that terminated the subprocess. */
199extern int synch_process_termsig;
200
201/* If synch_process_death is zero,
202 this is exit code of synchronous subprocess. */
203extern int synch_process_retcode;
204
205/* Nonzero means don't run process sentinels. This is used 188/* Nonzero means don't run process sentinels. This is used
206 when exiting. */ 189 when exiting. */
207extern int inhibit_sentinels; 190extern int inhibit_sentinels;
diff --git a/src/sysdep.c b/src/sysdep.c
index 1a3834f0379..7068a4f0977 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -266,45 +266,71 @@ init_baud_rate (int fd)
266 266
267#ifndef MSDOS 267#ifndef MSDOS
268 268
269static void 269/* Wait for the subprocess with process id CHILD to terminate or change status.
270wait_for_termination_1 (pid_t pid, int interruptible) 270 CHILD must be a child process that has not been reaped.
271 If STATUS is non-null, store the waitpid-style exit status into *STATUS
272 and tell wait_reading_process_output that it needs to look around.
273 Use waitpid-style OPTIONS when waiting.
274 If INTERRUPTIBLE, this function is interruptible by a signal.
275
276 Return CHILD if successful, 0 if no status is available;
277 the latter is possible only when options & NOHANG. */
278static pid_t
279get_child_status (pid_t child, int *status, int options, bool interruptible)
271{ 280{
272 while (1) 281 pid_t pid;
282
283 /* Invoke waitpid only with a known process ID; do not invoke
284 waitpid with a nonpositive argument. Otherwise, Emacs might
285 reap an unwanted process by mistake. For example, invoking
286 waitpid (-1, ...) can mess up glib by reaping glib's subprocesses,
287 so that another thread running glib won't find them. */
288 eassert (0 < child);
289
290 while ((pid = waitpid (child, status, options)) < 0)
273 { 291 {
274 int status; 292 /* CHILD must be a child process that has not been reaped, and
275 int wait_result = waitpid (pid, &status, 0); 293 STATUS and OPTIONS must be valid. */
276 if (wait_result < 0) 294 eassert (errno == EINTR);
277 {
278 if (errno != EINTR)
279 break;
280 }
281 else
282 {
283 record_child_status_change (wait_result, status);
284 break;
285 }
286 295
287 /* Note: the MS-Windows emulation of waitpid calls QUIT 296 /* Note: the MS-Windows emulation of waitpid calls QUIT
288 internally. */ 297 internally. */
289 if (interruptible) 298 if (interruptible)
290 QUIT; 299 QUIT;
291 } 300 }
292}
293 301
294/* Wait for subprocess with process id `pid' to terminate and 302 /* If successful and status is requested, tell wait_reading_process_output
295 make sure it will get eliminated (not remain forever as a zombie) */ 303 that it needs to wake up and look around. */
304 if (pid && status && input_available_clear_time)
305 *input_available_clear_time = make_emacs_time (0, 0);
296 306
307 return pid;
308}
309
310/* Wait for the subprocess with process id CHILD to terminate.
311 CHILD must be a child process that has not been reaped.
312 If STATUS is non-null, store the waitpid-style exit status into *STATUS
313 and tell wait_reading_process_output that it needs to look around.
314 If INTERRUPTIBLE, this function is interruptible by a signal. */
297void 315void
298wait_for_termination (pid_t pid) 316wait_for_termination (pid_t child, int *status, bool interruptible)
299{ 317{
300 wait_for_termination_1 (pid, 0); 318 get_child_status (child, status, 0, interruptible);
301} 319}
302 320
303/* Like the above, but allow keyboard interruption. */ 321/* Report whether the subprocess with process id CHILD has changed status.
304void 322 Termination counts as a change of status.
305interruptible_wait_for_termination (pid_t pid) 323 CHILD must be a child process that has not been reaped.
324 If STATUS is non-null, store the waitpid-style exit status into *STATUS
325 and tell wait_reading_process_output that it needs to look around.
326 Use waitpid-style OPTIONS to check status, but do not wait.
327
328 Return CHILD if successful, 0 if no status is available because
329 the process's state has not changed. */
330pid_t
331child_status_changed (pid_t child, int *status, int options)
306{ 332{
307 wait_for_termination_1 (pid, 1); 333 return get_child_status (child, status, WNOHANG | options, 0);
308} 334}
309 335
310/* 336/*
@@ -454,6 +480,7 @@ sys_subshell (void)
454 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ 480 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
455#endif 481#endif
456 pid_t pid; 482 pid_t pid;
483 int status;
457 struct save_signal saved_handlers[5]; 484 struct save_signal saved_handlers[5];
458 Lisp_Object dir; 485 Lisp_Object dir;
459 unsigned char *volatile str_volatile = 0; 486 unsigned char *volatile str_volatile = 0;
@@ -491,7 +518,6 @@ sys_subshell (void)
491#ifdef DOS_NT 518#ifdef DOS_NT
492 pid = 0; 519 pid = 0;
493 save_signal_handlers (saved_handlers); 520 save_signal_handlers (saved_handlers);
494 synch_process_alive = 1;
495#else 521#else
496 pid = vfork (); 522 pid = vfork ();
497 if (pid == -1) 523 if (pid == -1)
@@ -560,14 +586,12 @@ sys_subshell (void)
560 /* Do this now if we did not do it before. */ 586 /* Do this now if we did not do it before. */
561#ifndef MSDOS 587#ifndef MSDOS
562 save_signal_handlers (saved_handlers); 588 save_signal_handlers (saved_handlers);
563 synch_process_alive = 1;
564#endif 589#endif
565 590
566#ifndef DOS_NT 591#ifndef DOS_NT
567 wait_for_termination (pid); 592 wait_for_termination (pid, &status, 0);
568#endif 593#endif
569 restore_signal_handlers (saved_handlers); 594 restore_signal_handlers (saved_handlers);
570 synch_process_alive = 0;
571} 595}
572 596
573static void 597static void
diff --git a/src/syswait.h b/src/syswait.h
index aa4c4bcf527..360407d558e 100644
--- a/src/syswait.h
+++ b/src/syswait.h
@@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
23#ifndef EMACS_SYSWAIT_H 23#ifndef EMACS_SYSWAIT_H
24#define EMACS_SYSWAIT_H 24#define EMACS_SYSWAIT_H
25 25
26#include <stdbool.h>
26#include <sys/types.h> 27#include <sys/types.h>
27 28
28#ifdef HAVE_SYS_WAIT_H /* We have sys/wait.h with POSIXoid definitions. */ 29#ifdef HAVE_SYS_WAIT_H /* We have sys/wait.h with POSIXoid definitions. */
@@ -52,10 +53,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
52#endif 53#endif
53 54
54/* Defined in process.c. */ 55/* Defined in process.c. */
55extern void record_child_status_change (pid_t, int); 56extern void record_deleted_pid (pid_t);
56 57
57/* Defined in sysdep.c. */ 58/* Defined in sysdep.c. */
58extern void wait_for_termination (pid_t); 59extern void wait_for_termination (pid_t, int *, bool);
59extern void interruptible_wait_for_termination (pid_t); 60extern pid_t child_status_changed (pid_t, int *, int);
60 61
61#endif /* EMACS_SYSWAIT_H */ 62#endif /* EMACS_SYSWAIT_H */
diff --git a/src/w32proc.c b/src/w32proc.c
index 9b111b40e36..87af8682390 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -1274,33 +1274,7 @@ waitpid (pid_t pid, int *status, int options)
1274#endif 1274#endif
1275 1275
1276 if (status) 1276 if (status)
1277 { 1277 *status = retval;
1278 *status = retval;
1279 }
1280 else if (synch_process_alive)
1281 {
1282 synch_process_alive = 0;
1283
1284 /* Report the status of the synchronous process. */
1285 if (WIFEXITED (retval))
1286 synch_process_retcode = WEXITSTATUS (retval);
1287 else if (WIFSIGNALED (retval))
1288 {
1289 int code = WTERMSIG (retval);
1290 const char *signame;
1291
1292 synchronize_system_messages_locale ();
1293 signame = strsignal (code);
1294
1295 if (signame == 0)
1296 signame = "unknown";
1297
1298 synch_process_death = signame;
1299 }
1300
1301 reap_subprocess (cp);
1302 }
1303
1304 reap_subprocess (cp); 1278 reap_subprocess (cp);
1305 1279
1306 return pid; 1280 return pid;