/*************************************************************/
引入的数据结构: wait_queue_head and wait_queue
/*************************************************************/
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
struct __wait_queue {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
/*************************************************************/
wait_queue:解决的是个什么样的问题?
当前进程要等待一个事件的发生:如某个条件成立
把当前进程设置为: interruptible 或者uninterruptible
并通过wait_queue把当前进程 加入到和这个时间相关的wait_queue_head的链表中;
当事件发生时,或者说条件成立时:通过 wait_queue_head找到睡眠在该事件上的进程
并唤醒它;
/*************************************************************/
init_waitqueue_head(&epfile->wait);
wait_event_interruptible(epfile->wait, (ep = epfile->ep));
wake_up(&epfile->wait);
static inline int waitqueue_active(wait_queue_head_t *q)
{
return !list_empty(&q->task_list);
}
/*************************************************************/
以f_fs.c 中一个具体的wait_queue为例:看下使用的接口
操作函数的参数都是: wait_queue_head_t,而不是wait_queue
F_fs.c (drivers\usb\gadget\function):ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
F_fs.c (drivers\usb\gadget\function):init_waitqueue_head(&epfile->wait);
F_fs.c (drivers\usb\gadget\function):waitqueue_active(&epfile->wait));
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
#define init_waitqueue_head(q) \
do { \
static struct lock_class_key __key; \
\
__init_waitqueue_head((q), #q, &__key); \
} while (0)
void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
spin_lock_init(&q->lock);
lockdep_set_class_and_name(&q->lock, key, name);
INIT_LIST_HEAD(&q->task_list);
}
struct ffs_epfile {
wait_queue_head_t wait;
}
/*************************************************************/
怎样使当前进程睡眠的?
/*************************************************************/
/
wait_event_interruptible(epfile->wait, (ep = epfile->ep));
/**
* wait_event_interruptible - sleep until a condition gets true
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __wait_event_interruptible(wq, condition); \
__ret; \
})
#define __wait_event_interruptible(wq, condition) \
___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \
schedule())
#define ___wait_event(wq, condition, state, exclusive, ret, cmd) \
({ \
__label__ __out; \
wait_queue_t __wait;[这才引入了wait_queue_t,用户看到的只是 wait_queue_head]\
long __ret = ret; /* explicit shadow */ \
\
INIT_LIST_HEAD(&__wait.task_list); \
if (exclusive) \
__wait.flags = WQ_FLAG_EXCLUSIVE; \
else \
__wait.flags = 0; \
\
for (;;) { \
long __int = prepare_to_wait_event(&wq, &__wait, state);\
\
if (condition) \
break; \
cmd; \
} \
finish_wait(&wq, &__wait); \
__out: __ret; \
})
long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
unsigned long flags;
if (signal_pending_state(state, current))
return -ERESTARTSYS;
wait->private = current;
wait->func = autoremove_wake_function;
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list)) {//[说的是wait_queue的task_list是empty而不是说的 wait_queue_head]
if (wait->flags & WQ_FLAG_EXCLUSIVE)
__add_wait_queue_tail(q, wait);
else
__add_wait_queue(q, wait);
}
set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
return 0;
}
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
怎样唤醒睡眠进程?
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
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;
}
}
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
int ret = default_wake_function(wait, mode, sync, key);
if (ret)
list_del_init(&wait->task_list);
return ret;
}
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);
}
try_to_wake_up->ttwu_do_activate->ttwu_do_wakeup:p->state = TASK_RUNNING;
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
raw_spin_lock(&rq->lock);
ttwu_do_activate(rq, p, 0);
raw_spin_unlock(&rq->lock);
}
static void
ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
{
check_preempt_curr(rq, p, wake_flags);
trace_sched_wakeup(p, true);
p->state = TASK_RUNNING;
引入的数据结构: wait_queue_head and wait_queue
/*************************************************************/
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
struct __wait_queue {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
/*************************************************************/
wait_queue:解决的是个什么样的问题?
当前进程要等待一个事件的发生:如某个条件成立
把当前进程设置为: interruptible 或者uninterruptible
并通过wait_queue把当前进程 加入到和这个时间相关的wait_queue_head的链表中;
当事件发生时,或者说条件成立时:通过 wait_queue_head找到睡眠在该事件上的进程
并唤醒它;
/*************************************************************/
init_waitqueue_head(&epfile->wait);
wait_event_interruptible(epfile->wait, (ep = epfile->ep));
wake_up(&epfile->wait);
static inline int waitqueue_active(wait_queue_head_t *q)
{
return !list_empty(&q->task_list);
}
/*************************************************************/
以f_fs.c 中一个具体的wait_queue为例:看下使用的接口
操作函数的参数都是: wait_queue_head_t,而不是wait_queue
F_fs.c (drivers\usb\gadget\function):ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
F_fs.c (drivers\usb\gadget\function):init_waitqueue_head(&epfile->wait);
F_fs.c (drivers\usb\gadget\function):waitqueue_active(&epfile->wait));
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
#define init_waitqueue_head(q) \
do { \
static struct lock_class_key __key; \
\
__init_waitqueue_head((q), #q, &__key); \
} while (0)
void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
spin_lock_init(&q->lock);
lockdep_set_class_and_name(&q->lock, key, name);
INIT_LIST_HEAD(&q->task_list);
}
struct ffs_epfile {
wait_queue_head_t wait;
}
/*************************************************************/
怎样使当前进程睡眠的?
/*************************************************************/
/
wait_event_interruptible(epfile->wait, (ep = epfile->ep));
/**
* wait_event_interruptible - sleep until a condition gets true
* @wq: the waitqueue to wait on
* @condition: a C expression for the event to wait for
*
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
* @condition evaluates to true or a signal is received.
* The @condition is checked each time the waitqueue @wq is woken up.
*
* wake_up() has to be called after changing any variable that could
* change the result of the wait condition.
*
* The function will return -ERESTARTSYS if it was interrupted by a
* signal and 0 if @condition evaluated to true.
*/
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __wait_event_interruptible(wq, condition); \
__ret; \
})
#define __wait_event_interruptible(wq, condition) \
___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \
schedule())
#define ___wait_event(wq, condition, state, exclusive, ret, cmd) \
({ \
__label__ __out; \
wait_queue_t __wait;[这才引入了wait_queue_t,用户看到的只是 wait_queue_head]\
long __ret = ret; /* explicit shadow */ \
\
INIT_LIST_HEAD(&__wait.task_list); \
if (exclusive) \
__wait.flags = WQ_FLAG_EXCLUSIVE; \
else \
__wait.flags = 0; \
\
for (;;) { \
long __int = prepare_to_wait_event(&wq, &__wait, state);\
\
if (condition) \
break; \
cmd; \
} \
finish_wait(&wq, &__wait); \
__out: __ret; \
})
long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
{
unsigned long flags;
if (signal_pending_state(state, current))
return -ERESTARTSYS;
wait->private = current;
wait->func = autoremove_wake_function;
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list)) {//[说的是wait_queue的task_list是empty而不是说的 wait_queue_head]
if (wait->flags & WQ_FLAG_EXCLUSIVE)
__add_wait_queue_tail(q, wait);
else
__add_wait_queue(q, wait);
}
set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
return 0;
}
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
怎样唤醒睡眠进程?
F_fs.c (drivers\usb\gadget\function):wake_up(&epfile->wait);
/*************************************************************/
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
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;
}
}
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
int ret = default_wake_function(wait, mode, sync, key);
if (ret)
list_del_init(&wait->task_list);
return ret;
}
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);
}
try_to_wake_up->ttwu_do_activate->ttwu_do_wakeup:p->state = TASK_RUNNING;
static void ttwu_queue(struct task_struct *p, int cpu)
{
struct rq *rq = cpu_rq(cpu);
raw_spin_lock(&rq->lock);
ttwu_do_activate(rq, p, 0);
raw_spin_unlock(&rq->lock);
}
static void
ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
{
check_preempt_curr(rq, p, wake_flags);
trace_sched_wakeup(p, true);
p->state = TASK_RUNNING;
}
- static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
- {
- const struct sched_class *class;
- if (p->sched_class == rq->curr->sched_class) { //如果rq和p同属一个调度类,那么直接用调用该调度类进行判断就行了。
- rq->curr->sched_class->check_preempt_curr(rq, p, flags);
- } else {//否则
- for_each_class(class) {
- if (class == rq->curr->sched_class) //这是个很巧妙的实现。for_each_class扫描的顺序是stop_task、rt_task、normal_task、idle_task
- break; //如果这个条件判断为真,那么说名curr的优先级一定大于p的,那么不能抢占。
- if (class == p->sched_class) {
- resched_task(rq->curr); //将curr设置为可以抢占的
- break;
- }
- }
- }
- /*
- * A queue event has occurred, and we're going to schedule. In
- * this case, we can save a useless back to back clock update.
- */
- if (rq->curr->on_rq && test_tsk_need_resched(rq->curr))
- rq->skip_clock_update = 1;
- }
1. static
2. {
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.