- /* 有多少空间被释放 */
-
static int spacefreee(struct scull_pipe *dev)
-
{
-
if (dev->rp == dev->wp)
-
{
-
return dev->buffersize - 1;
-
}
-
-
/* 这条语句很好,空间为写指针位置之后,
-
* 读指针位置之前的这段空间
-
*/
-
return ( (dev->rp - dev->wp + dev->buffersize) % dev->buffersize ) -1 ;
-
}
下面看手工休眠的过程。
第一步是建立并初始化一个等待队列入口。
其中name是等待队列入口变量的名称。也可以通过下面两个步骤完成这个工作:
- wait_queue_t my_wait;
-
init_wait(&my_wait);
下一个步骤是将等待队列入口添加到队列中,并设置进程的状态,前面的两种方法都可通过下面的函数完成:
- void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);
queue 和 wait分别是等待队列头和进程入口。state是进程的新状态;它应该是TASK_INTERRUPTIBLE 或TASK_UNINTERRUPTIBLE
这里先看下,结构体wait_queue_head_t和wait_queue_t 的具体定义:
- typedef struct __wait_queue_head wait_queue_head_t;
-
struct __wait_queue_head
-
{
-
spinlock_t lock;
-
struct list_head task_list;
-
};
- typedef struct __wait_queue wait_queue_t;
-
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
-
int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key);
-
-
struct __wait_queue
-
{
-
unsigned int flags;
-
#define WQ_FLAG_EXCLUSIVE 0x01
-
void *private;
-
wait_queue_func_t func;
-
struct list_head task_list;
-
};
在调用了prepare_to_wait 之后,进程即可调用schedule,当然在这之前,应确保仍有必要等待。
一旦schedule返回,就到了清理时间了,这个工作也可通过下面的特殊函数完成:
- void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait);
- /*
-
* finish_wait - clean up after waiting in a queue
-
* @q: waitqueue waited on
-
* @wait: wait descriptor
-
*
-
* Sets current thread back to running state and removes
-
* the wait descriptor from the given waitqueue if still
-
* queued.
-
*/
-
void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
-
{
-
unsigned long flags;
-
-
__set_current_state(TASK_RUNNING);
-
/*
-
* We can check for list emptiness outside the lock
-
* IFF:
-
* - we use the "careful" check that verifies both
-
* the next and prev pointers, so that there cannot
-
* be any half-pending updates in progress on other
-
* CPU's that we haven't seen yet (and that might
-
* still change the stack area.
-
* and
-
* - all other users take the lock (ie we can only
-
* have _one_ other CPU that looks at or modifies
-
* the list).
-
*/
-
if (!list_empty_careful(&wait->task_list)) {
-
spin_lock_irqsave(&q->lock, flags);
-
list_del_init(&wait->task_list);
-
spin_unlock_irqrestore(&q->lock, flags);
-
}
-
}
之后,代码可测试其状态,并判断是否需要重新等待。
好了,让我们来看看DEFINE_WAIT(my_wait)等得定义吧,跟踪下。
而init_wait(&my_wait)的定义如下:
- #define init_wait(wait) \
-
do { \
-
(wait)->private = current; \
-
(wait)->func = autoremove_wake_function; \
-
INIT_LIST_HEAD(&(wait)->task_list); \
-
} while (0)
- static inline void INIT_LIST_HEAD(struct list_head *list)
-
{
-
list->next = list;
-
list->prev = list;
-
}
由上面看来DEFINE_WAIT(my_wait)同
wait_queue_t my_wait;
init_wait(my_wait);
确实做得是一样的事情。
再来看看prepare_to_wait()函数吧.
- void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
-
{
-
unsigned long flags;
-
-
wait->flags &= ~WQ_FLAG_EXCLUSIVE;
-
spin_lock_irqsave(&q->lock, flags);
-
if (list_empty(&wait->task_list))
-
__add_wait_queue(q, wait);
-
set_current_state(state);
-
spin_unlock_irqrestore(&q->lock, flags);
-
}
- static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
-
{
-
list_add(&new->task_list, &head->task_list);
-
}
- static inline void __list_add(struct list_head *new,
-
struct list_head *prev,
-
struct list_head *next)
-
{
-
next->prev = new;
-
new->next = next;
-
new->prev = prev;
-
prev->next = new;
-
}
再来看finish_wait 函数
- /*
-
* finish_wait - clean up after waiting in a queue
-
* @q: waitqueue waited on
-
* @wait: wait descriptor
-
*
-
* Sets current thread back to running state and removes
-
* the wait descriptor from the given waitqueue if still
-
* queued.
-
*/
-
void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
-
{
-
unsigned long flags;
-
-
__set_current_state(TASK_RUNNING);
-
/*
-
* We can check for list emptiness outside the lock
-
* IFF:
-
* - we use the "careful" check that verifies both
-
* the next and prev pointers, so that there cannot
-
* be any half-pending updates in progress on other
-
* CPU's that we haven't seen yet (and that might
-
* still change the stack area.
-
* and
-
* - all other users take the lock (ie we can only
-
* have _one_ other CPU that looks at or modifies
-
* the list).
-
*/
-
if (!list_empty_careful(&wait->task_list)) {
-
spin_lock_irqsave(&q->lock, flags);
-
list_del_init(&wait->task_list);
-
spin_unlock_irqrestore(&q->lock, flags);
-
}
-
}
- wait_event(queue, condition) 其实里面的内容就是我们上面说的东西,看代码:
- /**
-
* wait_event - 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_UNINTERRUPTIBLE) until the
-
* @condition evaluates to true. 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.
-
*/
-
#define wait_event(wq, condition) \
-
do { \
-
if (condition) \
-
break; \
-
__wait_event(wq, condition); \
-
} while (0)
- #define __wait_event(wq, condition) \
-
do { \
-
DEFINE_WAIT(__wait); \
-
\
-
for (;;) { \
-
prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \
-
if (condition) \
-
break; \
-
schedule(); \
-
} \
-
finish_wait(&wq, &__wait); \
-
} while (0)