《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)

Process  Relationships

Terminal  Logins

Unix 是1971年开始的吧,但是这个terminal login的机制最起码30年没变过。。。非常成熟的机制
《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第1张图片


All the processes shown in Figure9.1 have a real user ID of 0 and an effective user ID of 0(i.e.,  they  all  have superuser  privileges). The init process  also execs the getty program with an empty environment.

It  is getty that  calls open for  the  terminal  device. The  terminal  is  opened  for reading  and  writing.


Once the device is open, file descriptors  0,  1,  and  2  are set  to  the  device. Then gettyoutputs  something  like
login: and  waits  for  us  to  enter  our  user  name。

something like this:



《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第2张图片

《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第3张图片


All the processes shown in Figure9.2 have superuser privileges, since the original init process  has  superuser privileges. The  process  ID  of  the  bottom  three  processes  in Figure9.2  is  the  same,  since  the  process  ID does  not  change  across  an exec.Also,  all the processes other than the original init process have a parent process ID of 1.

If we log in correctly, login will
•Change to our home directory(chdir)

•Change the ownership of our terminal device (chown) so we own it

•Change the access permissions for our terminal device so we have permission to read from and write to it

•Set our group IDs by calling setgid and initgroups

•Initialize  the  environment  with  all  the  information  that loginhas:  our  home directory (HOME), shell 
(SHELL), user name (USER and LOGNAME), and a default path (PATH)

•Change to our user ID ( setuid)and invoke our login shell, as in    execl("/bin/sh", "-sh", (char *)0);

《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第4张图片








Network  Logins



the  connection  between  the terminal and the computer isn’t point-to-point. In this case, loginis simply a service  available, just like any other network service, such as FTP or SMTP.



  A single  process  waits  for  most  network  connections:  the inetd process, sometimes  called  the Internet  superserver.


As  part  of  the  system  start-up,init invokes  a  shell  that  executes  the  shell  script /etc/rc.One  of  the  daemons that  is  started  by  this  shell  script  is inetd.Once  the shell  script  terminates,  the  parent  process  of inetd becomes init; inetd waits  for TCP/IP connection requests to arrive at the host. 

《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第5张图片

The telnetd process  then  opens  a  pseudo  terminal  device  and  splits  into  two processes  using fork.The parent handles  the  communication  across  the  network connection,  and  the  child  does  an exec of  the login program



Process  Groups


In  addition  to  having  a  process  ID,  each  process  belongs  to  a  process  group. 
Each process  group  has  a  unique  process  group  ID.



#include <unistd.h>
pid_t getpgrp(void);
Returns: process group ID of calling process


#include <unistd.h>
pid_t getpgid(pid_t pid);
Returns: process group ID if OK, −1 on error

If pid is 0, the process group ID of the calling process is returned.  Thus
getpgid(0);
is equivalent to
getpgrp();

特别注意这两个API的名称。。。被坑10分钟debug

Each process group can have a process group leader.The leader is identified by its process group ID being equal to its process ID.

The process  group  still  exists,  as  long  as  at  least  one process  is  in  the  group,  regardless  of  whether  the group  leader  terminates. This  is called  the  process  group  lifetime—the  period  of  time  that  begins  when  the group  is created and ends when the last remaining process leaves the group.


#include <stdio.h>
#include <unistd.h>

int main()
{
        pid_t temp = 0;
        //test pid_t getpgrp(void);
        printf("The group ID of current process : %d\n",getpgrp());


        //test pid_t getpgrp(pid_t pid);
        printf("The group ID of current process : %d\n",getpgid(getpid()));
        return 0;
}
test result:
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_9$ ./a.out
The group ID of current process : 20071
The group ID of current process : 20071





先印证一下fork出来的child process是parent process的group 成员

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>


