[ltt-dev] [RFC PATCH 3/7] urcu:implement userspace lock
Lai Jiangshan
laijs at cn.fujitsu.com
Tue Aug 16 04:27:24 EDT 2011
On 08/16/2011 03:58 PM, Lai Jiangshan wrote:
> The pthread APIs don't have proxies APIs, so I have to
> reinvent the wheel.
>
> Signed-off-by: Lai Jiangshan <laijs at cn.fujitsu.com>
> ---
> urcu.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> urcu/futex.h | 2 +
> urcu/static/urcu.h | 5 +++
> 3 files changed, 89 insertions(+), 0 deletions(-)
>
> diff --git a/urcu.c b/urcu.c
> index 064a155..bd54467 100644
> --- a/urcu.c
> +++ b/urcu.c
> @@ -337,6 +337,88 @@ out:
> }
> #else /* #ifndef URCU_WAIT_READER */
>
> +static inline void urcu_sync_proxy_lock(int32_t *lock, int32_t proxy_owner)
> +{
> + assert(_CMM_LOAD_SHARED(*lock) == 0);
> + _CMM_STORE_SHARED(*lock, proxy_owner);
> +}
> +
> +static inline void urcu_sync_proxy_unlock(int32_t *lock)
> +{
> + _CMM_STORE_SHARED(*lock, 0);
> +}
> +
> +static void urcu_sync_lock(int32_t *lock, int32_t self)
> +{
> + for (;;) {
> + int32_t o = _CMM_LOAD_SHARED(*lock);
> +
> + if (likely(o == 0)) {
> + o = uatomic_cmpxchg(lock, 0, self);
> + if (likely(o == 0))
> + return;
> + }
> +
> + if ((o & FUTEX_WAITERS) == 0) {
> + if (uatomic_cmpxchg(lock, o, o | FUTEX_WAITERS) != o)
> + continue;
> + }
this lock can only use for URCU_WAIT_READER and URCU_BOOST_READER.
if you use it for normal conditions, you should add the following line here:
self = self | FUTEX_WAITERS;
for URCU_WAIT_READER and URCU_BOOST_READER, this line of code will cause
a un-needed syscall, so it is removed.
More for userspace lock: http://www.akkadia.org/drepper/futex.pdf
> +
> + futex_async(lock, FUTEX_WAIT, o | FUTEX_WAITERS, NULL, NULL, 0);
> + }
> +}
> +
> +/*
> + * returns:
> + * -2: error, lock is held by other.
> + * -1: error, lock is not held by anyone.
> + * 0: success unlock.
> + * 1: failed to unlock when have waiters.
> + */
> +static int urcu_sync_try_unlock(int32_t *lock, int32_t self)
> +{
> + int32_t o = _CMM_LOAD_SHARED(*lock);
> +
> + if (likely(o == self)) {
> + o = uatomic_cmpxchg(lock, self, 0);
> + if (likely(o == self))
> + return 0;
> + }
> +
> + if (o == (self | FUTEX_WAITERS))
> + return 1;
> + if (!o)
> + return -1;
> + else
> + return -2;
> +}
> +
> +static void urcu_sync_slow_unlock(int32_t *lock)
> +{
> + _CMM_STORE_SHARED(*lock, 0);
> + futex_async(lock, FUTEX_WAKE, 1, NULL, NULL, 0);
> +}
> +
> +static void urcu_sync_unlock(int32_t *lock, int32_t self)
> +{
> + int ret = urcu_sync_try_unlock(lock, self);
> +
> + assert(ret == 0 || ret == 1);
> +
> + if (unlikely(ret == 1))
> + urcu_sync_slow_unlock(lock);
> +}
> +
> +static void urcu_sync_unlock_if_not_proxy_unlocked(int32_t *lock, int32_t self)
> +{
> + int ret = urcu_sync_try_unlock(lock, self);
> +
> + assert(ret == -1 || ret == 0 || ret == 1);
> +
> + if (unlikely(ret == 1))
> + urcu_sync_slow_unlock(lock);
> +}
> +
> #endif /* #else #ifndef URCU_WAIT_READER */
>
> /*
> diff --git a/urcu/futex.h b/urcu/futex.h
> index 98acc12..e47c307 100644
> --- a/urcu/futex.h
> +++ b/urcu/futex.h
> @@ -31,6 +31,8 @@ extern "C" {
> #define FUTEX_WAIT 0
> #define FUTEX_WAKE 1
>
> +#define FUTEX_WAITERS 0x80000000
> +
> /*
> * sys_futex compatibility header.
> * Use *only* *either of* futex_noasync OR futex_async on a given address.
> diff --git a/urcu/static/urcu.h b/urcu/static/urcu.h
> index ebdefbe..32d1af8 100644
> --- a/urcu/static/urcu.h
> +++ b/urcu/static/urcu.h
> @@ -308,6 +308,11 @@ static inline void _rcu_read_unlock(void)
> }
> #else /* #ifndef URCU_WAIT_READER */
>
> +static inline int32_t urcu_sync_lock_onwer(int32_t *lock)
> +{
> + return _CMM_LOAD_SHARED(*lock) & ~FUTEX_WAITERS;
> +}
> +
> #endif /* #else #ifndef URCU_WAIT_READER */
>
> #ifdef __cplusplus
More information about the lttng-dev
mailing list