diff options
author | Petri Savolainen <petri.savolainen@nokia.com> | 2016-09-15 16:39:21 +0300 |
---|---|---|
committer | Maxim Uvarov <maxim.uvarov@linaro.org> | 2016-09-22 19:02:36 +0300 |
commit | 5f4f2e0da6e04637b6b4bd7aa6bb4d4d32680525 (patch) | |
tree | 5ea82c0aa89e2c191443729af222fca666e0d3a4 | |
parent | 92336dd2808af4826371d467588dcb81daafe4cf (diff) |
linux-gen: ticketlock: inline ticketlock implementation
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.savolainen@nokia.com>
Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org>
Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
-rw-r--r-- | platform/linux-generic/Makefile.am | 1 | ||||
-rw-r--r-- | platform/linux-generic/include/odp/api/plat/ticketlock_inlines.h | 87 | ||||
-rw-r--r-- | platform/linux-generic/odp_ticketlock.c | 68 |
3 files changed, 97 insertions, 59 deletions
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index e3c0f566c..900ac0861 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 000000000..957d22e44 --- /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 353af9af1..f18d78f57 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); } |