《UNIX环境高级编程》--9进程关系

进程关系

  1. 终端登录:

    • BSD系统:

      • 当系统自举时,内核创建进程ID为 1 的进程,即init进程
      • init进程读取文件/etc/ttys,对每个允许登录的终端设备,init调用一次fork,其所生成的子进程则exec getty程序(以一个空的环境)
      • getty对终端设备调用open函数,以读、写方式将终端打开。

        • 一旦设备被打开则文件描述符0、1、2被设置到该设备
        • 然后getty输出login:之类的信息,并等待用户键入用户名
        • 当用户键入了用户名后,getty的工作就完成了,它以类似下列的方式调用login程序:

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

          其中envpgetty以终端名和在gettytab中说明的环境字符串为login创建的环境。-p标志通知login保留传递给它的环境,也可以将其他环境字符串添加到该环境中,但是不能替换它

      • login能处理多项工作
        • login得到了用户名,所以能够调用getpwnam获取相应用户的口令文件登录项,然后调用getpass以显示Password:
        • 接着login读取用户键入的口令,它调用crypt将用户键入的口令加密,并且与该用户在阴影口令文件中登录的pw_passwd字段比较
        • 如果用户自己键入的口令都无效,则login以参数1调用exit表示登录过程失败
          • 父进程init了解了子进程的终止情况后,再次调用fork其后又调用了getty,对此终端重复上述过程
        • 如果用户键入的口令正确,则login完成下列工作:
          • 将当前工作目录更改为用户的起始目录
          • 调用chown更改该终端的所有权,使得登录用户成为它的所有者
          • 将对该终端设备的访问权限变成”用户读和写“
          • 调用setgidinitgroups设置进程组ID
          • login得到的所有信息初始化环境:起始目录(HOME)、shell(SHELL)、用户名(USERLOGNAME)以及一个系统默认路径(PATH)
          • login进程调用setuid,将进程的用户ID更改登录用户的用户ID,并调用该用户的登录shell,其方式类似于:execl("/bin/sh","-sh",(char*)0);
          • 至此,登录用户的登录shell开始运行。登录shell读取其启动文件(如.profile)。这些启动文件通常是更改某些环境变量并增加很多环境变量。当执行完启动文件后,用户最后得到shell提示符,并能键入命令
    • MAC OS X系统:它部分地给予Free BSD,因此启动步骤与FreeBSD几乎相同,除了:
      • init工作是由launchd完成的
      • 一开始提供的就是图形终端
    • Linux:步骤几乎与Free BSD相同。但是init读取的是/etc/inittab文件而不是/etc/ttys文件

    login

  2. 网络登录:对于网络登录,所有登录都是经由内核的网络接口驱动程序。

    • BSD系统中,由init执行shell脚本/etc/rc,此shell脚本启动inetd守护进程。由inetd负责处理网络登录
    • Linux系统中,使用xinetd代替inetd进程

进程组

  1. 进程组:每个进程除了有一个进程ID之外,还属于一个进程组。进程组是一个或者多个进程的集合。

    • 通常进程组是在同一个作业中结合起来的
    • 同一个进程组中的各进程接收来自同一个终端的信号
    • 每个进程中都有一个唯一的进程组ID标志
      • 进程组ID类似于进程ID,是一个整数并且可以存放在pid_t数据类型中
    • 每个进程组都有一个组长进程。进程组ID就等于组长进程的进程ID
      • 进程组的组长进程可以创建该组中的进程
      • 进程组的组长进程也可以终止。只要进程组中至少有一个进程存在,则该进程中就存在,这与组长进程是否终止无关
    • 进程组的生命周期:从组长进程创建进程中开始,到组内最后一个进程离开为止的时间
      • 这里用离开,是因为进程可以从一个进程组转移到另一个进程组
  2. getpgrp/getpgid函数:获取进程所属的进程组:

    
    #include
    
    pid_t getpgrp(void);
    pid_t getpgid(pid_t pid);

    • 对于getpgrp函数:其返回值是调用进程的进程组ID(没有失败值)
    • 对于getpgid函数:
      • 参数:pid为待查看进程的进程ID。如果pid=0,则返回调用进程的进程组ID

    这里没有要求pid和本进程的关系

  3. 返回值:成功,则返回进程组ID;失败返回 -1

