POSIX defines sessions thus:
A collection of process groups established for job control purposes. Each process group is a member of a session. A process is considered to be a member of the session of which its process group is a member. A newly created process joins the session of its creator. A process can alter its session membership; see setsid(). There can be multiple process groups in the same session.
All process groups belong to a session. The concepts aren't dependent though, so I wouldn't say that a process group is a concept which exists only within a session.
Background processes are given their own process group when they're created, so disown
ing them doesn't change their process group; disown
only manipulates Bash's job table:
disown
[-ar
] [-h
] [jobspec ...]
Without options, remove each jobspec from the table of active jobs. If jobspec is not present, and
neither the -a
nor the -r
option is supplied, the current job is used. If the -h
option is given,
each jobspec is not removed from the table, but is marked so that SIGHUP
is not sent to the job if the
shell receives a SIGHUP
. If no jobspec is supplied, the -a
option means to remove or mark all jobs;
the -r
option without a jobspec argument restricts operation to running jobs. The return value is 0
unless a jobspec does not specify a valid job.
There is no conflict; a process will by default be in a unique process group which is the process group of its parent:
$ cat pg.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
fork();
printf("pid=%d pgid=%d\n", getpid(), getpgrp());
}
$ make pg
cc pg.c -o pg
$ ./pg
pid=12495 pgid=12495
pid=12496 pgid=12495
$
The fork
splits our process into parent (12495
) and child (12496
), and the child belongs to the unique process group of the parent (12495
). bash
departs from this because it issues additional system calls:
$ echo $$
12366
$
And then in another terminal we run:
$ strace -f -o blah -p 12366
And then back in the first terminal:
$ ./pg
pid=12676 pgid=12676
pid=12677 pgid=12676
$
And then we control+c the strace
, and inspect the system calls:
$ egrep 'exec|pgid' blah
12366 setpgid(12676, 12676) = 0
12676 setpgid(12676, 12676 <unfinished ...>
12676 <... setpgid resumed> ) = 0
12676 execve("./pg", ["./pg"], [/* 23 vars */]) = 0
12676 write(1, "pid=12676 pgid=12676\n", 21 <unfinished ...>
12677 write(1, "pid=12677 pgid=12676\n", 21 <unfinished ...>
bash
has used the setpgid
call to set the process group, thus placing our pg
process into process group unrelated to that of the shell. (setsid(2)
would be another way to tweak the process group, if you're hunting for system calls.)
Best Answer
In general, yes, the process group ID is equal to the process ID of the process that created the process group — and that process created the process group by putting itself in the group.
You can find this information in the documentation of the
setpgid
system call, and of its variantsetpgrp
. The details have historically varied between BSD and System V. The most common use cases are:setpgrp()
or withsetpgid(0, 0)
in which either0
can be replaced by an explicitgetpid()
.Note that while the process is putting itself into the group, in practice, this is often done by a launcher (shell, or daemon monitor) before executing the program, i.e. it is done by code in the launcher between
fork
andexecve
in the child process.A process puts itself into an existing process group in the same session. Shells do this for pipelines: to run
foo | bar
in its own process group, a shell typically does something like this:foo
.bar
.The call to
setpgid
may be performed in the parent process instead of or in addition to the child. Doing it in both avoids a race condition in case the second child's initialization overtakes the first child's.A shell with job control normally runs in its own process group. But before exiting or suspending, it returns to its original process group (i.e. it puts itself back into the process group that started it, assuming that group still exists).
The POSIX specification for
setpgid
describes these use cases. It further explains that there isn't much else that is guaranteed to work. In particular, while old BSD systems allowed a process to join a process group in a different session or to make up a new PGID, this is not the case on most modern systems (including modern BSD).