aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.c
diff options
context:
space:
mode:
authorPaul Eggert2012-11-24 00:24:11 -0800
committerPaul Eggert2012-11-24 00:24:11 -0800
commitd4547511735190a81449727a89dc90f6ef1d99a3 (patch)
tree21a30d3770b340cfbd67df4875d3c9a1d782bc20 /src/process.c
parent0c5ef1333558423f0eb0f14934fffb1b4bce0946 (diff)
downloademacs-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/process.c')
-rw-r--r--src/process.c191
1 files changed, 103 insertions, 88 deletions
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. */
792static Lisp_Object deleted_pid_list; 801static 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
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.
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. */
6311void 6302void
6312record_child_status_change (pid_t pid, int w) 6303record_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)))
6402enum { CAN_HANDLE_MULTIPLE_CHILDREN = 0 };
6403#else
6404enum { CAN_HANDLE_MULTIPLE_CHILDREN = 1 };
6405#endif
6406
6408static void 6407static void
6409handle_child_signal (int sig) 6408handle_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
6414static void 6429static void