[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