From: yooooooooooooo on 7 Mar 2010 07:14 int tcsetpgrp(int fildes, pid_t pgid_id) The situation is like this: Parent process ppid belongs to foreground process group, and it is associated with the session's controlling terminal which should be no more than one per session. Later ppid fork a child process cpid, make it process group leader of cpid, and call tcsetpgrp to make process group cpid the foreground process group. My question is, when the child process cpid terminates, which process does the session's controlling terminal is associated to if cpid has never called tcsetpgrp again to change the association of the unique controlling terminal. Thanks.
From: Ersek, Laszlo on 7 Mar 2010 16:15 In article <9b544467-82fb-4026-af72-4c4db1d3e726(a)t9g2000prh.googlegroups.com>, yooooooooooooo <yszhou4tech(a)gmail.com> writes: > int tcsetpgrp(int fildes, pid_t pgid_id) > > The situation is like this: Parent process ppid belongs to foreground > process group, and it is associated with the session's controlling > terminal which should be no more than one per session. Let's call it a shell: - PID = ppid - SID = ppid (SID = PID, session leader) - PGID = ppid (PGID = PID, process group leader) - has a controlling terminal >>A session leader that has control of a terminal is called the "controlling process" of that terminal.<< http://www.gnu.org/software/libc/manual/html_node/Controlling-Terminal.html It is called "controlling process" for a reason, because it is the one process that manipulates the terminal. I imagine the meaning of the "controlling terminal" expression like this: each (slave) terminal device has a (SID, PGID) pair built-in. Each process with that SID has the terminal as its controlling terminal, and each process with that PGID is in the foreground process group of the terminal. The shell (the controlling process) moves process groups between foreground and background by manipulating the PGID component of this pair, by tcsetpgrp(). When the (slave) terminal device was open()ed originally by the shell (without the O_NOCTTY flag), the (SID, PGID) pair of the terminal device was initialized to (ppid, ppid). The controlling process is simply the process whose PID matches the terminal's SID component. > Later ppid fork a child process cpid, make it process group leader of > cpid, So the user types $ /bin/true and the shell fork()s a child shell: - PID = cpid - SID = ppid (in the session of the parent, the session leader) - PGID = ppid (in the process group of the parent) - has the same controlling terminal Then both the parent (setpgid(cpid, 0)) and the child (setpgid(0, 0)) shell tries to move the child shell into its own process group, making it the leader of the new process group: - PID = cpid - SID = ppid (in the session of the session leader shell) - PGID = cpid (PID = PGID, process group leader) > and call tcsetpgrp to make process group cpid the foreground process > group. So the parent shell (the controlling process) changes the terminal to point to this process group as the foreground group, with a call to tcsetpgrp(fd, cpid). The terminal's built-in pair will look like: (SID, PGID) == (ppid, cpid) Then the child executes the /bin/true image and terminates. > My question is, when the child process cpid terminates, which process > does the session's controlling terminal is associated to if cpid has > never called tcsetpgrp again to change the association of the unique > controlling terminal. The imaginary pair of the terminal still looks like (SID, PGID) == (ppid, cpid) The parent shell (= the controlling process, = the session leader) notices the termination of the child by way of SIGCHLD. It then calls tcsetpgrp(fd, cpid), putting its own group (with it as its sole member) back to the foreground position. (This call probably requires the blocking of ignoring of SIGTTOU, as at the time of the call, the parent shell itself is not in the foreground process group.) .... The above is not much more than speculation. Please read all of the following for authoritative answers (the links are to SUSv3): "11. General Terminal Interface" http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap11.html "tcsetpgrp - set the foreground process group ID" http://www.opengroup.org/onlinepubs/000095399/functions/tcsetpgrp.html "setpgid - set process group ID for job control" (rationale!) http://www.opengroup.org/onlinepubs/000095399/functions/setpgid.html (Links this time to SUSv3, because the SUSv2 page of setpgid() contains a confusing typo.) And the 27 "Job Control" chapter of the GNU libc manual: http://www.gnu.org/software/libc/manual/html_node/Job-Control.html Notably, SUS doesn't speak of any explicit "session id", it's my reasoning device. .... You probably questioned before why setsid() is disallowed for processes that are already process group leaders, ie. for which PID = PGID holds. http://www.opengroup.org/onlinepubs/000095399/functions/setsid.html Suppose we allow setsid() for a process group leader: session leader: - PID = 1000 - SID = 1000 (session leader) - PGID = 1000 (process group leader) forked child 1: - PID = 1001 - SID = 1000 (same session) - PGID = 1001 (in its own process group, process group leader) forked child 2: - PID = 1002 - SID = 1000 (same session) - PGID = 1001 (same process group as forked child 1) Now if "forked child 1" could do a setsid(), setting both its SID and PGID to its PID: forked child 1 after imaginary setsid(): - PID = 1001 - SID = 1001 (leader of new session) - PGID = 1001 (process group leader -- no change) This would result in a situation where the two members of process group 1001 belong to different sessions (1000 and 1001). "forked child 2" is allowed to do setsid(), because then its PGID is in fact changed: forked child 2 after setsid(): - PID = 1002 - SID = 1002 (new session, leader) - PGID = 1002 (new process group, leader) And this is why a fork() enables a setsid() in the child: even if PID == PGID holds in the parent (so that a setsid() would create a new session but not a new process group), it won't hold in the child (because the child's new PID will be different from the parent's PID and thus the inherited PGID), and thus setsid() effects an actual change in PGID in the child when it sets PGID to PID, moving the child out of the original process group. .... Sorry for all the errors. Cheers, lacos
From: Ersek, Laszlo on 7 Mar 2010 17:47 In article <33NyY+nY8ulY(a)ludens>, lacos(a)ludens.elte.hu (Ersek, Laszlo) writes: > The parent shell (= the controlling process, = the session leader) > notices the termination of the child by way of SIGCHLD. > It then calls > tcsetpgrp(fd, cpid), putting its own group (with it as its sole member) > back to the foreground position. > (This call probably requires the > blocking of ignoring of SIGTTOU, as at the time of the call, the parent > shell itself is not in the foreground process group.) The second block is full of typos. Correction: ----v---- It then calls tcsetpgrp(fd, ppid), putting its own group (with itself as the only member of that group) back to the foreground position. ----^---- Sorry, lacos
From: yolila on 8 Mar 2010 10:16 Thank you, Ersek, for the notions of "each (slave) terminal device has a (SID, PGID) pair built-in", and such good material for my reference. It does make sense. I got that the key point when calling tcsetpgrp from a background process is the disposition of SIGTTOU signal. I experiment it with the following code neglecting error checking: #include <stdio.h> #include <unistd.h> #include <signal.h> int main() { setpgid(0, 0); signal(SIGTTOU, SIG_IGN); // 1 tcsetpgrp(STDIN_FILENO, getpid()); printf("Hello, I am newly from background.\n"); tcsetpgrp(STDIN_FILENO, getppid()); // 2 //sleep(2); return 0; } If code line 1 was commented out, running this program in the background would make itself be stopped. If code line 2 was commented out, and running this program in the background, the whole program worked fine except that after this process was done, bash would log out current user which I didn't get the inner mechanism within this result. Thanks, the answer really helped a lot. : )
|
Pages: 1 Prev: Please help with this one-line sed Next: #define _XOPEN_SOURCE 600 - where to define? |