本章是最为难懂,最为晦涩的一章。主要讲解进程组,session, 终端,作业之间关系和概念。
1. 终端登录
终端登录由init自举fork getty进程,getty 调用类似execle("/usr/bin/login","login","-p",username,(char*)0,envp)这样的语句来完成登录过程。
正确登录后,login 就将当前工作目录更改为用户的起始目录(chdir),调用chown改变终端的所有权。调用setgid及initgroups设置进程的组ID。然后login所得到的所以信息初始化环境:起始目录,shell,用户名以及默认系统路径PATH,最后login 进程改变为登录用户的用户ID(setuid)并调用该用户的登录sheel.
execl("/bin/sh","-sh", (char*)0)
2. 进程组概念
#include
#include
pid_t getpgrp(void);
int setpgid(pid_t pid, pid_t pgid)
一个改变和设置组ID的例子
#include
#include
#include
int main()
{
pid_t pid;
if((pid=fork())<0)
{
printf("fork error\n");
return 1;
}
else if(pid==0)
{
printf("Child pid=%d,gid=%d\n", getpid(),getpgrp());
sleep(3);
setpgid(pid,pid);
printf("Child pid=%d,gid=%d\n", getpid(),getpgrp());
}
else
{
printf("Parent pid=%d,gid=%d\n", getpid(),getpgrp());
if(wait(NULL)==-1)
{
printf("wait error\n");
}
printf("Parent pid=%d,gid=%d\n", getpid(),getpgrp());
}
}
可以通过setsid来脱离原有session 创建新的session. 组长进程不能调用setsid,否则出错。调用后新session脱离原有控制终端。
setsid的一般会在创建精灵进程时被调用。
4. session ,控制终端和进程组关系
5. 孤儿进程组
父进程终止的进程组称为孤儿进程组。父进程终止后,子进程由init进程领养。父进程结束后,kernel 会向子进程发送SIGHUP 和SIGCONT信号。
下面demo,如果子进程不注册接收SIGHUP的signal 函数,那子进程将会被终止。
子进程试图读终端会失败。
#include
#include
#include
#include
#include
#include
#include
static void pr_ids(char* name)
{
printf("%s: pid=%d, ppid=%d, pgid=%d\n",name, getpid(),getppid(),getpgrp());
fflush(stdout);
}
static void sig_hup(int signo)
{
printf("Received signal hup\n");
return;
}
int main()
{
pid_t pid;
if((pid=fork())<0)
{
printf("fork error\n");
exit(-1);
}
else if (pid>0) //parent
{
sleep(5);
exit(0);
}
else
{
pr_ids("child");
/*
if (signal(SIGHUP,sig_hup)==SIG_ERR)
{
printf("signal error\n");
return -1;
}
*/
kill(getpid(),SIGTSTP);
pr_ids("child");
char c;
if(read(0,&c,1)!=1)
printf("read error, errno =%d, reason=%s\n", errno, strerror(errno));
exit(0);
}
}