aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/process.c')
-rw-r--r--src/process.c136
1 files changed, 53 insertions, 83 deletions
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