Search code examples
linuxbashchild-processpssuspend

Bash: why kill -STOP a child process makes my child and current process to show the same command line in ps


I have this piece of code in a script. Here is a script called test.sh that illustrates it:

#!/bin/bash
$@ &
pid=$!

#kill -STOP $pid

echo "PID = $pid"
echo '$@  = '"$@"

ps -p $pid -o uname,pid,command
echo
ps -A -o uname,pid,stat,command | grep 'script.sh' | grep -v grep

#kill -CONT $pid
wait $pid

exit 0

kill commands are commented out, this is intended. What happens is:

  • I launch this script with another script as argument: ./test.sh ./script.sh
  • test.sh launches ./script.sh, record its PID and shows infos
  • Infos show the child PID and a process corresponding to ./script.sh


    root@test# ./test.sh ./script.sh
    PID = 53370
    $@  = ./script.sh
    USER        PID   COMMAND
    root      53370   /bin/bash ./script.sh                  <-- Child process
    
    USER      PID    STAT   COMMAND
    root      53369  S+     /bin/bash ./test.sh ./script.sh  <-- Current process
    root      53370  S+     /bin/bash ./script.sh            <-- Child process

Everything normal.

Now, if I uncomment the kill commands, the script shows this information:



    root@test# ./test.sh ./script.sh
    PID = 53422
    $@  = ./script.sh
    USER        PID   COMMAND
    root      53422   /bin/bash ./test.sh ./script.sh          <-- Child process
    
    USER      PID    STAT   COMMAND
    root      53421  S+     /bin/bash ./test.sh ./script.sh    <-- Current process
    root      53422  T+     /bin/bash ./test.sh ./script.sh    <-- Child process

I'm not sure to understand why when I suspend my child process, I get the exact same COMMAND value for my current process and my child process in ps output.

Why is this happening? I'd like to understand to mechanism between the parent and the child process in this situation.


Solution

  • Because you have stopped the child while it was between the fork() and the execve(), before it was able to execute the script.sh script.

    Add a sleep 1 before the kill -STOP to see the effect.

    A fork() creates the child as a copy of the parent process (which means that it will show in the ps output with the same process name, command line arguments, and almost everything else except the pid). When the child calls the execve() system call, it replaces all that.

    After a fork(), there's no guarantee which of the parent or the child will run first (and in fact, they can run at the same time on separate processors, or any of them could be preempted indefinitely) -- and any "philosophical" conclusions drawn from the order in which they do different operations wrt each other are completely pointless ;-)