__lll_lock是glibc中mutex调用的一个宏,glibc-2.25
-
#define __lll_lock(futex, private) \
-
((void) \
-
({ \
-
int *__futex = (futex); \
-
if (__glibc_unlikely \
-
(atomic_compare_and_exchange_bool_acq (__futex, 1, 0))) \
-
{ \
-
if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
-
__lll_lock_wait_private (__futex); \
-
else \
-
__lll_lock_wait (__futex, private); \
-
} \
-
}))
-
#define lll_lock(futex, private) \
-
__lll_lock (&(futex), private)
先记录一下atomic_compare_and_exchange_bool_acq的作用:
-
/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
-
Return zero if *MEM was changed or non-zero if no exchange happened. */
-
#ifndef atomic_compare_and_exchange_bool_acq
-
# ifdef __arch_compare_and_exchange_bool_32_acq
-
# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
-
__atomic_bool_bysize (__arch_compare_and_exchange_bool,acq, \
-
mem, newval, oldval)
-
# else
-
# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
-
({ /* Cannot use __oldval here, because macros later in this file might \
-
call this macro with __oldval argument. */ \
-
__typeof (oldval) __atg3_old = (oldval); \
-
atomic_compare_and_exchange_val_acq (mem, newval, __atg3_old) \
-
!= __atg3_old; \
-
})
-
# endif
-
#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,代码如下:
-
/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
-
Return the old *MEM value. */
-
#if !defined atomic_compare_and_exchange_val_acq \
-
&& defined __arch_compare_and_exchange_val_32_acq
-
# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
-
__atomic_val_bysize (__arch_compare_and_exchange_val,acq, \
-
mem, newval, oldval)
-
#endif
如果oldval 等于*mem,那么就更新*mem的内容为newval,否则不更新。无论更新与否,都返回旧的*mem值。
还有一个atomic_exchange_acq,从名字就可以看出,这个原子操作没有比较,直接把newval存储在*mem中,然后返回就的*mem值。
-
/* Store NEWVALUE in *MEM and return the old value. */
-
#ifndef atomic_exchange_acq
-
# define atomic_exchange_acq(mem, newvalue) \
-
({ __typeof (*(mem)) __atg5_oldval; \
-
__typeof (mem) __atg5_memp = (mem); \
-
__typeof (*(mem)) __atg5_value = (newvalue); \
-
\
-
do \
-
__atg5_oldval = *__atg5_memp; \
-
while (__builtin_expect \
-
(atomic_compare_and_exchange_bool_acq (__atg5_memp, __atg5_value, \
-
__atg5_oldval), 0)); \
-
\
-
__atg5_oldval; })
-
#endif
继续回到__lll_lock.
从5-6行的if可以看到,如果_futex的值为0,表示没有其他的竞争者,那么atomic_compare_and_exchange_bool_acq就把1存储在_futex里,然后直接返回。否则就要调用__lll_lock_wait.
-
void
-
__lll_lock_wait_private (int *futex)
-
{
-
if (*futex == 2)
-
lll_futex_wait (futex, 2, LLL_PRIVATE); /* Wait if *futex == 2. */
-
-
while (atomic_exchange_acq (futex, 2) != 0)
-
lll_futex_wait (futex, 2, LLL_PRIVATE); /* Wait if *futex == 2. */
-
}
-
-
-
/* This function doesn't get included in libc. */
-
#if IS_IN (libpthread)
-
void
-
__lll_lock_wait (int *futex, int private)
-
{
-
if (*futex == 2)
-
lll_futex_wait (futex, 2, private); /* Wait if *futex == 2. */
-
-
while (atomic_exchange_acq (futex, 2) != 0)
-
lll_futex_wait (futex, 2, private); /* Wait if *futex == 2. */
-
}
-
#endif
__lll_lock_wait_private和__lll_lock_wait,private的取值可以在LLL_PRIVATE和LLL_SHARED,可以先不管。
这个函数把futex设置为2,如果futex的旧值不是2,就调用lll_futex_wait等待。
阅读(1833) | 评论(0) | 转发(1) |