int main()
{
        pid_t pid = 0;


        printf("Current process ID:%d\n",getpid());


        if((pid = fork()) < 0)
        {
                printf("fork error\n");
        }
        else if(pid == 0)
        {
                printf("Current process group of child process ID: %d\n",getpgrp());
                exit(0);
        }
        else if(pid > 0)
        {
                waitpid(pid,NULL,0);
                printf("Current process group of child process ID : %d\n",getpgrp());
        }


        return 0;
}
test result:

jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_9$ ./a.out
Current process ID:20128
Current process group of child process ID: 20128
Current process group of parent process ID : 20128



A process joins an existing process group or creates a new process group by calling setpgid 

#include <unistd.h>
int setpgid(pid_t pid,pid_t pgid );
Returns: 0 if OK,−1 on error


This function sets the process group ID to pgid in the process whose process ID equals pid.If the  two  arguments  are equal,  the  process  specified  by pid becomes  a  process group leader .If pid is 0, the process ID of the caller is used. Also, if pgid is 0, the process ID specified by pid is used as the process group ID。

Furthermore, it can’t change the process group ID of one of its children after that child has called one of the exec functions.



Sessions



A session is a collection of one or more process groups。



《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第6张图片

A process establishes a new session by calling the setsid function.

#include <unistd.h>
pid_t setsid(void);
Returns: process group ID if OK, −1 on error

If the calling process is not a process group leader ,t his function creates a new session.
也就是说sessions leader 和group leader不可能是同一个ID
Three things happen.
1.  The process  becomes  the session  leader of  this  new  session. (A  session  leader  is  the  process  that  creates  a  session.) The  process  is  the  only  process  in  this  new  session.

2.  The process becomes the process group leader of a new process group.  The new  process group ID is the process ID of the calling process.

3.  The process has no controlling terminal. (We’ll discuss controlling terminals in  the  next  section.) If  the  process  had  a  controlling  terminal  before calling  setsid, that association is broken.



#include <unistd.h>
pid_t getsid(pid_t pid);
Returns: session leader’s process group ID if OK, −1 on error


这个demo出来的很艰难。。。。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t pid = 0;


        printf("Current process -- parent process ID:%d\n",getpid());


        printf("Current process group of parent process ID : %d\n",getpgrp());
       
        if((pid = fork()) < 0)
        {
                printf("fork error\n");
        }
        else if(pid == 0)
        {
                pid_t pgrp;


                printf("child process ID:%d\n",getpid());


                printf("Current process group of child process ID: %d\n",getpgrp());


                printf("after set new group\n");

                setsid();

                printf("Current process group of child process ID: %d\n",getpgrp());
                printf("Current sessions ID :%d\n",getsid(getpid()));
                exit(0);
        }
        else if(pid > 0)
        {
                waitpid(pid,NULL,0);
                printf("Current process group of parent process ID : %d\n",getpgrp());
                printf("Current session ID of parent process : %d\n",getsid(getpid()));
        }


        return 0;
}

jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_9$ ./a.out
Current process -- parent process ID:20833
Current process group of parent process ID : 20833
child process ID:20834
Current process group of child process ID: 20833
after set new group
Current process group of child process ID: 20834
Current sessions ID :20834
Current process group of parent process ID : 20833
Current session ID of parent process : 20635




If pid is  0, getsid re turns  the  process  group  ID  of  the  calling  process’s  session  leader.

For  security  reasons,  some  implementations  may  restrict  the  calling  process  from obtaining  the  process  group  ID  of  the  session  leader  if pid doesn’t  belong  to  the  same session as the caller.




Controlling  Terminal



•A session  can  have  a  single controlling  terminal.This  is  usually  the  terminal  device (in the case of a terminal login) or pseudo terminal device (in the case of a  network login) on which we log in.

•The  session  leader  that  establishes  the  connection  to  the  controlling  terminal  is  called the controlling process.

•The  process  groups  within  a  session  can  be  divided  into  a  single foreground  process group and one or more background process groups .

•If a session has a controlling terminal, it has a single foreground process group  and all other process groups in the session are background process groups.这就意味着有且只有一个foreground group,允许多个background group。

