Kill Background Process on Sigint

Kill background process on SIGINT

Looks like dash isn't supporting SIGINT or INT (at least this is the case in the Linux subsystem for Windows). Solution is to use bash and SIGINT will work as it should.

sublime.sh:

#!/bin/bash

set -e

# Just to make sure, this line takes PID1 in Docker environments
# So SIGINT/SIGKILL won't be blocked
echo "pid1" > /dev/null

echo -e "\n///////////////////////////////////////////////\n"

# Keep alive (in background) hack from Docker environments
tail -f /dev/null &
pid[0]=$!

echo "tail process id: ${pid[0]}"
echo -e "Keep-alive process started with Sublime Text 3\nPress SIGINT (CTRL+C) to kill it..."

# Start Sublime Text 3
DISPLAY=localhost:0 /usr/bin/sublime

# http://stackoverflow.com/a/19274804/1442219
# http://stackoverflow.com/a/360275/1442219
trap "kill ${pid[0]}; exit 1" SIGINT

echo -e "\n///////////////////////////////////////////////\n"

wait

sublime.cmd

@ECHO OFF
"C:\Windows\System32\bash.exe" -c "./sublime.sh"

How can I catch SIGINT and have it only kill foreground processes in C?

I think your core question is how to interpose on the standard signal semantics of a process group.
By default all the processes that you fork() remain within the process group you belong to. A system call, setpgid(), can create a new process group, divorcing group signal semantics for the new processes.

Certain signals are delivered to process groups. Notifications from the tty driver are broadcast to the process group which the session leader of the tty currently belongs to. Simple, right :-?

So, what you want to do is use setpgid() in the child processes you start to create a new process group. Any processes they subsequently start will inherit their new process group; so they have no way back to the original, root, process group [ I think, the ground is uneven here ].

I've written a sample program which creates a little set of processes which just hang around sleeping until they are sent a SIG_TERM signal. Each of these processes are placed in their own process group ( waste of resources, but much smaller code ). When you hit Control-C on this program running, it announces its SIG_INT, then delivers a SIG_TERM to all the processes it started. When you hit Control-D, the main process exits.

You can tell this program works if you input Control-C, Control-D, you should find with ps/pgrep that no residual children exist, and the output screen display the correctly configured (NPROC) number of processes receiving a SIG_TERM (15).

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef NPROC
#define NPROC 7
#endif
static int children[NPROC];
static int nproc;

static void SigPrint(char *act, int signo) {
char buf[100];
int n;
n = sprintf(buf, "[%d]:(%d) -> %s\n", getpid(), signo, act);
write(1, buf, n);
}

static void SigDie(int signo) {
SigPrint("Die", signo);
_exit(1);
}

static void SigDisp(int signo) {
SigPrint("Dispatch", signo);
int i;
for (i = 0; i < nproc; i++) {
if (kill(children[i], SIGTERM) < 0) {
perror("kill");
}
}
}

int main(void) {
signal(SIGINT, SigDisp);
signal(SIGTERM, SigDie);
for (nproc = 0; nproc < NPROC; nproc++) {
children[nproc] = fork();
if (children[nproc] == 0) {
signal(SIGINT, SIG_DFL);
if (setpgid(0, 0) < 0) {
perror("setpgid");
_exit(1);
}
while (sleep(5)) {
}
_exit(0);
} else if (children[nproc] < 0) {
perror("fork");
kill(getpid(), SIGINT);
perror("kill");
_exit(1); /*Just in case... */
}
}
int c;
while ((c = getchar()) != EOF) {
putchar(c);
}
return 0;
}

When you run this, you should get output something like:

^C[15141]:(2) -> Dispatch
[15142]:(15) -> Die
[15143]:(15) -> Die
[15146]:(15) -> Die
[15144]:(15) -> Die
[15145]:(15) -> Die
[15147]:(15) -> Die
[15148]:(15) -> Die

with different values for the [pid] field.

This program shows how to divorce child processes from the notifications of the parents. It could be much better, the model here is quite rich.

How do I kill background processes / jobs when my shell script exits?

To clean up some mess, trap can be used. It can provide a list of stuff executed when a specific signal arrives:

trap "echo hello" SIGINT

but can also be used to execute something if the shell exits:

trap "killall background" EXIT

It's a builtin, so help trap will give you information (works with bash). If you only want to kill background jobs, you can do

trap 'kill $(jobs -p)' EXIT

Watch out to use single ', to prevent the shell from substituting the $() immediately.

Sending SIGINT to foreground process works but not background

I guess what you are trying to achieve is that when script2 receives the SIGINT it continues and prints the message. Then, you need

#!/bin/bash
echo "~~ENTRY"
trap 'echo you hit ctrl-c, waking up...; CONT=true' SIGINT
CONT=false
while ! $CONT
do
sleep 1
done
echo "~~EXIT"

How to terminate 2 background processes running in bash script?

I would use something in the line of

function killSubproc(){
kill $(jobs -p -r)
}

./test.py one 10 &
./test.py two 5 &

trap killSubproc INT
wait

It is not limited to 2 subprocess, as you can see.
The idea is simply to kill all (still running) process when you hit Ctrl+C
jobs -p -r gives the process number of all running subprocess (-r limits to running subprocess, since some of your script may have terminated naturally ; -p gives process number, not jobs numbers)

And wait, without any argument, wait for all subprocess to end.
That way, your main script is running in foreground while some subtasks are running. It still receives the ctrl+c.
Yet, it terminates if all your subprocess terminates naturally.
And also if you hit ctrl+c

Note: test.py is just a test script I've used, that runs for $2 seconds (10 and 5 here) and display $1 string each second (one and two here)



Related Topics



Leave a reply



Submit