Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/bin/sh PR bin/52640 PR bin/52641



details:   https://anonhg.NetBSD.org/src/rev/f76a833f17b6
branches:  trunk
changeset: 827320:f76a833f17b6
user:      kre <kre%NetBSD.org@localhost>
date:      Mon Oct 23 10:52:07 2017 +0000

description:
PR bin/52640  PR bin/52641

Don't delete jobs from the jobs table merely because they finished,
if they are not the job we are waiting upon.   (bin/52640 part 1)

In a sub-shell environment, don't allow wait to find jobs from the
parent shell that had already exited (before the sub-shell was
created) and return status for them as if they are our children.
(bin/52640 part 2)

Don't have the "jobs" command also be an implicit "wait" command
in non-interactive shells.  (bin/52641)

Use WCONTINUED (when it exists) so we can report on stopped jobs that
"mysteriously" move back to running state without the user issuing
a "bg" command (eg: kill -CONT <pid>)   Previously they would keep
being reported as stopped until they exited.

When a job is detected as having changed status just as we're
issuing a "jobs" command (i.e.: the change occurred between the last
prompt and the jobs command being entered) don't report it twice,
once from the status change, and then again in the jobs command
output.   Once is enough (keep the jobs output, suppress the other).

Apply some sanity to the way jobs_invalid is processed - ignore it
in getjob() instead of just ignoring it most of the time there, and
instead always check it before calling getjob() in situations where
we can handle only children of the current shell.  This allows the
(totally broken) save/clear/restore of jobs_invalid in jobscmd() to
be done away with (previously an error while in the clear state would
have left jobs_invalid incorrectly cleared - shouldn't have mattered
since jobs_invalid => subshell => error causes exit, but better to be safe).

Add/improve the DEBUG more tracing.

XXX pullup -8

diffstat:

 bin/sh/jobs.c |  74 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 54 insertions(+), 20 deletions(-)

diffs (228 lines):