•Whenever  we  press  the  terminal’s  interrupt  key  (often  DELETE  or  Control- C),  the interrupt signal is sent to all processes in the foreground process group.

•Whenever  we  press  the  terminal’s  quit  key  (often  Control-backslash),  the  quit  signal is sent to all processes in the foreground process group.

•If a modem  (or  network)  disconnect  is  detected  by  the  terminal  interface,  the  hang-up signal is sent to the controlling process (the session leader).


《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第7张图片

我之前有个疑问,会不会有下图这种情况出现呢?
《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第8张图片
交集,可能吗?我一开始也比较纠结,APUE居然没有给出说明。理性的分析就能得出结论。Impossible!

我们是可以调用getpgrp()的,返回组ID,这个时候proc2和proc3返回什么值呢? 他不可能返回两个不同的组ID

于是完全可以得出结论,group process 和group process 之间不可能出现交集进程!


The way  a  program guarantees  that  it  is  talking  to  the  controlling  terminal  is  to open the  file /dev/tty 
Naturally,  if the program doesn’t have a controlling terminal, the open of this device will fail.



tcgetpgrp, tcsetpgrp,and tcgetsid Functions

#include <unistd.h>
pid_t tcgetpgrp(int fd );
Returns: process group ID of foreground process group if OK,−1 on error
int tcsetpgrp(int fd ,pid_t pgrpid );
Returns: 0 if OK,−1 on error
#include <termios.h>
pid_t tcgetsid(int fd );
Returns: session leader’s process group ID if OK, −1 on error


注意filedecriptor必须是和terminal相关联的文件,例如/dev/tty , 否则返回-1

#include <stdio.h>
#include <unistd.h>

int main()
{
        int file_descriptor = 0;


        if((file_descriptor = open("/dev/tty","r")) < 0)
        {
                printf("open error\n");
        }


        printf("foreground ID:%d\n",tcgetpgrp(file_descriptor));


        close(file_descriptor);
        return 0;
}



jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_9$ ./a.out
foreground ID:20905


Most applications don’t call these two functions directly.Instead, the functions are  normally called by job-control shells.



Job Control

很多人对job control的必要性有争议,但是没办法这好似POXIS的明文规定,要支持这家伙




Orphaned Process  Groups


就是前面讲的zombie。。。。

We’ve  mentioned  that  a  process  whose  parent  terminates  is  called  an  orphan  and  is inherited  by  the init process.  

#include"apue.h"
#include"myerr.h"
#include"errno.h"
#include"stdio.h"


static void
sig_hup(int signo)
{
        printf("SIGHUP received,pid = %d\n",getpid());
}


static void
pr_ids(char* name)
{
        printf("%s: pid = %d,ppid = %d,pgrp = %d,tppgrp = %d,\n",name,getpid(),getppid(),getpgrp(),tcgetpgrp(STDIN_FILENO));
        fflush(stdout);
}

int main(int argc,char* argv[])
{
        char c;
        pid_t pid;


        pr_ids("parent");
        if((pid = fork()) < 0)
        {
                err_sys("fork error\n");
        }
        else if(pid > 0)
        {
                sleep(5);
                exit(0);
        }
        else
        {
                pr_ids("child");
                signal(SIGHUP,sig_hup);
                kill(getpid(),SIGTSTP);
                pr_ids("child");
                if(read(STDIN_FILENO,&c,1) != 1)
                {
                        printf("read error from controlling TTY,errno = %d\n",errno);
                }
                exit(0);
        }
}

jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_9$ ./a.out
parent: pid = 20928,ppid = 20635,pgrp = 20928,tppgrp = 20928,
child: pid = 20929,ppid = 20928,pgrp = 20928,tppgrp = 20928,
SIGHUP received,pid = 20929
child: pid = 20929,ppid = 1,pgrp = 20928,tppgrp = 20635,
read error from controlling TTY,errno = 5






《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码)_第9张图片










你可能感兴趣的:(《APUE》Chapter 9 Process relationships (学习笔记加上自己的代码))