Linux内核睡眠机制

JoyboyCZ
发布于 2023-3-29 17:26
浏览
0收藏

这里事先推荐给大家一个Linux源码的阅读网站,真的很方便!![preempt.h - tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.h - Linux source code (v6.2.8) - Bootlin]

​ 进程通过睡眠机制释放处理器,使其能够处理其它进程。处理器睡眠的原因可能在于感知数据的可用性,或等待资源释放。

​ 内核调度器管理要运行的任务列表,这被称作运行队列。睡眠进程不再被调度,因为已将它们从运行列表中移除。除非其状态改变(唤醒),负责睡眠进程将永远不会被执行。进程一旦进入等待状态,就可以释放处理器,一定要确保有条件或其它进程会唤醒它。Linux内核通过提供一组函数和数据结构来简化睡眠机制的实现。

等待队列

等待队列实际上用于处理被阻塞的I/O,以等待特定条件成立,并感知数据或资源可用性。为了理解其工作方式,来看一看它在include/linux/wait.h中的结构

struct __wait_queue {
	unsigned int flags;
#define WQ_FLAG_EXCLUSIVE 0x01
	void *private;
	wait_queue_func_t func;
	struct list_head task_list;
};

入睡的每一个进程都在list_head中排队并进入睡眠状态。

处理等待队列将会用到如下常用函数:

  • 静态声明:

    DECLARE_WAIT_QUEUE_HEAD(name)
    
  • 动态声明:

    struct wait_queue_head {
        spinlock_t		lock;		/* 采用了自旋锁,要考虑自旋时长,避免过度影响系统性能 */
        struct list_head head;
    };
    typedef struct wait_queue_head wait_queue_head_t;
    wait_queue_head_t my_wait_queue;
    init_waitqueue_head(&my_wait_queue);
    
  • 阻塞:

    #define wait_event_interruptible(wq_head, condition)				\
    ({										\
    	int __ret = 0;								\
    	might_sleep();								\
    	if (!(condition))							\
    		__ret = __wait_event_interruptible(wq_head, condition);		\
    	__ret;									\
    })
    int wait_event_interruptible(wait_queue_head_t q, CONDITION)	/* 如果CONDITION条件为false,则阻塞等待队列中的当前任务 */
    
  • 解除阻塞:

    void wake_up_interruptible(wait_queue_head_t *q);	/* 如果上述条件为true,则唤醒等待队列中休眠的进程 */
    

    如果想唤醒队列中等待的所有进程,应该使用wake_up_interruptible_all.

    #define wake_up_interruptible_all(x)	__wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
    

收藏
回复
举报
回复
    相关推荐