03.01.2012 00:07, Chet Ramey wrote:
I tried:
---
trap bg USR1
---
Now if I first send SIGSTOP to the job and then SIGUSR1 to
bash, that works.
Is it possible to avoid sending SIGSTOP to the job, and make
the trap handler to do both things at once? Not that it is strictly
required since you already described a few other ways, but I wonder. :)
Well, this is getting pretty esoteric. On one hand, you can avoid the
entire SIGSTOP/SIGCONT issue by initially starting the job in the
background with `&'. On the other, if you want to move a foreground
job to the background, you have to get it to give up control somehow, and
sending it a signal is the way to do that.
Hello Chet, I double-checked that, and with the attached
quick hack I was able to do:
trap bg USR1
and move the job to the background with just that SIGUSR1.
Do you think such a feature is worth being implemented?
If yes, feel free to give me the suggestions and I'll try to
implement it properly. The attached patch is just a POC of
course, it is entirely incorrect.
--- jobs.c.old 2011-01-07 18:59:29.000000000 +0300
+++ jobs.c 2012-01-04 16:07:49.001668244 +0400
@@ -1391,6 +1391,26 @@
return (NO_JOB);
}
+static int
+find_foreground_job (procp)
+ PROCESS **procp;
+{
+ register int i;
+
+ /* XXX could use js.j_firstj here, and should check js.j_lastj */
+ for (i = 0; i < js.j_jobslots; i++)
+ {
+ if (jobs[i] && IS_FOREGROUND (i))
+ {
+ if (procp)
+ *procp = jobs[i]->pipe;
+ return (i);
+ }
+ }
+
+ return (NO_JOB);
+}
+
/* Find a job given a PID. If BLOCK is non-zero, block SIGCHLD as
required by find_job. */
int
@@ -3067,6 +3087,7 @@
PROCESS *child;
pid_t pid;
int call_set_current, last_stopped_job, job, children_exited, waitpid_flags;
+ int wifcontinued;
static int wcontinued = WCONTINUED; /* run-time fix for glibc problem */
call_set_current = children_exited = 0;
@@ -3117,12 +3138,24 @@
/* If waitpid returns 0, there are running children. If it returns -1,
the only other error POSIX says it can return is EINTR. */
CHECK_TERMSIG;
+ wifcontinued = WIFCONTINUED(status);
+ if (pid <= 0 && errno == EINTR)
+ {
+ PROCESS *p;
+ int i = find_foreground_job(&p);
+ if (i != NO_JOB)
+ {
+ pid = p->pid;
+ wifcontinued = 0;
+ status = 0x7f;
+ }
+ }
if (pid <= 0)
continue; /* jumps right to the test */
/* children_exited is used to run traps on SIGCHLD. We don't want to
run the trap if a process is just being continued. */
- if (WIFCONTINUED(status) == 0)
+ if (wifcontinued == 0)
{
children_exited++;
js.c_living--;
@@ -3148,7 +3181,7 @@
/* Remember status, and whether or not the process is running. */
child->status = status;
- child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
+ child->running = wifcontinued ? PS_RUNNING : PS_DONE;
if (PEXITED (child))
{