Linux系统中进程的状态


Linux系统中进程存在R、S、D、T、Z、X六种状态。

   D   Uninterruptible sleep (usually IO)

      R   Running or runnable (on run queue)

      S   Interruptible sleep (waiting for an event to complete)

      T   Stopped, either by a job control signal or because it is being traced.

      W   paging (not valid since the 2.6.xx kernel)

      X   dead (should never be seen)

      Z   Defunct ("zombie") process, terminated but not

           reaped by its parent.

其中,主要需要了解的是D(不可中断的睡眠状态)、S(可中断的睡眠状态)、R(运行状态)、Z(僵尸进程)。

进程的运行状态自然没有什么好多说的,进程在cpu的运行队列上,可以被cpu调度到。

DS两种状态有什么区别
TASK_INTERRUPTIBLE是可以被信号和wake_up()唤醒的,当信号到来时,进程会被设置为可运行。而TASK_UNINTERRUPTIBLE只能被wake_up()唤醒。 信号是在软件层次上对中断机制的一种模拟,软中断

信号事件的发生有两个来源:

硬件来源:(比如我们按下了键盘或者其它硬件故障)

软件来源:最常用发送信号的系统函数是kill, raise, alarmsetitimer以及sigqueue函数,软件来源还包括一些非法运算等操作。

可中断的睡眠状态和不可中断的睡眠状态。处于睡眠状态的进程不会被调度到CPU进行执行,而是否可中断的意思是指进程是否会响应异步信号,如果是可中断的,当进程收到某个信 号时其会重新回到TASK_RUNNING状态。值得注意的是,如果处于不可中断的睡眠状态时,进程将不响应异步信号,比如你无法“kill -9”



设置TASK_INTERRUPTIBLE状态的一个例子

/* 
 * Read a single request into the userspace filesystem's buffer.  This 
 * function waits until a request is available, then removes it from 
 * the pending list and copies request data to userspace buffer.  If 
 * no reply is needed (FORGET) or request has been aborted or there 
 * was an error during the copying then it's finished by calling 
 * request_end().  Otherwise add it to the processing list, and set 
 * the 'sent' flag. 
 */ 
static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, 
                  unsigned long nr_segs, loff_t pos) 

    int err; 
    struct fuse_req *req; 
    struct fuse_in *in; 
    struct fuse_copy_state cs; 
    unsigned reqsize; 
    struct file *file = iocb->ki_filp; 
    struct fuse_conn *fc = fuse_get_conn(file); 
    if (!fc) 
        return -EPERM; 
 
 restart: 
    spin_lock(&fc->lock); 
    err = -EAGAIN; 
    if ((file->f_flags & O_NONBLOCK) && fc->connected && 
        !request_pending(fc)) 
        goto err_unlock; 
 
    request_wait(fc); 



/* Wait until a request is available on the pending list */ 
static void request_wait(struct fuse_conn *fc) 
__releases(&fc->lock) 
__acquires(&fc->lock) 

    DECLARE_WAITQUEUE(wait, current); 
 
    add_wait_queue_exclusive(&fc->waitq, &wait); 
    while (fc->connected && !request_pending(fc)) { 
        set_current_state(TASK_INTERRUPTIBLE); 
        if (signal_pending(current)) 
            break
 
        spin_unlock(&fc->lock); 
        schedule(); 
        spin_lock(&fc->lock); 
    } 
    set_current_state(TASK_RUNNING); 
    remove_wait_queue(&fc->waitq, &wait); 



static void end_io_requests(struct fuse_conn *fc) 
__releases(&fc->lock) 
__acquires(&fc->lock) 

    while (!list_empty(&fc->io)) { 
        struct fuse_req *req = 
            list_entry(fc->io.next, struct fuse_req, list); 
        void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; 
 
        req->aborted = 1
        req->out.h.error = -ECONNABORTED; 
        req->state = FUSE_REQ_FINISHED; 
        list_del_init(&req->list); 
        wake_up(&req->waitq); 
        if (end) { 
            req->end = NULL; 
            __fuse_get_request(req); 
            spin_unlock(&fc->lock); 
            wait_event(req->waitq, !req->locked); 
            end(fc, req); 
            fuse_put_request(fc, req); 
            spin_lock(&fc->lock); 
        } 
    } 


