tags:

views:

425

answers:

1

Hi,

I'm currently implementing process groups into my operating system project's POSIX subsystem. However, I've become a little confused at the POSIX specification (setsid) (along by Wikipedia's page on Process groups).

Our terminal layer sends SIGINT to the foreground process (group, whose id should equal the group leader's PID). In this case, that foreground process (our "login" application) becomes a group leader by calling setsid. When the user logs in, the program forks and executes the user's shell. At this stage, my understanding is that I call setpgid from the forked child before calling exec*. This means the executed program will be a part of the process group from the outset.

If I wanted to run the newly forked child outside the process group I would merely call setsid in the forked child before calling exec*.

Is this correct? Are there any really obscure things I should be checking or doing?

As a follow-on question, which I believe I already know, is it a requirement for fork to transfer group membership? Or is it something that must be done using setpgid after every fork call? I gather process groups are transferred by fork from the POSIX definition of fork.

Thanks in advance.

+4  A: 

Interesting question - not least because it stayed without even a partial answer for so long.

POSIX Base Definitions

Some quotes from the definitions part of POSIX:

3.290 Process Group

A collection of processes that permits the signaling of related processes. Each process in the system is a member of a process group that is identified by a process group ID. A newly created process joins the process group of its creator.

3.291 Process Group ID

The unique positive integer identifier representing a process group during its lifetime.

Note: See also Process Group ID Reuse defined in Process ID Reuse .

3.292 Process Group Leader

A process whose process ID is the same as its process group ID.

3.293 Process Group Lifetime

The period of time that begins when a process group is created and ends when the last remaining process in the group leaves the group, due either to the end of the lifetime of the last process or to the last remaining process calling the setsid() or setpgid() functions.

Note: The setsid() and setpgid() functions are defined in detail in the System Interfaces volume of POSIX.1-2008.

[...]

3.337 Session

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.

Note: The setsid() function is defined in detail in the System Interfaces volume of POSIX.1-2008.

3.338 Session Leader

A process that has created a session.

Note: For further information, see the setsid() function defined in the System Interfaces volume of POSIX.1-2008.

3.339 Session Lifetime

The period between when a session is created and the end of the lifetime of all the process groups that remain as members of the session.


POSIX System Interfaces

NAME

setsid - create session and set process group ID

SYNOPSIS

   #include <unistd.h>

   pid_t setsid(void);

DESCRIPTION

The setsid() function shall create a new session, if the calling process is not a process group leader. Upon return the calling process shall be the session leader of this new session, shall be the process group leader of a new process group, and shall have no controlling terminal. The process group ID of the calling process shall be set equal to the process ID of the calling process. The calling process shall be the only process in the new process group and the only process in the new session.

And:

NAME

setpgid - set process group ID for job control

SYNOPSIS

   #include <unistd.h>

   int setpgid(pid_t pid, pid_t pgid);

DESCRIPTION

The setpgid() function shall either join an existing process group or create a new process group within the session of the calling process.

The process group ID of a session leader shall not change.

Upon successful completion, the process group ID of the process with a process ID that matches pid shall be set to pgid.

As a special case, if pid is 0, the process ID of the calling process shall be used. Also, if pgid is 0, the process ID of the indicated process shall be used.


Interpretation

As the definitions make clear, a session may consist of multiple process groups. Within broad limits, a process may change process groups (though it belongs to just one process group at any time). The options for session handling are more limited; basically, a process either remains a member of its original session, or it can make itself the leader of a new session.

Copying parts of the question:

Our terminal layer sends SIGINT to the foreground process (group, whose id should equal the group leader's PID). In this case, that foreground process (our "login" application) becomes a group leader by calling setsid. When the user logs in, the program forks and executes the user's shell. At this stage, my understanding is that I call setpgid from the forked child before calling exec*. This means the executed program will be a part of the process group from the outset.

I suspect the parentheses should be 'the foreground process group (whose id should equal the group leader's PID)'. By definition (3.292), the process group leader is the process whose PID is the same as the process group ID. I haven't quote the relevant material, but I believe that dispatching the signal to the process group leader is correct

Note that the foreground process becomes a session leader by calling setsid()and also becomes the process group leader too. I would expect that the login program would set up the user's shell as a process group leader (and probably a session leader) after forking but before executing the shell. All child processes inherit process group and session from their parent processes automatically; you have to override that if you want it to be different.

If I wanted to run the newly forked child outside the process group I would merely call setsid in the forked child before calling exec*.

You could do that, but it would also create a new session. You probably want to use setpgid() (modern standard; possibly setpgrp() which is an older standard from SVID) rather than setsid().

Is this correct? Are there any really obscure things I should be checking or doing?

Yes, this is mostly correct. Yes, there probably are some obscure things to keep track of too. For example, you might need to think about the controlling TTY.

As a follow-on question, which I believe I already know, is it a requirement for fork to transfer group membership? Or is it something that must be done using setpgid after every fork call? I gather process groups are transferred by fork from the POSIX definition of fork.

The child process after a fork() belongs to the same set of groups (as in /etc/group), and also to the same session and same process group - but it is not a session leader nor is it a process group leader.

Jonathan Leffler
Good research, and it's consistent with what I've gathered when playing around with writing a shell, but with just that experience I would hardly dare to speak with authority on sessions and process groups -- I think the question went unanswered because most people don't understand it either!
ephemient
Thank you very much for the in-depth answer - this is exactly what I needed.
Matthew Iselin