7

I basically want to run a script (which calls more scripts) in a new process group so that I can send signal to all the processes called by the script.

In Linux, I found out setsid helps me in doing that, but this is not available on FreeBSD.

Syntax for setsid (provided by util-linux-ng).

setsid /path/to/myscript

I, however learnt that session and process group are not the same. But starting a new session also solves my problem.

Thirupathi Thangavel
  • 2,418
  • 3
  • 29
  • 49
  • 1
    If you can compile C code, source for a setsid program for FreeBSD is at http://lists.freebsd.org/pipermail/freebsd-hackers/2011-February/034433.html . – Mark Plotnick Jun 16 '15 at 18:30

3 Answers3

17

Sessions and groups are not the same thing. Let's make things clean:

A session consists of one or more process groups, and can have a controlling terminal. When the session has a controlling terminal, the session has, at any moment, exactly one foreground process group and one or more background process groups. In such a scenario, all terminal-generated signals and input is seen by every process in the foreground process group.

Also, when a session has a controlling terminal, the shell process is usually the session leader, dictating which process group is the foreground process group (implicitly making the other groups background process groups). Processes in a group are usually put there by a linear pipeline. For example, ls -l | grep a | sort will typically create a new process group where ls, grep and sort live.

Shells that support job control (which also requires support by the kernel and the terminal driver), as in the case of bash, create a new process group for each command invoked -- and if you invoke it to run in the background (with the & notation), that process group is not given the control of the terminal, and the shell makes it a background process group (and the foreground process group remains the shell).

So, as you can see, you almost certainly don't want to create a session in this case. A typical situation where you'd want to create a session is if you were daemonizing a process, but other than that, there is usually not much use in creating a new session.

You can run the script as a background job, as I mentioned, this will create a new process group. Since fork() inherits the process group ID, every process executed by the script will be in the same group. For example, consider this simple script:

#!/bin/bash

ps -o pid,ppid,pgid,comm | grep ".*"

This prints something like:

  PID  PPID  PGID COMMAND
11888 11885 11888 bash
12343 11888 12343 execute.sh
12344 12343 12343 ps
12345 12343 12343 grep

As you can see, execute.sh, ps and grep are all on the same process group (the value in PGID).

So all you want is:

/path/to/myscript &

Then you can check the process group ID of myscript with ps -o pid,ppid,pgid,comm | grep myscript. To send a signal to the group, use kill with the negative of the process group ID (PGID is the PID of the leader of the group). A signal sent to a group is delivered to every process in that group. In the above example, to send SIGTERM to every process started by execute.sh, including the script itself, you would use kill -- -12343. (Note that sending a signal to the whole group is different from sending a signal to just the group leader: kill 12343 and kill -- -12343 are different!)

HTNW
  • 27,182
  • 1
  • 32
  • 60
Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • 13
    I want to call my script (lets say script-1) from a main script. And I want this script to be run under a new process group. Calling script-1 in the background does not start it under new process group. – Thirupathi Thangavel Jun 11 '15 at 10:08
  • Running command on the background will put it in another group. However, if you want to run something that e.g. uses `read`builtin of `bash`, is there a way to start such a script in a new process group? The reason I would like to have new process group is that SIGINT would be delivered only that group in case Ctrl+C is pressed. – Mikko Rantalainen Jan 27 '21 at 20:03
  • 2
    "job control is by default turned off in non-interactive mode" (https://stackoverflow.com/a/690297/18096) and only, it seems, when job control is enabled do background pipelines get their own process group – Martin Dorey Feb 01 '21 at 01:12
3

Using FreeBSD you may try using the script command that will internally execute the setsid command.

stty -echo -onlcr   # avoid added \r in output
script -q /dev/null /path/to/myscript
stty echo onlcr
# sync  # ... if terminal prompt does not return
taroj
  • 31
  • 1
2

This is not exactly answer, but is an alternative approach based on names.

You can have a common part of name for all process. For example we have my_proc_group_29387172 part for all the following processes:

-rwxrwxr-x.   my_proc_group_29387172_microservice_1
-rwxrwxr-x.   my_proc_group_29387172_microservice_2
-rwxrwxr-x.   my_proc_group_29387172_data_dumper

Spawn all of them (and as much as you want):

ADDR=1 ./my_proc_group_29387172_microservice_1
ADDR=2 ./my_proc_group_29387172_microservice_1
ADDR=3 ./my_proc_group_29387172_microservice_2
./my_proc_group_29387172_data_dumper

When you want to kill all processes you can use pkill command (pattern kill) or killall with --regexp parameter:

pkill my_proc_group_29387172

Benefit :) - you can start as many process as you want at any time (or any day) from any script.

Drawback :( - you can kill innocent processes if they has common part of name with your pattern.

DenisKolodin
  • 13,501
  • 3
  • 62
  • 65