从上面的例子,可以看到内核中关于设置进程为睡眠状态的一些应用场景,这个例子是fuse驱动中的一个处理过程。进程等待一个读请求有效,在等待过程中将进程设置为TASK_INTERRUPTIBLE状态,并调用schedule()调度运行其它进程。当IO完成的时候,IO操作的回调函数wake_up(&req->waitq);唤醒休眠的进程。该处使用TASK_INTERRUPTIBLE主要是防止如果IO操作长时间没有完成,进程长时间休眠而没有办法退出进程。设置成TASK_INTERRUPTIBLE,如果进程长时间等待IO未果,可以通过向进程发送信号,来结束进程休眠在等待IO完成上面。



之后我们再分析一处使用TASK_UNINTERRUPTIBLE的例子

get_registers函数用来获取usb device芯片中的某个寄存器的值,比如某些wifi芯片是usb接口的,在操作这种wifi芯片上的寄存器的时候必须通过usb来通信获取。对于pcie接口的芯片,我们可以认为这个过程就是读写内存一样(pcie空间被映射到了内存地址)。对于usb就不是如此了,这个过程包括usb device向设备发起一个读请求,usb device再回应这个请求,这个过程是需要消耗一定时间的。如下面的函数处理过程,先将发起读请求的进程设置为TASK_UNINTERRUPTIBLE状态,再调用usb_submit_urb发起读请求,最后调用schedule()调度执行其它进程。当这个读请求的IO完成的时候,IO请求的回调函数ctrl_callback中会执行wake_up将之前休眠的进程唤醒。

static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, 
             void *data) 

    int ret; 
    char *buffer; 
    DECLARE_WAITQUEUE(wait, current); 
 
    buffer = kmalloc(size, GFP_KERNEL); 
    if (!buffer) { 
        if (netif_msg_drv(pegasus)) 
            dev_warn(&pegasus->intf->dev, "out of memory in %s\n"
                    __func__); 
        return -ENOMEM; 
    } 
    add_wait_queue(&pegasus->ctrl_wait, &wait); 
    set_current_state(TASK_UNINTERRUPTIBLE); 
    while (pegasus->flags & ETH_REGS_CHANGED) 
        schedule(); 
    remove_wait_queue(&pegasus->ctrl_wait, &wait); 
    set_current_state(TASK_RUNNING); 
 
    pegasus->dr.bRequestType = PEGASUS_REQT_READ; 
    pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; 
    pegasus->dr.wValue = cpu_to_le16(0); 
    pegasus->dr.wIndex = cpu_to_le16(indx); 
    pegasus->dr.wLength = cpu_to_le16(size); 
    pegasus->ctrl_urb->transfer_buffer_length = size; 
 
    usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, 
                 usb_rcvctrlpipe(pegasus->usb, 0), 
                 (char *) &pegasus->dr, 
                 buffer, size, ctrl_callback, pegasus); 
 
    add_wait_queue(&pegasus->ctrl_wait, &wait); 
    set_current_state(TASK_UNINTERRUPTIBLE); 
 
    /* using ATOMIC, we'd never wake up if we slept */ 
    if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { 
        set_current_state(TASK_RUNNING); 
        if (ret == -ENODEV) 
            netif_device_detach(pegasus->net); 
        if (netif_msg_drv(pegasus) && printk_ratelimit()) 
            dev_err(&pegasus->intf->dev, "%s, status %d\n"
                    __func__, ret); 
        goto out; 
    } 
 
    schedule(); 
out: 
    remove_wait_queue(&pegasus->ctrl_wait, &wait); 
    memcpy(data, buffer, size); 
    kfree(buffer); 
 
    return ret; 


static void ctrl_callback(struct urb *urb) 

    pegasus_t *pegasus = urb->context; 
    int status = urb->status; 
 
    if (!pegasus) 
        return
 
    switch (status) { 
    case 0
        if (pegasus->flags & ETH_REGS_CHANGE) { 
            pegasus->flags &= ~ETH_REGS_CHANGE; 
            pegasus->flags |= ETH_REGS_CHANGED; 
            update_eth_regs_async(pegasus); 
            return
        } 
        break
    case -EINPROGRESS: 
        return
    case -ENOENT: 
        break
    default
        if (netif_msg_drv(pegasus) && printk_ratelimit()) 
            dev_dbg(&pegasus->intf->dev, "%s, status %d\n"
                __func__, status); 
    } 
    pegasus->flags &= ~ETH_REGS_CHANGED; 
    wake_up(&pegasus->ctrl_wait); 



01-04 03:54