Linux进程(六):睡眠与进程0、进程1
- 深度睡眠/浅睡眠
- 进程0和进程1
深度睡眠/浅睡眠
在Linux系统中,进程有两种睡眠状态:深度睡眠和浅度睡眠。其中:深度睡眠只能被资源所唤醒,浅度睡眠可以被资源和
signal
所唤醒。
深度睡眠有时不可避免,例如发生
page fault
时:在执行某个程序时,若某些代码段还没有进内存,在我们调用到某个函数时,可能会发生缺页中断。此时Linux内核将把这个进程置为深度睡眠。
若上述情况不使用深度睡眠,也就是说若在发生
page fault
后该进程可被
signal
唤醒,那我们可以设想这样一种情况:在进程发生缺页中断后进入睡眠状态,此时该进程收到某个信号A,于是该进程需要执行信号A的信号处理函数,若该信号处理函数此时也不在内存内,则又将发生缺页中断并进入睡眠态,若此时该进程又收到信号A,那就进程将一直在
唤醒->缺页->睡眠
这个循环中反复。因此在Linux内核中,深度睡眠不可避免。
以下是一段模拟进程在等待资源时进入深度睡眠的代码:
static ssize_t globalfifo_read(struct file *filp, char __user *buf,size_t count, loff_t *ppos){int ret;struct globalfifo_dev *dev = container_of(filp->private_data,struct globalfifo_dev, miscdev);DECLARE_WAITQUEUE(wait, current);mutex_lock(&dev->mutex);add_wait_queue(&dev->r_wait, &wait);while (dev->current_len == 0) {//进入次循环表示暂时没有可读资源,需要等待//若设置了非阻塞,则跳出循环if (filp->f_flags & O_NONBLOCK) {ret = -EAGAIN;goto out;}//将进程的状态置为TASK_INTERUPTIBLE//若设置为TASK_UNINTERRUPTIBLE,状态将变为深度睡眠__set_current_state(TASK_INTERRUPTIBLE);mutex_unlock(&dev->mutex);//放弃cpuschedule();//若是被信号唤醒,直接goto跳出循环if (signal_pending(current)) {ret = -ERESTARTSYS;goto out2;}//若不是被信号唤醒,则执行任务mutex_lock(&dev->mutex);}if (count > dev->current_len)count = dev->current_len;if (copy_to_user(buf, dev->mem, count)) {ret = -EFAULT;goto out;} else {memcpy(dev->mem, dev->mem + count, dev->current_len - count);dev->current_len -= count;printk(KERN_INFO \"read %d bytes(s),current_len:%d\\n\", count,dev->current_len);wake_up_interruptible(&dev->w_wait);ret = count;}out:mutex_unlock(&dev->mutex);out2:remove_wait_queue(&dev->r_wait, &wait);set_current_state(TASK_RUNNING);return ret;}
进程0和进程1
在Linux,每一个
task_struct
都是被父进程创建出来的。那么此处就存在一个问题:Linux系统中的进程数的根
init
进程是如何被创建出来的呢?
init
进程也可以被称为Linux中的进程1,它是由Linux中的进程0所创建的。我们可以在
/proc
中查看Linux中进程1的父进程:
可以看到进程1的
PPid
字段显示的是
0
。这说明进程1的父进程实际上是Linux系统中的进程0。而进程0是在Linux系统开机启动的过程中所创建的进程。
但是我们在
pstree
中看不到Linux的进程0(注意,
init
进程为进程1),因为进程0在创建进程1之后就退化成了Linux系统中的
IDLE
进程。
IDLE
进程是Linux系统中的一个特殊调度类:当所有的进程都睡眠或停止时,CPU才会调用
IDLE
进程,同时CPU将被切换为低功耗模式。所以当进程0被调度时,CPU将会被置为Wait For Interrupter或者更深的睡眠状态。在Wait For Interrupter状态中时,CPU只有在接收到一个中断才会被唤醒,否则运行功耗十分低,并且一旦产生一个中断,就可能会唤醒另一个进程。
这种设计的好处之一在于有效避免了在进程睡眠或等待时的判断,使得每个进程在进入睡眠状态之前不需要考虑自己是否是最后一个可调度的进程而把CPU置为WFI状态。