diff -r fc1138d84f96 -r f76a833f17b6 bin/sh/jobs.c
--- a/bin/sh/jobs.c     Mon Oct 23 09:35:35 2017 +0000
+++ b/bin/sh/jobs.c     Mon Oct 23 10:52:07 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: jobs.c,v 1.90 2017/10/19 01:57:18 kre Exp $    */
+/*     $NetBSD: jobs.c,v 1.91 2017/10/23 10:52:07 kre Exp $    */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)jobs.c     8.5 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: jobs.c,v 1.90 2017/10/19 01:57:18 kre Exp $");
+__RCSID("$NetBSD: jobs.c,v 1.91 2017/10/23 10:52:07 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -82,6 +82,14 @@
 #include "mystring.h"
 
 
+#ifndef        WCONTINUED
+#define        WCONTINUED 0            /* So we can compile on old systems */
+#endif
+#ifndef        WIFCONTINUED
+#define        WIFCONTINUED(x) (0)             /* ditto */
+#endif
+
+
 static struct job *jobtab;             /* array of jobs */
 static int njobs;                      /* size of array */
 static int jobs_invalid;               /* set in child */
@@ -98,6 +106,7 @@
 STATIC int dowait(int, struct job *);
 #define WBLOCK 1
 #define WNOFREE 2
+#define WSILENT 4
 STATIC int jobstatus(const struct job *, int);
 STATIC int waitproc(int, struct job *, int *);
 STATIC void cmdtxt(union node *);
@@ -247,6 +256,8 @@
        int i;
        int status;
 
+       if (jobs_invalid)
+               error("No current jobs");
        jp = getjob(arg_ptr, 0);
        if (jp->jobctl == 0)
                error("job not created under job control");
@@ -339,6 +350,8 @@
        int i;
 
        nextopt("");
+       if (jobs_invalid)
+               error("No current jobs");
        do {
                jp = getjob(*argptr, 0);
                if (jp->jobctl == 0)
@@ -468,7 +481,7 @@
                                fmtstr(s + col, 16, "Done");
                } else {
 #if JOBS
-                       if (WIFSTOPPED(ps->status)) 
+                       if (WIFSTOPPED(ps->status))
                                st = WSTOPSIG(ps->status);
                        else /* WIFSIGNALED(ps->status) */
 #endif
@@ -512,22 +525,21 @@
 jobscmd(int argc, char **argv)
 {
        int mode, m;
-       int sv = jobs_invalid;
 
-       jobs_invalid = 0;
        mode = 0;
        while ((m = nextopt("lp")))
                if (m == 'l')
                        mode = SHOW_PID;
                else
                        mode = SHOW_PGID;
+       if (!iflag)
+               mode |= SHOW_NO_FREE;
        if (*argptr)
                do
                        showjob(out1, getjob(*argptr,0), mode);
                while (*++argptr);
        else
                showjobs(out1, mode);
-       jobs_invalid = sv;
        return 0;
 }
 
@@ -551,8 +563,8 @@
        CTRACE(DBG_JOBS, ("showjobs(%x) called\n", mode));
 
        /* If not even one one job changed, there is nothing to do */
-       gotpid = dowait(0, NULL);
-       while (dowait(0, NULL) > 0)
+       gotpid = dowait(WSILENT, NULL);
+       while (dowait(WSILENT, NULL) > 0)
                continue;
 #ifdef JOBS
        /*
@@ -653,11 +665,20 @@
 
        nextopt("");
 
+       /*
+        * If we have forked, and not yet created any new jobs, then
+        * we have no children, whatever jobtab claims,
+        * so simply return in that case.
+        *
+        * The return code is 127 if we had any pid args (none are found)
+        * but 0 for plain old "wait".
+        */
+       if (jobs_invalid)
+               return *argptr ? 127 : 0;
+
        if (!*argptr) {
                /* wait for all jobs */
                jp = jobtab;
-               if (jobs_invalid)
-                       return 0;
                for (;;) {
                        if (jp >= jobtab + njobs) {
                                /* no running procs */
@@ -714,6 +735,8 @@
 {
        struct job *jp;
 
+       if (jobs_invalid)
+               error("No such job: %s", name);
        jp = getjob(name, 1);
        if (jp == 0)
                return 0;
@@ -732,7 +755,7 @@
        int pid;
        int i;
        const char *err_msg = "No such job: %s";
-               
+
        if (name == NULL) {
 #if JOBS
                jobno = curjob;
@@ -791,7 +814,7 @@
                }
        }
 
-       if (!jobs_invalid && jobno >= 0 && jobno < njobs) {
+       if (jobno >= 0 && jobno < njobs) {
                jp = jobtab + jobno;
                if (jp->used)
                        return jp;
@@ -942,7 +965,8 @@
        const char *nullerr = "Can't open %s";
 
        wasroot = rootshell;
-       CTRACE(DBG_JOBS, ("Child shell %d%s\n",getpid(),vforked?" vforked":""));
+       CTRACE(DBG_JOBS, ("Child shell %d %sforked from %d (mode %d)\n",
+           getpid(), vforked?"v":"", getppid(), mode));
        if (!vforked)
                rootshell = 0;
 
@@ -1107,12 +1131,19 @@
                        for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
                                if (sp->pid == -1)
                                        continue;
-                               if (sp->pid == pid) {
+                               if (sp->pid == pid &&
+                                 (sp->status==-1 || WIFSTOPPED(sp->status))) {
                                        VTRACE(DBG_JOBS | DBG_PROCS,
                        ("Job %d: changing status of proc %d from %#x to %#x\n",
                                                jp - jobtab + 1, pid,
                                                sp->status, status));
-                                       sp->status = status;
+                                       if (WIFCONTINUED(status)) {
+                                               if (sp->status != -1)
+                                                       jp->changed = 1;
+                                               sp->status = -1;
+                                               jp->state = 0;
+                                       } else
+                                               sp->status = status;
                                        thisjob = jp;
                                }
                                if (sp->status == -1)
@@ -1122,6 +1153,7 @@
                        }
                        if (stopped) {          /* stopped or done */
                                int state = done ? JOBDONE : JOBSTOPPED;
+
                                if (jp->state != state) {
                                        VTRACE(DBG_JOBS,
                                ("Job %d: changing state from %d to %d\n",
@@ -1136,14 +1168,15 @@
                }
        }
 
-       if (thisjob && thisjob->state != JOBRUNNING) {
+       if (thisjob && (thisjob->state != JOBRUNNING || thisjob->changed)) {
                int mode = 0;
+
                if (!rootshell || !iflag)
                        mode = SHOW_SIGNALLED;
                if ((job == thisjob && (flags & WNOFREE) == 0) ||
-                   (job != thisjob && (flags & WNOFREE) != 0))
+                   job != thisjob)
                        mode = SHOW_SIGNALLED | SHOW_NO_FREE;
-               if (mode)
+               if (mode && (flags & WSILENT) == 0)
                        showjob(out2, thisjob, mode);
                else {
                        VTRACE(DBG_JOBS,
@@ -1204,11 +1237,12 @@
        int flags = 0;
 
 #if JOBS
-       if (jp != NULL && jp->jobctl)
-               flags |= WUNTRACED;
+       if (mflag || (jp != NULL && jp->jobctl))
+               flags |= WUNTRACED | WCONTINUED;
 #endif
        if (block == 0)
                flags |= WNOHANG;
+       VTRACE(DBG_WAIT, ("waitproc: doing waitpid(flags=%#x)\n", flags));
        return waitpid(-1, status, flags);
 #else
 #ifdef SYSV



Home | Main Index | Thread Index | Old Index