entry widget broken in 3.99.1?
I've found a bug in process.c that prevents you from getting the exit status
of a child process under certain circumstances.
Description of problem:
In the handler for SIGCHLD, a call is made to waitpid() to check the status
of each of the child processes. In the current version of process.c, a
non-zero return value is interpreted as meaning that the child has exited
and the child's status has been read:
static int internal_process_alivep(SCM process)
...
res = waitpid(PROCPID(process), &info, WNOHANG);
if (res == 0)
/* process is still running */
return TRUE;
else {
/* process has terminated and we must save this information */
PROCESS(process)->exited = TRUE;
PROCESS(process)->exit_status = info;
return FALSE;
...
This is not always the case. If (process-wait [process]) has been called to
wait on a particular child, it will read the status, and the waitpid() call
in the SIGCHLD handler will return a -1 (no such child). The info field
doesn't contain any data and it is written over the exit_status that was
saved by (process-wait [process]) -- thus the exit_status field now contains
random garbage.
The fix:
Always check the return status from waitpid() to see if it returns the
requested pid:
res = waitpid(PROCPID(process), &info, WNOHANG);
if (res == 0)
{
/* process is still running */
return TRUE;
}
else if (res == PROCPID(process))
{
/* process has terminated and we must save this information */
PROCESS(process)->exited = TRUE;
PROCESS(process)->exit_status = info;
return FALSE;
}
else
{
/* might not have found process because we've already waited for it */
/* if so, then status has already been updated */
return FALSE;
}
[All calls to waitpid() should be handled similarly]
I've included a context diff below. It has only been tested on Linux
2.0.31, but judging by the man pages, it ought to work for Solaris 2.5 also.
Unfortunately, I re-indented bsome of the code while I was debugging, and
haven't un-done my formatting changes. So, there are cosmetic-only changes
reflected in some of the patch. Sorry.
------------------------------cut here------------------------------
*** process.c.old Fri Apr 10 02:13:18 1998
--- process.c Thu May 14 09:05:51 1998
***************
*** 81,108 ****
}
static int internal_process_alivep(SCM process)
! {
! int info, res;
if (PROCESS(process)->exited)
return FALSE;
! else {
/* Use waitpid to gain the info. */
res = waitpid(PROCPID(process), &info, WNOHANG);
if (res == 0)
/* process is still running */
return TRUE;
! else {
/* process has terminated and we must save this information */
PROCESS(process)->exited = TRUE;
PROCESS(process)->exit_status = info;
return FALSE;
}
}
! }
static void process_terminate_handler(int sig) /* called when a child dies */
! {
register int i;
SCM proc;
--- 81,118 ----
}
static int internal_process_alivep(SCM process)
! {
! int info = 0, res = -1;
if (PROCESS(process)->exited)
return FALSE;
! else
! {
/* Use waitpid to gain the info. */
res = waitpid(PROCPID(process), &info, WNOHANG);
if (res == 0)
+ {
/* process is still running */
return TRUE;
! }
! else if (res == PROCPID(process))
! {
/* process has terminated and we must save this information */
PROCESS(process)->exited = TRUE;
PROCESS(process)->exit_status = info;
return FALSE;
}
+ else
+ {
+ /* might not have found process because we've already waited for it */
+ /* if so, then status has already been updated */
+ return FALSE;
}
! }
! }
static void process_terminate_handler(int sig) /* called when a child dies */
! {
register int i;
SCM proc;
***************
*** 110,118 ****
static int in_handler = 0;
signal(SIGCHLD, process_terminate_handler); /* Necessary on System V */
! if (in_handler++) /* Execution is re-entrant */ return;
! do {
#endif
/* Find the process which is terminated
* Note that this loop can find:
--- 120,130 ----
static int in_handler = 0;
signal(SIGCHLD, process_terminate_handler); /* Necessary on System V */
! if (in_handler++) /* Execution is re-entrant */
! return;
! do
! {
#endif
/* Find the process which is terminated
* Note that this loop can find:
***************
*** 124,130 ****
* PURGE_PROCESS_TABLE
* Sometimes I think that life is a little bit complicated....
*/
! for(i = 0; i<MAX_PROC_NUM; i++) {
proc = proc_arr[i];
if (PROCESSP(proc) && !internal_process_alivep(proc))
/* This process has exited. We can delete it from the table */
--- 136,143 ----
* PURGE_PROCESS_TABLE
* Sometimes I think that life is a little bit complicated....
*/
! for(i = 0; i<MAX_PROC_NUM; i++)
! {
proc = proc_arr[i];
if (PROCESSP(proc) && !internal_process_alivep(proc))
/* This process has exited. We can delete it from the table */
***************
*** 138,144 ****
*/
} while (--in_handler > 0);
#endif
! }
static SCM make_process(void)
--- 151,157 ----
*/
} while (--in_handler > 0);
#endif
! }
static SCM make_process(void)
***************
*** 446,489 ****
}
static PRIMITIVE process_wait(SCM process)
! {
PURGE_PROCESS_TABLE();
if(NPROCESSP(process)) Err("process-wait: bad process", process);
if (PROCESS(process)->exited) return Ntruth;
! else {
! int ret = waitpid(PROCPID(process), &PROCESS(process)->exit_status, 0);
PROCESS(process)->exited = TRUE;
! return (ret == 0) ? Ntruth : Truth;
}
! }
static PRIMITIVE process_xstatus(SCM process)
! {
! int info, n;
PURGE_PROCESS_TABLE();
! if (NPROCESSP(process)) Err("process-exit-status: bad process", process);
! if (PROCESS(process)->exited) n = PROCESS(process)->exit_status;
! else {
! if (waitpid(PROCPID(process), &info, WNOHANG) == 0) {
/* Process is still running */
return Ntruth;
}
! else {
/* Process is now terminated */
PROCESS(process)->exited = TRUE;
PROCESS(process)->exit_status = info;
n = WEXITSTATUS(info);
}
}
return STk_makeinteger((long) n);
! }
static PRIMITIVE process_send_signal(SCM process, SCM signal)
{
--- 459,519 ----
}
static PRIMITIVE process_wait(SCM process)
! {
PURGE_PROCESS_TABLE();
if(NPROCESSP(process)) Err("process-wait: bad process", process);
if (PROCESS(process)->exited) return Ntruth;
! else
! {
! int info=0, res=-1;
+ res = waitpid(PROCPID(process), &info, 0);
+
+ if (res == PROCPID(process))
+ {
+ PROCESS(process)->exit_status = info;
PROCESS(process)->exited = TRUE;
! return Truth;
}
! else
! return Ntruth;
! }
! }
static PRIMITIVE process_xstatus(SCM process)
! {
! int info, n, res;
PURGE_PROCESS_TABLE();
! if (NPROCESSP(process))
! Err("process-exit-status: bad process", process);
! if (PROCESS(process)->exited)
! n = WEXITSTATUS(PROCESS(process)->exit_status);
! else
! {
! res = waitpid(PROCPID(process), &info, WNOHANG);
! if (res == 0)
! {
/* Process is still running */
return Ntruth;
}
! else if (res == PROCPID(process))
! {
/* Process is now terminated */
PROCESS(process)->exited = TRUE;
PROCESS(process)->exit_status = info;
n = WEXITSTATUS(info);
}
+ else
+ return Ntruth;
}
return STk_makeinteger((long) n);
! }
static PRIMITIVE process_send_signal(SCM process, SCM signal)
{
------------------------------cut here------------------------------
Received on Mon May 18 1998 - 21:54:02 CEST
This archive was generated by hypermail 2.3.0
: Mon Jul 21 2014 - 19:38:59 CEST