Linux进程状态详解

以下部分的代码示例,来自于Linux内核的0.11版本源码

在定义进程的数据结构task_struct时,有一个state字段是用来表示进程状态的,这里总结了下关于state字段的操作

关于进程的几个状态值在sched.h中定义如下
#define  TASK_RUNNING                 0
#define  TASK_INTERRUPTIBLE     1
#define  TASK_UNINTERRUPTIBLE               2
#define  TASK_ZOMBIE                    3
#define  TASK_STOPPED                  4
在Linus对state的注释中,是这样写的,state<0为不可运行状态(可能是初始化时的值,后面将讨论)、state=0为运行状态(就绪也属于此状态)、state>0为进程停止运行状态(不论是进程正处于睡眠或是已经退出终止了)

下面讨论对state的字段修改是在哪些地方

[进程初始化时的state字段修改]
首先当一个进程被创建的时候,它的状态是 TASK_UNINTERRUPTIBLE;因为这时它的数据都是从父进程赋值而来的,还没有设置成自己进程的数据。
           *p = *current;         /* NOTE! this doesn't copy the supervisor stack */
                p->state = TASK_UNINTERRUPTIBLE;
当进程数据设置完成后,进程变为可运行状态
p->state = TASK_RUNNING;             /* do this last, just in case */
以上者两部分代码都是来自fork.c的copy_process函数。在最后设置好了新建进程的state字段后,copy_process函数返回。

[进程退出时的状态设置]
当进程退出的时候,state字段被设置为 TASK_ZOMBIE,在exit.c的do_exit函数中,对当前退出的进程,将其状态设置成 TASK_ZOMBIE.
                current->state = TASK_ZOMBIE;
                current->exit_code = code;
                tell_father(current->father);
                schedule();
                  return  (-1);

[父进程等待子进程结束时的状态设置]
调用waitpid(exit.c文件中)时,挂起调用的进程,直到指定pid的子进程退出或终止或者收到要求终止该进程的信号。。。
在waitpid函数的最后,有一条语句如下
if  (flag) {
                                  if  (options & WNOHANG)
                                                  return  0;
                                current->state=TASK_INTERRUPTIBLE;
                                schedule();
这里的flag=1表示指定等待的pid的进程既没有终止也不处于僵死状态。所以,这里将当前等待的进程设置成可中断的睡眠状态。并且重新进行进程调度

[进程调度修改进程的状态]
在sched.c的schedule函数中
if  (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
                                                (*p)->state==TASK_INTERRUPTIBLE)
                                                                (*p)->state=TASK_RUNNING;
当进程等待的事件发生时,将进程的状态设置成可运行的状态

[通过系统调用将进程暂停]
但通过系统调用将进程暂停时,进程的状态被设置成可中断的睡眠状态,然后重新进行进程调度。具体代码如下(sched.c的sys_pause函数)
int  sys_pause( void  )
{
                current->state = TASK_INTERRUPTIBLE;
                schedule();
                  return  0;
}

[进程进入不可中断睡眠状态]
当进程进入睡眠时,将进程设置为不可中断的睡眠状态。直到明确地唤醒才会返回。代码如下(sched.c的sleep_on函数)。这里的参数*p是放置等待任务的队列头指针,针对某一资源的等待队列
void  sleep_on( struct  task_struct **p)
{
                  struct  task_struct *tmp;

                  if  (!p)
                                  return  ;
                  if  (current == &(init_task.task))
                                panic(  "task[0] trying to sleep"  ); //进程0不能陷入睡眠
                tmp = *p;
                *p = current;
                current->state = TASK_UNINTERRUPTIBLE; //将进程状态设为不可中断状态
                schedule();  //重新进程调度
             //只有当这个等待的任务被唤醒时,调度程序才会返回到这里,因此这里再次将进程的状态设为0,也就是可运行状态 。既然是都在等待这个资     
          // 源  ,那么在资源可用时,就有必要将所有等待该资源的进程唤醒。这个函数嵌套调用,将等待该资源的所有进程唤醒
           if  (tmp)  
                        tmp->state=0;  
}

[进程进入可中断的睡眠状态]
将当前进程设置为可中断的等待状态,并放入由*p指定的等待队列中。代码如下
void  interruptible_sleep_on( struct  task_struct **p)
{
                  struct  task_struct *tmp;

                  if  (!p)
                                  return  ;
                  if  (current == &(init_task.task))
                                panic(  "task[0] trying to sleep"  );   //进程0不能进入睡眠
                tmp=*p;
                *p=current;   //将进程放入等待队列中
repeat:    current->state = TASK_INTERRUPTIBLE;   //设置进程状态
                schedule();   //重新对进程做调度
           //个人对这剩下的部分不是特别理解
                  if  (*p && *p != current) {  //调度程序回到这里说明这个进程被唤醒。但如果这里等待队列中还有进程且p指向的不是当前进程,那么说               
                                                  // 明当前进程放入等待队列后,又有其它进程被放入等待队列中。将这些进程都设为可运行
                                (**p).state=0;
                                  goto  repeat;
                }
                *p=NULL;    
                  if  (tmp)
                                tmp->state=0;
}

[进程的唤醒]
将等待队列中的进程唤醒,设置进程的状态为可运行的。代码如下(sched.c的wake_up函数)
void  wake_up( struct  task_struct **p)
{
                  if  (p && *p) {
                                (**p).state=0;
                                *p=NULL;
                }
}

你可能感兴趣的:(Linux进程状态详解)