Chet Ramey wrote:
>
> > >POSIX shells are required to remember at least CHILD_MAX (but
> > >optionally more) process statuses. There is a gray area about whether
> > >or not the user can query the status of those processes, implying that
> > >once the status of a background or foreground job has been reported,
> > >its status, and the status of its constituent processes, can be
> > >discarded, but those rules are hard to decipher.
> >
> > Are you saying that waitpid should be able to return the status of an
> > exited process when it is called repeatedly? I've never seen anything
> > like that. I thought that once you'd done a wait the process was
> > unzombified, it goes away, and it is unavailable for future querying.
>
> No. The portion of the POSIX spec describing the shell's behavior is
> independent of the exact function used to query a process's status. It
> says the shell has to remember. It doesn't mention waitpid(), nor does
> it need to.
>
> You're assuming that the shell just does a waitpid() whenever it needs to
> get a particular process's status. No shell does it that way.
In practice, when does bash need to get a process status on a per
pid (and not per job) basis?
FWIW, attached is a patch to bash that may improve its behavior on Cygwin.
The idea is that when a new process is stored in the memory array, any
existing process with the same pid is marked "reused". "reused" processes
are never considered when searching for a process by pid. They are still
still available, e.g. to get the status of processes in a job.
It's a proof of principle code, not meant to be efficient. It can still print
a debug message on stderr.
Pierre
--- jobs.h.orig 2002-01-17 12:35:11.000000000 -0500
+++ jobs.h 2004-09-16 14:11:02.107380800 -0400
@@ -55,6 +55,7 @@ typedef struct process {
WAIT status; /* The status of this command as returned by wait. */
int running; /* Non-zero if this process is running. */
char *command; /* The particular program that is running. */
+ int reused;
} PROCESS;
/* PRUNNING really means `not exited' */
--- jobs.c.orig 2002-05-09 11:56:20.000000000 -0400
+++ jobs.c 2004-09-16 14:01:25.478228800 -0400
@@ -737,7 +737,35 @@ add_process (name, pid)
char *name;
pid_t pid;
{
- PROCESS *t, *p;
+ PROCESS *t, *p, * p_start;
+ register int i;
+
+ for (i = -1; i < job_slots; i++)
+ {
+ if (i < 0)
+ {
+ if (!(p = the_pipeline))
+ continue;
+ }
+ else if (jobs[i])
+ p = jobs[i]->pipe;
+ else
+ continue;
+
+ p_start = p;
+ do
+ {
+ if (p->pid == pid && !p->reused)
+ {
+ p->reused = 1;
+ fprintf(stderr, "Found old pid %d in job %d\n", pid, i);
+ goto done;
+ }
+ p = p->next;
+ }
+ while (p != p_start);
+ }
+ done:
t = (PROCESS *)xmalloc (sizeof (PROCESS));
t->next = the_pipeline;
@@ -745,6 +773,7 @@ add_process (name, pid)
WSTATUS (t->status) = 0;
t->running = PS_RUNNING;
t->command = name;
+ t->reused = 0;
the_pipeline = t;
if (t->next == 0)
@@ -902,12 +931,11 @@ find_pipeline (pid, running_only, jobp)
do
{
/* Return it if we found it. */
- if (p->pid == pid)
+ if (p->pid == pid && !p->reused)
{
if ((running_only && PRUNNING(p)) || (running_only == 0))
return (p);
}
-
p = p->next;
}
while (p != the_pipeline);
@@ -937,7 +965,7 @@ find_job (pid, running_only)
do
{
- if (p->pid == pid)
+ if (p->pid == pid && !p->reused)
{
if ((running_only && PRUNNING(p)) || (running_only == 0))
return (i);
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Problem reports: http://cygwin.com/problems.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/