10、进程关系

1、终端登录
本地和远程登录都经内核中的终端设备驱动程序。
(1)本地终端登录
    终端设备文件中,每个终端设备都有一行,每一行说明设备名和传到getty程序的参数。
    系统自举时,init进程(ID=1)使系统进入多用户模式,读取终端设备文件,对每一个允许登录的终端设备调用一次fork,生成的子进程exec getty程序(以空环境运行)。此时所有进程的实际用户ID和有效用户ID都是0(因为init进程具有root权限,都具有root权限)。
    getty对终端设备调用open函数,以读写方式打开终端。如果是调制解调器则直到用户拨号调制解调器,线路接通再open。打开后文件描述符0、1、2被设置到该设备。
    getty输出“login:”,用户键入用户名后,如下方式调用login程序。
    login得到用户名,调用getpwnam得到相应用户的口令文件登陆项。然后调用getpass显示“Psaaword:”,接着读取用户口令,调用crypt加密用户键入的口令,并与用户在阴影口令文件登陆项的pw_passwd字段进行比较。如果几次输入口令无效,进程退出,父进程init再次调用fork执行getty。

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

这里写图片描述

    如果用户正确登陆,login完成如下工作
(1)更改当前目录为用户其实目录(chdir)
(2)使当前用户成为该终端的所有者(chown)
(3)改变终端设备为该用户读和写
(4)调用setgid和initgroups设置进程组ID
(5)login得到的信息来初始化环境:起始目录(HOME)、shell(SHELL)、用户名(USER和LOGNAME)、一个系统默认路径(PATH)
(6)login进程更改为登录用户的用户ID(setuid),调用该用户的登录shell

//符号“-”表示该shell作为登录shell调用
execl("/bin/sh","-sh",(char *)0);

    现在shell读取启动文件,GUN Bourne-again shell是 .bash_profile、.bash_login或 .profile。这些启动文件通常改变某些环境变量并增加很多环境变量。执行完启动文件后,用户得到shell提示符,并能键入命令。

(2)网络登录
    所有登录都经内核的网络接口驱动程序(如以太网驱动程序),等待一个网络连接请求的到达,而不是像上面一样一个进程等待一个可能的登录。
    系统使用伪终端的软件驱动程序,仿真串型终端的运行行为,并将终端操作映射为网络操作。
    init调用一个shell执行脚本/etc/rc,此脚本启动一个守护进程inetd(Linux有些版本使用扩展的因特网服务守护进程xinetd),shell脚本终止则inetd的父进程变为init。inetd进程等待TCP/IP连接请求到达主机。当一个请求到达,执行一次fork生成子进程exec其他程序。
    在另一个主机上或同一主机上启动TELNET客户进程来登录。

//打开一个到hostname主机的TCP连接
telnet hostname

    hostname主机启动TELNET的服务进程。然后,客户进程和服务进程使用TELNET应用协议通过TCP连接交换数据。
这里写图片描述
    telnetd进程(这里是服务器端,客户端也通过telnet进行网络连接)打开一个伪终端备,fork为两个进程。子进程使文件描述符0、1、2与伪终端相连。子进程再exec执行login程序,父进程负责通过通过网络进行通信。如果登录正确则和上面一样。Mac OS X上执行网络登录的更好办法是使用ssh。

2、进程组
    同一进程组中的各进程接收来自同一终端的各种信号。一个进程组有一个组长进程,组长进程的ID就是进程组ID。一个进程只能为自己和它的子进程设置进程组ID。

//返回进程组ID
pid_t getpgrp(void);

//将pid进程的进程组ID设为pgid
int setpgid(pid_t pid, pid_t pgid);

3、会话
会话session是一个或多个进程的集合。

//如果当前进程不是一个进程组组长,进程调用下面函数建立一个新会话,否则返回错误。
//为了避免这个情况,通常父进程调用fork后终止,子进程继承父进程的进程组ID,而且其进程ID和父进程ID不同,从而保证子进程不是一个进程组组长。
pid_t setsid(void);

//返回会话首进程的进程组ID
pid_t getsid(pid_t pid);

4、控制终端
    建立与控制终端连接的会话首进程为控制进程。一个会话的几个进程组为一个前台进程组,几个为后台进程组。任何时候键入中断键,都会把中断信号发送给前台进程组的所有进程。
这里写图片描述
5、

//得到前台进程组ID,它与在fd上打开的终端相关联(得到)
pid_t tcgetpgrp(int fd);

//设置进程组pgrpid为前台进程组,fd必须引用该会话的控制终端
int tcsetpgrp(int fd, pid_t pgrpid);

6、作业控制
一个终端上允许启动多个作业(进程组)。作业控制用于处理后台程序想要使用中断,即从终端输入输出的情况。他比较好的处理一个终端在多个进程之间转换。父进程是shell作为前台作业执行时终止,子进程变为后台进程组。
7、会话实现
这里写图片描述

//会话结构session
s_count 会话中进程组数
s_leader 指向会话中首个进程
s_ttyvp 指向控制终端vnode
s_ttyp 指向控制终端tty
s_sid 会话ID

//每个终端和伪终端在内核中分配一个tty结构
t_session 指向将此终端作为控制终端的会话结构
t_pgrp 指向前台进程组pgrp结构
t_terminos 包含与终端相关的信息
t_winsize  包含终端窗口当前大小的winsize

//pgrp结构包含特定进程组信息
pg_id 进程组ID
pg_sessions 指向此进程组所属会话session结构
pg_members 指向进程组中进程结构的p_pglist,p_pglist是双向链表,它把进程组中所有进程串联起来

//proc结构包含每个进程的信息
p_pglist 双向链表,它把进程组中所有进程串联起来
p_pid 进程ID
p_pptr 指向父进程proc结构
p_pgrp 指向本进程所属组
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值