Hi *,
since this topic often occurs, not the least when porting to
Syllable, Plan 9, Linux/µclibc-ng/nios2, etc. here’s a patch
relative to mksh R52c (last formal release), enabling a num‐
ber of debugging-related output lines whenever something re‐
lated to job signal handling occurs (start a process, handle
SIGCHLD, wait for a process, etc). Well, some of it.
I’m posting this here after a quick test in the hope that it
helps someone, especially in comparing output against a code
base that is known to work, ceteris paribus.
Index: jobs.c
===================================================================
RCS file: /cvs/src/bin/mksh/jobs.c,v
retrieving revision 1.120
diff -u -p -r1.120 jobs.c
--- jobs.c 4 Mar 2016 14:26:13 -0000 1.120
+++ jobs.c 26 Jun 2016 16:04:36 -0000
@@ -139,7 +139,9 @@ static int const tt_sigs[] = { SIGTSTP,
static void j_set_async(Job *);
static void j_startjob(Job *);
static int j_waitj(Job *, int, const char *);
-static void j_sigchld(int);
+static void j_sigchld_impl(int);
+static void j_sigchld_manual(int);
+static void j_sigchld_intr(int);
static void j_print(Job *, int, struct shf *);
static Job *j_lookup(const char *, int *);
static Job *new_job(void);
@@ -169,7 +171,7 @@ j_init(void)
(void)sigemptyset(&sm_sigchld);
(void)sigaddset(&sm_sigchld, SIGCHLD);
- setsig(&sigtraps[SIGCHLD], j_sigchld,
+ setsig(&sigtraps[SIGCHLD], j_sigchld_intr,
SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
#else
/* Make sure SIGCHLD isn't ignored - can do odd things under SYSV */
@@ -499,6 +501,23 @@ exchild(struct op *t, int flags,
/* create child process */
forksleep = 1;
+ shellf("{D: exchild (no-sigsuspend %s, unemployed %s, noprospectofwork
%s) before fork<%s>}\n",
+#ifdef MKSH_NO_SIGSUSPEND
+ "on",
+#else
+ "off",
+#endif
+#ifdef MKSH_UNEMPLOYED
+ "on",
+#else
+ "off",
+#endif
+#ifdef MKSH_NOPROSPECTOFWORK
+ "on",
+#else
+ "off",
+#endif
+ p->command);
while ((cldpid = fork()) < 0 && errno == EAGAIN && forksleep < 32) {
if (intrsig)
/* allow user to ^C out... */
@@ -518,6 +537,8 @@ exchild(struct op *t, int flags,
errorf("can't fork - try again");
}
p->pid = cldpid ? cldpid : (procpid = getpid());
+ shellf("{D: after fork, child %d, in %s}\n", (int)p->pid,
+ cldpid ? "parent" : "child");
#ifndef MKSH_UNEMPLOYED
/* job control set up */
@@ -595,6 +616,7 @@ exchild(struct op *t, int flags,
#endif
Flag(FTALKING) = 0;
cleartraps();
+ shellf("{D:child %d, handing over to exec}\n", (int)p->pid);
/* no return */
execute(t, (flags & XERROK) | XEXEC, NULL);
#ifndef MKSH_SMALL
@@ -621,6 +643,7 @@ exchild(struct op *t, int flags,
coproc.job = (void *)j;
}
if (flags & XBGND) {
+ shellf("{D:parent, backgrounding child %d}\n",
(int)p->pid);
j_set_async(j);
if (Flag(FTALKING)) {
shf_fprintf(shl_out, "[%d]", j->job);
@@ -630,8 +653,10 @@ exchild(struct op *t, int flags,
shf_putchar('\n', shl_out);
shf_flush(shl_out);
}
- } else
+ } else {
+ shellf("{D:parent, waiting for child %d}\n",
(int)p->pid);
rv = j_waitj(j, jwflags, "jw:last proc");
+ }
}
#ifndef MKSH_NOPROSPECTOFWORK
@@ -1115,6 +1140,7 @@ j_waitj(Job *j,
#ifdef MKSH_NO_SIGSUSPEND
sigset_t omask;
#endif
+ shellf("{D:j_waitj called}\n");
/*
* No auto-notify on the job we are waiting on.
@@ -1132,17 +1158,21 @@ j_waitj(Job *j,
((flags & JW_STOPPEDWAIT) && j->state == PSTOPPED)) {
#ifndef MKSH_NOPROSPECTOFWORK
#ifdef MKSH_NO_SIGSUSPEND
+ shellf("{D:j_waitj waiting for job: pause (no sigsuspend)}\n");
sigprocmask(SIG_SETMASK, &sm_default, &omask);
pause();
/* note that handlers may run here so they need to know */
sigprocmask(SIG_SETMASK, &omask, NULL);
#else
+ shellf("{D:j_waitj waiting for job: default (sigsuspend)}\n");
sigsuspend(&sm_default);
#endif
#else
- j_sigchld(SIGCHLD);
+ shellf("{D:j_waitj waiting for job: manual (once)}\n");
+ j_sigchld_manual(SIGCHLD);
#endif
if (fatal_trap) {
+ shellf("{D:j_waitj waiting for job resulted in
fatal_trap}\n");
int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY);
j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
runtraps(TF_FATAL);
@@ -1150,9 +1180,11 @@ j_waitj(Job *j,
j->flags |= oldf;
}
if ((flags & JW_INTERRUPT) && (rv = trap_pending())) {
+ shellf("{D:j_waitj waiting for job resulted in
trap_pending}\n");
j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
return (-rv);
}
+ shellf("{D:j_waitj waiting for job resulted ok}\n");
}
j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY);
@@ -1305,7 +1337,7 @@ j_waitj(Job *j,
*/
/* ARGSUSED */
static void
-j_sigchld(int sig MKSH_A_UNUSED)
+j_sigchld_impl(int sig MKSH_A_UNUSED)
{
int saved_errno = errno;
Job *j;
@@ -1336,6 +1368,8 @@ j_sigchld(int sig MKSH_A_UNUSED)
getrusage(RUSAGE_CHILDREN, &ru0);
do {
+ char dbg[1000];
+
#ifndef MKSH_NOPROSPECTOFWORK
pid = waitpid(-1, &status, (WNOHANG |
#if defined(WCONTINUED) && defined(WIFCONTINUED)
@@ -1345,6 +1379,8 @@ j_sigchld(int sig MKSH_A_UNUSED)
#else
pid = wait(&status);
#endif
+ snprintf(dbg, sizeof(dbg), "{D:j_sigchld waited for job, got
%d}\n", pid);
+ write(2, dbg, strlen(dbg));
/*
* return if this would block (0) or no children
@@ -1362,6 +1398,7 @@ j_sigchld(int sig MKSH_A_UNUSED)
goto found;
found:
if (j == NULL) {
+ write(2, "{D:j_sigchld did not find job}\n", 31);
/* Can occur if process has kids, then execs shell
warningf(true, "bad process waited for (pid = %d)",
pid);
@@ -1369,6 +1406,7 @@ j_sigchld(int sig MKSH_A_UNUSED)
ru0 = ru1;
continue;
}
+ write(2, "{D:j_sigchld found job}\n", 24);
timeradd(&j->usrtime, &ru1.ru_utime, &j->usrtime);
timersub(&j->usrtime, &ru0.ru_utime, &j->usrtime);
@@ -1398,16 +1436,33 @@ j_sigchld(int sig MKSH_A_UNUSED)
}
#ifndef MKSH_NOPROSPECTOFWORK
while (/* CONSTCOND */ 1);
+ write(2, "{D:j_sigchld ended waiting continuously}\n", 41);
#else
while (/* CONSTCOND */ 0);
+ write(2, "{D:j_sigchld ended waiting once}\n", 33);
#endif
+ goto j_sigchld_out2;
j_sigchld_out:
+ write(2, "{D:j_sigchld ended waiting via goto}\n", 37);
+ j_sigchld_out2:
#ifdef MKSH_NO_SIGSUSPEND
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
errno = saved_errno;
}
+static void
+j_sigchld_manual(int sig)
+{
+ write(2, "{D:j_sigchld called manually}\n", 30);
+ j_sigchld_impl(sig);
+}
+static void
+j_sigchld_intr(int sig)
+{
+ write(2, "{D:j_sigchld called from interrupt handler}\n", 44);
+ j_sigchld_impl(sig);
+}
/*
* Called only when a process in j has exited/stopped (ie, called only
Enjoy,
//mirabilos
--
Stéphane, I actually don’t block Googlemail, they’re just too utterly
stupid to successfully deliver to me (or anyone else using Greylisting
and not whitelisting their ranges). Same for a few other providers such
as Hotmail. Some spammers (Yahoo) I do block.