Linux中的进程(1)

进程运行状态

  • TASK_RUNNING,当前运行进程以及运行队列中的进程都处于该状态中。进程调度时,调度程序只在处于该状态的进程中选择最优进程来运行。
  • TASK_INTERRUPTIBLE,在等待队列中,可被信号中断的等待状态。收到信号后,进程可能停止或者重新插入到运行队列中。
  • TASK_UNINTERRUPTIBLE,直接等待硬件状态,不可被中断。
  • TASK_ZOMBIE,僵死状态。进程已经消亡,但其PCB仍存在task数组中。在进程退出时,将状态设为TASK_ZOMBIE,然后发送信号给父进程,由父进程在统计其中的一些数据后,释放它的task_struct结构。
  • TASK_STOPPED,进程因接收到信号(如:SIGSTOP、SIGSTP、SIGTTIN、SIGTTOU)
    而停止或由于其他进程使用ptrace系统调用来跟踪而将控制权交回控制进程。
  • TASK_SWAPPING,进程被交换到了交换区(2.0版中未实现)。

TASK_UNINTERRUPTIBLE什么时候能醒来?

    for (;;) {

        set_current_state(TASK_UNINTERRUPTIBLE);
        if (do_i_need_to_sleep())
            schedule(); //跑到这里之后,这个task是否会永久睡眠?
    }

其实设定成TASK_INTERRUPTIBLE的可以由以下几种方法唤醒。

  • 一种是通过wake_up_process()直接唤醒TASK_INTERRUPTIBLE的task,这个例子之一就是semaphore的down()和up()。
    [http://blog.csdn.net/hongzg1982/article/details/47401103]

  • 一种是通过wait queue方法唤醒TASK_INTERRUPTIBLE的task。在代码中搜TASK_INTERRUPTIBLE,有很多例子。
    [http://www.cnblogs.com/parrynee/archive/2010/01/14/1648165.html]
    这里讲以下wait queue唤醒TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的通常的方法

        DECLARE_WAIT_QUEUE_HEAD(test_wait);

        void test_thread_func(){
            for(;;){
                DECLARE_WAITQUEUE(wait, current);
                __set_current_state(TASK_UNINTERRUPTIBLE);//或者用TASK_INTERRUPTIBLE
                add_wait_queue(&pkmap_map_wait, &wait);
                ...
                schedule();
                ...
                remove_wait_queue(&pkmap_map_wait, &wait);
            }
        }
        void test_irq_fun(){
            ...
            if(condition)
                wake_up(tas_wait);//或者wake_up_interruptible(tas_wait)
            ...
        }

        //wake_up或者wake_up_interruptible是怎么唤醒wait queue上面的进程的?
        void __wake_up(wait_queue_head_t *q, unsigned int mode,
            int nr_exclusive, void *key)
        {
            unsigned long flags;

            spin_lock_irqsave(&q->lock, flags);
            __wake_up_common(q, mode, nr_exclusive, 0, key);
            spin_unlock_irqrestore(&q->lock, flags);
        }

        static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
            int nr_exclusive, int wake_flags, void *key)
        {
            wait_queue_t *curr, *next;

            list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
                unsigned flags = curr->flags;

                if (curr->func(curr, mode, wake_flags, key) &&
                    (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
                break;
            }
        }
        //最后调用的curr->func其实是DECLARE_WAITQUEUE()这个宏里边赋值上去的default_wake_function()函数
        #define __WAITQUEUE_INITIALIZER(name, tsk) { \
            .private    = tsk,                      \
            .func       = default_wake_function,            \
            .task_list  = { NULL, NULL } }

        int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
              void *key)
        {
            return try_to_wake_up(curr->private, mode, wake_flags);
        }

接口说明

//下面的函数可以实现,进入睡眠,然后在timout时间到期之后醒来
//在调用这个函数之前,必须通过set_current_state()来设置当前task状态,
//你可以设置TASK_UNINTERRUPTIBLE,也可以设置TASK_INTERRUPTIBLE
//设置为TASK_UNINTERRUPTIBLE可以保证当前进程至少睡眠timeout的时间,且返回值是0
//设置为TASK_INTERRUPTIBLE,可能会提前醒来,因为TASK_INTERRUPTIBLE会被signal唤醒。这种情况下会返回剩余的jiffies时间。如果timout时间到期也没有提前醒来,当然也是返回0。

signed long __sched schedule_timeout(signed long timeout)
{
    struct timer_list timer;
    unsigned long expire;

    switch (timeout)
    {
    case MAX_SCHEDULE_TIMEOUT:
        /*
         * These two special cases are useful to be comfortable
         * in the caller. Nothing more. We could take
         * MAX_SCHEDULE_TIMEOUT from one of the negative value
         * but I' d like to return a valid offset (>=0) to allow
         * the caller to do everything it want with the retval.
         */
        schedule();
        goto out;
    default:
        /*
         * Another bit of PARANOID. Note that the retval will be
         * 0 since no piece of kernel is supposed to do a check
         * for a negative retval of schedule_timeout() (since it
         * should never happens anyway). You just have the printk()
         * that will tell you if something is gone wrong and where.
         */
        if (timeout < 0) {
            printk(KERN_ERR "schedule_timeout: wrong timeout "
                "value %lx\n", timeout);
            dump_stack();
            current->state = TASK_RUNNING;
            goto out;
        }
    }

    expire = timeout + jiffies;

    setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
    __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);
    schedule();
    del_singleshot_timer_sync(&timer);

    /* Remove the timer from the object tracker */
    destroy_timer_on_stack(&timer);
    timeout = expire - jiffies;

 out:
    return timeout < 0 ? 0 : timeout;
}
//例子:msleep()函数就是使用schedule_timeout()函数来实现时间延迟的
void msleep(unsigned int msecs)
{
    unsigned long timeout = msecs_to_jiffies(msecs) + 1;

    while (timeout)
        timeout = schedule_timeout_uninterruptible(timeout);
}

signed long __sched schedule_timeout_uninterruptible(signed long timeout)
{
    __set_current_state(TASK_UNINTERRUPTIBLE);
    return schedule_timeout(timeout);
}

你可能感兴趣的:(linux,task)