分类: LINUX
2008-08-06 18:06:52
一旦定义了一个元素,必须把它插入等待队列。函数add_wait_queue()将一个非互斥进程插入等待队列链表的第一个位置。
函数另外 add_wai_queue_exclusive()把一个互斥的进程插入等待队列链表的最后一个位置。Remove_wait_queue()函数
从等待队列链表中删除一个进程,waitqueue_active()检查一个给定的等待队列是否为空。
下面是对以上介绍的几个进行解析:
1、add_wait_queue()
void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
wait->flags &= ~WQ_FLAG_EXCLUSIVE; // #define WQ_FLAG_EXCLUSIVE 0x01
spin_lock_irqsave(&q->lock, flags);//?????????????????
__add_wait_queue(q, wait);
(&->, );
}
下面是对__add_wait_queue函数的定义:
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
list_add(&new->task_list, &head->task_list);
}
下面是list_add(&new->task_list,&head->task_list)相应函数的原代码:
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
__list_add()函数上面已经介绍。
2、add_wai_queue_exclusive()//这个函数与上面的函数相类似,唯一不同的是flags值所决定的互斥与非
互斥。
void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
wait->flags |= WQ_FLAG_EXCLUSIVE;// #define WQ_FLAG_EXCLUSIVE 0x01
spin_lock_irqsave(&q->lock, flags);
__add_wait_queue_tail(q, wait);
spin_unlock_irqrestore(&q->lock, flags);
}
3、remove_wait_queue()//这个函数从等待队列链表中删除一个进程
void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
__remove_wait_queue(q, wait);
/*
static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
{
list_del(&old->task_list);
}
*/
spin_unlock_irqrestore(&q->lock, flags);
}
下面将list_del()函数的原代码列举出来,并将以分析:
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;// #define LIST_POISON1 ((void *) 0x00100100)
entry->prev = LIST_POISON2;// #define LIST_POISON2 ((void *) 0x00200200)
//上面的LIST_POISON1和LIST_POISON2的作用是这样解释的:关于这个地址的处理内核处理的很简单,要么打印日志信息报错,要么直接不处理.
}
下面又是对__list_del()函数的解释:
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
要等待特定条件下的进程可以调用如下列表中的任何一个函数:
sleep_on(wait_queue_head_t *q)
void ( *) { unsigned long ; ; (&, current); current-> = ; (, &, &); (); (, &, &); }
下面就对sleep_on()函数中的结构一一解释: //#define (((".sched.text")))
这个宏定义的作用是进行属性设置
static void ( *, *,
unsigned long *)
{
(&->, *);//为等待队列头q设置锁,并且进行关中断和保存状态
(, );//上面已经对这个函数有了解释。
(&->); //释放锁
}
static void( *, *, unsigned long *) { (&->); (, );//关于这个函数的功能,上面也给出了解释。
(&->, *); }
由此可以发现,函数sleep_on_head和sleep_on_tail是成对使用的。
使用schedule()进行进程的切换,因为sleep_on()使得当前进程睡眠,那么睡眠之后,执行此函数进行另外一个进程的运行。
这个函数的功能是将等待队列wait添加到等待队列头q中,flags是用来设置等待队列wait的互斥或非
互斥性的。并将目前进程的状态设置成TASK_UNINTERRUPTIBLE,并定义一个等待队列,之后把它附
属到等待队列头q,直到资源可以获得,q引导的等待队列被唤醒。
interruptible_sleep_on()与sleep_on()函数是相类似的,但是稍有不同:一个将当前状态设置为
TASK_INTERRUPTIBLE, 后者将状态设置为TASK_UNINTERRUPTIBLE,因此可,接受一个信号就可以
唤醒当前进程。 sleep_on()应该与wake_up()成对使用,interruptible_sleep_on()与wake_up_interruptible()成对使用。
sleep_on_timeout()和interruptible_sleep_on_timeout()与前面函数类似,但是它们允许调用者定义一个时间间隔, 过了这个间隔以后,进程将由内核唤醒。当然,所使用的进程切换函数不是schedule()而是
schedule_timeout();我们可以发现,sleep_on_timeout()这个函数所实现的时间等待功能是通过函数schedule_timeout()来实现的。
prepare_to_wait()\prepare_to_wait_exclusive()\finish_wait()三个函数提供了另外一种途径来使当前进程
在一个等待队列中睡眠。
下面是对prepare_to_wait()和prepare_to_wait_exclusive()以及finish_wait()三个函数作出解释:
prepare_to_wait()
( *, *, int )
{ unsigned long ; -> &= ~;//非互斥设置
(&->, ); if ((&->))//判断等待队列是否为空
(, );//
/* * don't alter the task state if this is just going to * queue an async wait queue callback */ if (()) //#define () (!() || (()->))
set_current_state(); (&->, ); }
//
prepare_to_wait_exclusive()函数和prepare_to_wait()函数实现的功能基本上一致,区别在于前者将flags设置为1(互斥),后者将flags设置为0(即非互斥)
void ( *, *) { unsigned long ; __set_current_state();//设置当前进程为运行状态,这里使用的函数前面已经解释过了。
/* * 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用来测试等待是否为空并且是否没有正在被修改。
NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen * to the list entry is list_del_init(). Eg. it cannot be used * if another CPU could re-list_add() it.
wait_event()和wait_event_interruptible()宏使它们的调用进程在等待队列上睡眠,一直到修改了给定条件为止。
下面是对wait_event()和wait_event_interruptible()函数的原代码的分析:
wait_event()
#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)
#define () \ = { \ . = current, \ . = , \ . = (().), \ }
{ int = (, , , );//此函数在前面已经讲解过
if () (&->);//default_wake_function函数运行成功时,就将对应所处理的进程从等待队列中删除。
return ; }
static void (struct *) { (->, ->);//删除操作主要由此函数实现。
();//从等待队列中删除了这个进程所依附的等待队列节点后,对此节点进行归0操作。为什么不释放?我想应该是这个等待队列还会再次使用。
} static void (struct *) { -> = ; -> = ; }