linuxbashsignalsparent-childsuspend

What is the best way to suspend a child process when the parent process is suspended in a bash script?


Question

Say I have a bash script test.sh with the following content:

python test.py

How can I modify the bash script so that it also suspend the python process once it received SIGTSTP itself?

Thanks in advance!


My Attempts

I tried just SIGSTOP or SIGTSTP the parent process but they child process still keep going.

I also tried trapping the signal and pass it to the child process but now I'm having trouble resuming it. Here is my code:

#!/bin/bash

suspend_pid() {
    local pid=$1
    echo "Received SIGTSTP. Suspending child process $pid"
    kill -19 "$pid"
    echo "Suspending main process $$"
    kill -19 $$
}

continue_pid() {
    local pid=$1
    echo "Received SIGCONT. Resuming child process $pid"
    kill -18 "$pid"
    echo "Resuming main process $$"
    kill -18 $$
}

python test.py &
python_pid=$!

trap "suspend_pid $python_pid" SIGTSTP
trap "continue_pid $python_pid" SIGCONT

# Wait for the Python script to complete
wait $python_pid

echo "THE END"

It succeeded in pausing the parent and child process but failed in resuming them. I got the following output when I run kill -SIGCONT <parent_pid>

Received SIGCONT. Resuming child process 26944
Resuming main process 26942
Received SIGCONT. Resuming child process 26944
Resuming main process 26942
THE END
Received SIGCONT. Resuming child process 26944
Resuming main process 26942
Received SIGCONT. Resuming child process 26944
Resuming main process 26942

I guess in continue_pid(), kill -18 $$ also calls continue_pid()?


Solution

  • I achieved what I wanted by just suspending/continuing the child process (using SIGUSR1 and SIGUSR2) and making the parent script wait for the termination of the child process.

    I changed the script to be like this:

    # Function to handle SIGTSTP signal
    suspend_pid() {
        local pid=$1
        echo "Received SIGUSR1. Suspending child process $pid"
        kill -19 "$pid"
    }
    
    continue_pid() {
        local pid=$1
        echo "Received SIGUSR2. Resuming child process $pid"
        kill -18 "$pid"
    }
    
    python -u test.py > test.py.out 2>&1 &
    python_pid=$!
    
    trap "suspend_pid $python_pid" SIGUSR1
    trap "continue_pid $python_pid" SIGUSR2
    
    while true; do
        process_status=$(ps -p $python_pid -o stat=)
        if [[ -n $process_status ]]; then
            sleep 1
        else
            break
        fi
    done
    
    echo "The End"
    

    It works pretty well.