免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 5630 | 回复: 21

[推荐] LKML上一篇关于barrier文档草案的讨论 [复制链接]

论坛徽章:
0
发表于 2006-03-08 17:36 |显示全部楼层
地址:
http://groups.google.com/group/l ... d0#cdfbcb70e9c48cd0

有兴趣的可以在这里讨论,那边都是牛人

论坛徽章:
0
发表于 2006-03-09 09:19 |显示全部楼层
原帖由 xiaozhaoz 于 2006-3-8 17:36 发表
地址:
http://groups.google.com/group/l ... d0#cdfbcb70e9c48cd0

有兴趣的可以在这里讨论,那边都是牛人


昨天的, 偶也看到了

可惜是个PATCH, 需要make pdfdocs之类才能看吧? 还有barrier()和mb()的区别也尚未整理

过两天整理下发上来

论坛徽章:
0
发表于 2006-03-09 09:33 |显示全部楼层
lkml潜水好久了, 一句话都不敢说

论坛徽章:
0
发表于 2006-03-09 10:19 |显示全部楼层
Robert Love 说自己在上面潜了三年,才敢参与讨论。

patch 直接看不行吗? 为什么要转?

这篇文档草案有很多问题, 后面有很多牛人的砖块。

论坛徽章:
0
发表于 2006-03-09 10:54 |显示全部楼层
谢谢xiaozhaoz大哥! 刚刚见到这篇文章, 看上去也不错
http://www.linuxjournal.com/article/8212

论坛徽章:
0
发表于 2006-03-09 11:10 |显示全部楼层
这个我以前看过,建议你先看
Memory Ordering in Modern Microprocessors, Part 1
http://www.linuxjournal.com/article/8211

这两篇文档的作者是Paul McKenney, Linux中实现RCU的IBM guy, 上面的讨论中,也有他的参与。

论坛徽章:
0
发表于 2006-03-09 11:19 |显示全部楼层
讨论一下,为什么他的那个例子:
+ (2) Multiprocessor interaction
+
+     When there's a system with more than one processor, these may be working
+     on the same set of data, but attempting not to use locks as locks are
+     quite expensive. This means that accesses that affect both CPUs may have
+     to be carefully ordered to prevent error.
+
+     Consider the R/W semaphore slow path. In that, a waiting process is
+     queued on the semaphore, as noted by it having a record on its stack
+     linked to the semaphore's list:
+
+       struct rw_semaphore {
+               ...
+               struct list_head waiters;
+       };
+
+       struct rwsem_waiter {
+               struct list_head list;
+               struct task_struct *task;
+       };
+
+     To wake up the waiter, the up_read() or up_write() functions have to read
+     the pointer from this record to know as to where the next waiter record
+     is, clear the task pointer, call wake_up_process() on the task, and
+     release the task struct reference held:
+
+       READ waiter->list.next;
+       READ waiter->task;
+       WRITE waiter->task;
+       CALL wakeup
+       RELEASE task
+
+     If any of these steps occur out of order, then the whole thing may fail.
+
+     Note that the waiter does not get the semaphore lock again - it just waits
+     for its task pointer to be cleared. Since the record is on its stack, this
+     means that if the task pointer is cleared _before_ the next pointer in the
+     list is read, then another CPU might start processing the waiter and it
+     might clobber its stack before up*() functions have a chance to read the
+     next pointer.
+
+       CPU 0                           CPU 1
+       =============================== ===============================
+                                       down_xxx()
+                                       Queue waiter
+                                       Sleep
+       up_yyy()
+       READ waiter->task;
+       WRITE waiter->task;
+       <preempt>
+                                       Resume processing
+                                       down_xxx() returns
+                                       call foo()
+                                       foo() clobbers *waiter
+       </preempt>
+       READ waiter->list.next;
+       --- OOPS ---
+
+     This could be dealt with using a spinlock, but then the down_xxx()
+     function has to get the spinlock again after it's been woken up, which is
+     a waste of resources.
+
+     The way to deal with this is to insert an SMP memory barrier:
+
+       READ waiter->list.next;
+       READ waiter->task;
+       smp_mb(); //为什么这个地方需要smp_mb()?? 我觉得用mb()应该就可以了,因为他只要保证了read 在write和wakeup前面,就能保证sleep的任务不会被唤醒而导致访问乱序。
+       WRITE waiter->task;
+       CALL wakeup
+       RELEASE task
+
+     In this case, the barrier makes a guarantee that all memory accesses
+     before the barrier will happen before all the memory accesses after the
+     barrier. It does _not_ guarantee that all memory accesses before the
+     barrier will be complete by the time the barrier is complete.

论坛徽章:
0
发表于 2006-03-09 13:37 |显示全部楼层
>+       smp_mb(); //为什么这个地方需要smp_mb()?? 我觉得用mb()应该就可以了,因为他只要保证了read 在write和wakeup前面,就能保证sleep的任务不会被唤醒而导致访问乱序。

看smp_mb()的定义, 感觉mb()更严格一些:
include/asm-i386/system.h

  1. #ifdef CONFIG_SMP
  2. #define smp_mb()        mb()
  3. #define smp_rmb()        rmb()
  4. #define smp_wmb()        wmb()
  5. #define smp_read_barrier_depends()        read_barrier_depends()
  6. #define set_mb(var, value) do { xchg(&var, value); } while (0)
  7. #else
  8. #define smp_mb()        barrier()
  9. #define smp_rmb()        barrier()
  10. #define smp_wmb()        barrier()
  11. #define smp_read_barrier_depends()        do { } while(0)
  12. #define set_mb(var, value) do { var = value; barrier(); } while (0)
  13. #endif
复制代码


我不理解的是, mb()和barrier()有何区别? 前者比后者严格, 这是肯定的。 但barrier()宏有用吗? 它的定义是:
#define barrier() __asm__ __volatile__("": : :"memory")

只在inline asm的约束部分提醒GCC该指令会修改内存──这意味着GCC会据以做什么工作呢?

论坛徽章:
0
发表于 2006-03-09 13:52 |显示全部楼层
barrier()宏:

jkl大师这么回答的:CPU越过内存屏障后,将刷新自已对存储器的缓冲状态。这条语句实际上不生成任何代码,但可使gcc在barrier()之后刷新寄存器对变量的分配。

论坛徽章:
0
发表于 2006-03-09 14:59 |显示全部楼层
对barrier() 我的理解是这只是一个compiler barrier, 这个barrier加入到代码中,会使cache invalidation

而mb是hardware barrier,在代码运行中,CPU会prevent from reordering cache visit.

我想知道,在SMP情况下, smp_mb()和mb()差别。 从名字上看, 好像
smp应该对多个CPU的cache 一致启作用,而mb只能保证本CPU cache访问一致。
但实际情况看样子不是这样。

当然 在 像x86这样的CPU smp_mb() == mb(), 但memory barrier 函数 考虑的是所有CPU通用,所以其它CPU可能不是这样。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP