Chinaunix首页 | 论坛 | 博客
  • 博客访问: 503636
  • 博文数量: 68
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 806
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-30 22:06
文章分类
文章存档

2011年(1)

2009年(8)

2008年(59)

我的朋友

分类: LINUX

2008-08-03 16:52:46

 synchronize_rcu()
 
 一.作用
该函数由RCU写端调用,它将阻塞写者,直到所有读执行单元完成对临界区的访问后,写者才可以继续下一步操
作。如果有多个RCU写端调用该函数,他们将在所有读执行单元完成对临界区的访问后全部被唤醒。
需要指出的是,函数synchronize_rcu 的实现实际上使用函数call_rcu。


二.代码详解
 定义在:linux/kernel/rcupdate.c
 606/**
 607 * synchronize_rcu - wait until a grace period has elapsed.
 608 *
 609 * Control will return to the caller some time after a full grace
 610 * period has elapsed, in other words after all currently executing RCU
 611 * read-side critical sections have completed.  RCU read-side critical
 612 * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
 613 * and may be nested.
 614 *
 615 * If your read-side code is not protected by rcu_read_lock(), do -not-
 616 * use synchronize_rcu().
 617 */
 618void synchronize_rcu(void)
 619{
 620        struct rcu_synchronize rcu;
 621
 622        init_completion(&rcu.completion);
 623        /* Will wake me after RCU finished */
 624        call_rcu(&rcu.head, wakeme_after_rcu);
 625
 626        /* Wait for it */
 627        wait_for_completion(&rcu.completion);
 628}
 
 其中 struct rcu_synchronize为:
  592struct rcu_synchronize {
  593        struct rcu_head head;
  594        struct completion completion;
  595};

rcu_head结构定义了        struct rcu_head *next;      //指向rcu_head的指针
               void (*func)(struct rcu_head *head);  //回调函数
回调函数完成写执行单元最后的数据释放或修改操作。

completion结构的定义:
  13struct completion {
  14        unsigned int done;
  15        wait_queue_head_t wait;
  16};
unsigned int done;
指示等待的事件是否完成。初始化时为0。如果为0,则表示等待的事件未完成。大于0表示等待的事件已经完成。
wait_queue_head_t wait;
存放等待该事件完成的进程队列。





下面void synchronize_rcu(void)字段解释:
 622>  init_completion(&rcu.completion);  初始化rcu.completion结构,初始化为等待事件未完成
 624>  call_rcu(&rcu.head, wakeme_after_rcu);  在当前CPU的私有数据中,注册回调函数。
 其中回调函数的complete(&rcu->completion); 用来唤醒等待队列的进程。
 参考:http://blog.chinaunix.net/u1/55599/showart_1101879.html

 
 
 627>  wait_for_completion(&rcu.completion);
 作用:具体进程调用过程。
 
 定义在:linux/kernel/sched.c
3731void fastcall __sched wait_for_completion(struct completion *x)
3732{
3733        might_sleep();
3734
3735        spin_lock_irq(&x->wait.lock);
3736        if (!x->done) {
3737                DECLARE_WAITQUEUE(wait, current);
3738
3739                wait.flags |= WQ_FLAG_EXCLUSIVE;
3740                __add_wait_queue_tail(&x->wait, &wait);
3741                do {
3742                        __set_current_state(TASK_UNINTERRUPTIBLE);
3743                        spin_unlock_irq(&x->wait.lock);
3744                        schedule();
3745                        spin_lock_irq(&x->wait.lock);
3746                } while (!x->done);
3747                __remove_wait_queue(&x->wait, &wait);
3748        }
3749        x->done--;
3750        spin_unlock_irq(&x->wait.lock);
3751}

参考:http://blog.chinaunix.net/u2/73528/showart_1101096.html


might_sleep()函数是检查是否需要重新调度,如果是,则进行重新调度,无论这个时候进程是位于内核空间还是用户空间.

该函数相当于信号量中的down()操作。不过在操作中使用自旋锁并屏蔽中断。如果done为0,则说明等待的事件没有完成,
则调用DECLARE_WAITQUEUE()定义等待队列wait并将当前进程添加进等待队列wait。然后将wait添加进该完成量的等待队列的末尾.

进入循环。设置当前进程为不可中断状态(TASK_UNINTERRUPTIBLE),释放自旋锁且开中断。并让当前进程进入睡眠状态。一旦进程被调度唤醒
数据又获得自旋锁且屏蔽中断。并查看等待的事件是否完成。如果完成(大于0),则从完成量的等待队列中删除等待的进程,并自减  done ,
释放自旋锁,从等待状态返回继续运行。否则继续睡眠。如果done于大0,则说明等待的事件已经完成,则自减done,直接返回。

阅读(10235) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~