【APUE】Chapter9 Process Relationships

这一章看的比较混乱,可能是因为例子少;再有就是,这一章就是一个铺垫的章节。

9.2 terminal logins

  啥叫termnial? 我感觉书上的terminal指的更可能是一些物理设备(keyboard, modem这类的)

  /etc/ttys里面存着这些终端,一行代表一个终端的信息。

  限于基础知识有限,上面的内容可能理解的有误,但是对于terminal logins有一点是可以确定的:计算机事先知道有多少terminals可以logins。

  其中BSD Terminal Logins是重点讲述的,其主要流程如下流程如下:

    init (process ID 1)

    ?? fork once per terminal;creates empty environment

    init

    ?? each child execs getty

    getty

    ?? opens terminal device; real user name; initial environment set;

    login

    ??

    ??  file descriptor 0 1 2

    terminal device driver

    ??

    ??  hard-wired connection

    user at a terminal

  在上面的过程中,可以看到Chapter 8 中fork exec的作用。

(1)先看到getty(包括getty)发生了什么

  environment:init给getty的还是一个empty environment;getty自己create了一个environment再传给login,这个时候environment中就已经包含了terminal的信息了(如TERM)。

  open terminal device: 打开terminal device,设定file descriptor 0 1 2 (input、output、error)

  read user name: output类似“login:”等着用户输入

  可以用下面的内容来理解getty:

  execle("/bin/login", "login", "-p", username, (char*)0, envp);

  最后getty调用了login program

(2)再看login做了哪些事情

  a. 获取密码,校验密码。

  b. 转换到这个用户的home路径

  c. 把terminal device的ownship转换给用户

  d. 设定groupid

  e. ...

9.3 Network Logins

  与terminal logins不同的是,计算机事先是不知道有多少,那些,谁,要network logins的。

  因此,没有像/etc/ttys一行的terminal配置文件可以读。怎么办呢?这就要用一种类似service的方式去处理。

  为了能够最终统一处理terminal和network的logins,unix系统中存在一种pseudo terminal的机智,可以翻译为虚拟终端。

  为什么要有虚拟终端呢?

  我觉得有两个原因:

  1)作为终端用户,个人习惯来说,远程网络操作和terminal操作不希望有啥不同

  2)作为unix系统,既然已经开发了terminal logins的程序,自然希望network logins的程序也能复用terminal logins的处理程序。因为二者除了登入的方式不同,一旦与系统发生交互,处理的内容都是类似的。

  因此,pseudo terminal就出现了,完成了上述的诉求。即使从network logins的,只要login完成了,与terminal的操作并无两样。

  下面只需要关注如何产生pseudo terminal的,流程如下。

                        init process ID 1

TCP connection request from TELNET client → ?? executes the shell script /etc/rc

                        inetd

                        ?? fork (when connection request arrives from TELNET client)

                        inetd

                        ??

                        telnetd

                        ??

                        pseudo terminal device

                        ?? fork

                        parent process : handle the communication across the network connection

                        child process : does an exec of the login program

                        parent & child connected through the pseudo terminal

                        child process

                        ??

                        ??

                        login shell

  上述的过程就是:

    在系统的start-up阶段,init会执行一个/etc/rc的shell script,这个脚本的目的是启动inetd daemons。

    随后,inetd daemons就一直等着,直到有来自telnet client的请求就fork出去一个小弟inetd去处理这个请求。

    这个inetd小弟处理请求的方式是执行TELNET server,即telnetd。

    随后telnetd随即打开一个pseudo terminal device,并且用fork的方式一分为二:

      parent process : 负责管network connection的事情

      child process : 负责管执行login相关的东西

      parent 与 child 之间通过pseudo terminal来关联

9.4 Process Group

   一堆process组成一个process group,猜测有process group是为了方便集体对某种类型的process进行集体操作。不细说。

9.5 Sessions

   多个process groups构成了Session。

9.8 Job Control

  这一部分书上有个了例子,从结果来看:不带job control的shell,一个terminal只能产生一个PGID;带job control的shell,一个terminal可以产生好几个PGID.

9.10 Orphaned Process Groups

  由于缺乏后面signal的知识,就只看9.12这个代码。

  代码不复杂,这里不详细记录了。

  只说让我疑惑的地方。

...signal(SIGHUP, sig_hup);
kill(getpid(), SIGTSTP);...

  源代码中有这么两行,是在fork后的child process中执行的。

  先放着signal不管,这个kill就比较让人看着不好理解:都kill了,为什么child process后面的语句还能执行呢?

  先man 2 kill一下:“kill - send signal to a process”。这才知道,kill做的事情是发送一个信号

  那么再看一下发送的这个信号SIGTSTP是啥意思呢?

  书上有这么一段话:“Unfortunately, the term stop has different meanings.....Therefore, the terminal driver calls the character that generates the interactive stop signal the suspend character, not the stop character”。

  可以理解为:这里的stop并不是说直接给弄没了,而是先让这个进程等着的意思。

  再回来看signal。

  源代码中故意弄没了parent process,留着child process,这样就造成了orphaned process group的情况。按照系统的要求,对于orphaned process group中的所有的余留的进程,都会被发送一个hang-up的信号(SIGHUP),随后伴随着就SIGCONT的信号。signal这个语句就是为了能让child process接收到SIGHUP这个信号,并继续执行下去。

  通过这个事情,这个kill跟他原来的意思还是差挺多的,还是要多注意一些。

  

     

  

  

  

