123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
- <html><head>
- <!-- saved from http://www.win.tue.nl/~aeb/linux/lk/lk-10.html -->
- <meta name="GENERATOR" content="SGML-Tools 1.0.9"><title>The Linux kernel: Processes</title>
- </head>
- <body>
- <hr>
- <h2><a name="s10">10. Processes</a></h2>
- <p>Before looking at the Linux implementation, first a general Unix
- description of threads, processes, process groups and sessions.
- </p><p>
- (See also <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html">General Terminal Interface</a>)
- </p><p>A session contains a number of process groups, and a process group
- contains a number of processes, and a process contains a number
- of threads.
- </p><p>A session can have a controlling tty.
- At most one process group in a session can be a foreground process group.
- An interrupt character typed on a tty ("Teletype", i.e., terminal)
- causes a signal to be sent to all members of the foreground process group
- in the session (if any) that has that tty as controlling tty.
- </p><p>All these objects have numbers, and we have thread IDs, process IDs,
- process group IDs and session IDs.
- </p><p>
- </p><h2><a name="ss10.1">10.1 Processes</a>
- </h2>
- <p>
- </p><h3>Creation</h3>
- <p>A new process is traditionally started using the <code>fork()</code>
- system call:
- </p><blockquote>
- <pre>pid_t p;
- p = fork();
- if (p == (pid_t) -1)
- /* ERROR */
- else if (p == 0)
- /* CHILD */
- else
- /* PARENT */
- </pre>
- </blockquote>
- <p>This creates a child as a duplicate of its parent.
- Parent and child are identical in almost all respects.
- In the code they are distinguished by the fact that the parent
- learns the process ID of its child, while <code>fork()</code>
- returns 0 in the child. (It can find the process ID of its
- parent using the <code>getppid()</code> system call.)
- </p><p>
- </p><h3>Termination</h3>
- <p>Normal termination is when the process does
- </p><blockquote>
- <pre>exit(n);
- </pre>
- </blockquote>
- or
- <blockquote>
- <pre>return n;
- </pre>
- </blockquote>
- from its <code>main()</code> procedure. It returns the single byte <code>n</code>
- to its parent.
- <p>Abnormal termination is usually caused by a signal.
- </p><p>
- </p><h3>Collecting the exit code. Zombies</h3>
- <p>The parent does
- </p><blockquote>
- <pre>pid_t p;
- int status;
- p = wait(&status);
- </pre>
- </blockquote>
- and collects two bytes:
- <p>
- <figure>
- <eps file="absent">
- <img src="ctty_files/exit_status.png">
- </eps>
- </figure></p><p>A process that has terminated but has not yet been waited for
- is a <i>zombie</i>. It need only store these two bytes:
- exit code and reason for termination.
- </p><p>On the other hand, if the parent dies first, <code>init</code> (process 1)
- inherits the child and becomes its parent.
- </p><p>
- </p><h3>Signals</h3>
- <p>
- </p><h3>Stopping</h3>
- <p>Some signals cause a process to stop:
- <code>SIGSTOP</code> (stop!),
- <code>SIGTSTP</code> (stop from tty: probably ^Z was typed),
- <code>SIGTTIN</code> (tty input asked by background process),
- <code>SIGTTOU</code> (tty output sent by background process, and this was
- disallowed by <code>stty tostop</code>).
- </p><p>Apart from ^Z there also is ^Y. The former stops the process
- when it is typed, the latter stops it when it is read.
- </p><p>Signals generated by typing the corresponding character on some tty
- are sent to all processes that are in the foreground process group
- of the session that has that tty as controlling tty. (Details below.)
- </p><p>If a process is being traced, every signal will stop it.
- </p><p>
- </p><h3>Continuing</h3>
- <p><code>SIGCONT</code>: continue a stopped process.
- </p><p>
- </p><h3>Terminating</h3>
- <p><code>SIGKILL</code> (die! now!),
- <code>SIGTERM</code> (please, go away),
- <code>SIGHUP</code> (modem hangup),
- <code>SIGINT</code> (^C),
- <code>SIGQUIT</code> (^\), etc.
- Many signals have as default action to kill the target.
- (Sometimes with an additional core dump, when such is
- allowed by rlimit.)
- The signals <code>SIGCHLD</code> and <code>SIGWINCH</code>
- are ignored by default.
- All except <code>SIGKILL</code> and <code>SIGSTOP</code> can be
- caught or ignored or blocked.
- For details, see <code>signal(7)</code>.
- </p><p>
- </p><h2><a name="ss10.2">10.2 Process groups</a>
- </h2>
- <p>Every process is member of a unique <i>process group</i>,
- identified by its <i>process group ID</i>.
- (When the process is created, it becomes a member of the process group
- of its parent.)
- By convention, the process group ID of a process group
- equals the process ID of the first member of the process group,
- called the <i>process group leader</i>.
- A process finds the ID of its process group using the system call
- <code>getpgrp()</code>, or, equivalently, <code>getpgid(0)</code>.
- One finds the process group ID of process <code>p</code> using
- <code>getpgid(p)</code>.
- </p><p>One may use the command <code>ps j</code> to see PPID (parent process ID),
- PID (process ID), PGID (process group ID) and SID (session ID)
- of processes. With a shell that does not know about job control,
- like <code>ash</code>, each of its children will be in the same session
- and have the same process group as the shell. With a shell that knows
- about job control, like <code>bash</code>, the processes of one pipeline, like
- </p><blockquote>
- <pre>% cat paper | ideal | pic | tbl | eqn | ditroff > out
- </pre>
- </blockquote>
- form a single process group.
- <p>
- </p><h3>Creation</h3>
- <p>A process <code>pid</code> is put into the process group <code>pgid</code> by
- </p><blockquote>
- <pre>setpgid(pid, pgid);
- </pre>
- </blockquote>
- If <code>pgid == pid</code> or <code>pgid == 0</code> then this creates
- a new process group with process group leader <code>pid</code>.
- Otherwise, this puts <code>pid</code> into the already existing
- process group <code>pgid</code>.
- A zero <code>pid</code> refers to the current process.
- The call <code>setpgrp()</code> is equivalent to <code>setpgid(0,0)</code>.
- <p>
- </p><h3>Restrictions on setpgid()</h3>
- <p>The calling process must be <code>pid</code> itself, or its parent,
- and the parent can only do this before <code>pid</code> has done
- <code>exec()</code>, and only when both belong to the same session.
- It is an error if process <code>pid</code> is a session leader
- (and this call would change its <code>pgid</code>).
- </p><p>
- </p><h3>Typical sequence</h3>
- <p>
- </p><blockquote>
- <pre>p = fork();
- if (p == (pid_t) -1) {
- /* ERROR */
- } else if (p == 0) { /* CHILD */
- setpgid(0, pgid);
- ...
- } else { /* PARENT */
- setpgid(p, pgid);
- ...
- }
- </pre>
- </blockquote>
- This ensures that regardless of whether parent or child is scheduled
- first, the process group setting is as expected by both.
- <p>
- </p><h3>Signalling and waiting</h3>
- <p>One can signal all members of a process group:
- </p><blockquote>
- <pre>killpg(pgrp, sig);
- </pre>
- </blockquote>
- <p>One can wait for children in ones own process group:
- </p><blockquote>
- <pre>waitpid(0, &status, ...);
- </pre>
- </blockquote>
- or in a specified process group:
- <blockquote>
- <pre>waitpid(-pgrp, &status, ...);
- </pre>
- </blockquote>
- <p>
- </p><h3>Foreground process group</h3>
- <p>Among the process groups in a session at most one can be
- the <i>foreground process group</i> of that session.
- The tty input and tty signals (signals generated by ^C, ^Z, etc.)
- go to processes in this foreground process group.
- </p><p>A process can determine the foreground process group in its session
- using <code>tcgetpgrp(fd)</code>, where <code>fd</code> refers to its
- controlling tty. If there is none, this returns a random value
- larger than 1 that is not a process group ID.
- </p><p>A process can set the foreground process group in its session
- using <code>tcsetpgrp(fd,pgrp)</code>, where <code>fd</code> refers to its
- controlling tty, and <code>pgrp</code> is a process group in
- its session, and this session still is associated to the controlling
- tty of the calling process.
- </p><p>How does one get <code>fd</code>? By definition, <code>/dev/tty</code>
- refers to the controlling tty, entirely independent of redirects
- of standard input and output. (There is also the function
- <code>ctermid()</code> to get the name of the controlling terminal.
- On a POSIX standard system it will return <code>/dev/tty</code>.)
- Opening the name of the
- controlling tty gives a file descriptor <code>fd</code>.
- </p><p>
- </p><h3>Background process groups</h3>
- <p>All process groups in a session that are not foreground
- process group are <i>background process groups</i>.
- Since the user at the keyboard is interacting with foreground
- processes, background processes should stay away from it.
- When a background process reads from the terminal it gets
- a SIGTTIN signal. Normally, that will stop it, the job control shell
- notices and tells the user, who can say <code>fg</code> to continue
- this background process as a foreground process, and then this
- process can read from the terminal. But if the background process
- ignores or blocks the SIGTTIN signal, or if its process group
- is orphaned (see below), then the read() returns an EIO error,
- and no signal is sent. (Indeed, the idea is to tell the process
- that reading from the terminal is not allowed right now.
- If it wouldn't see the signal, then it will see the error return.)
- </p><p>When a background process writes to the terminal, it may get
- a SIGTTOU signal. May: namely, when the flag that this must happen
- is set (it is off by default). One can set the flag by
- </p><blockquote>
- <pre>% stty tostop
- </pre>
- </blockquote>
- and clear it again by
- <blockquote>
- <pre>% stty -tostop
- </pre>
- </blockquote>
- and inspect it by
- <blockquote>
- <pre>% stty -a
- </pre>
- </blockquote>
- Again, if TOSTOP is set but the background process ignores or blocks
- the SIGTTOU signal, or if its process group is orphaned (see below),
- then the write() returns an EIO error, and no signal is sent.
- [vda: correction. SUS says that if SIGTTOU is blocked/ignored, write succeeds. ]
- <p>
- </p><h3>Orphaned process groups</h3>
- <p>The process group leader is the first member of the process group.
- It may terminate before the others, and then the process group is
- without leader.
- </p><p>A process group is called <i>orphaned</i> when <i>the
- parent of every member is either in the process group
- or outside the session</i>.
- In particular, the process group of the session leader
- is always orphaned.
- </p><p>If termination of a process causes a process group to become
- orphaned, and some member is stopped, then all are sent first SIGHUP
- and then SIGCONT.
- </p><p>The idea is that perhaps the parent of the process group leader
- is a job control shell. (In the same session but a different
- process group.) As long as this parent is alive, it can
- handle the stopping and starting of members in the process group.
- When it dies, there may be nobody to continue stopped processes.
- Therefore, these stopped processes are sent SIGHUP, so that they
- die unless they catch or ignore it, and then SIGCONT to continue them.
- </p><p>Note that the process group of the session leader is already
- orphaned, so no signals are sent when the session leader dies.
- </p><p>Note also that a process group can become orphaned in two ways
- by termination of a process: either it was a parent and not itself
- in the process group, or it was the last element of the process group
- with a parent outside but in the same session.
- Furthermore, that a process group can become orphaned
- other than by termination of a process, namely when some
- member is moved to a different process group.
- </p><p>
- </p><h2><a name="ss10.3">10.3 Sessions</a>
- </h2>
- <p>Every process group is in a unique <i>session</i>.
- (When the process is created, it becomes a member of the session
- of its parent.)
- By convention, the session ID of a session
- equals the process ID of the first member of the session,
- called the <i>session leader</i>.
- A process finds the ID of its session using the system call
- <code>getsid()</code>.
- </p><p>Every session may have a <i>controlling tty</i>,
- that then also is called the controlling tty of each of
- its member processes.
- A file descriptor for the controlling tty is obtained by
- opening <code>/dev/tty</code>. (And when that fails, there was no
- controlling tty.) Given a file descriptor for the controlling tty,
- one may obtain the SID using <code>tcgetsid(fd)</code>.
- </p><p>A session is often set up by a login process. The terminal
- on which one is logged in then becomes the controlling tty
- of the session. All processes that are descendants of the
- login process will in general be members of the session.
- </p><p>
- </p><h3>Creation</h3>
- <p>A new session is created by
- </p><blockquote>
- <pre>pid = setsid();
- </pre>
- </blockquote>
- This is allowed only when the current process is not a process group leader.
- In order to be sure of that we fork first:
- <blockquote>
- <pre>p = fork();
- if (p) exit(0);
- pid = setsid();
- </pre>
- </blockquote>
- The result is that the current process (with process ID <code>pid</code>)
- becomes session leader of a new session with session ID <code>pid</code>.
- Moreover, it becomes process group leader of a new process group.
- Both session and process group contain only the single process <code>pid</code>.
- Furthermore, this process has no controlling tty.
- <p>The restriction that the current process must not be a process group leader
- is needed: otherwise its PID serves as PGID of some existing process group
- and cannot be used as the PGID of a new process group.
- </p><p>
- </p><h3>Getting a controlling tty</h3>
- <p>How does one get a controlling terminal? Nobody knows,
- this is a great mystery.
- </p><p>The System V approach is that the first tty opened by the process
- becomes its controlling tty.
- </p><p>The BSD approach is that one has to explicitly call
- </p><blockquote>
- <pre>ioctl(fd, TIOCSCTTY, 0/1);
- </pre>
- </blockquote>
- to get a controlling tty.
- <p>Linux tries to be compatible with both, as always, and this
- results in a very obscure complex of conditions. Roughly:
- </p><p>The <code>TIOCSCTTY</code> ioctl will give us a controlling tty,
- provided that (i) the current process is a session leader,
- and (ii) it does not yet have a controlling tty, and
- (iii) maybe the tty should not already control some other session;
- if it does it is an error if we aren't root, or we steal the tty
- if we are all-powerful.
- [vda: correction: third parameter controls this: if 1, we steal tty from
- any such session, if 0, we don't steal]
- </p><p>Opening some terminal will give us a controlling tty,
- provided that (i) the current process is a session leader, and
- (ii) it does not yet have a controlling tty, and
- (iii) the tty does not already control some other session, and
- (iv) the open did not have the <code>O_NOCTTY</code> flag, and
- (v) the tty is not the foreground VT, and
- (vi) the tty is not the console, and
- (vii) maybe the tty should not be master or slave pty.
- </p><p>
- </p><h3>Getting rid of a controlling tty</h3>
- <p>If a process wants to continue as a daemon, it must detach itself
- from its controlling tty. Above we saw that <code>setsid()</code>
- will remove the controlling tty. Also the ioctl TIOCNOTTY does this.
- Moreover, in order not to get a controlling tty again as soon as it
- opens a tty, the process has to fork once more, to assure that it
- is not a session leader. Typical code fragment:
- </p><p>
- </p><pre> if ((fork()) != 0)
- exit(0);
- setsid();
- if ((fork()) != 0)
- exit(0);
- </pre>
- <p>See also <code>daemon(3)</code>.
- </p><p>
- </p><h3>Disconnect</h3>
- <p>If the terminal goes away by modem hangup, and the line was not local,
- then a SIGHUP is sent to the session leader.
- Any further reads from the gone terminal return EOF.
- (Or possibly -1 with <code>errno</code> set to EIO.)
- </p><p>If the terminal is the slave side of a pseudotty, and the master side
- is closed (for the last time), then a SIGHUP is sent to the foreground
- process group of the slave side.
- </p><p>When the session leader dies, a SIGHUP is sent to all processes
- in the foreground process group. Moreover, the terminal stops being
- the controlling terminal of this session (so that it can become
- the controlling terminal of another session).
- </p><p>Thus, if the terminal goes away and the session leader is
- a job control shell, then it can handle things for its descendants,
- e.g. by sending them again a SIGHUP.
- If on the other hand the session leader is an innocent process
- that does not catch SIGHUP, it will die, and all foreground processes
- get a SIGHUP.
- </p><p>
- </p><h2><a name="ss10.4">10.4 Threads</a>
- </h2>
- <p>A process can have several threads. New threads (with the same PID
- as the parent thread) are started using the <code>clone</code> system
- call using the <code>CLONE_THREAD</code> flag. Threads are distinguished
- by a <i>thread ID</i> (TID). An ordinary process has a single thread
- with TID equal to PID. The system call <code>gettid()</code> returns the
- TID. The system call <code>tkill()</code> sends a signal to a single thread.
- </p><p>Example: a process with two threads. Both only print PID and TID and exit.
- (Linux 2.4.19 or later.)
- </p><pre>% cat << EOF > gettid-demo.c
- #include <unistd.h>
- #include <sys/types.h>
- #define CLONE_SIGHAND 0x00000800
- #define CLONE_THREAD 0x00010000
- #include <linux/unistd.h>
- #include <errno.h>
- _syscall0(pid_t,gettid)
- int thread(void *p) {
- printf("thread: %d %d\n", gettid(), getpid());
- }
- main() {
- unsigned char stack[4096];
- int i;
- i = clone(thread, stack+2048, CLONE_THREAD | CLONE_SIGHAND, NULL);
- if (i == -1)
- perror("clone");
- else
- printf("clone returns %d\n", i);
- printf("parent: %d %d\n", gettid(), getpid());
- }
- EOF
- % cc -o gettid-demo gettid-demo.c
- % ./gettid-demo
- clone returns 21826
- parent: 21825 21825
- thread: 21826 21825
- %
- </pre>
- <p>
- </p><p>
- </p><hr>
- </body></html>
|