9进程关系

来源:互联网 发布:js初始化数组 编辑:程序博客网 时间:2024/04/28 05:59

BSD终端登录

1)系统管理员创建/etc/ttys文件。其中,每个终端设备都有一行,每一行说明设备名和传递给getty程序的参数。

2)系统自举时,内核创建进程ID为1的进程,也就是init进程。init进程使系统进入多用户状态。init进程读取文件/etc/ttys。对每一个允许登录的终端设备,init调用一次fork,它所生的子进程则执行(exec)getty程序。init以空环境执行getty程序

3)getty为终端设备调用open函数,以读写方式将终端打开。如果设备是调制解调器,则open可能会在设备驱动程序中滞留,直到用户拨号调制解调器,并且呼叫被应答。一旦设备被打开,则文件描述符0,1,2就被设置到该设备。

4)输入用户名,调用execle("/bin/login","login","-p",username,(char*)0,envp);

5)当登录shell终止时,init会得到通知,会对该终端重复全部上述过程。

PAM(pluggable authentication)

PAM允许管理员配置使用何种身份验证方法来访问那些使用PAM库编写承德服务。

-----------------------------------------------------------------

网络登录

通过网络登录时,终端和计算机之间的连接不是点对点连接。login只是一种可用的服务。

BSD网络登录

1)BSD有一个称为inetd的进程,它等待大多数网络连接。

2)init调用一个shell,使其执行/etc/rc。由此shell脚本启动一个守护进程inetd。inetd的父进程变成init。inetd等待TCP/IP连接请求到达主机,而当一个连接请求到达时,它执行一次fork,然后生成的子进程执行适当的程序。

3)一个telnet连接到主机。启动一个telnet服务进程。telnetd

4)然后,telnetd进程打开一个伪终端设备,并用fork分成两个进程。父进程处理通过网络连接的通信,子进程则执行login程序,父子进程通过伪终端相连接。在调用exec之前,子进程使其文件描述符0,1,2与伪终端相连。如果登录正确,login执行终端登录步骤。

 

linux网络登录使用xinetd代替inetd

----------------------------------------------------------------------------------------

进程组

进程组释一个或多个进程的集合。通常,它们与同一作业相关联,可以接受来自同一终端的各种信号。

#include <unistd.h>

pid_t getpgrp(void);

pid_t getpgid(pid_t pid)

getpgid(0)=getpgrp()

组长进程:进程组ID等于其进程ID。

组长进程可以创建一个进程组,创建该组中的进程,然后终止。只要在某个进程组中又一个进程存在,则该进程组就存在,与其组长是否终止无关。从开始创建到最后一个离开称为生存期。进程组中最后一个进程可以终止,或者转移到另一个进程组。

#include<unistd.h>

int setpgid(pid_t pid, pid_t pgid)

如果两个参数相同,则由pid指定的进程变成进程组组长。如果pid=0,则使用调用者的进程ID。另外,如果pgid=0,则由pid指定的进程ID将用作进程组ID。

一个进程只能为它自己或它的子进程设置进程组ID。在它的子进程调用了exec函数之一后,就不能改变子进程的进程组ID。

在大多数作业控制shell中,在fork之后调用此函数,使父进程设置其子进程的进程组ID,并且使子进程设置其自己的进程组ID。这两个调用中有一个是冗余的。但可以保证,在父,子,进程认为子进程已进入了该进程组时,这确实已经发生了。如果不这么做,会由于先后次序的不确定,造成组员身份的不确定产生竞争条件。

---------------------------------------------------------------------------------

会话

会话是一个或多个进程组的集合。

通常是由shell的管道线将几个进程编成一组的。

#include <unistd.h>

pid_t setsid(void)//成功返回进程组ID,出错返回-1

如果调用此函数的进程不是一个进程组的组长,则此函数就会创建一个新会话,将发生:

1)该进程变成新会话首进程(session leader)。该进程现在是新会话中唯一的进程。

2)该进程成为一个新进程组的组长进程。新进程组ID是该调用进程的进程ID

3)该进程没有控制终端。如果在调用setsid之前该进程有一个控制终端,那么这种联系也会被中断。

如果该调用进程已经是一个进程组的组长,返回出错。为避免此,通常先调用fork,然后使其父进程终止,而子进程则继续。造成子进程不是组长。

会话首进程是具有唯一进程ID的单个进程,所以可以将会话首进程的进程ID视为会话ID。

#include<unistd.h>

pid_t getsid(pid_t pid)// 返回会话首进程的进程组ID,若出错返回-1

如若pid并不属于调用者所在的会话,那么调用者就不能得到该会话首进程的进程组ID。

------------------------------------------------------------------------

控制终端

会话和进程组有一些其他特性:

1)一个会话可以有一个控制终端。通常是登录到其上的终端设备或伪终端设备。

2)建立与控制终端连接的会话首进程被称为控制进程。

3)一个会话中的几个进程组可被分成一个前台进程组以及一个或几个后台进程组。

4)如果一个会话有一个控制终端,则它有一个前台进程组,会话中的其他进程组则为后台进程组。

5)无论何时键入终端的中断键,就会将中断信号发送给前台进程组的所有进程。

6)无论何时键入终端的退出键,就会将退出信号发送给前台进程组中的所有进程。

7)如果终端接口检测到调制解调器已经断开连接,则将挂断信号发送给控制进程。

-----------------------------------------------------------------------------

#include <unistd.h>

pid_t tcgetpgrp(int filedes)//若成功则返回前台进程组的进程组ID,若出错返回-1

int tcsetpgrp(int filedes, pid_t pgrpid)//如果进程有一个控制终端,则进程可以调用此函数将前台进程组ID设置为pgrpid。pggrpid的值应当是在同一会话中的一个进程组的ID。filedes必须引用该会话的控制终端。成功返回0,出错返回-1。

pid_t tcgetsid(int filedes)//若成功返回会话首进程的进程组ID,若出错返回-1

----------------------------------------------------------------------------------

作业控制

允许在一个终端上启动多个作业(进程组),它控制哪一个作业可以访问该终端,以及那些作业在后台运行。

要求的形式支持:

1)支持作业控制的shell

2)内核中的终端驱动程序必须支持作业控制

3)内核必须提供对某些作业控制信号的支持。

-------------------------------------------------------------------------

孤儿进程组:该组中每个成员的父进程要么是该组的一个成员,要么不是该组所属会话的成员。

此情形下errno=EIO