Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1033647
  • 博文数量: 123
  • 博客积分: 5051
  • 博客等级: 大校
  • 技术积分: 1356
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-14 10:56
文章分类
文章存档

2012年(1)

2011年(21)

2010年(13)

2009年(55)

2008年(33)

分类: LINUX

2008-08-06 18:06:52

一旦定义了一个元素,必须把它插入等待队列。函数add_wait_queue()将一个非互斥进程插入等待队列链表的第一个位置。

函数另外 add_wai_queue_exclusive()把一个互斥的进程插入等待队列链表的最后一个位置。Remove_wait_queue()函数

从等待队列链表中删除一个进程,waitqueue_active()检查一个给定的等待队列是否为空。

下面是对以上介绍的几个进行解析:

1add_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()函数上面已经介绍。


2add_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);

}

3remove_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_POISON1LIST_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_headsleep_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 *) { -> = ; -> = ; }
阅读(2081) | 评论(2) | 转发(0) |
0

上一篇:轮询操作

下一篇:linux内核学习好网站

给主人留下些什么吧!~~

KYlinux2008-08-10 12:13:11

LIST_POISON1和LIST_POISON2访问不可访问的地址,引起中断。 本处中断处理函数,只是没有实际内容。(我的理解)

KYlinux2008-08-10 12:09:51

spin_lock_irqsave(&q->lock, flags);//????????????????? 设置自旋锁,且屏蔽中断。保存但前CPU状态,对这个任务操作完成恢复到CPU保存时刻状态。 其中,当时互斥进程时,会被插到队列的尾部。如果不是互斥进程,插到队列头的后面 在wake_up()唤醒时,会很方便。 具体我博客介绍:http://blog.chinaunix.net/u1/55599/showart_1108399.html