Chinaunix首页 | 论坛 | 博客
  • 博客访问: 415726
  • 博文数量: 61
  • 博客积分: 1991
  • 博客等级: 上尉
  • 技术积分: 492
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-08 12:28
文章分类

全部博文(61)

文章存档

2011年(5)

2010年(21)

2009年(3)

2008年(4)

2007年(28)

我的朋友

分类: BSD

2007-05-10 16:18:34

FreeBSD支持多任务处理环境。每个运行的任务或者线程被称作进程(process)。FreeBSD进程的上下文由用户级状态(包括地址空间和运行时环境)和内核级状态(包括调度参数、资源控制和标识信息)组成。上下文包含内核为该进程提供服务时用到的每个资源和信息。用户可以创建进程、控制进程的执行、在进程状态发生改变是得到通知。每个进程都与一个唯一的值相联系,这个值叫做进程ID(PID)。当内核向用户报告状态变化时用这个值来识别进程。用户调用的系统调用需要识别进程,也要用到这个值。

内核通过复制另外一个进程的上下文来创建新的进程。这个新的进程被称作原(父)进程的子进程。创建进程时被复制的上下文包含用户级的执行状态和被内核管理的该进程的系统状态。

图2.1描述了进程的生命周期。使用系统调用fork,一个进程可以通过拷贝自己的方式创建新的进程。fork会返回两次。一次是在父进程中返回子进程的PID,另一次是在子进程中返回0。父进程与子进程的关联在系统中形成分层的结构。新进程共享父进程的资源,比如文件描述符、信号句柄状态和内存结构。

Figure 2.1. Process-management system calls

 

尽管可以通过拷贝父进程的方式来创建新的进程,但载入和运行一个不同的程序是更有用和更普遍的做法。一个进程可以用另外一个程序的内存映像来覆盖自己,可以使用系统调用execve来给这个新创建的映像传递参数。其中一个参数是文件名。这个文件的内容是一个可以被系统识别的格式。它可以是一个可执行文件。也可以一个被解释执行的文件,它可以指定一个解释程序来解释并执行它。

执行系统调用exit可以终止一个进程。exit传递一个8位的exit状态给进程的父进程。如果一个进程想与他的父进程传递多于1字节的信息,它必须使用管道或socket建立一个IPC通道,或者使用中介文件。

一个进程可以使用系统调用wait把自己挂起,直到它的某个子进程运行结束。wait会返回子进程的PID和exit状态。当一个父进程的子进程非正常退出,它可以使自己接收到一个通知信号。使用系统调用wait4,一个父进程可以得到导致子进程退出原因的事件和子进程运行是销毁的资源情况。如果一个进程是孤儿进程(因为它执行完成之前它的父进程就退出了),当它退出时,内核可以安排把它的exit状态返回给一个特殊的系统进程。

系统根据 process-priority 参数来调度进程的运行。在默认的分时调度系统下,这个优先级被基于内核的调度运算发展管理。用户进程可以使用一个指定的参数来影响进程调度,这个参数控制它的所有调度优先级。用户进程要根据内核的调度策略共享它在CPU下的资源。FreeBSD也有一个实时的调度器。进程运行在实时调度器下管理自己的优先级,内核不能改变这些优先级。内核运行一个高于所有其他进程的最高优先级的实时进程。因此,实时进程不用共享CPU下的资源。

信号

系统定义了一组可以传递给进程的信号。FreeBSD的信号模拟硬件中断。一个进程可以指定一个用户级的子程序作为信号处理器(handler)。一个信号产生时,当它被handler捕获时,它就被阻止在更深层触发。捕获信号的工作包括保持当前进程的上下文,然后为运行handler而产生新的上下文。当信号到达handler时,即可以终止当前进程,也可以返回到当前进程(通常是在设置一个全局变量后)。如果handler返回,而信号没有被阻塞,它还能继续产生和被捕获。

进程可以选择将一个信号忽略还是有内核默认处理。某些信号的默认动作是终止进程。这个终止动作可能会同时产生一个包含当前进程内存映像的核心文件,这个文件用户事后的诊断。

有些信号不能被捕获也不能忽略。这些信号包括用来终止失控的进程的SIGKILL和用于工作控制的SIGSTOP。

进程可以选择在专用堆栈上分发信号。这样就使精细的软件堆栈操作成为可能。例如,一个支持协同工作的语言需要为每个协同工作的程序提供一个堆栈。这个语言可以在运行时分割FreeBSD提供的单独的堆栈来分配这个堆栈空间。如果内核不支持单独的信号堆栈,这个为每个协同程序分配的空间就要被扩大到空间的总需求大小来捕获信号。

所有的信号都有相同的优先级。如果有多个信号同时未被处理,这些信号分发到进程的顺序是明确的。信号处理器处理一个信号会导致它被阻塞。但是其他的信号仍会发生。内核提供机制,对于指定信号的发生,进程可以保护代码临界区。

进程组和会话

进程是被组织到进程组里的。进程组可用来控制终端访问,以及为给相关联进程集合发送信号提供方法。一个进程继承它的父进程的进程组。内核提供机制允许进程改变它和它的子孙进程的进程组。创建一个新的进程组是很容易的。新进程组的值就是创建进程的进程标识符。

进程组有时被称为job,被象shell这样的高级别系统软件操作。一类被shell创建的job是pipeline,它是用管道(pipe)把几个进程连接在一起。第一个进程的输出作为第二个进程的输入,第二个进程的输出作为第三个进程的输入,以此类推。shell为pileline上的每个结点创建一个进程,把这些进程放到一个进程组中。

一个用户进程能够发送信号给一个进程组中的每个进程,就想发送给一个单进程一样。一个在指定进程组中的进程可以接收软中断来影响这个组,可以使这个组挂起、恢复运行,也可以使这个组中断或终止运行。

一个终端(或者更普遍的是一个模拟终端的伪终端)有一个分配给它的进程组标识符。这个标识符通常分给一个与这个终端相关联的进程组。一个工作控制shell可以创建几个进程组与同一个终端相关联,这个终端是这些进程组中每个进程的控制终端。如果一个进程的控制终端的进程组标识符与这个进程匹配,这个进程可以对控制终端的描述符进行读取操作。否则,如果不匹配,当它尝试从控制终端读取时将被阻塞。通过改变终端的进程组标识符,shell可以在终端的几个不同的job之间进行仲裁。这个仲裁被称作工作控制(job control)。

正像一组相关联的进程可以归集到一个进程组一样,一组进程组也可以归集到一个会话(session)中。Session的主要作用是为服务进程及它的子进程创建一个单独的环境,以及把一个用户的登录shell和这个shell产生的job归集在一起。

阅读(1582) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~