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

65 Views Asked by At

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()?

2

There are 2 best solutions below

0
QZ Shao On BEST ANSWER

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.

1
PiRho On

Similar to this answer from Stack Overflow, you can trap the python process as follows:

#!/bin/bash

# Set a trap for SIGTSTP
trap 'suspend_python' SIGTSTP

# Function to suspend the python process
suspend_python() {
  echo "Suspending Python process..."
  kill -TSTP $!
}

# Run the python process
python test.py