Moved ticketlock implementation into ticketlock_inlines.h header file, which enables inlined version to be used inside implementation and through API.
Signed-off-by: Petri Savolainen <petri.savolai...@nokia.com> --- platform/linux-generic/Makefile.am | 1 + .../include/odp/api/plat/ticketlock_inlines.h | 87 ++++++++++++++++++++++ platform/linux-generic/odp_ticketlock.c | 68 +++-------------- 3 files changed, 97 insertions(+), 59 deletions(-) create mode 100644 platform/linux-generic/include/odp/api/plat/ticketlock_inlines.h diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index e3c0f56..900ac08 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -88,6 +88,7 @@ odpapiplatinclude_HEADERS = \ $(srcdir)/include/odp/api/plat/sync_inlines.h \ $(srcdir)/include/odp/api/plat/thread_types.h \ $(srcdir)/include/odp/api/plat/thrmask_types.h \ + $(srcdir)/include/odp/api/plat/ticketlock_inlines.h \ $(srcdir)/include/odp/api/plat/ticketlock_types.h \ $(srcdir)/include/odp/api/plat/time_types.h \ $(srcdir)/include/odp/api/plat/timer_types.h \ diff --git a/platform/linux-generic/include/odp/api/plat/ticketlock_inlines.h b/platform/linux-generic/include/odp/api/plat/ticketlock_inlines.h new file mode 100644 index 0000000..957d22e --- /dev/null +++ b/platform/linux-generic/include/odp/api/plat/ticketlock_inlines.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * Ticketlock inline functions + */ + +#ifndef _ODP_PLAT_TICKETLOCK_INLINES_H_ +#define _ODP_PLAT_TICKETLOCK_INLINES_H_ + +#include <odp/api/ticketlock.h> +#include <odp/api/atomic.h> +#include <odp/api/sync.h> +#include <odp/api/cpu.h> + +static inline void _odp_ticketlock_lock(odp_ticketlock_t *ticketlock) +{ + uint32_t ticket; + + /* Take a ticket using an atomic increment of 'next_ticket'. + * This can be a relaxed operation but it cannot have the + * acquire semantics since we haven't acquired the lock yet */ + ticket = odp_atomic_fetch_inc_u32(&ticketlock->next_ticket); + + /* Spin waiting for our turn. Use load-acquire so that we acquire + * all stores from the previous lock owner */ + while (ticket != odp_atomic_load_acq_u32(&ticketlock->cur_ticket)) + odp_cpu_pause(); +} + +static inline int _odp_ticketlock_trylock(odp_ticketlock_t *tklock) +{ + /* We read 'next_ticket' and 'cur_ticket' non-atomically which should + * not be a problem as they are not independent of each other. + * 'cur_ticket' is always <= to 'next_ticket' and if we see an + * older value of 'cur_ticket', this only means the lock will + * look busy and trylock will fail. */ + uint32_t next = odp_atomic_load_u32(&tklock->next_ticket); + uint32_t cur = odp_atomic_load_u32(&tklock->cur_ticket); + /* First check that lock is available and possible to take without + * spinning. */ + if (next == cur) { + /* Then try to take the lock by incrementing 'next_ticket' + * but only if it still has the original value which is + * equal to 'cur_ticket'. + * We don't have to include 'cur_ticket' in the comparison + * because it cannot be larger than 'next_ticket' (only + * smaller if the lock is busy). + * If CAS fails, it means some other thread intercepted and + * took a ticket which means the lock is not available + * anymore */ + if (odp_atomic_cas_acq_u32(&tklock->next_ticket, + &next, next + 1)) + return 1; + } + return 0; +} + +static inline void _odp_ticketlock_unlock(odp_ticketlock_t *ticketlock) +{ + /* Release the lock by incrementing 'cur_ticket'. As we are the + * lock owner and thus the only thread that is allowed to write + * 'cur_ticket', we don't need to do this with an (expensive) + * atomic RMW operation. Instead load-relaxed the current value + * and a store-release of the incremented value */ + uint32_t cur = odp_atomic_load_u32(&ticketlock->cur_ticket); + + odp_atomic_store_rel_u32(&ticketlock->cur_ticket, cur + 1); +} + +static inline int _odp_ticketlock_is_locked(odp_ticketlock_t *ticketlock) +{ + /* Compare 'cur_ticket' with 'next_ticket'. Ideally we should read + * both variables atomically but the information can become stale + * immediately anyway so the function can only be used reliably in + * a quiescent system where non-atomic loads should not pose a + * problem */ + return odp_atomic_load_u32(&ticketlock->cur_ticket) != + odp_atomic_load_u32(&ticketlock->next_ticket); +} + +#endif diff --git a/platform/linux-generic/odp_ticketlock.c b/platform/linux-generic/odp_ticketlock.c index 353af9a..f18d78f 100644 --- a/platform/linux-generic/odp_ticketlock.c +++ b/platform/linux-generic/odp_ticketlock.c @@ -4,10 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include <odp/api/ticketlock.h> -#include <odp/api/atomic.h> -#include <odp/api/sync.h> -#include <odp/api/cpu.h> +#include <odp/api/plat/ticketlock_inlines.h> void odp_ticketlock_init(odp_ticketlock_t *ticketlock) { @@ -15,69 +12,22 @@ void odp_ticketlock_init(odp_ticketlock_t *ticketlock) odp_atomic_init_u32(&ticketlock->cur_ticket, 0); } -void odp_ticketlock_lock(odp_ticketlock_t *ticketlock) +void odp_ticketlock_lock(odp_ticketlock_t *lock) { - uint32_t ticket; - - /* Take a ticket using an atomic increment of 'next_ticket'. - * This can be a relaxed operation but it cannot have the - * acquire semantics since we haven't acquired the lock yet */ - ticket = odp_atomic_fetch_inc_u32(&ticketlock->next_ticket); - - /* Spin waiting for our turn. Use load-acquire so that we acquire - * all stores from the previous lock owner */ - while (ticket != odp_atomic_load_acq_u32(&ticketlock->cur_ticket)) - odp_cpu_pause(); + return _odp_ticketlock_lock(lock); } -int odp_ticketlock_trylock(odp_ticketlock_t *tklock) +int odp_ticketlock_trylock(odp_ticketlock_t *lock) { - /* We read 'next_ticket' and 'cur_ticket' non-atomically which should - * not be a problem as they are not independent of each other. - * 'cur_ticket' is always <= to 'next_ticket' and if we see an - * older value of 'cur_ticket', this only means the lock will - * look busy and trylock will fail. */ - uint32_t next = odp_atomic_load_u32(&tklock->next_ticket); - uint32_t cur = odp_atomic_load_u32(&tklock->cur_ticket); - /* First check that lock is available and possible to take without - * spinning. */ - if (next == cur) { - /* Then try to take the lock by incrementing 'next_ticket' - * but only if it still has the original value which is - * equal to 'cur_ticket'. - * We don't have to include 'cur_ticket' in the comparison - * because it cannot be larger than 'next_ticket' (only - * smaller if the lock is busy). - * If CAS fails, it means some other thread intercepted and - * took a ticket which means the lock is not available - * anymore */ - if (odp_atomic_cas_acq_u32(&tklock->next_ticket, - &next, next + 1)) - return 1; - } - return 0; + return _odp_ticketlock_trylock(lock); } -void odp_ticketlock_unlock(odp_ticketlock_t *ticketlock) +void odp_ticketlock_unlock(odp_ticketlock_t *lock) { - /* Release the lock by incrementing 'cur_ticket'. As we are the - * lock owner and thus the only thread that is allowed to write - * 'cur_ticket', we don't need to do this with an (expensive) - * atomic RMW operation. Instead load-relaxed the current value - * and a store-release of the incremented value */ - uint32_t cur = odp_atomic_load_u32(&ticketlock->cur_ticket); - - odp_atomic_store_rel_u32(&ticketlock->cur_ticket, cur + 1); - + _odp_ticketlock_unlock(lock); } -int odp_ticketlock_is_locked(odp_ticketlock_t *ticketlock) +int odp_ticketlock_is_locked(odp_ticketlock_t *lock) { - /* Compare 'cur_ticket' with 'next_ticket'. Ideally we should read - * both variables atomically but the information can become stale - * immediately anyway so the function can only be used reliably in - * a quiescent system where non-atomic loads should not pose a - * problem */ - return odp_atomic_load_u32(&ticketlock->cur_ticket) != - odp_atomic_load_u32(&ticketlock->next_ticket); + return _odp_ticketlock_is_locked(lock); } -- 2.8.1