Chinaunix首页 | 论坛 | 博客
  • 博客访问: 159847
  • 博文数量: 45
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 273
  • 用 户 组: 普通用户
  • 注册时间: 2014-05-28 10:30
文章分类
文章存档

2017年(6)

2016年(3)

2015年(8)

2014年(28)

我的朋友

分类: LINUX

2017-07-25 16:21:58

__lll_lock是glibc中mutex调用的一个宏,glibc-2.25

点击(此处)折叠或打开

  1. #define __lll_lock(futex, private) \
  2.   ((void) \
  3.    ({ \
  4.      int *__futex = (futex); \
  5.      if (__glibc_unlikely \
  6.          (atomic_compare_and_exchange_bool_acq (__futex, 1, 0))) \
  7.        { \
  8.          if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
  9.            __lll_lock_wait_private (__futex); \
  10.          else \
  11.            __lll_lock_wait (__futex, private); \
  12.        } \
  13.    }))
  14. #define lll_lock(futex, private) \
  15.   __lll_lock (&(futex), private)
先记录一下atomic_compare_and_exchange_bool_acq的作用:

点击(此处)折叠或打开

  1. /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
  2.    Return zero if *MEM was changed or non-zero if no exchange happened. */
  3. #ifndef atomic_compare_and_exchange_bool_acq
  4. # ifdef __arch_compare_and_exchange_bool_32_acq
  5. # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
  6.   __atomic_bool_bysize (__arch_compare_and_exchange_bool,acq, \
  7.                 mem, newval, oldval)
  8. # else
  9. # define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
  10.   ({ /* Cannot use __oldval here, because macros later in this file might \
  11.     call this macro with __oldval argument. */ \
  12.      __typeof (oldval) __atg3_old = (oldval); \
  13.      atomic_compare_and_exchange_val_acq (mem, newval, __atg3_old) \
  14.        != __atg3_old; \
  15.   })
  16. # endif
  17. #endif
具体的实现先不看了,只看一下注释就明白了。三个参数:mem, newval,oldval;如果oldval 等于*mem,那么设置*mem=newval,并且返回0; 如果*mem的值没有改变,那么就返回非0。 直白一点就是*mem等于oldval就返回0,不等于就返回非0。这也正好对应了posix里面的mutex,如果没有竞争,直接上锁成功,返回0;只有存在竞争的时候,才需要系统调用(futex)。
和atomic_compare_and_exchange_bool_acq对应的还有atomic_compare_and_exchange_val_acq,代码如下:

点击(此处)折叠或打开

  1. /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
  2.    Return the old *MEM value. */
  3. #if !defined atomic_compare_and_exchange_val_acq \
  4.     && defined __arch_compare_and_exchange_val_32_acq
  5. # define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
  6.   __atomic_val_bysize (__arch_compare_and_exchange_val,acq, \
  7.                mem, newval, oldval)
  8. #endif
如果oldval 等于*mem,那么就更新*mem的内容为newval,否则不更新。无论更新与否,都返回旧的*mem值。
还有一个atomic_exchange_acq,从名字就可以看出,这个原子操作没有比较,直接把newval存储在*mem中,然后返回就的*mem值。

点击(此处)折叠或打开

  1. /* Store NEWVALUE in *MEM and return the old value. */
  2. #ifndef atomic_exchange_acq
  3. # define atomic_exchange_acq(mem, newvalue) \
  4.   ({ __typeof (*(mem)) __atg5_oldval; \
  5.      __typeof (mem) __atg5_memp = (mem); \
  6.      __typeof (*(mem)) __atg5_value = (newvalue); \
  7.                                           \
  8.      do \
  9.        __atg5_oldval = *__atg5_memp; \
  10.      while (__builtin_expect \
  11.         (atomic_compare_and_exchange_bool_acq (__atg5_memp, __atg5_value, \
  12.                            __atg5_oldval), 0)); \
  13.                                           \
  14.      __atg5_oldval; })
  15. #endif

继续回到__lll_lock.
从5-6行的if可以看到,如果_futex的值为0,表示没有其他的竞争者,那么atomic_compare_and_exchange_bool_acq就把1存储在_futex里,然后直接返回。否则就要调用__lll_lock_wait.

点击(此处)折叠或打开

  1. void
  2. __lll_lock_wait_private (int *futex)
  3. {
  4.   if (*futex == 2)
  5.     lll_futex_wait (futex, 2, LLL_PRIVATE); /* Wait if *futex == 2. */

  6.   while (atomic_exchange_acq (futex, 2) != 0)
  7.     lll_futex_wait (futex, 2, LLL_PRIVATE); /* Wait if *futex == 2. */
  8. }


  9. /* This function doesn't get included in libc. */
  10. #if IS_IN (libpthread)
  11. void
  12. __lll_lock_wait (int *futex, int private)
  13. {
  14.   if (*futex == 2)
  15.     lll_futex_wait (futex, 2, private); /* Wait if *futex == 2. */

  16.   while (atomic_exchange_acq (futex, 2) != 0)
  17.     lll_futex_wait (futex, 2, private); /* Wait if *futex == 2. */
  18. }
  19. #endif
__lll_lock_wait_private和__lll_lock_wait,private的取值可以在LLL_PRIVATE和LLL_SHARED,可以先不管。
这个函数把futex设置为2,如果futex的旧值不是2,就调用lll_futex_wait等待。



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