时间: 2024-12-09 12:44:38

【APUE】Chapter9 Process Relationships的相关文章

【APUE】Chapter8 Process Control

这章的内容比较多.按照小节序号来组织笔记的结构:再结合函数的示例带代码标注出来需要注意的地方. 下面的内容只是个人看书时思考内容的总结,并不能代替看书(毕竟APUE是一本大多数人公认的UNIX圣经). 8.2 Process Identifiers 1. unix system给系统分配进程pid采用的是delay reuse策略:即,刚用完被释放的pid不会马上分配给新的进程,目的是防止新进程错误使用与之前进程相同的ID(这块内容还没太懂,以后再看):但具体等多久不一定. 2. 有几个特殊的p

【APUE】Chapter7 Process Environment

这一章内容是Process的基础准备篇章.这一章的内容都是基于C Programm为例子. (一)进程开始: kernel → C start-up rountine → main function 其中C start-up rountine做的事情中包括:获得command-line arguments & environment 好像还有其他的事情,后面再说. (二)进程结束: 五种normal termination方式: 1. return from main 2. exit 3. _e

【APUE】孤儿进程与僵死进程

基本概念: 在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程:一个进程

【APUE】进程基础

进程标识符:非负整数 ID为0的进程通常是是调度进程,常被称为交换进程.该进程是内核的一部分,它并不执行任何磁盘上的程序,因此也被称为系统进程 ID为1的进程是init进程,在自举过程结束时由内核调用,此进程负责在自举内核后启动一个UNIX系统,init通常读入与系统有关的初始化文件,并将系统引导到一个状态,init进程不会终止.它是普通的用户进程,以超级用户特权运行 常用函数: pid_t getpid(void)  返回调用进程的进程id pid_t getppid(void) 返回调用进程

【APUE】fork函数

#include <unisth.h> pid_t fork(void) fork函数被调用一次,返回两次.子进程的返回值是0,父进程的返回值是子进程的进程id. 子进程和父进程继续执行fork调用之后的指令,子进程是父进程的副本,子进程获得父进程数据空间.堆和栈的副本.注意:这是子进程所拥有的副本,父子进程并不共享这些存储空间部分.父子进程共享正文段 #include <stdio.h> #include <sys/types.h> #include <unis

【APUE】wait与waitpid函数

当一个进程终止时,内核就向其父进程发送SIGCHLD信号.因为子进程终止是个异步事件,所以这种信号也是内核向父进程发的异步通知.父进程可以选择忽略该信号,或者提供一个该信号发生时即被调用执行的函数.对于这种信号的系统默认动作是忽略它. 调用wait或waitpid的进程发生的情况如下: 1.如果所有子进程都还在运行,则阻塞 2.如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回 3.如果它没有任何子进程,则立即出错返回 #include <sys/wait.h>

【APUE】进程间通信之管道

管道是UNIX系统IPC最古老形式,并且所有UNIX系统都提供此种通信机制.管道由下面两种局限性: 1)历史上,它们是半双工的(即数据只能在一个方向上流动) 2)它们只能在具有公共祖先的进程之间使用.通常,一个管道由一个进程创建,然后该进程调用fork,此后父.子进程之间就可应用该管道 管道由调用pipe函数创建: #include <unistd.h> int pipe(int filedes[2]);//若成功则返回0,出错返回-1 注意:filedes[0]为读而打开,filedes[1

【APUE】用户态与内核态的区别

当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态).此时处理器处于特权级最高的(0级)内核代码中 执行.当进程处于内核态时,执行的内核代码会使用当前进程的内核栈.每个进程都有自己的内核栈.当进程在执行用户自己的代码时,则称其处于用户运行态(用 户态).即此时处理器在特权级最低的(3级)用户代码中运行. 内核态与用户态是操作系统的两种运行级别,跟intel cpu没有必然的联系, intel cpu提供Ring0-Ring3三种级别的运行模式,Rin

【APUE】vim常用命令

转自:http://coolshell.cn/articles/5426.html 基本命令: i → Insert 模式,按 ESC 回到 Normal 模式. x → 删当前光标所在的一个字符. :wq → 存盘 + 退出 (:w 存盘, :q 退出)   (陈皓注::w 后可以跟文件名) dd → 删除当前行,并把删除的行存到剪贴板里 p → 粘贴剪贴板 简单的移动光标 0 → 数字零,到行头 ^ → 到本行第一个不是blank字符的位置(所谓blank字符就是空格,tab,换行,回车等)