Does Linux allow process group ids to be reassigned to processes?
Suppose pid X
is a process group leader and X
terminates, but other processes in the process group remain running (with X
as their pgid). Will Linux prevent the value X
from being assigned as a pid to a new process?
I ask this because of a failure condition POSIX allows for setsid
:
[EPERM] The calling process is already a process group leader, or the process group ID of a process other than the calling process matches the process ID of the calling process.
This error seems to be an unrecoverable condition for code using process groups (i.e. shells) that would be triggered "at random", making it even more odious. I would assume any 开发者_JAVA百科implementation aiming at sane levels of quality would avoid reassigning X
as a pid while it's still in use as a pgid, but I can't find this documented anywhere.
Not a problem, because fork guarantees:
The child process ID also shall not match any active process group ID.
And fork
is the only way to create new processes.
Nemo is correct that POSIX guarantees that fork()
will not re-use an existing PGID as a PID; however, there is more to the story.
Process groups, and process group leaders, can also be changed using setpgid()
. The following example code causes the existence of a process group equal to the PID of the current process, which the current process is not in:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
int main()
{
pid_t pgrp_orig;
pid_t child;
int status;
/* Fork so that we are not a process group leader */
if (fork()) {
/* Grandparent process */
wait(&status);
return 0;
}
/* Record our original process group, then start a new one */
pgrp_orig = getpgrp();
if (setpgid(0, 0))
perror("setpgid");
child = fork();
if (!child) {
/* Child process */
pause();
return 0;
}
/* Switch back to original process group. Child remains in the new one */
if (setpgid(0, pgrp_orig))
perror("setpgid");
printf("Parent pid=%ld, pgid=%ld\n", (long)getpid(), (long)getpgrp());
printf("Child pid=%ld, pgid=%ld\n", (long)child, (long)getpgid(child));
/* Wake child up to finish up */
kill(child, SIGUSR1);
wait(&status);
return 0;
}
Note that if the parent process tries to call setsid()
here before the child exits, the failure condition you asked about will be triggered.
However, due to the restrictions on the allowable transitions that setpgid()
can cause, this can't cause the kind of random failures you're worried about. The breakage is confined to a single session.
精彩评论