On 04/05/17 01:46, Ola Liljedahl wrote: > On 4 April 2017 at 21:25, Maxim Uvarov <maxim.uva...@linaro.org> wrote: >> it's better to have 2 separate files for that. One for ODP_CONFIG_LLDSCD > "better"? In what way? > >> defined and one for not. Also ODP_ prefix should not be used for >> internal things (not api). > OK this was not clear, some of the defines in odp_config_internal.h > use an ODP_ prefix, some not. You mean there is a system to that? > > Shouldn't those defines that are part of the API be declared/described > in the API header files (located in include/odp/api/spec)? How else do > you know that they are part of the API? And if they are part of the > API, how does the application (the 'A' in API) access the definitions > *and* their values? > > There are API's for querying about things like total number of queues > but those API's are separate and do not depend on some define with a > specific name. >
That is not api setting. It's linux-generic internal settings. ODP apps do not use that values. Maxim. >> >> Maxim. >> >> On 04/04/17 21:48, Brian Brooks wrote: >>> Signed-off-by: Ola Liljedahl <ola.liljed...@arm.com> >>> Reviewed-by: Brian Brooks <brian.bro...@arm.com> >>> --- >>> platform/linux-generic/include/odp_llqueue.h | 285 >>> +++++++++++++++++++++++++++ >>> 1 file changed, 285 insertions(+) >>> create mode 100644 platform/linux-generic/include/odp_llqueue.h >>> >>> diff --git a/platform/linux-generic/include/odp_llqueue.h >>> b/platform/linux-generic/include/odp_llqueue.h >>> new file mode 100644 >>> index 00000000..aa46ace3 >>> --- /dev/null >>> +++ b/platform/linux-generic/include/odp_llqueue.h >>> @@ -0,0 +1,285 @@ >>> +/* Copyright (c) 2017, ARM Limited. >>> + * All rights reserved. >>> + * >>> + * SPDX-License-Identifier: BSD-3-Clause >>> + */ >>> + >>> +#ifndef ODP_LLQUEUE_H_ >>> +#define ODP_LLQUEUE_H_ >>> + >>> +#include <odp/api/cpu.h> >>> +#include <odp/api/hints.h> >>> +#include <odp/api/spinlock.h> >>> + >>> +#include <odp_config_internal.h> >>> +#include <odp_debug_internal.h> >>> +#include <odp_llsc.h> >>> + >>> +#include <stdint.h> >>> +#include <stdlib.h> >>> + >>> +/****************************************************************************** >>> + * Linked list queues >>> + >>> *****************************************************************************/ >>> + >>> +/* The scalar equivalent of a double pointer */ >>> +#if __SIZEOF_PTRDIFF_T__ == 4 >>> +typedef uint64_t dintptr_t; >>> +#endif >>> +#if __SIZEOF_PTRDIFF_T__ == 8 >>> +typedef __int128 dintptr_t; >>> +#endif >>> + >>> +#define SENTINEL ((void *)~(uintptr_t)0) >>> + >>> +struct llnode { >>> + struct llnode *next; >>> +}; >>> + >>> +union llht { >>> + struct { >>> + struct llnode *head, *tail; >>> + } st; >>> + dintptr_t ui; >>> +}; >>> + >>> +struct llqueue { >>> + union llht u; >>> +#ifndef ODP_CONFIG_LLDSCD >>> + odp_spinlock_t lock; >>> +#endif >>> +}; >>> + >>> +static inline struct llnode *llq_head(struct llqueue *llq) >>> +{ >>> + return __atomic_load_n(&llq->u.st.head, __ATOMIC_RELAXED); >>> +} >>> + >>> +static inline void llqueue_init(struct llqueue *llq) >>> +{ >>> + llq->u.st.head = NULL; >>> + llq->u.st.tail = NULL; >>> +#ifndef ODP_CONFIG_LLDSCD >>> + odp_spinlock_init(&llq->lock); >>> +#endif >>> +} >>> + >>> +#ifdef ODP_CONFIG_LLDSCD >>> + >>> +static inline void llq_enqueue(struct llqueue *llq, struct llnode *node) >>> +{ >>> + union llht old, neu; >>> + >>> + ODP_ASSERT(node->next == NULL); >>> + node->next = SENTINEL; >>> + do { >>> + old.ui = lld(&llq->u.ui, __ATOMIC_RELAXED); >>> + neu.st.head = old.st.head == NULL ? node : old.st.head; >>> + neu.st.tail = node; >>> + } while (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELEASE))); >>> + if (old.st.tail != NULL) { >>> + /* List was not empty */ >>> + ODP_ASSERT(old.st.tail->next == SENTINEL); >>> + old.st.tail->next = node; >>> + } >>> +} >>> + >>> +#else >>> + >>> +static inline void llq_enqueue(struct llqueue *llq, struct llnode *node) >>> +{ >>> + ODP_ASSERT(node->next == NULL); >>> + node->next = SENTINEL; >>> + >>> + odp_spinlock_lock(&llq->lock); >>> + if (llq->u.st.head == NULL) { >>> + llq->u.st.head = node; >>> + llq->u.st.tail = node; >>> + } else { >>> + llq->u.st.tail->next = node; >>> + llq->u.st.tail = node; >>> + } >>> + odp_spinlock_unlock(&llq->lock); >>> +} >>> + >>> +#endif >>> + >>> +#ifdef ODP_CONFIG_LLDSCD >>> + >>> +static inline struct llnode *llq_dequeue(struct llqueue *llq) >>> +{ >>> + struct llnode *head; >>> + union llht old, neu; >>> + >>> + /* llq_dequeue() may be used in a busy-waiting fashion >>> + * Read head using plain load to avoid disturbing remote LL/SC >>> + */ >>> + head = __atomic_load_n(&llq->u.st.head, __ATOMIC_ACQUIRE); >>> + if (head == NULL) >>> + return NULL; >>> + /* Read head->next before LL to minimize cache miss latency >>> + * in LL/SC below >>> + */ >>> + (void)__atomic_load_n(&head->next, __ATOMIC_RELAXED); >>> + >>> + do { >>> + old.ui = lld(&llq->u.ui, __ATOMIC_RELAXED); >>> + if (odp_unlikely(old.st.head == NULL)) { >>> + /* Empty list */ >>> + return NULL; >>> + } else if (odp_unlikely(old.st.head == old.st.tail)) { >>> + /* Single-element in list */ >>> + neu.st.head = NULL; >>> + neu.st.tail = NULL; >>> + } else { >>> + /* Multi-element list, dequeue head */ >>> + struct llnode *next; >>> + /* Wait until llq_enqueue() has written true next >>> + * pointer >>> + */ >>> + while ((next = __atomic_load_n(&old.st.head->next, >>> + __ATOMIC_RELAXED)) == >>> + SENTINEL) >>> + odp_cpu_pause(); >>> + neu.st.head = next; >>> + neu.st.tail = old.st.tail; >>> + } >>> + } while (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELAXED))); >>> + old.st.head->next = NULL; >>> + return old.st.head; >>> +} >>> + >>> +#else >>> + >>> +static inline struct llnode *llq_dequeue(struct llqueue *llq) >>> +{ >>> + struct llnode *head; >>> + struct llnode *node = NULL; >>> + >>> + head = __atomic_load_n(&llq->u.st.head, __ATOMIC_RELAXED); >>> + if (head == NULL) >>> + return NULL; >>> + >>> + odp_spinlock_lock(&llq->lock); >>> + if (llq->u.st.head != NULL) { >>> + node = llq->u.st.head; >>> + if (llq->u.st.head == llq->u.st.tail) { >>> + ODP_ASSERT(node->next == SENTINEL); >>> + llq->u.st.head = NULL; >>> + llq->u.st.tail = NULL; >>> + } else { >>> + ODP_ASSERT(node->next != SENTINEL); >>> + llq->u.st.head = node->next; >>> + } >>> + node->next = NULL; >>> + } >>> + odp_spinlock_unlock(&llq->lock); >>> + return node; >>> +} >>> + >>> +#endif >>> + >>> +#ifdef ODP_CONFIG_LLDSCD >>> + >>> +static inline odp_bool_t llq_dequeue_cond(struct llqueue *llq, >>> + struct llnode *exp) >>> +{ >>> + union llht old, neu; >>> + >>> + do { >>> + old.ui = lld(&llq->u.ui, __ATOMIC_ACQUIRE); >>> + if (odp_unlikely(old.st.head == NULL || old.st.head != exp)) { >>> + /* Empty list or wrong head */ >>> + return false; >>> + } else if (odp_unlikely(old.st.head == old.st.tail)) { >>> + /* Single-element in list */ >>> + neu.st.head = NULL; >>> + neu.st.tail = NULL; >>> + } else { >>> + /* Multi-element list, dequeue head */ >>> + struct llnode *next; >>> + >>> + /* Wait until llq_enqueue() has written true next >>> + * pointer */ >>> + while ((next = __atomic_load_n(&old.st.head->next, >>> + __ATOMIC_RELAXED)) == >>> + SENTINEL) >>> + odp_cpu_pause(); >>> + >>> + neu.st.head = next; >>> + neu.st.tail = old.st.tail; >>> + } >>> + } while (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELAXED))); >>> + old.st.head->next = NULL; >>> + return true; >>> +} >>> + >>> +#else >>> + >>> +static inline odp_bool_t llq_dequeue_cond(struct llqueue *llq, >>> + struct llnode *node) >>> +{ >>> + odp_bool_t success = false; >>> + >>> + odp_spinlock_lock(&llq->lock); >>> + if (odp_likely(llq->u.st.head != NULL && llq->u.st.head == node)) { >>> + success = true; >>> + if (llq->u.st.head == llq->u.st.tail) { >>> + ODP_ASSERT(node->next == SENTINEL); >>> + llq->u.st.head = NULL; >>> + llq->u.st.tail = NULL; >>> + } else { >>> + ODP_ASSERT(node->next != SENTINEL); >>> + llq->u.st.head = node->next; >>> + } >>> + node->next = NULL; >>> + } >>> + odp_spinlock_unlock(&llq->lock); >>> + return success; >>> +} >>> + >>> +#endif >>> + >>> +#ifdef ODP_CONFIG_LLDSCD >>> + >>> +/* If 'node' is a head of llq then move it to tail */ >>> +static inline odp_bool_t llq_cond_rotate(struct llqueue *llq, >>> + struct llnode *node) >>> +{ >>> + /* Difficult to make this into a single atomic operation >>> + * Instead use existing primitives. >>> + */ >>> + if (odp_likely(llq_dequeue_cond(llq, node))) { >>> + llq_enqueue(llq, node); >>> + return true; >>> + } >>> + return false; >>> +} >>> + >>> +#else >>> + >>> +/* If 'node' is a head of llq then move it to tail */ >>> +static inline odp_bool_t llq_cond_rotate(struct llqueue *llq, >>> + struct llnode *node) >>> +{ >>> + odp_bool_t success = false; >>> + >>> + odp_spinlock_lock(&llq->lock); >>> + if (odp_likely(llq->u.st.head == node)) { >>> + success = true; >>> + if (llq->u.st.tail != node) { >>> + ODP_ASSERT(node->next != SENTINEL); >>> + llq->u.st.head = node->next; >>> + llq->u.st.tail->next = node; >>> + llq->u.st.tail = node; >>> + node->next = SENTINEL; >>> + } >>> + /* Else 'node' is only element on list => nothing to do */ >>> + } >>> + odp_spinlock_unlock(&llq->lock); >>> + return success; >>> +} >>> + >>> +#endif >>> + >>> +#endif >>> >>