1

I was running an application in the foreground, and put it in the background by hitting CTRL+Z (and stopped). To get it back running, I ran the command bg %1 (which is its JOBSPEC).

I thought why not trying to get it running back with kill -CONT <PID>. So, I ran jobs -l to get its PID, and used this pid with kill with CONT signal.

However, the program didn't go live again! jobs -l after trying kill with CONT reports that it is running, but it is not (as it is grayed out).

I looked at the applications PID using the command ps and found two of the same command with different PIDs (and status Tl).

I then looked at the same thing using pstree and found they are all under a parent process. The parent process is different from the one listed by jobs -l as it seems the one I put in the background initiated another program. The other program seems created children processes.

What I noticed is summarized as:

  • Using kill to send CONT to the parent process gets the program running.

  • The parent process PID is different from the one reported by jobs -l. In other words, the process I should have sent CONT signal to is different from the one I find using jobs -l.

  • Sending CONT to a parent process doesn't apply the same signal on the children.

  • Using the command bg to return a process to running, sends CONT signal to the parent all its children.

Are my conclusions correct? If so, then this means using the command bg would save time of sending CONT to every related process.is this correct?

EDIT The main application I called from the command line and which I put in the background is git difftool. The other application that I am talking about that it created new children itself is meld which I setup to be used as the diffing tool in git.

  • Answerers do not have or know anything about the mystery program that forks children that in their turn fork grandchildren, and so will not be able to confirm any conclusions about that. – JdeBP Sep 26 '18 at 14:53
  • Updated the question. – joker Sep 26 '18 at 14:59
5

First of all, jobs -l doesn't list processes, but process groups (aka jobs). Each process group has a process leader, whose process id (pid) is equal to its process group id (pgid).

In order to send a signal to all processes in a process group, and not just to its leader, you should call kill with the negative of the pgid. This is described in the kill(2) manpage:

If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid.

The same works in the shell:

$ sh -c 'while echo -n 1; do sleep 1; done'
111^Z
[1]+  Stopped                 sh -c 'while echo -n 1; do sleep 1; done'
$ jobs -l
[1]+ 11046 Stopped                 sh -c 'while echo -n 1; do sleep 1; done'
$ kill -CONT 11046
   <nothing>
$ kill -CONT -11046
$ 11111111...

Now, to your conclusions:

Using kill to send CONT to the parent process gets the program running.

correct

The parent process PID is different from the one reported by jobs -l. In other words, the process I should have sent CONT signal to is different from the one I find using jobs -l.

wrong, it's the same pid, and it's also the same as its pgid.

Sending CONT to a parent process doesn't apply the same signal on the children.

correct

Using the command bg to return a process to running, sends CONT signal to the parent and all its children.

right, but only if the parent and the children are all in the same process group. Also, it doesn't call kill(2) for each process in turn, it just calls it once with the negative of the pgid (= pid of the process group leader), and relies on the kernel to route the signal to all processes in that group.

0

I don't see this behaviour here.

  • Here's my sample code, entered verbatim on the command line:

    bash -c 'echo This is parent $$; sleep 7; bash -c "echo This is child \$$; sleep 7; echo Child done"; echo This is parent $$ again; sleep 7'
    
  • As soon as you get the This is child xx message, hit CtrlZ to suspend the process.

  • Wait a further 7 seconds to confirm that it really has paused

  • Now jobs -l to list the process leader (parent PID). Actually, we can use the jobs number, in this case %1

  • Continue the process in the background kill -CONT %1

I saw that the child continued and then exited, allowing the parent to complete.

Here is the complete run result (including >$ shell prompts)

>$ bash -c 'echo This is parent $$; sleep 7; bash -c "echo This is child \$$; sleep 7; echo Child done"; echo This is parent $$ again; sleep 7'
This is parent 2004
This is child 10696

[1]+  Stopped                 bash -c 'echo This is parent $$; sleep 7; bash -c "echo This is child \$$; sleep 7; echo Child done"; echo This is parent $$ again; sleep 7'
>$ jobs -l
[1]+  2004 Stopped                 bash -c 'echo This is parent $$; sleep 7; bash -c "echo This is child \$$; sleep 7; echo Child done"; echo This is parent $$ again; sleep 7'
>$ kill -CONT %1
>$ Child done
This is parent 2004 again

If you want to experiment further with an automated test-harness, you can use kill -TSTP ... to send the same signal as is generated by CtrlZ on the keyboard.

  • I tried your example, and you are correct when you refer to the process using %<JOBSPEC> with bg and/or kill -CONT. However, when I try kill with referring to the process by its ID, things don't work. I have run the experiments in two scripts files (you can run them using script) but not sure how to share them with you. – joker Sep 26 '18 at 21:08
  • 1
    @joker oh I see what you mean. Yes, the %n is a jobspec, which as answered very nicely by mosvy is a process group corresponding to the command/pipeline that's been suspended with Ctrl/Z. You can use kill to send signals to a process group by treating it as a negative value - so in my example above the kill -CONT %1 was equivalent to kill -CONT -2004. – roaima Sep 27 '18 at 22:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.