会话

  1. 会话session是一个或者多个进程组的集合。

  2. setsid函数:创建一个新会话

    
    #include
    
    pid_t setsid(void);
    • 返回值:
      • 成功:返回进程组ID
      • 失败:返回 -1

    进程调用setsid建立一个新会话。如果调用此函数的进程不是一个进程组的组长进程,则此函数创建一个新会话并且发生下面三件事:

    • 该进程会变成新会话的会话首进程session leader。此时该进程是新会话中的唯一进程

    会话首进程是创建该会话的进程

  3. 该进程成为一个新进程组的组长进程。新进程组ID就是该调用进程的进程ID
  4. 该进程没有控制终端。即使调用setsid之前该进程有一个控制终端,该联系也被切断

  5. 如果调用此函数的进程是个进程组的组长,则此函数返回出错。
    通常是进程首先 fork,然后父进程终止,子进程调用 setsid继续执行。这确保了子进程不是一个进程组的组长
  6. getsid函数:返回进程所在的会话ID(会话ID等于会话首进程的进程组ID,会话首进程总是进程组的组长进程,因此它也等于会话首进程的进程ID)

    
    #include
    
    pid_t getsid(pid_t pid);
    • 参数:
      • pid:待查看进程的进程ID
    • 返回值:
      • 成功:会话ID
      • 失败:返回 -1

    如果pid为0,则getsid返回调用进程的会话ID。如果pid并不属于调用者所在的会话,则调用进程就不能得到该会话ID

作业控制

  1. 会话和进程组还有一些特性:

    • 一个会话可以有一个控制终端controlling terminal
      • 这可以是终端设备(在终端登录的情况下)
      • 也可以是伪终端设备(在网络登录的情况下)
    • 建立与控制终端连接的会话首进程称作控制进程controlling process
    • 一个会话中的进程组可以分成一个前台进程组,以及一个或者多个后台进程组
    • 如果一个会话有一个控制终端,则它有一个前台进程组,其他进程组为后台进程组
    • 无论何时键入终端的中断键(通常是Ctrl+C),都会将中断信号发送至前台进程组的所有进程
    • 无论何时键入终端的退出键(通常是Ctrl+\),都会将退出信号发送至前台进程组的所有进程
  2. tcgetpgrp/tcsetpgrp函数:获取/设置当前进程所在会话的前台进程组ID

    
    #include
    
    pid_t tcgetpgrp(int fd);
    int tcsetpgrp(int fd,pid_t pgrpid);
    • 参数:

      • fd:进程在fd这个描述符上打开的终端
      • pgrpid:待设置的前台进程组ID
    • 返回值:

      • 对于tcgetpgrp:成功则返回前台进程组ID,失败返回 -1
      • 对于 tcsetpgrp:成功返回 0;失败返回 -1

    如果进程有一个控制终端,则该进程可以调用tcsetpgrp将前台进程组ID设置为pgrpid,其中:

    • pgrpid必须是同一个会话的一个进程组的ID
    • fd必须引用该会话的控制终端

    注意:大多数应用程序并不直接使用这两个函数,它们通常是由作业控制shell调用

  3. tcgetsid函数:获取会话首进程的进程组ID(也就是会话ID)

    
    #include
    
    pid_t tcgetsid(int fd);
    • 参数:
      • fd:进程在fd这个描述符上打开的终端
    • 返回值:
      • 成功则返回前台进程组ID
      • 失败返回 -1

    注意会话ID不一定等于前台进程组的组ID。对于一个会话,会话ID通常不变(前提是没有函数主动设置它);但是前台进程组进程由于作业调度会经常发生变化

你可能感兴趣的:(Linux/Uinx)