linux内核任务调度-- wait_event

linux内核中经常需要进行进程的调度

struct wait_queue_head {
    spinlock_t        lock;
    struct list_head    head;
};

struct wait_queue_head *wq_head,

#define wait_event(wq_head, condition)                        \
do {                                        \
    might_sleep();                                \
    if (condition)                                \
        break;                                \
    __wait_event(wq_head, condition);                    \
} while (0)

定义了一个 wait结构,设置进程睡眠。如果有其他进程唤醒这个进程后,判断条件是否满足,

如果满足,从睡眠链表中删除wait对象退出睡眠,否则进程继续睡眠。

系列函数:

wait_event(wq_head, condition);  睡眠不可中断,不可接收信号处理;如ctrl +c等

wait_event_timeout(wq_head, condition, timeout) ; 条件满足 或者时间到达,进程回复

wait_event_interruptible(wq_head, condition)  可以接收信号打断睡眠,

wait_event_interruptible_timeout(wq_head, condition, timeout)  可以打断并且时间到了,进程回复

TASK_RUNNING: 正在运行或处于就绪状态:就绪状态是指进程申请到了CPU以外的其他所有资源,提醒:一般的操作系统教科书将正在CPU上执 行的进程定义为RUNNING状态、而将可执行但是尚未被调度执行的进程定义为READY状态,这两种状态在Linux下统一为 TASK_RUNNING状态.
TASK_INTERRUPTIBLE: 处于等待队伍中,等待资源有效时唤醒(比如等待键盘输入、socket连接、信号等等),但可以被中断唤醒.一般情况下,进程列表中的绝大多数进程都处于 TASK_INTERRUPTIBLE状态.毕竟皇帝只有一个(单个CPU时),后宫佳丽几千;如果不是绝大多数进程都在睡眠,CPU又怎么响应得过来.
TASK_UNINTERRUPTIBLE:处于等待队伍中,等待资源有效时唤醒(比如等待键盘输入、socket连接、信号等等),但不可以被中断唤醒.
TASK_ZOMBIE:僵死状态,进程资源用户空间被释放,但内核中的进程PCB并没有释放,等待父进程回收.
TASK_STOPPED:进程被外部程序暂停(如收到SIGSTOP信号,进程会进入到TASK_STOPPED状态),当再次允许时继续执行(进程收到SIGCONT信号,进入TASK_RUNNING状态),因此处于这一状态的进程可以被唤醒.

分析代码:

 条件满足后调用 __wait_event();

#define wait_event(wq_head, condition)						\
do {										\
	might_sleep();								\
	if (condition)								\
		break;								\
	__wait_event(wq_head, condition);					\
} while (0)

TASK_UNINTERRUPTIBLE 表示进程运行状态
#define __wait_event(wq_head, condition)					\
	(void)___wait_event(wq_head, condition, TASK_UNINTERRUPTIBLE, 0, 0,	\
			    schedule())

目的:创建一个等待条目 struct wait_queue_entry __wq_entry;   

初始化:  init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0);  获取当前进程id

调用: prepare_to_wait_event

#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd)		\
({										\
	__label__ __out;							\
	struct wait_queue_entry __wq_entry;		 //创建一个等待条目
	long __ret = ret;	/* explicit shadow */				\
	//初始化 创建的条目, 获取当前进程的pid
	init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0);	\
	for (;;) {								\
		long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\
										\
		if (condition)							\
			break;							\
										\
		if (___wait_is_interruptible(state) && __int) {			\
			__ret = __int;						\
			goto __out;						\
		}								\
										\
		cmd;								\
	}									\
	finish_wait(&wq_head, &__wq_entry);					\
__out:	__ret;									\
})

void init_wait_entry(struct wait_queue_entry *wq_entry, int flags)
{
	wq_entry->flags = flags;
	wq_entry->private = current;               //保存了当前进程的pid
	wq_entry->func = autoremove_wake_function; //系统默认的 处理函数
	INIT_LIST_HEAD(&wq_entry->entry);
}

prepare_to_wait_event 实现:

将 新创建的等待队列条目放入等待队列链表中 :

WQ_FLAG_EXCLUSIVE : 区分插入睡眠链表中的方式,队列或者栈;

设置当前进程运行状态 就是current->state

long prepare_to_wait_event(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry, int state)
{
	unsigned long flags;
	long ret = 0;

	spin_lock_irqsave(&wq_head->lock, flags);
	if (unlikely(signal_pending_state(state, current))) {
		list_del_init(&wq_entry->entry);
		ret = -ERESTARTSYS;
	} else {
		if (list_empty(&wq_entry->entry)) {
			if (wq_entry->flags & WQ_FLAG_EXCLUSIVE)
				__add_wait_queue_entry_tail(wq_head, wq_entry);
			else
				__add_wait_queue(wq_head, wq_entry);
		}
		set_current_state(state);
	}
	spin_unlock_irqrestore(&wq_head->lock, flags);

	return ret;
}

#define __wait_event_interruptible_exclusive(wq, condition)            \
    ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 1, 0,            \
              schedule())

WQ_FLAG_EXCLUSIVE 值就来自于上面标红的1传入的.区别排他性的等待;

测试举例:

创建一个进程,调度一下新创建的进程, 老进程睡眠, 新创建的进程中唤醒;

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/wait.h>
int flag = 0;

static struct task_struct *test_task, *poldtask; 
wait_queue_head_t test_que;
//static DECLARE_WAIT_QUEUE_HEAD(test_que);
int test_thread(void * testPtr)
{
	printk("cj the old task state :%ld \n", poldtask->state);
	printk("cj the thread current pid : %d\n", current->pid);
	flag = 1;
	wake_up_interruptible(&test_que);
	return 0;
}

static int test_wait_init(void )
{
	struct wait_queue_entry data;
	int i = 0;
	//创建线程
	test_task = kthread_create(test_thread, NULL, "test_task");
	printk("the pid of test_task is %d \n", test_task->pid);
	printk("current pid is %d \n", current->pid);	

	init_waitqueue_head(&test_que);
	init_waitqueue_entry(&data, current);
	add_wait_queue(&test_que, &data);
	poldtask = current;
	wake_up_process(test_task); //唤醒新创建的进程
	schedule_timeout_interruptible(10*10);  //调度一下
	wait_event_interruptible(test_que, flag);  //默认flag == 0 会进入睡眠
	for(; i<10; i++)
		printk("test_wait_init end  %d \n", i );
	return 0 ;
}

static void test_wait_exit(void)
{
}


module_init(test_wait_init);
module_exit(test_wait_exit);
MODULE_LICENSE("GPL");












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值