diff mbox series

[API-NEXT,1/4] helper: cuckootable: Specify queue ring_size

Message ID 20170328192330.62599-1-brian.brooks@arm.com
State Superseded
Headers show
Series [API-NEXT,1/4] helper: cuckootable: Specify queue ring_size | expand

Commit Message

Brian Brooks March 28, 2017, 7:23 p.m. UTC
From: Ola Liljedahl <ola.liljedahl@arm.com>


Signed-off-by: Ola Liljedahl <ola.liljedahl@arm.com>

Reviewed-by: Brian Brooks <brian.brooks@arm.com>

Reviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>

---
 helper/cuckootable.c | 1 +
 1 file changed, 1 insertion(+)

-- 
2.12.1

Comments

Bill Fischofer March 28, 2017, 11:50 p.m. UTC | #1
This part generates numerous checkpatch warnings and errors. Please
run checkpatch and correct for v2.

Also, this part introduces a number of errors that result in failure
to compile using clang. Please test with both gcc and clang to ensure
that it compiles cleanly for both (gcc looks fine)

Specific clang issues:
  CC       odp_packet.lo
odp_packet.c:656:9: error: cast from 'odp_buffer_t' (aka
'_odp_abi_buffer_t *') to 'odp_buffer_hdr_t *' (aka 'struct
odp_buffer_hdr_t *') increases required alignment from 1 to 8
[-Werror,-Wcast-align]
        return (odp_buffer_hdr_t *)(_odp_packet_to_buffer(pkt));
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

clang requires an intermediate cast to (void *) to avoid these warnings.

1 error generated.
Makefile:1004: recipe for target 'odp_packet.lo' failed


clang also generates numerous link errors:

  CC       odp_bench_packet-odp_bench_packet.o
make[3]: *** No rule to make target '../../../lib/libodp-linux.la',
needed by 'odp_bench_packet'.

.  CC       atomic_main.o
make[5]: *** No rule to make target
'../../../../../lib/libodp-linux.la', needed by 'atomic_main'.

  CC       classification_main.o
make[5]: *** No rule to make target
'../../../../../lib/libodp-linux.la', needed by 'classification_main'.

...and many others like this.

On Tue, Mar 28, 2017 at 2:23 PM, Brian Brooks <brian.brooks@arm.com> wrote:
> This work derives from Ola Liljedahl's prototype [1] which introduced a

> scalable scheduler design based on primarily lock-free algorithms and

> data structures designed to decrease contention. A thread searches

> through a data structure containing only queues that are both non-empty

> and allowed to be scheduled to that thread. Strict priority scheduling is

> respected, and (W)RR scheduling may be used within queues of the same priority.

> Lastly, pre-scheduling or stashing is not employed since it is optional

> functionality that can be implemented in the application.

>

> In addition to scalable ring buffers, the algorithm also uses unbounded

> concurrent queues. LL/SC and CAS variants exist in cases where absense of

> ABA problem cannot be proved, and also in cases where the compiler's atomic

> built-ins may not be lowered to the desired instruction(s). Finally, a version

> of the algorithm that uses locks is also provided.

>

> See platform/linux-generic/include/odp_config_internal.h for further build

> time configuration.

>

> Use --enable-schedule-scalable to conditionally compile this scheduler

> into the library.

>

> [1] https://lists.linaro.org/pipermail/lng-odp/2016-September/025682.html

>

> Signed-off-by: Brian Brooks <brian.brooks@arm.com>

> Signed-off-by: Kevin Wang <kevin.wang@arm.com>

> Signed-off-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>

> Signed-off-by: Ola Liljedahl <ola.liljedahl@arm.com>

> ---

>  platform/linux-generic/Makefile.am                 |   21 +-

>  .../include/odp/api/plat/schedule_types.h          |   20 +-

>  platform/linux-generic/include/odp_atomic16.h      |  244 +++

>  platform/linux-generic/include/odp_bitset.h        |  155 ++

>  .../linux-generic/include/odp_config_internal.h    |   90 +-

>  platform/linux-generic/include/odp_internal.h      |    2 +

>  platform/linux-generic/include/odp_llqueue.h       |  386 ++++

>  platform/linux-generic/include/odp_llsc.h          |  325 ++++

>  .../linux-generic/include/odp_packet_internal.h    |    3 +

>  .../linux-generic/include/odp_queue_internal.h     |  122 +-

>  platform/linux-generic/include/odp_schedule_if.h   |  166 +-

>  .../include/odp_schedule_ordered_internal.h        |  150 ++

>  platform/linux-generic/m4/odp_schedule.m4          |   55 +-

>  platform/linux-generic/odp_classification.c        |    4 +-

>  platform/linux-generic/odp_packet.c                |    5 +

>  platform/linux-generic/odp_packet_io.c             |   88 +-

>  platform/linux-generic/odp_queue.c                 |    2 +-

>  platform/linux-generic/odp_queue_scalable.c        |  944 ++++++++++

>  platform/linux-generic/odp_schedule_if.c           |   36 +-

>  platform/linux-generic/odp_schedule_scalable.c     | 1959 ++++++++++++++++++++

>  .../linux-generic/odp_schedule_scalable_ordered.c  |  298 +++

>  platform/linux-generic/odp_traffic_mngr.c          |    7 +-

>  platform/linux-generic/pktio/loop.c                |   11 +-

>  test/common_plat/performance/odp_sched_latency.c   |   69 +-

>  test/common_plat/performance/odp_scheduling.c      |   12 +-

>  .../api/classification/odp_classification_basic.c  |    8 +-

>  .../classification/odp_classification_test_pmr.c   |   42 +-

>  .../validation/api/scheduler/scheduler.c           |   11 +-

>  test/common_plat/validation/api/timer/timer.c      |    5 +-

>  29 files changed, 5123 insertions(+), 117 deletions(-)

>  create mode 100644 platform/linux-generic/include/odp_atomic16.h

>  create mode 100644 platform/linux-generic/include/odp_bitset.h

>  create mode 100644 platform/linux-generic/include/odp_llqueue.h

>  create mode 100644 platform/linux-generic/include/odp_llsc.h

>  create mode 100644 platform/linux-generic/include/odp_schedule_ordered_internal.h

>  create mode 100644 platform/linux-generic/odp_queue_scalable.c

>  create mode 100644 platform/linux-generic/odp_schedule_scalable.c

>  create mode 100644 platform/linux-generic/odp_schedule_scalable_ordered.c

>

> diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am

> index 70683cac..8c263b99 100644

> --- a/platform/linux-generic/Makefile.am

> +++ b/platform/linux-generic/Makefile.am

> @@ -151,6 +151,8 @@ noinst_HEADERS = \

>                   ${srcdir}/include/odp_debug_internal.h \

>                   ${srcdir}/include/odp_forward_typedefs_internal.h \

>                   ${srcdir}/include/odp_internal.h \

> +                 ${srcdir}/include/odp_llqueue.h \

> +                 ${srcdir}/include/odp_llsc.h \

>                   ${srcdir}/include/odp_name_table_internal.h \

>                   ${srcdir}/include/odp_packet_internal.h \

>                   ${srcdir}/include/odp_packet_io_internal.h \

> @@ -219,13 +221,9 @@ __LIB__libodp_linux_la_SOURCES = \

>                            pktio/ring.c \

>                            odp_pkt_queue.c \

>                            odp_pool.c \

> -                          odp_queue.c \

>                            odp_rwlock.c \

>                            odp_rwlock_recursive.c \

> -                          odp_schedule.c \

>                            odp_schedule_if.c \

> -                          odp_schedule_sp.c \

> -                          odp_schedule_iquery.c \

>                            odp_shared_memory.c \

>                            odp_sorted_list.c \

>                            odp_spinlock.c \

> @@ -250,6 +248,21 @@ __LIB__libodp_linux_la_SOURCES = \

>                            arch/@ARCH_DIR@/odp_cpu_arch.c \

>                            arch/@ARCH_DIR@/odp_sysinfo_parse.c

>

> +if ODP_SCHEDULE_SP

> +__LIB__libodp_linux_la_SOURCES += odp_schedule_sp.c

> +endif

> +

> +if ODP_SCHEDULE_IQUERY

> +__LIB__libodp_linux_la_SOURCES += odp_schedule_iquery.c

> +endif

> +

> +if ODP_SCHEDULE_SCALABLE

> +__LIB__libodp_linux_la_SOURCES += odp_queue_scalable.c odp_schedule_scalable.c \

> +                                 odp_schedule_scalable_ordered.c

> +else

> +__LIB__libodp_linux_la_SOURCES += odp_queue.c odp_schedule.c

> +endif

> +

>  if HAVE_PCAP

>  __LIB__libodp_linux_la_SOURCES += pktio/pcap.c

>  endif

> diff --git a/platform/linux-generic/include/odp/api/plat/schedule_types.h b/platform/linux-generic/include/odp/api/plat/schedule_types.h

> index 535fd6d0..d9bb39a6 100644

> --- a/platform/linux-generic/include/odp/api/plat/schedule_types.h

> +++ b/platform/linux-generic/include/odp/api/plat/schedule_types.h

> @@ -18,6 +18,8 @@

>  extern "C" {

>  #endif

>

> +#include <odp/api/std_types.h>

> +

>  /** @addtogroup odp_scheduler

>   *  @{

>   */

> @@ -27,6 +29,20 @@ extern "C" {

>

>  typedef int odp_schedule_prio_t;

>

> +#ifdef ODP_SCHEDULE_SCALABLE

> +

> +#define ODP_SCHED_PRIO_NUM  8

> +

> +#define ODP_SCHED_PRIO_HIGHEST 0

> +

> +#define ODP_SCHED_PRIO_LOWEST (ODP_SCHED_PRIO_NUM - 1)

> +

> +#define ODP_SCHED_PRIO_DEFAULT (ODP_SCHED_PRIO_NUM / 2)

> +

> +#define ODP_SCHED_PRIO_NORMAL ODP_SCHED_PRIO_DEFAULT

> +

> +#else

> +

>  #define ODP_SCHED_PRIO_HIGHEST  0

>

>  #define ODP_SCHED_PRIO_NORMAL   4

> @@ -35,6 +51,8 @@ typedef int odp_schedule_prio_t;

>

>  #define ODP_SCHED_PRIO_DEFAULT  ODP_SCHED_PRIO_NORMAL

>

> +#endif

> +

>  typedef int odp_schedule_sync_t;

>

>  #define ODP_SCHED_SYNC_PARALLEL 0

> @@ -44,7 +62,7 @@ typedef int odp_schedule_sync_t;

>  typedef int odp_schedule_group_t;

>

>  /* These must be kept in sync with thread_globals_t in odp_thread.c */

> -#define ODP_SCHED_GROUP_INVALID -1

> +#define ODP_SCHED_GROUP_INVALID ((odp_schedule_group_t) -1)

>  #define ODP_SCHED_GROUP_ALL     0

>  #define ODP_SCHED_GROUP_WORKER  1

>  #define ODP_SCHED_GROUP_CONTROL 2

> diff --git a/platform/linux-generic/include/odp_atomic16.h b/platform/linux-generic/include/odp_atomic16.h

> new file mode 100644

> index 00000000..5afd66c5

> --- /dev/null

> +++ b/platform/linux-generic/include/odp_atomic16.h

> @@ -0,0 +1,244 @@

> +/* Copyright (c) 2017, ARM Limited.

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#ifndef _ODP_ATOMIC16_H_

> +#define _ODP_ATOMIC16_H_

> +

> +#include "odp_llsc.h"

> +

> +#if defined __ARM_ARCH && __ARM_ARCH == 8

> +

> +#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */

> +static inline __int128 casp(__int128 *var, __int128 old, __int128 neu, int mo)

> +{

> +       if (mo == __ATOMIC_RELAXED) {

> +               __asm __volatile("casp %0, %H0, %1, %H1, [%2]"

> +                                : "+r" (old)

> +                                : "r" (neu), "r" (var)

> +                                : "memory");

> +       } else if (mo == __ATOMIC_ACQUIRE) {

> +               __asm __volatile("caspa %0, %H0, %1, %H1, [%2]"

> +                                : "+r" (old)

> +                                : "r" (neu), "r" (var)

> +                                : "memory");

> +       } else if (mo == __ATOMIC_ACQ_REL) {

> +               __asm __volatile("caspal %0, %H0, %1, %H1, [%2]"

> +                                : "+r" (old)

> +                                : "r" (neu), "r" (var)

> +                                : "memory");

> +       } else if (mo == __ATOMIC_RELEASE) {

> +               __asm __volatile("caspl %0, %H0, %1, %H1, [%2]"

> +                                : "+r" (old)

> +                                : "r" (neu), "r" (var)

> +                                : "memory");

> +       } else {

> +               abort();

> +       }

> +       return old;

> +}

> +#endif

> +

> +static inline bool __atomic_compare_exchange_16(register __int128 *var,

> +                       __int128 *exp, register __int128 neu,

> +                       bool weak, int mo_success, int mo_failure)

> +{

> +#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */

> +       (void)weak;

> +       (void)mo_failure;

> +       __int128 old;

> +       __int128 expected;

> +

> +       expected = *exp;

> +       old = casp(var, expected, neu, mo_success);

> +       *exp = old; /* Always update, atomically read value */

> +       return old == expected;

> +#else

> +       (void)weak; /* Always do strong CAS or we can't perform atomic read */

> +       /* Ignore memory ordering for failure, memory order for

> +        * success must be stronger or equal

> +        */

> +       (void)mo_failure;

> +       int ll_mo;

> +       int sc_mo;

> +

> +       register __int128 old;

> +       register __int128 expected;

> +

> +       ll_mo = mo_success == __ATOMIC_ACQUIRE ||

> +               mo_success == __ATOMIC_ACQ_REL ?

> +               __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;

> +

> +       sc_mo = mo_success == __ATOMIC_RELEASE ||

> +               mo_success == __ATOMIC_ACQ_REL ?

> +               __ATOMIC_RELEASE : __ATOMIC_RELAXED;

> +

> +       expected = *exp;

> +       __asm __volatile("" ::: "memory");

> +       do {

> +               /* Atomicity of LLD is not guaranteed */

> +               old = lld(var, ll_mo);

> +               /* Must write back neu or old to verify atomicity of LLD */

> +       } while (odp_unlikely(scd(var, old == expected ? neu : old, sc_mo)));

> +       *exp = old; /* Always update, atomically read value */

> +       return old == expected;

> +#endif

> +}

> +

> +static inline bool __atomic_compare_exchange_16_frail(register __int128 *var,

> +                       __int128 *exp, register __int128 neu, bool weak,

> +                       int mo_success, int mo_failure)

> +{

> +#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */

> +       (void)weak;

> +       (void)mo_failure;

> +       __int128 old;

> +       __int128 expected;

> +

> +       expected = *exp;

> +       old = casp(var, expected, neu, mo_success);

> +       *exp = old; /* Always update, atomically read value */

> +       return old == expected;

> +#else

> +       (void)weak; /* Weak CAS and non-atomic load on failure */

> +       (void)mo_failure; /* Ignore memory ordering for failure */

> +       int ll_mo;

> +       int sc_mo;

> +       register __int128 expected;

> +       register __int128 old;

> +

> +       /* memory order for success must be stronger or equal */

> +       ll_mo = mo_success == __ATOMIC_ACQUIRE ||

> +               mo_success == __ATOMIC_ACQ_REL ?

> +               __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;

> +       sc_mo = mo_success == __ATOMIC_RELEASE ||

> +               mo_success == __ATOMIC_ACQ_REL ?

> +               __ATOMIC_RELEASE : __ATOMIC_RELAXED;

> +       expected = *exp;

> +       __asm __volatile("" ::: "memory");

> +       /* Atomicity of LLD is not guaranteed */

> +       old = lld(var, ll_mo);

> +       if (odp_likely(old == expected && !scd(var, neu, sc_mo))) {

> +               /* Right value and SC succeeded */

> +               __asm __volatile("" ::: "memory");

> +               return 1;

> +       }

> +       __asm __volatile("" ::: "memory");

> +       /* Wrong value or SC failed */

> +       *exp = old; /* Old possibly torn value */

> +       return 0; /* Failure, *exp updated */

> +#endif

> +}

> +

> +static inline __int128 __atomic_load_16(__int128 *var, int mo)

> +{

> +       __int128 old = *var; /* Possibly torn read */

> +

> +       /* Do CAS to ensure atomicity

> +        * Either CAS succeeds (writing back the same value)

> +        * Or CAS fails and returns the old value (atomic read)

> +        */

> +       (void)__atomic_compare_exchange_n(var,

> +                       &old,

> +                       old,

> +                       false, /* weak= */

> +                       mo,

> +                       mo);

> +       return old;

> +}

> +

> +static inline __int128 __atomic_exchange_16(__int128 *var,

> +                                           __int128 neu, int mo)

> +{

> +#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */

> +       __int128 old;

> +       __int128 expected;

> +

> +       do {

> +               expected = *var;

> +               old = casp(var, expected, neu, mo);

> +       } while (old != expected);

> +       return old;

> +#else

> +       int ll_mo;

> +       int sc_mo;

> +       register __int128 old;

> +

> +       ll_mo = mo == __ATOMIC_ACQUIRE || mo == __ATOMIC_ACQ_REL ?

> +               __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;

> +       sc_mo = mo == __ATOMIC_RELEASE || mo == __ATOMIC_ACQ_REL ?

> +               __ATOMIC_RELEASE : __ATOMIC_RELAXED;

> +       do {

> +               /* Atomicity of LLD is not guaranteed */

> +               old = lld(var, ll_mo);

> +               /* Must successfully write back to verify atomicity of LLD */

> +       } while (odp_unlikely(scd(var, neu, sc_mo)));

> +       return old;

> +#endif

> +}

> +

> +static inline __int128 __atomic_fetch_and_16(__int128 *var,

> +                                            __int128 mask, int mo)

> +{

> +#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */

> +       __int128 old;

> +       __int128 expected;

> +

> +       do {

> +               expected = *var;

> +               old = casp(var, expected, expected & mask, mo);

> +       } while (old != expected);

> +       return old;

> +#else

> +       int ll_mo;

> +       int sc_mo;

> +       register __int128 old;

> +

> +       ll_mo = mo == __ATOMIC_ACQUIRE || mo == __ATOMIC_ACQ_REL ?

> +                       __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;

> +       sc_mo = mo == __ATOMIC_RELEASE || mo == __ATOMIC_ACQ_REL ?

> +                       __ATOMIC_RELEASE : __ATOMIC_RELAXED;

> +       do {

> +               /* Atomicity of LLD is not guaranteed */

> +               old = lld(var, ll_mo);

> +               /* Must successfully write back to verify atomicity of LLD */

> +       } while (odp_unlikely(scd(var, old & mask, sc_mo)));

> +       return old;

> +#endif

> +}

> +

> +static inline __int128 __atomic_fetch_or_16(__int128 *var,

> +                       __int128 mask,

> +                       int mo)

> +{

> +#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */

> +       __int128 old;

> +       __int128 expected;

> +

> +       do {

> +               expected = *var;

> +               old = casp(var, expected, expected | mask, mo);

> +       } while (old != expected);

> +       return old;

> +#else

> +       int ll_mo;

> +       int sc_mo;

> +       register __int128 old;

> +

> +       ll_mo = mo == __ATOMIC_ACQUIRE || mo == __ATOMIC_ACQ_REL ?

> +                       __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;

> +       sc_mo = mo == __ATOMIC_RELEASE || mo == __ATOMIC_ACQ_REL ?

> +                       __ATOMIC_RELEASE : __ATOMIC_RELAXED;

> +       do {

> +               /* Atomicity of LLD is not guaranteed */

> +               old = lld(var, ll_mo);

> +               /* Must successfully write back to verify atomicity of LLD */

> +       } while (odp_unlikely(scd(var, old | mask, sc_mo)));

> +       return old;

> +#endif

> +}

> +

> +#endif

> +#endif

> diff --git a/platform/linux-generic/include/odp_bitset.h b/platform/linux-generic/include/odp_bitset.h

> new file mode 100644

> index 00000000..db004267

> --- /dev/null

> +++ b/platform/linux-generic/include/odp_bitset.h

> @@ -0,0 +1,155 @@

> +/* Copyright (c) 2017, ARM Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#ifndef _ODP_BITSET_H_

> +#define _ODP_BITSET_H_

> +

> +/******************************************************************************

> + * bitset abstract data type

> + *****************************************************************************/

> +/* This could be a struct of scalars to support larger bit sets */

> +

> +#if ATOM_BITSET_SIZE <= 32

> +

> +typedef uint32_t bitset_t;

> +

> +static inline bitset_t bitset_mask(uint32_t bit)

> +{

> +       return 1UL << bit;

> +}

> +

> +/* Return first-bit-set with StdC ffs() semantics */

> +static inline uint32_t bitset_ffs(bitset_t b)

> +{

> +       return __builtin_ffsl(b);

> +}

> +

> +/* Load-exclusive with memory ordering */

> +static inline bitset_t bitset_ldex(bitset_t *bs, int mo)

> +{

> +       return LDXR32(bs, mo);

> +}

> +

> +#elif ATOM_BITSET_SIZE <= 64

> +

> +typedef uint64_t bitset_t;

> +

> +static inline bitset_t bitset_mask(uint32_t bit)

> +{

> +       return 1ULL << bit;

> +}

> +

> +/* Return first-bit-set with StdC ffs() semantics */

> +static inline uint32_t bitset_ffs(bitset_t b)

> +{

> +       return __builtin_ffsll(b);

> +}

> +

> +/* Load-exclusive with memory ordering */

> +static inline bitset_t bitset_ldex(bitset_t *bs, int mo)

> +{

> +       return LDXR64(bs, mo);

> +}

> +

> +#elif ATOM_BITSET_SIZE <= 128

> +

> +#if __SIZEOF_INT128__ == 16

> +typedef unsigned __int128 bitset_t;

> +

> +static inline bitset_t bitset_mask(uint32_t bit)

> +{

> +       if (bit < 64)

> +               return 1ULL << bit;

> +       else

> +               return (unsigned __int128)(1ULL << (bit - 64)) << 64;

> +}

> +

> +/* Return first-bit-set with StdC ffs() semantics */

> +static inline uint32_t bitset_ffs(bitset_t b)

> +{

> +       if ((uint64_t)b != 0)

> +               return __builtin_ffsll((uint64_t)b);

> +       else if ((b >> 64) != 0)

> +               return __builtin_ffsll((uint64_t)(b >> 64)) + 64;

> +       else

> +               return 0;

> +}

> +

> +/* Load-exclusive with memory ordering */

> +static inline bitset_t bitset_ldex(bitset_t *bs, int mo)

> +{

> +       return LDXR128(bs, mo);

> +}

> +

> +#else

> +#error __int128 not supported by compiler

> +#endif

> +

> +#else

> +#error Unsupported size of bit sets (ATOM_BITSET_SIZE)

> +#endif

> +

> +/* Atomic load with memory ordering */

> +static inline bitset_t atom_bitset_load(bitset_t *bs, int mo)

> +{

> +       return __atomic_load_n(bs, mo);

> +}

> +

> +/* Atomic bit set with memory ordering */

> +static inline void atom_bitset_set(bitset_t *bs, uint32_t bit, int mo)

> +{

> +       (void)__atomic_fetch_or(bs, bitset_mask(bit), mo);

> +}

> +

> +/* Atomic bit clear with memory ordering */

> +static inline void atom_bitset_clr(bitset_t *bs, uint32_t bit, int mo)

> +{

> +       (void)__atomic_fetch_and(bs, ~bitset_mask(bit), mo);

> +}

> +

> +/* Atomic exchange with memory ordering */

> +static inline bitset_t atom_bitset_xchg(bitset_t *bs, bitset_t neu, int mo)

> +{

> +       return __atomic_exchange_n(bs, neu, mo);

> +}

> +

> +/* Return a & ~b */

> +static inline bitset_t bitset_andn(bitset_t a, bitset_t b)

> +{

> +       return a & ~b;

> +}

> +

> +static inline bool bitset_is_eql(bitset_t a, bitset_t b)

> +{

> +       return a == b;

> +}

> +

> +static inline bitset_t bitset_clr(bitset_t bs, uint32_t bit)

> +{

> +       return bs & ~bitset_mask(bit);

> +}

> +

> +static inline bitset_t bitset_set(bitset_t bs, uint32_t bit)

> +{

> +       return bs | bitset_mask(bit);

> +}

> +

> +static inline bitset_t bitset_null(void)

> +{

> +       return 0U;

> +}

> +

> +static inline bool bitset_is_null(bitset_t a)

> +{

> +       return a == 0U;

> +}

> +

> +static inline bool bitset_is_set(bitset_t a, uint32_t bit)

> +{

> +       return (a & bitset_mask(bit)) != 0;

> +}

> +

> +#endif

> diff --git a/platform/linux-generic/include/odp_config_internal.h b/platform/linux-generic/include/odp_config_internal.h

> index dadd59e7..b1ee48f2 100644

> --- a/platform/linux-generic/include/odp_config_internal.h

> +++ b/platform/linux-generic/include/odp_config_internal.h

> @@ -22,6 +22,13 @@ extern "C" {

>  #define ODP_CONFIG_QUEUES 1024

>

>  /*

> + * Maximum queue depth. Maximum number of elements that can be stored in a

> + * queue. This value is used only when the size is not explicitly provided

> + * during queue creation.

> + */

> +#define ODP_CONFIG_QUEUE_SIZE 4096

> +

> +/*

>   * Maximum number of ordered locks per queue

>   */

>  #define CONFIG_QUEUE_MAX_ORD_LOCKS 4

> @@ -104,7 +111,7 @@ extern "C" {

>   *

>   * This the the number of separate SHM areas that can be reserved concurrently

>   */

> -#define ODP_CONFIG_SHM_BLOCKS (ODP_CONFIG_POOLS + 48)

> +#define ODP_CONFIG_SHM_BLOCKS (ODP_CONFIG_POOLS + ODP_CONFIG_QUEUES + 48)

>

>  /*

>   * Size of the virtual address space pre-reserver for ISHM

> @@ -120,7 +127,7 @@ extern "C" {

>   *

>   * This the the number of separate SHM areas that can be reserved concurrently

>   */

> -#define ODPDRV_CONFIG_SHM_BLOCKS 48

> +#define ODPDRV_CONFIG_SHM_BLOCKS ODP_CONFIG_SHM_BLOCKS

>

>  /* Maximum event burst size

>   *

> @@ -129,6 +136,21 @@ extern "C" {

>   */

>  #define CONFIG_BURST_SIZE 16

>

> +/* Default weight (in events) for WRR in scalable scheduler

> + *

> + * This controls the per-queue weight for WRR between queues of the same

> + * priority in the scalable scheduler

> + * A higher value improves throughput while a lower value increases fairness

> + * and thus likely decreases latency

> + *

> + * If WRR is undesired, set the value to ~0 which will use the largest possible

> + * weight

> + *

> + * Note: an API for specifying this on a per-queue basis would be useful but is

> + * not yet available

> + */

> +#define CONFIG_WRR_WEIGHT 64

> +

>  /*

>   * Maximum number of events in a pool

>   */

> @@ -139,6 +161,70 @@ extern "C" {

>   */

>  #define CONFIG_POOL_CACHE_SIZE 256

>

> +/*

> + * Split queue producer/consumer metadata into separate cache lines.

> + * This is beneficial on e.g. Cortex-A57 but not so much on A53.

> + */

> +#define ODP_CONFIG_USE_SPLIT_PRODCONS

> +

> +/*

> + * Split queue read/write metadata into separate cache lines.

> + * This enhances scalability even further on Cortex-A57.

> + */

> +#define ODP_CONFIG_USE_SPLIT_READWRITE

> +

> +/*

> + * Use locks to protect queue (ring buffer) and scheduler state updates

> + * On x86, this decreases overhead but also degrades scalability

> + */

> +#ifndef __ARM_ARCH

> +#define CONFIG_QSCHST_LOCK

> +#endif

> +

> +#ifdef CONFIG_QSCHST_LOCK

> +/* Keep all ring buffer/qschst data together when using locks

> + */

> +#undef ODP_CONFIG_USE_SPLIT_PRODCONS

> +#undef ODP_CONFIG_USE_SPLIT_READWRITE

> +#endif

> +

> +/*

> + * Use spin lock instead of (lock-free) atomic operations in llqueue

> + * This is recommended on architectures which implement CAS instead

> + * of LL/SC as CAS is susceptible to the ABA problem

> + */

> +#ifndef __ARM_ARCH

> +#define ODP_CONFIG_LLQ_LOCK

> +#endif

> +

> +/*

> + * Size of atomic bit set. This limits the max number of threads,

> + * scheduler groups and reorder windows. On ARMv8/64-bit and x86-64, the

> + * (lock-free) max is 128

> + */

> +#define ATOM_BITSET_SIZE 64

> +

> +/*

> + * Use LL/SC atomic primitives instead of __atomic_compare_exchange built-ins

> + */

> +#ifdef __ARM_ARCH

> +#define ODP_CONFIG_USE_LLSC

> +#endif

> +

> +/*

> + * Use DMB;STR instead of STRL on ARM

> + */

> +#ifdef __ARM_ARCH

> +#define ODP_CONFIG_USE_DMB

> +#endif

> +

> +/*

> + * Use ARM event signalling mechanism

> + */

> +#ifdef __ARM_ARCH

> +#define ODP_CONFIG_USE_WFE

> +#endif

> +

>  #ifdef __cplusplus

>  }

>  #endif

> diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h

> index 05c8a422..60eb9daa 100644

> --- a/platform/linux-generic/include/odp_internal.h

> +++ b/platform/linux-generic/include/odp_internal.h

> @@ -28,6 +28,8 @@ extern __thread int __odp_errno;

>

>  #define MAX_CPU_NUMBER 128

>

> +#define IS_POWER_TWO(x) ((((x) - 1) & (x)) == 0)

> +

>  typedef struct {

>         uint64_t cpu_hz_max[MAX_CPU_NUMBER];

>         uint64_t page_size;

> diff --git a/platform/linux-generic/include/odp_llqueue.h b/platform/linux-generic/include/odp_llqueue.h

> new file mode 100644

> index 00000000..6f20c641

> --- /dev/null

> +++ b/platform/linux-generic/include/odp_llqueue.h

> @@ -0,0 +1,386 @@

> +/* 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

> + *****************************************************************************/

> +

> +#if defined(__ARM_ARCH) && !defined(ODP_CONFIG_USE_LLSC) && \

> +       !defined(ODP_CONFIG_LLQ_LOCK)

> +#error ODP_CONFIG_USE_LLSC required on ARM for double-word atomics if not \

> +       using spinlock

> +#endif

> +

> +/* 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;

> +#ifdef ODP_CONFIG_LLQ_LOCK

> +       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;

> +#ifdef ODP_CONFIG_LLQ_LOCK

> +       odp_spinlock_init(&llq->lock);

> +#endif

> +}

> +

> +#ifndef ODP_CONFIG_LLQ_LOCK

> +

> +static inline void llq_enqueue(struct llqueue *llq, struct llnode *node)

> +{

> +       union llht old;

> +       union llht neu;

> +

> +       ODP_ASSERT(node->next == NULL);

> +       node->next = SENTINEL;

> +#ifdef ODP_CONFIG_USE_LLSC

> +       /* Prefetch for store for faster LL/SC execution */

> +       __builtin_prefetch(&llq->u.ui, 1, 0);

> +retry: /* Failed SC requires new LL */

> +       old.ui = lld(&llq->u.ui, __ATOMIC_RELAXED);

> +#else

> +       __atomic_load(&llq->u, &old, __ATOMIC_RELAXED);

> +retry: /* Failed CAS returns existing value */

> +       (void)0; /* Need statement after label */

> +#endif

> +       neu.st.head = old.st.head == NULL ? node : old.st.head;

> +       neu.st.tail = node;

> +#ifdef ODP_CONFIG_USE_LLSC

> +       if (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELEASE))) {

> +#else

> +       if (odp_unlikely(!__atomic_compare_exchange(&llq->u,

> +                                                   &old,

> +                                                   &neu,

> +                                                   false, /* weak= */

> +                                                   __ATOMIC_RELEASE,

> +                                                   __ATOMIC_RELAXED))) {

> +#endif

> +               odp_cpu_pause();

> +               goto retry;

> +       }

> +       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 = llq->u.st.tail = node;

> +       } else {

> +               llq->u.st.tail->next = node;

> +               llq->u.st.tail = node;

> +       }

> +       odp_spinlock_unlock(&llq->lock);

> +}

> +

> +#endif

> +

> +#ifndef ODP_CONFIG_LLQ_LOCK

> +

> +static inline struct llnode *llq_dequeue(struct llqueue *llq)

> +{

> +       struct llnode *head;

> +       union llht old;

> +

> +       /* 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);

> +

> +#ifdef ODP_CONFIG_USE_LLSC

> +       /* Prefetch for store for faster LL/SC execution */

> +       __builtin_prefetch(&llq->u.ui, 1, 0);

> +retry: /* Failed SC requires new LL */

> +       old.ui = lld(&llq->u.ui, __ATOMIC_RELAXED);

> +#else

> +       __atomic_load(&llq->u, &old, __ATOMIC_RELAXED);

> +retry: /* Failed CAS returns existing value */

> +#endif

> +       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 */

> +               union llht neu;

> +

> +               neu.st.head = NULL;

> +               neu.st.tail = NULL;

> +#ifdef ODP_CONFIG_USE_LLSC

> +               if (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELAXED))) {

> +#else

> +               if (odp_unlikely(!__atomic_compare_exchange(

> +                                       &llq->u,

> +                                       &old,

> +                                       &neu,

> +                                       false, /* weak= */

> +                                       __ATOMIC_RELAXED,

> +                                       __ATOMIC_RELAXED))) {

> +#endif

> +                       /* Failed */

> +                       odp_cpu_pause();

> +                       goto retry;

> +               }

> +               ODP_ASSERT(old.st.head->next == SENTINEL);

> +       } else {

> +               /* Multi-element list, dequeue head */

> +               struct llnode *next;

> +               union llht neu;

> +               /* 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;

> +#ifdef ODP_CONFIG_USE_LLSC

> +               if (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELAXED))) {

> +#else

> +               if (odp_unlikely(!__atomic_compare_exchange(

> +                                       &llq->u,

> +                                       &old,

> +                                       &neu,

> +                                       false, /* weak= */

> +                                       __ATOMIC_RELAXED,

> +                                       __ATOMIC_RELAXED))) {

> +#endif

> +                       /* Failed */

> +                       odp_cpu_pause();

> +                       goto retry;

> +               }

> +               ODP_ASSERT(old.st.head->next != SENTINEL);

> +       }

> +       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 = 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

> +

> +#ifndef ODP_CONFIG_LLQ_LOCK

> +

> +static inline odp_bool_t llq_dequeue_cond(struct llqueue *llq,

> +                                         struct llnode *exp)

> +{

> +       union llht old;

> +

> +#ifdef ODP_CONFIG_USE_LLSC

> +       /* Prefetch for store for faster LL/SC execution */

> +       __builtin_prefetch(&llq->u.ui, 1, 0);

> +retry: /* Failed SC requires new LL */

> +       old.ui = lld(&llq->u.ui, __ATOMIC_RELAXED);

> +#else

> +       __atomic_load(&llq->u, &old, __ATOMIC_RELAXED);

> +retry: /* Failed CAS returns existing value */

> +#endif

> +       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 */

> +               union llht neu;

> +

> +               neu.st.head = NULL;

> +               neu.st.tail = NULL;

> +#ifdef ODP_CONFIG_USE_LLSC

> +               if (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELAXED))) {

> +#else

> +               if (odp_unlikely(!__atomic_compare_exchange(

> +                                       &llq->u,

> +                                       &old,

> +                                       &neu,

> +                                       false, /* weak= */

> +                                       __ATOMIC_RELAXED,

> +                                       __ATOMIC_RELAXED))) {

> +#endif

> +                       /* Failed */

> +                       odp_cpu_pause();

> +                       goto retry;

> +               }

> +               ODP_ASSERT(old.st.head->next == SENTINEL);

> +       } else {

> +               /* Multi-element list, dequeue head */

> +               struct llnode *next;

> +               union llht neu;

> +

> +               /* 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;

> +#ifdef ODP_CONFIG_USE_LLSC

> +               if (odp_unlikely(scd(&llq->u.ui, neu.ui, __ATOMIC_RELAXED))) {

> +#else

> +               if (odp_unlikely(!__atomic_compare_exchange(

> +                                       &llq->u,

> +                                       &old,

> +                                       &neu,

> +                                       false, /* weak= */

> +                                       __ATOMIC_RELAXED,

> +                                       __ATOMIC_RELAXED))) {

> +#endif

> +                       /* Failed */

> +                       odp_cpu_pause();

> +                       goto retry;

> +               }

> +               ODP_ASSERT(old.st.head->next != SENTINEL);

> +       }

> +       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 = 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

> +

> +#ifndef ODP_CONFIG_LLQ_LOCK

> +

> +/* 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

> diff --git a/platform/linux-generic/include/odp_llsc.h b/platform/linux-generic/include/odp_llsc.h

> new file mode 100644

> index 00000000..a7b6166e

> --- /dev/null

> +++ b/platform/linux-generic/include/odp_llsc.h

> @@ -0,0 +1,325 @@

> +/* Copyright (c) 2017, ARM Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:    BSD-3-Clause

> + */

> +

> +#ifndef ODP_LLSC_H_

> +#define ODP_LLSC_H_

> +

> +#include <odp_config_internal.h>

> +

> +/******************************************************************************

> + * LL/SC primitives

> + *****************************************************************************/

> +

> +#if defined __ARM_ARCH

> +#if __ARM_ARCH == 7 || (__ARM_ARCH == 8 && __ARM_64BIT_STATE == 0)

> +static inline void dmb(void)

> +{

> +       __asm volatile("dmb" : : : "memory");

> +}

> +

> +static inline uint32_t ll8(uint8_t *var, int mm)

> +{

> +       uint8_t old;

> +

> +       __asm volatile("ldrexb %0, [%1]"

> +                       : "=&r" (old)

> +                       : "r" (var)

> +                       : );

> +       /* Barrier after an acquiring load */

> +       if (mm == __ATOMIC_ACQUIRE)

> +               dmb();

> +       return old;

> +}

> +

> +static inline uint32_t ll16(uint16_t *var, int mm)

> +{

> +       uint16_t old;

> +

> +       __asm volatile("ldrexh %0, [%1]"

> +                       : "=&r" (old)

> +                       : "r" (var)

> +                       : );

> +       /* Barrier after an acquiring load */

> +       if (mm == __ATOMIC_ACQUIRE)

> +               dmb();

> +       return old;

> +}

> +

> +static inline uint32_t ll(uint32_t *var, int mm)

> +{

> +       uint32_t old;

> +

> +       __asm volatile("ldrex %0, [%1]"

> +                       : "=&r" (old)

> +                       : "r" (var)

> +                       : );

> +       /* Barrier after an acquiring load */

> +       if (mm == __ATOMIC_ACQUIRE)

> +               dmb();

> +       return old;

> +}

> +#define ll32(a, b) ll((a), (b))

> +

> +/* Return 0 on success, 1 on failure */

> +static inline uint32_t sc(uint32_t *var, uint32_t neu, int mm)

> +{

> +       uint32_t ret;

> +

> +       /* Barrier before a releasing store */

> +       if (mm == __ATOMIC_RELEASE)

> +               dmb();

> +       __asm volatile("strex %0, %1, [%2]"

> +                       : "=&r" (ret)

> +                       : "r" (neu), "r" (var)

> +                       : );

> +       return ret;

> +}

> +#define sc32(a, b, c) sc((a), (b), (c))

> +

> +static inline uint64_t lld(uint64_t *var, int mm)

> +{

> +       uint64_t old;

> +

> +       __asm volatile("ldrexd %0, %H0, [%1]"

> +                       : "=&r" (old)

> +                       : "r" (var)

> +                       : );

> +       /* Barrier after an acquiring load */

> +       if (mm == __ATOMIC_ACQUIRE)

> +               dmb();

> +       return old;

> +}

> +#define ll64(a, b) lld((a), (b))

> +

> +/* Return 0 on success, 1 on failure */

> +static inline uint32_t scd(uint64_t *var, uint64_t neu, int mm)

> +{

> +       uint32_t ret;

> +

> +       /* Barrier before a releasing store */

> +       if (mm == __ATOMIC_RELEASE)

> +               dmb();

> +       __asm volatile("strexd %0, %1, %H1, [%2]"

> +                       : "=&r" (ret)

> +                       : "r" (neu), "r" (var)

> +                       : );

> +       return ret;

> +}

> +#define sc64(a, b, c) scd((a), (b), (c))

> +

> +#endif

> +

> +#if __ARM_ARCH == 8 && __ARM_64BIT_STATE == 1

> +static inline uint16_t ll8(uint8_t *var, int mm)

> +{

> +       uint16_t old;

> +

> +       if (mm == __ATOMIC_ACQUIRE)

> +               __asm volatile("ldaxrb %w0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("ldxrb %w0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return old;

> +}

> +

> +static inline uint16_t ll16(uint16_t *var, int mm)

> +{

> +       uint16_t old;

> +

> +       if (mm == __ATOMIC_ACQUIRE)

> +               __asm volatile("ldaxrh %w0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("ldxrh %w0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return old;

> +}

> +

> +static inline uint32_t ll32(uint32_t *var, int mm)

> +{

> +       uint32_t old;

> +

> +       if (mm == __ATOMIC_ACQUIRE)

> +               __asm volatile("ldaxr %w0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("ldxr %w0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return old;

> +}

> +

> +/* Return 0 on success, 1 on failure */

> +static inline uint32_t sc32(uint32_t *var, uint32_t neu, int mm)

> +{

> +       uint32_t ret;

> +

> +       if (mm == __ATOMIC_RELEASE)

> +               __asm volatile("stlxr %w0, %w1, [%2]"

> +                               : "=&r" (ret)

> +                               : "r" (neu), "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("stxr %w0, %w1, [%2]"

> +                               : "=&r" (ret)

> +                               : "r" (neu), "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return ret;

> +}

> +

> +static inline uint64_t ll(uint64_t *var, int mm)

> +{

> +       uint64_t old;

> +

> +       if (mm == __ATOMIC_ACQUIRE)

> +               __asm volatile("ldaxr %0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("ldxr %0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return old;

> +}

> +#define ll64(a, b) ll((a), (b))

> +

> +/* Return 0 on success, 1 on failure */

> +static inline uint32_t sc(uint64_t *var, uint64_t neu, int mm)

> +{

> +       uint32_t ret;

> +

> +       if (mm == __ATOMIC_RELEASE)

> +               __asm volatile("stlxr %w0, %1, [%2]"

> +                               : "=&r" (ret)

> +                               : "r" (neu), "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("stxr %w0, %1, [%2]"

> +                               : "=&r" (ret)

> +                               : "r" (neu), "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return ret;

> +}

> +#define sc64(a, b, c) sc((a), (b), (c))

> +static inline __int128 lld(__int128 *var, int mm)

> +{

> +       __int128 old;

> +

> +       if (mm == __ATOMIC_ACQUIRE)

> +               __asm volatile("ldaxp %0, %H0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("ldxp %0, %H0, [%1]"

> +                               : "=&r" (old)

> +                               : "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return old;

> +}

> +

> +/* Return 0 on success, 1 on failure */

> +static inline uint32_t scd(__int128 *var, __int128 neu, int mm)

> +{

> +       uint32_t ret;

> +

> +       if (mm == __ATOMIC_RELEASE)

> +               __asm volatile("stlxp %w0, %1, %H1, [%2]"

> +                               : "=&r" (ret)

> +                               : "r" (neu), "r" (var)

> +                               : "memory");

> +       else if (mm == __ATOMIC_RELAXED)

> +               __asm volatile("stxp %w0, %1, %H1, [%2]"

> +                               : "=&r" (ret)

> +                               : "r" (neu), "r" (var)

> +                               : );

> +       else

> +               ODP_ABORT();

> +       return ret;

> +}

> +#endif

> +#endif

> +

> +static inline void sevl(void)

> +{

> +#if defined __ARM_ARCH

> +       __asm volatile("sevl" : : : );

> +#endif

> +}

> +

> +static inline void sev(void)

> +{

> +#if defined __ARM_ARCH

> +       __asm volatile("sev" : : : "memory");

> +#endif

> +}

> +

> +static inline int wfe(void)

> +{

> +#if defined __ARM_ARCH

> +       __asm volatile("wfe" : : : "memory");

> +#endif

> +       return 1;

> +}

> +

> +#ifdef ODP_CONFIG_USE_WFE

> +#define SEVL() sevl()

> +#define WFE() wfe()

> +#define SEV() do { __asm volatile("dsb ish" ::: "memory"); sev(); } while (0)

> +#if defined __ARM_ARCH && __ARM_ARCH == 8 && __ARM_64BIT_STATE == 1

> +#define LDXR128(addr, mo) lld((addr), (mo))

> +#endif

> +#define LDXR64(addr, mo) ll64((addr), (mo))

> +#define LDXR32(addr, mo) ll32((addr), (mo))

> +#define LDXR16(addr, mo) ll16((addr), (mo))

> +#define LDXR8(addr, mo) ll8((addr), (mo))

> +/* When using WFE do not stall the pipeline using other means */

> +#define DOZE() (void)0

> +#else

> +#define SEVL() (void)0

> +#define WFE() 1

> +#define SEV() (void)0

> +#define LDXR128(addr, mo) __atomic_load_n((addr), (mo))

> +#define LDXR64(addr, mo) __atomic_load_n((addr), (mo))

> +#define LDXR32(addr, mo) __atomic_load_n((addr), (mo))

> +#define LDXR16(addr, mo) __atomic_load_n((addr), (mo))

> +#define LDXR8(addr, mo) __atomic_load_n((addr), (mo))

> +#if defined __ARM_ARCH

> +#define DOZE() __asm volatile("isb" ::: "memory")

> +#else

> +#define DOZE() __asm volatile("pause" ::: "memory")

> +#endif

> +#endif

> +

> +#endif

> diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h

> index 0a9f1779..c9d14766 100644

> --- a/platform/linux-generic/include/odp_packet_internal.h

> +++ b/platform/linux-generic/include/odp_packet_internal.h

> @@ -235,6 +235,9 @@ odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt);

>  /* Convert a buffer handle to a packet handle */

>  odp_packet_t _odp_packet_from_buffer(odp_buffer_t buf);

>

> +/* Convert a packet handle to a buffer hdr handle pointer */

> +odp_buffer_hdr_t *_odp_packet_to_buf_hdr_ptr(odp_packet_t pkt);

> +

>  static inline int packet_hdr_has_l2(odp_packet_hdr_t *pkt_hdr)

>  {

>         return pkt_hdr->p.input_flags.l2;

> diff --git a/platform/linux-generic/include/odp_queue_internal.h b/platform/linux-generic/include/odp_queue_internal.h

> index 560f826e..ebfc0f76 100644

> --- a/platform/linux-generic/include/odp_queue_internal.h

> +++ b/platform/linux-generic/include/odp_queue_internal.h

> @@ -19,16 +19,24 @@ extern "C" {

>  #endif

>

>  #include <odp/api/queue.h>

> -#include <odp_forward_typedefs_internal.h>

> -#include <odp_schedule_if.h>

> -#include <odp_buffer_internal.h>

> -#include <odp_align_internal.h>

> +#include <odp/api/std_types.h>

> +#include <odp/api/buffer.h>

>  #include <odp/api/packet_io.h>

>  #include <odp/api/align.h>

>  #include <odp/api/hints.h>

>  #include <odp/api/ticketlock.h>

> +

>  #include <odp_config_internal.h>

>

> +#include <odp_align_internal.h>

> +#include <odp_buffer_internal.h>

> +#include <odp_forward_typedefs_internal.h>

> +#ifdef ODP_SCHEDULE_SCALABLE

> +#include <odp_llsc.h>

> +#include <odp_schedule_ordered_internal.h>

> +#endif

> +#include <odp_schedule_if.h>

> +

>  #define QUEUE_MULTI_MAX CONFIG_BURST_SIZE

>

>  #define QUEUE_STATUS_FREE         0

> @@ -37,8 +45,6 @@ extern "C" {

>  #define QUEUE_STATUS_NOTSCHED     3

>  #define QUEUE_STATUS_SCHED        4

>

> -

> -/* forward declaration */

>  union queue_entry_u;

>

>  typedef int (*enq_func_t)(union queue_entry_u *, odp_buffer_hdr_t *);

> @@ -49,6 +55,37 @@ typedef int (*enq_multi_func_t)(union queue_entry_u *,

>  typedef        int (*deq_multi_func_t)(union queue_entry_u *,

>                                 odp_buffer_hdr_t **, int);

>

> +#ifdef ODP_SCHEDULE_SCALABLE

> +#define BUFFER_HDR_INVALID ((odp_buffer_hdr_t *)ODP_EVENT_INVALID)

> +

> +struct queue_entry_s {

> +       sched_elem_t     sched_elem;

> +       odp_shm_t        shm;

> +       odp_shm_t        rwin_shm;

> +

> +       odp_ticketlock_t lock ODP_ALIGNED_CACHE;

> +       int              status;

> +

> +       enq_func_t       enqueue ODP_ALIGNED_CACHE;

> +       deq_func_t       dequeue;

> +       enq_multi_func_t enqueue_multi;

> +       deq_multi_func_t dequeue_multi;

> +

> +       uint32_t           index;

> +       odp_queue_t        handle;

> +       odp_queue_type_t   type;

> +       odp_queue_param_t  param;

> +       odp_pktin_queue_t  pktin;

> +       odp_pktout_queue_t pktout;

> +       char               name[ODP_QUEUE_NAME_LEN];

> +};

> +

> +int _odp_queue_deq(sched_elem_t *q, odp_event_t *evp, int num);

> +int _odp_queue_deq_sc(sched_elem_t *q, odp_event_t *evp, int num);

> +

> +#else

> +#define BUFFER_HDR_INVALID NULL

> +

>  struct queue_entry_s {

>         odp_ticketlock_t  lock ODP_ALIGNED_CACHE;

>

> @@ -77,6 +114,8 @@ struct queue_entry_s {

>         char              name[ODP_QUEUE_NAME_LEN];

>  };

>

> +#endif

> +

>  union queue_entry_u {

>         struct queue_entry_s s;

>         uint8_t pad[ROUNDUP_CACHE_LINE(sizeof(struct queue_entry_s))];

> @@ -94,6 +133,12 @@ int queue_deq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[], int num);

>  void queue_lock(queue_entry_t *queue);

>  void queue_unlock(queue_entry_t *queue);

>

> +int queue_pktout_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr);

> +int queue_pktout_enq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[],

> +                          int num);

> +

> +int queue_tm_reorder(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr);

> +

>  static inline uint32_t queue_to_id(odp_queue_t handle)

>  {

>         return _odp_typeval(handle) - 1;

> @@ -107,6 +152,71 @@ static inline queue_entry_t *queue_to_qentry(odp_queue_t handle)

>         return get_qentry(queue_id);

>  }

>

> +static inline odp_queue_t queue_get_handle(queue_entry_t *queue)

> +{

> +       return queue->s.handle;

> +}

> +

> +static inline odp_pktout_queue_t queue_get_pktout(queue_entry_t *queue)

> +{

> +       return queue->s.pktout;

> +}

> +

> +static inline void queue_set_pktout(queue_entry_t *queue,

> +                                   odp_pktio_t pktio,

> +                                   int index)

> +{

> +       queue->s.pktout.pktio = pktio;

> +       queue->s.pktout.index = index;

> +}

> +

> +static inline odp_pktin_queue_t queue_get_pktin(queue_entry_t *queue)

> +{

> +       return queue->s.pktin;

> +}

> +

> +static inline void queue_set_pktin(queue_entry_t *queue,

> +                                  odp_pktio_t pktio,

> +                                  int index)

> +{

> +       queue->s.pktin.pktio = pktio;

> +       queue->s.pktin.index = index;

> +}

> +

> +static inline void queue_set_enq_func(queue_entry_t *queue, enq_func_t func)

> +{

> +       queue->s.enqueue = func;

> +}

> +

> +static inline void queue_set_enq_multi_func(queue_entry_t *queue,

> +                                           enq_multi_func_t func)

> +{

> +       queue->s.enqueue_multi = func;

> +}

> +

> +static inline void queue_set_deq_func(queue_entry_t *queue, deq_func_t func)

> +{

> +       queue->s.dequeue = func;

> +}

> +

> +static inline void queue_set_deq_multi_func(queue_entry_t *queue,

> +                                           deq_multi_func_t func)

> +{

> +       queue->s.dequeue_multi = func;

> +}

> +

> +static inline void queue_set_type(queue_entry_t *queue, odp_queue_type_t type)

> +{

> +       queue->s.type = type;

> +}

> +

> +#ifdef ODP_SCHEDULE_SCALABLE

> +static inline reorder_window_t *queue_get_rwin(queue_entry_t *queue)

> +{

> +       return queue->s.sched_elem.rwin;

> +}

> +#endif

> +

>  #ifdef __cplusplus

>  }

>  #endif

> diff --git a/platform/linux-generic/include/odp_schedule_if.h b/platform/linux-generic/include/odp_schedule_if.h

> index 530d157f..41998833 100644

> --- a/platform/linux-generic/include/odp_schedule_if.h

> +++ b/platform/linux-generic/include/odp_schedule_if.h

> @@ -4,6 +4,12 @@

>   * SPDX-License-Identifier:     BSD-3-Clause

>   */

>

> +/* Copyright (c) 2017, ARM Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

>  #ifndef ODP_SCHEDULE_IF_H_

>  #define ODP_SCHEDULE_IF_H_

>

> @@ -11,18 +17,168 @@

>  extern "C" {

>  #endif

>

> +#include <odp/api/align.h>

>  #include <odp/api/queue.h>

> -#include <odp_queue_internal.h>

>  #include <odp/api/schedule.h>

> +#include <odp/api/ticketlock.h>

> +

> +#include <odp_forward_typedefs_internal.h>

> +#ifdef ODP_SCHEDULE_SCALABLE

> +#include <odp_config_internal.h>

> +#include <odp_llqueue.h>

> +#include <odp_schedule_ordered_internal.h>

> +

> +#include <limits.h>

> +#endif

> +

> +/* Number of ordered locks per queue */

> +#define SCHEDULE_ORDERED_LOCKS_PER_QUEUE 2

> +

> +#ifdef ODP_SCHEDULE_SCALABLE

> +

> +typedef struct {

> +       union {

> +               struct {

> +                       struct llqueue llq;

> +                       uint32_t prio;

> +               };

> +               char line[ODP_CACHE_LINE_SIZE];

> +       };

> +} sched_queue_t ODP_ALIGNED_CACHE;

> +

> +#define TICKET_INVALID (uint16_t)(~0U)

> +

> +typedef struct {

> +       int32_t numevts;

> +       uint16_t wrr_budget;

> +       uint8_t cur_ticket;

> +       uint8_t nxt_ticket;

> +} qschedstate_t ODP_ALIGNED(sizeof(uint64_t));

> +

> +typedef uint32_t ringidx_t;

> +

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +#define SPLIT_PC ODP_ALIGNED_CACHE

> +#else

> +#define SPLIT_PC

> +#endif

> +

> +#ifdef ODP_CONFIG_USE_SPLIT_READWRITE

> +#define SPLIT_RW ODP_ALIGNED_CACHE

> +#else

> +#define SPLIT_RW

> +#endif

> +

> +#define ODP_NO_SCHED_QUEUE (ODP_SCHED_SYNC_ORDERED + 1)

> +

> +typedef struct {

> +       /* (ll)node must be first */

> +       struct llnode node;           /* 8:  0.. 7 */

> +       sched_queue_t *schedq;        /* 8:  8..15 */

> +#ifdef CONFIG_QSCHST_LOCK

> +       odp_ticketlock_t qschlock;

> +#endif

> +       qschedstate_t qschst;         /* 8: 16..23 */

> +       uint16_t pop_deficit;         /* 2: 24..25 */

> +       uint16_t qschst_type;         /* 2: 26..27 */

> +

> +       ringidx_t prod_read SPLIT_PC; /* 4: 28..31 */

> +

> +       ringidx_t prod_write SPLIT_RW;/* 4: 32..35 */

> +       ringidx_t prod_mask;          /* 4: 36..39 */

> +       odp_buffer_hdr_t **prod_ring; /* 8: 40..47 */

> +

> +       ringidx_t cons_write SPLIT_PC;/* 4: 48..51 */

> +

> +       ringidx_t cons_read SPLIT_RW; /* 4: 52..55 */

> +

> +       reorder_window_t *rwin;       /* 8: 56..63 */

> +       void *user_ctx;               /* 8: 64..71 */

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       odp_buffer_hdr_t **cons_ring;

> +       ringidx_t cons_mask;

> +       uint16_t cons_type;

> +#else

> +#define cons_mask prod_mask

> +#define cons_ring prod_ring

> +#define cons_type qschst_type

> +#endif

> +} sched_elem_t ODP_ALIGNED_CACHE;

> +

> +/*

> + * Scheduler group related declarations.

> + */

> +typedef bitset_t sched_group_mask_t;

> +

> +/* Number of scheduling groups */

> +#define MAX_SCHED_GROUP (sizeof(sched_group_mask_t) * CHAR_BIT)

> +

> +typedef struct {

> +       /* Threads currently associated with the sched group */

> +       bitset_t thr_actual[ODP_SCHED_PRIO_NUM] ODP_ALIGNED_CACHE;

> +       bitset_t thr_wanted;

> +       /* Used to spread queues over schedq's */

> +       uint32_t xcount[ODP_SCHED_PRIO_NUM];

> +       /* Number of schedq's per prio */

> +       uint32_t xfactor;

> +

> +       char name[ODP_SCHED_GROUP_NAME_LEN];

> +       /* shm handle for the group */

> +       odp_shm_t shm;

> +

> +       /* ODP_SCHED_PRIO_NUM * xfactor.

> +        * Must be the last memember in this struct.

> +        */

> +       sched_queue_t schedq[1] ODP_ALIGNED_CACHE;

> +} sched_group_t;

> +

> +/*

> + * Per thread state

> + */

> +/* Number of reorder contexts per thread */

> +#define TS_RVEC_SIZE 16

> +typedef struct {

> +       /* Atomic queue currently being processed or NULL */

> +       sched_elem_t *atomq;

> +       /* Current reorder context or NULL */

> +       reorder_context_t *rctx;

> +       uint8_t pause;

> +       uint8_t out_of_order;

> +       uint8_t tidx;

> +       uint8_t pad;

> +       uint32_t dequeued; /* Number of events dequeued from atomic queue */

> +       uint16_t pktin_next;/* Next pktin tag to poll */

> +       uint16_t pktin_poll_cnts;

> +       uint16_t ticket; /* Ticket for atomic queue or TICKET_INVALID */

> +       uint16_t num_schedq;

> +       uint16_t sg_sem; /* Set when sg_wanted is modified by other thread */

> +#define SCHEDQ_PER_THREAD (MAX_SCHED_GROUP * ODP_SCHED_PRIO_NUM)

> +       sched_queue_t *schedq_list[SCHEDQ_PER_THREAD];

> +       /* Current sched_group membership */

> +       sched_group_mask_t sg_actual[ODP_SCHED_PRIO_NUM];

> +       /* Future sched_group membership. */

> +       sched_group_mask_t sg_wanted[ODP_SCHED_PRIO_NUM];

> +       bitset_t priv_rvec_free;

> +       /* Bitset of free entries in rvec[] */

> +       bitset_t rvec_free ODP_ALIGNED_CACHE;

> +       /* Reordering contexts to allocate from */

> +       reorder_context_t rvec[TS_RVEC_SIZE] ODP_ALIGNED_CACHE;

> +} sched_scalable_thread_state_t ODP_ALIGNED_CACHE;

> +

> +void sched_update_enq(sched_elem_t *q, uint32_t actual);

> +void sched_update_enq_sp(sched_elem_t *q, uint32_t actual);

> +sched_queue_t *schedq_from_sched_group(odp_schedule_group_t grp, uint32_t prio);

> +void sched_group_xcount_dec(odp_schedule_group_t grp, uint32_t prio);

> +

> +#endif  /* ODP_SCHEDULE_SCALABLE */

>

>  typedef void (*schedule_pktio_start_fn_t)(int pktio_index, int num_in_queue,

>                                           int in_queue_idx[]);

>  typedef int (*schedule_thr_add_fn_t)(odp_schedule_group_t group, int thr);

>  typedef int (*schedule_thr_rem_fn_t)(odp_schedule_group_t group, int thr);

>  typedef int (*schedule_num_grps_fn_t)(void);

> -typedef int (*schedule_init_queue_fn_t)(uint32_t queue_index,

> -                                       const odp_schedule_param_t *sched_param

> -                                      );

> +typedef int (*schedule_init_queue_fn_t)(

> +       uint32_t queue_index, const odp_schedule_param_t *sched_param);

>  typedef void (*schedule_destroy_queue_fn_t)(uint32_t queue_index);

>  typedef int (*schedule_sched_queue_fn_t)(uint32_t queue_index);

>  typedef int (*schedule_unsched_queue_fn_t)(uint32_t queue_index);

> @@ -64,6 +220,7 @@ extern const schedule_fn_t *sched_fn;

>  int sched_cb_pktin_poll(int pktio_index, int num_queue, int index[]);

>  void sched_cb_pktio_stop_finalize(int pktio_index);

>  int sched_cb_num_pktio(void);

> +#ifndef ODP_SCHEDULE_SCALABLE

>  int sched_cb_num_queues(void);

>  int sched_cb_queue_prio(uint32_t queue_index);

>  int sched_cb_queue_grp(uint32_t queue_index);

> @@ -73,6 +230,7 @@ odp_queue_t sched_cb_queue_handle(uint32_t queue_index);

>  void sched_cb_queue_destroy_finalize(uint32_t queue_index);

>  int sched_cb_queue_deq_multi(uint32_t queue_index, odp_event_t ev[], int num);

>  int sched_cb_queue_empty(uint32_t queue_index);

> +#endif

>

>  /* API functions */

>  typedef struct {

> diff --git a/platform/linux-generic/include/odp_schedule_ordered_internal.h b/platform/linux-generic/include/odp_schedule_ordered_internal.h

> new file mode 100644

> index 00000000..a16deca8

> --- /dev/null

> +++ b/platform/linux-generic/include/odp_schedule_ordered_internal.h

> @@ -0,0 +1,150 @@

> +/* Copyright (c) 2017, ARM Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#ifndef ODP_SCHEDULE_ORDERED_INTERNAL_H_

> +#define ODP_SCHEDULE_ORDERED_INTERNAL_H_

> +

> +#ifdef __cplusplus

> +extern "C" {

> +#endif

> +

> +#ifdef ODP_SCHEDULE_SCALABLE

> +

> +#include <odp/api/shared_memory.h>

> +

> +#include <odp_internal.h>

> +

> +#include <odp_align_internal.h>

> +#include <odp_bitset.h>

> +#include <odp_llsc.h>

> +

> +/* High level functioning of reordering

> + * Datastructures -

> + * Reorder Window - Every ordered queue is associated with a reorder window.

> + *                  Reorder window stores reorder contexts from threads that

> + *                  have completed processing out-of-order.

> + * Reorder Context - Reorder context consists of events that a thread

> + *                   wants to enqueue while processing a batch of events

> + *                   from an ordered queue.

> + *

> + * Algorithm -

> + * 1) Thread identifies the ordered queue.

> + * 2) It 'reserves a slot in the reorder window and dequeues the

> + *    events' atomically. Atomicity is achieved by using a ticket-lock

> + *    like design where the reorder window slot is the ticket.

> + * 3a) Upon order-release/next schedule call, the thread

> + *     checks if it's slot (ticket) equals the head of the reorder window.

> + *     If yes, enqueues the events to the destination queue till

> + *         i) the reorder window is empty or

> + *         ii) there is a gap in the reorder window

> + *     If no, the reorder context is stored in the reorder window at

> + *     the reserved slot.

> + * 3b) Upon the first enqueue, the thread checks if it's slot (ticket)

> + *     equals the head of the reorder window.

> + *     If yes, enqueues the events immediately to the destination queue

> + *     If no, these (and subsequent) events are stored in the reorder context

> + *     (in the application given order)

> + */

> +

> +/* Head and change indicator variables are used to synchronise between

> + * concurrent insert operations in the reorder window. A thread performing

> + * an in-order insertion must be notified about the newly inserted

> + * reorder contexts so that it doesn’t halt the retire process too early.

> + * A thread performing an out-of-order insertion must correspondingly

> + * notify the thread doing in-order insertion of the new waiting reorder

> + * context, which may need to be handled by that thread.

> + *

> + * Also, an out-of-order insertion may become an in-order insertion if the

> + * thread doing an in-order insertion completes before this thread completes.

> + * We need a point of synchronisation where this knowledge and potential state

> + * change can be transferred between threads.

> + */

> +typedef struct hc {

> +       /* First missing context */

> +       uint32_t head;

> +       /* Change indicator */

> +       uint32_t chgi;

> +} hc_t ODP_ALIGNED(sizeof(uint64_t));

> +

> +/* Number of reorder contects in the reorder window.

> + * Should be at least one per CPU.

> + */

> +#define RWIN_SIZE 32

> +ODP_STATIC_ASSERT(IS_POWER_TWO(RWIN_SIZE), "RWIN_SIZE is not a power of 2");

> +

> +#define NUM_OLOCKS 2

> +

> +typedef struct reorder_context reorder_context_t;

> +

> +typedef struct reorder_window {

> +       /* head and change indicator */

> +       hc_t hc;

> +       uint32_t winmask;

> +       uint32_t tail;

> +       uint32_t turn;

> +       uint32_t olock[NUM_OLOCKS];

> +       uint16_t lock_count;

> +       /* Reorder contexts in this window */

> +       reorder_context_t *ring[RWIN_SIZE];

> +} reorder_window_t;

> +

> +/* Number of events that can be stored in a reorder context.

> + * This size is chosen so that there is no space left unused at the end

> + * of the last cache line (for 64b architectures and 64b handles).

> + */

> +#define RC_EVT_SIZE 18

> +

> +typedef struct reorder_context {

> +       /* Reorder window to which this context belongs */

> +       reorder_window_t *rwin;

> +       /* Pointer to TS->rvec_free */

> +       bitset_t *rvec_free;

> +       /* Our slot number in the reorder window */

> +       uint32_t sn;

> +       uint8_t olock_flags;

> +       /* Our index in thread_state rvec array */

> +       uint8_t idx;

> +       /* Use to link reorder contexts together */

> +       uint8_t next_idx;

> +       /* Current reorder context to save events in */

> +       uint8_t cur_idx;

> +       /* Number of events stored in this reorder context */

> +       uint8_t numevts;

> +       /* Events stored in this context */

> +       odp_buffer_hdr_t *events[RC_EVT_SIZE];

> +       queue_entry_t *destq[RC_EVT_SIZE];

> +} reorder_context_t ODP_ALIGNED_CACHE;

> +

> +reorder_window_t *rwin_alloc(int rwin_id, odp_shm_t *shm, unsigned lock_count);

> +bool rwin_reserve(reorder_window_t *rwin, uint32_t *sn);

> +void rwin_insert(reorder_window_t *rwin,

> +                reorder_context_t *rctx,

> +                uint32_t sn,

> +                void (*callback)(reorder_context_t *));

> +void rctx_init(reorder_context_t *rctx, uint16_t idx,

> +              reorder_window_t *rwin, uint32_t sn);

> +void rctx_free(const reorder_context_t *rctx);

> +void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,

> +                        uint32_t lock_index);

> +void olock_release(const reorder_context_t *rctx);

> +void rctx_retire(reorder_context_t *first);

> +void rctx_release(reorder_context_t *rctx);

> +

> +#else

> +

> +#define SUSTAIN_ORDER 1

> +

> +int schedule_ordered_queue_enq(uint32_t queue_index, void *p_buf_hdr,

> +                              int sustain, int *ret);

> +int schedule_ordered_queue_enq_multi(uint32_t queue_index, void *p_buf_hdr[],

> +                                    int num, int sustain, int *ret);

> +#endif

> +

> +#ifdef __cplusplus

> +}

> +#endif

> +

> +#endif

> diff --git a/platform/linux-generic/m4/odp_schedule.m4 b/platform/linux-generic/m4/odp_schedule.m4

> index 91c19f21..d862b8b2 100644

> --- a/platform/linux-generic/m4/odp_schedule.m4

> +++ b/platform/linux-generic/m4/odp_schedule.m4

> @@ -1,13 +1,44 @@

> -AC_ARG_ENABLE([schedule-sp],

> -    [  --enable-schedule-sp    enable strict priority scheduler],

> -    [if test x$enableval = xyes; then

> -       schedule_sp_enabled=yes

> -       ODP_CFLAGS="$ODP_CFLAGS -DODP_SCHEDULE_SP"

> -    fi])

> +# Checks for --enable-schedule-sp and defines ODP_SCHEDULE_SP and adds

> +# -DODP_SCHEDULE_SP to CFLAGS.

> +AC_ARG_ENABLE(

> +    [schedule_sp],

> +    [AC_HELP_STRING([--enable-schedule-sp],

> +                    [enable strict priority scheduler])],

> +    [if test "x$enableval" = xyes; then

> +         schedule_sp=true

> +         ODP_CFLAGS="$ODP_CFLAGS -DODP_SCHEDULE_SP"

> +     else

> +         schedule_sp=false

> +     fi],

> +    [schedule_sp=false])

> +AM_CONDITIONAL([ODP_SCHEDULE_SP], [test x$schedule_sp = xtrue])

>

> -AC_ARG_ENABLE([schedule-iquery],

> -    [  --enable-schedule-iquery    enable interests query (sparse bitmap) scheduler],

> -    [if test x$enableval = xyes; then

> -       schedule_iquery_enabled=yes

> -       ODP_CFLAGS="$ODP_CFLAGS -DODP_SCHEDULE_IQUERY"

> -    fi])

> +# Checks for --enable-schedule-iquery and defines ODP_SCHEDULE_IQUERY and adds

> +# -DODP_SCHEDULE_IQUERY to CFLAGS.

> +AC_ARG_ENABLE(

> +    [schedule_iquery],

> +    [AC_HELP_STRING([--enable-schedule-iquery],

> +                    [enable interests query (sparse bitmap) scheduler])],

> +    [if test "x$enableval" = xyes; then

> +         schedule_iquery=true

> +         ODP_CFLAGS="$ODP_CFLAGS -DODP_SCHEDULE_IQUERY"

> +     else

> +         schedule_iquery=false

> +     fi],

> +    [schedule_iquery=false])

> +AM_CONDITIONAL([ODP_SCHEDULE_IQUERY], [test x$schedule_iquery = xtrue])

> +

> +# Checks for --enable-schedule-scalable and defines ODP_SCHEDULE_SCALABLE and

> +# adds -DODP_SCHEDULE_SCALABLE to CFLAGS.

> +AC_ARG_ENABLE(

> +    [schedule_scalable],

> +    [AC_HELP_STRING([--enable-schedule-scalable],

> +                    [enable scalable scheduler])],

> +    [if test "x$enableval" = xyes; then

> +         schedule_scalable=true

> +         ODP_CFLAGS="$ODP_CFLAGS -DODP_SCHEDULE_SCALABLE"

> +     else

> +         schedule_scalable=false

> +     fi],

> +    [schedule_scalable=false])

> +AM_CONDITIONAL([ODP_SCHEDULE_SCALABLE], [test x$schedule_scalable = xtrue])

> diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c

> index 5d96b00b..8fb5c32f 100644

> --- a/platform/linux-generic/odp_classification.c

> +++ b/platform/linux-generic/odp_classification.c

> @@ -282,7 +282,7 @@ odp_queue_t odp_cos_queue(odp_cos_t cos_id)

>         if (!cos->s.queue)

>                 return ODP_QUEUE_INVALID;

>

> -       return cos->s.queue->s.handle;

> +       return queue_get_handle(cos->s.queue);

>  }

>

>  int odp_cos_drop_set(odp_cos_t cos_id, odp_cls_drop_t drop_policy)

> @@ -849,7 +849,7 @@ int cls_classify_packet(pktio_entry_t *entry, const uint8_t *base,

>

>         *pool = cos->s.pool;

>         pkt_hdr->p.input_flags.dst_queue = 1;

> -       pkt_hdr->dst_queue = cos->s.queue->s.handle;

> +       pkt_hdr->dst_queue = queue_get_handle(cos->s.queue);

>

>         return 0;

>  }

> diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c

> index b8aac6bf..8ae35867 100644

> --- a/platform/linux-generic/odp_packet.c

> +++ b/platform/linux-generic/odp_packet.c

> @@ -651,6 +651,11 @@ odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt)

>         return buffer_handle(packet_hdr(pkt));

>  }

>

> +odp_buffer_hdr_t *_odp_packet_to_buf_hdr_ptr(odp_packet_t pkt)

> +{

> +       return (odp_buffer_hdr_t *)(_odp_packet_to_buffer(pkt));

> +}

> +

>  odp_packet_t odp_packet_from_event(odp_event_t ev)

>  {

>         if (odp_unlikely(ev == ODP_EVENT_INVALID))

> diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c

> index 5e783d83..a267ee97 100644

> --- a/platform/linux-generic/odp_packet_io.c

> +++ b/platform/linux-generic/odp_packet_io.c

> @@ -5,23 +5,25 @@

>   */

>  #include <odp_posix_extensions.h>

>

> -#include <odp/api/packet_io.h>

> -#include <odp_packet_io_internal.h>

> -#include <odp_packet_io_queue.h>

>  #include <odp/api/packet.h>

> -#include <odp_packet_internal.h>

> -#include <odp_internal.h>

> +#include <odp/api/packet_io.h>

>  #include <odp/api/spinlock.h>

>  #include <odp/api/ticketlock.h>

>  #include <odp/api/shared_memory.h>

> -#include <odp_packet_socket.h>

> +#include <odp/api/time.h>

> +

> +#include <odp_internal.h>

>  #include <odp_config_internal.h>

> -#include <odp_queue_internal.h>

> -#include <odp_schedule_if.h>

> -#include <odp_classification_internal.h>

>  #include <odp_debug_internal.h>

> +

> +#include <odp_classification_internal.h>

> +#include <odp_queue_internal.h>

>  #include <odp_packet_io_ipc_internal.h>

> -#include <odp/api/time.h>

> +#include <odp_packet_io_internal.h>

> +#include <odp_packet_io_queue.h>

> +#include <odp_packet_internal.h>

> +#include <odp_packet_socket.h>

> +#include <odp_schedule_if.h>

>

>  #include <string.h>

>  #include <inttypes.h>

> @@ -470,7 +472,6 @@ int odp_pktio_start(odp_pktio_t hdl)

>                                 return -1;

>                         }

>                 }

> -

>                 sched_fn->pktio_start(pktio_to_id(hdl), num, index);

>         }

>

> @@ -552,7 +553,6 @@ static inline int pktin_recv_buf(odp_pktin_queue_t queue,

>         odp_packet_t packets[num];

>         odp_packet_hdr_t *pkt_hdr;

>         odp_buffer_hdr_t *buf_hdr;

> -       odp_buffer_t buf;

>         int i;

>         int pkts;

>         int num_rx = 0;

> @@ -562,9 +562,11 @@ static inline int pktin_recv_buf(odp_pktin_queue_t queue,

>         for (i = 0; i < pkts; i++) {

>                 pkt = packets[i];

>                 pkt_hdr = odp_packet_hdr(pkt);

> -               buf = _odp_packet_to_buffer(pkt);

> -               buf_hdr = buf_hdl_to_hdr(buf);

> -

> +#ifdef ODP_SCHEDULE_SCALABLE

> +               buf_hdr = _odp_packet_to_buf_hdr_ptr(pkt);

> +#else

> +               buf_hdr = buf_hdl_to_hdr(_odp_packet_to_buffer(pkt));

> +#endif

>                 if (pkt_hdr->p.input_flags.dst_queue) {

>                         queue_entry_t *dst_queue;

>                         int ret;

> @@ -582,11 +584,17 @@ static inline int pktin_recv_buf(odp_pktin_queue_t queue,

>

>  int pktout_enqueue(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr)

>  {

> -       odp_packet_t pkt = _odp_packet_from_buffer(buf_hdr->handle.handle);

> +       odp_packet_t pkt;

> +

> +#ifdef ODP_SCHEDULE_SCALABLE

> +       pkt = _odp_packet_from_buffer((odp_buffer_t)buf_hdr);

> +#else

> +       pkt = _odp_packet_from_buffer(buf_hdr->handle.handle);

> +#endif

>         int len = 1;

>         int nbr;

>

> -       nbr = odp_pktout_send(qentry->s.pktout, &pkt, len);

> +       nbr = odp_pktout_send(queue_get_pktout(qentry), &pkt, len);

>         return (nbr == len ? 0 : -1);

>  }

>

> @@ -604,9 +612,13 @@ int pktout_enq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[],

>         int i;

>

>         for (i = 0; i < num; ++i)

> +#ifdef ODP_SCHEDULE_SCALABLE

> +               pkt_tbl[i] = _odp_packet_from_buffer((odp_buffer_t)buf_hdr[i]);

> +#else

>                 pkt_tbl[i] = _odp_packet_from_buffer(buf_hdr[i]->handle.handle);

> +#endif

>

> -       nbr = odp_pktout_send(qentry->s.pktout, pkt_tbl, num);

> +       nbr = odp_pktout_send(queue_get_pktout(qentry), pkt_tbl, num);

>         return nbr;

>  }

>

> @@ -632,13 +644,14 @@ odp_buffer_hdr_t *pktin_dequeue(queue_entry_t *qentry)

>         int pkts;

>

>         buf_hdr = queue_deq(qentry);

> -       if (buf_hdr != NULL)

> +       if (buf_hdr != BUFFER_HDR_INVALID)

>                 return buf_hdr;

>

> -       pkts = pktin_recv_buf(qentry->s.pktin, hdr_tbl, QUEUE_MULTI_MAX);

> +       pkts = pktin_recv_buf(queue_get_pktin(qentry),

> +                             hdr_tbl, QUEUE_MULTI_MAX);

>

>         if (pkts <= 0)

> -               return NULL;

> +               return BUFFER_HDR_INVALID;

>

>         if (pkts > 1)

>                 queue_enq_multi(qentry, &hdr_tbl[1], pkts - 1);

> @@ -669,7 +682,8 @@ int pktin_deq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[], int num)

>         if (nbr == num)

>                 return nbr;

>

> -       pkts = pktin_recv_buf(qentry->s.pktin, hdr_tbl, QUEUE_MULTI_MAX);

> +       pkts = pktin_recv_buf(queue_get_pktin(qentry),

> +                             hdr_tbl, QUEUE_MULTI_MAX);

>         if (pkts <= 0)

>                 return nbr;

>

> @@ -684,7 +698,6 @@ int pktin_deq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[], int num)

>                 queue_enq_multi(qentry, hdr_tbl, j);

>         return nbr;

>  }

> -

>  int sched_cb_pktin_poll(int pktio_index, int num_queue, int index[])

>  {

>         odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX];

> @@ -1266,13 +1279,14 @@ int odp_pktin_queue_config(odp_pktio_t pktio,

>                                 queue_entry_t *qentry;

>

>                                 qentry = queue_to_qentry(queue);

> -                               qentry->s.pktin.index  = i;

> -                               qentry->s.pktin.pktio  = pktio;

> -

> -                               qentry->s.enqueue = pktin_enqueue;

> -                               qentry->s.dequeue = pktin_dequeue;

> -                               qentry->s.enqueue_multi = pktin_enq_multi;

> -                               qentry->s.dequeue_multi = pktin_deq_multi;

> +                               queue_set_pktin(qentry, pktio, i);

> +

> +                               queue_set_enq_func(qentry, pktin_enqueue);

> +                               queue_set_deq_func(qentry, pktin_dequeue);

> +                               queue_set_enq_multi_func(qentry,

> +                                                        pktin_enq_multi);

> +                               queue_set_deq_multi_func(qentry,

> +                                                        pktin_deq_multi);

>                         }

>

>                         entry->s.in_queue[i].queue = queue;

> @@ -1390,14 +1404,12 @@ int odp_pktout_queue_config(odp_pktio_t pktio,

>                         }

>

>                         qentry = queue_to_qentry(queue);

> -                       qentry->s.pktout.index  = i;

> -                       qentry->s.pktout.pktio  = pktio;

> -

> -                       /* Override default enqueue / dequeue functions */

> -                       qentry->s.enqueue       = pktout_enqueue;

> -                       qentry->s.dequeue       = pktout_dequeue;

> -                       qentry->s.enqueue_multi = pktout_enq_multi;

> -                       qentry->s.dequeue_multi = pktout_deq_multi;

> +                       queue_set_pktout(qentry, pktio, i);

> +

> +                       queue_set_enq_func(qentry, pktout_enqueue);

> +                       queue_set_deq_func(qentry, pktout_dequeue);

> +                       queue_set_enq_multi_func(qentry, pktout_enq_multi);

> +                       queue_set_deq_multi_func(qentry, pktout_deq_multi);

>

>                         entry->s.out_queue[i].queue = queue;

>                 }

> diff --git a/platform/linux-generic/odp_queue.c b/platform/linux-generic/odp_queue.c

> index fcf4bf5b..42b58c44 100644

> --- a/platform/linux-generic/odp_queue.c

> +++ b/platform/linux-generic/odp_queue.c

> @@ -291,11 +291,11 @@ void sched_cb_queue_destroy_finalize(uint32_t queue_index)

>  int odp_queue_destroy(odp_queue_t handle)

>  {

>         queue_entry_t *queue;

> -       queue = queue_to_qentry(handle);

>

>         if (handle == ODP_QUEUE_INVALID)

>                 return -1;

>

> +       queue = queue_to_qentry(handle);

>         LOCK(&queue->s.lock);

>         if (queue->s.status == QUEUE_STATUS_FREE) {

>                 UNLOCK(&queue->s.lock);

> diff --git a/platform/linux-generic/odp_queue_scalable.c b/platform/linux-generic/odp_queue_scalable.c

> new file mode 100644

> index 00000000..c08dd06a

> --- /dev/null

> +++ b/platform/linux-generic/odp_queue_scalable.c

> @@ -0,0 +1,944 @@

> +/* Copyright (c) 2017, ARM Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#include <odp/api/hints.h>

> +#include <odp/api/plat/ticketlock_inlines.h>

> +#include <odp/api/queue.h>

> +#include <odp/api/schedule.h>

> +#include <odp/api/shared_memory.h>

> +#include <odp/api/sync.h>

> +#include <odp/api/traffic_mngr.h>

> +

> +#include <odp_internal.h>

> +#include <odp_config_internal.h>

> +#include <odp_debug_internal.h>

> +

> +#include <odp_buffer_inlines.h>

> +#include <odp_packet_io_internal.h>

> +#include <odp_packet_io_queue.h>

> +#include <odp_pool_internal.h>

> +#include <odp_queue_internal.h>

> +#include <odp_schedule_if.h>

> +

> +#include <string.h>

> +#include <inttypes.h>

> +

> +#define NUM_INTERNAL_QUEUES 64

> +

> +#define MIN(a, b) \

> +       ({ \

> +               __typeof__(a) tmp_a = (a); \

> +               __typeof__(b) tmp_b = (b); \

> +               tmp_a < tmp_b ? tmp_a : tmp_b; \

> +       })

> +

> +#define LOCK(a)      _odp_ticketlock_lock(a)

> +#define UNLOCK(a)    _odp_ticketlock_unlock(a)

> +#define LOCK_INIT(a) odp_ticketlock_init(a)

> +

> +extern __thread sched_scalable_thread_state_t *sched_ts;

> +

> +typedef struct queue_table_t {

> +       queue_entry_t  queue[ODP_CONFIG_QUEUES];

> +} queue_table_t;

> +

> +static queue_table_t *queue_tbl;

> +

> +static inline odp_queue_t queue_from_id(uint32_t queue_id)

> +{

> +       return _odp_cast_scalar(odp_queue_t, queue_id + 1);

> +}

> +

> +queue_entry_t *get_qentry(uint32_t queue_id)

> +{

> +       return &queue_tbl->queue[queue_id];

> +}

> +

> +static int _odp_queue_disable_enq(sched_elem_t *q)

> +{

> +       ringidx_t old_read, old_write, new_write;

> +       uint32_t size;

> +

> +#ifndef ODP_CONFIG_USE_LLSC

> +       old_write = q->prod_write;

> +#endif

> +       size = q->prod_mask + 1;

> +       do {

> +               /* Need __atomic_load to avoid compiler reordering */

> +               old_read = __atomic_load_n(&q->prod_read, __ATOMIC_ACQUIRE);

> +#ifdef ODP_CONFIG_USE_LLSC

> +               old_write = ll32(&q->prod_write, __ATOMIC_RELAXED);

> +#endif

> +               if (old_write != old_read) {

> +                       /* Queue is not empty, cannot claim all elements

> +                       * Cannot disable enqueue.

> +                       */

> +                       return -1;

> +               }

> +               /* Claim all elements in ring */

> +               new_write = old_write + size;

> +#ifdef ODP_CONFIG_USE_LLSC

> +       } while (odp_unlikely(sc32(&q->prod_write,

> +                                new_write,

> +                                __ATOMIC_RELAXED)));

> +#else

> +       } while (!__atomic_compare_exchange_n(&q->prod_write,

> +                               &old_write, /* Updated on failure */

> +                               new_write,

> +                               true,

> +                               __ATOMIC_RELAXED,

> +                               __ATOMIC_RELAXED));

> +#endif

> +       /* All remaining elements claimed, noone else can enqueue */

> +       return 0;

> +}

> +

> +static uint32_t roundup_pow2(uint32_t v)

> +{

> +       uint32_t i;

> +

> +       /* Check if already power of 2 */

> +       if ((v & (v - 1)) == 0)

> +               return v;

> +

> +       for (i = 0; (i < (sizeof(v) * CHAR_BIT)) && (v != 0); i++)

> +               v = v >> 1;

> +

> +       return 1<<i;

> +}

> +

> +static int queue_init(int queue_idx, queue_entry_t *queue, const char *name,

> +                     const odp_queue_param_t *param)

> +{

> +       ringidx_t ring_idx;

> +       sched_elem_t *sched_elem;

> +       odp_shm_t shm;

> +       uint32_t ring_size;

> +       odp_buffer_hdr_t **ring;

> +

> +       sched_elem = &queue->s.sched_elem;

> +       ring_size = param->ring_size > 0 ?

> +                       roundup_pow2(param->ring_size) :

> +                       ODP_CONFIG_QUEUE_SIZE;

> +       strncpy(queue->s.name, name ? name : "", ODP_QUEUE_NAME_LEN - 1);

> +       queue->s.name[ODP_QUEUE_NAME_LEN - 1] = 0;

> +       memcpy(&queue->s.param, param, sizeof(odp_queue_param_t));

> +

> +       shm = odp_shm_reserve(name,

> +                       ring_size * sizeof(odp_buffer_hdr_t *),

> +                       ODP_CACHE_LINE_SIZE,

> +                       ODP_SHM_PROC);

> +       if (ODP_SHM_INVALID == shm)

> +               return -1;

> +

> +       ring = (odp_buffer_hdr_t **)odp_shm_addr(shm);

> +

> +       for (ring_idx = 0; ring_idx < ring_size; ring_idx++)

> +               ring[ring_idx] = NULL;

> +

> +       queue->s.shm = shm;

> +       queue->s.type = queue->s.param.type;

> +       queue->s.enqueue = queue_enq;

> +       queue->s.dequeue = queue_deq;

> +       queue->s.enqueue_multi = queue_enq_multi;

> +       queue->s.dequeue_multi = queue_deq_multi;

> +       queue->s.pktin = PKTIN_INVALID;

> +

> +       sched_elem->node.next = NULL;

> +#ifdef CONFIG_QSCHST_LOCK

> +       LOCK_INIT(&sched_elem->qschlock);

> +#endif

> +       sched_elem->qschst.numevts = 0;

> +       sched_elem->qschst.wrr_budget = CONFIG_WRR_WEIGHT;

> +       sched_elem->qschst.cur_ticket = 0;

> +       sched_elem->qschst.nxt_ticket = 0;

> +       sched_elem->pop_deficit = 0;

> +       if (queue->s.type == ODP_QUEUE_TYPE_SCHED)

> +               sched_elem->qschst_type = queue->s.param.sched.sync;

> +       else

> +               sched_elem->qschst_type = ODP_NO_SCHED_QUEUE;

> +       /* 2nd cache line - enqueue */

> +       sched_elem->prod_read = 0;

> +       sched_elem->prod_write = 0;

> +       sched_elem->prod_ring = ring;

> +       sched_elem->prod_mask = ring_size - 1;

> +       /* 3rd cache line - dequeue */

> +       sched_elem->cons_read = 0;

> +       sched_elem->cons_write = 0;

> +       sched_elem->rwin = NULL;

> +       sched_elem->schedq = NULL;

> +       sched_elem->user_ctx = queue->s.param.context;

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       sched_elem->cons_ring = ring;

> +       sched_elem->cons_mask = ring_size - 1;

> +       sched_elem->cons_type = sched_elem->qschst_type;

> +#endif

> +

> +       /* Queue initialized successfully, add it to the sched group */

> +       if (queue->s.type == ODP_QUEUE_TYPE_SCHED) {

> +               if (queue->s.param.sched.sync == ODP_SCHED_SYNC_ORDERED) {

> +                       sched_elem->rwin =

> +                               rwin_alloc(queue_idx, &queue->s.rwin_shm,

> +                                          queue->s.param.sched.lock_count);

> +                       if (sched_elem->rwin == NULL) {

> +                               ODP_ERR("Reorder window not created\n");

> +                               goto rwin_create_failed;

> +                       }

> +               }

> +               sched_elem->schedq =

> +                       schedq_from_sched_group(param->sched.group,

> +                                               param->sched.prio);

> +       }

> +

> +       return 0;

> +

> +rwin_create_failed:

> +       odp_shm_free(queue->s.shm);

> +       return -1;

> +}

> +

> +int odp_queue_init_global(void)

> +{

> +       uint32_t i;

> +       odp_shm_t shm;

> +

> +       ODP_DBG("Queue init ... ");

> +

> +       shm = odp_shm_reserve("odp_queues",

> +                             sizeof(queue_table_t),

> +                             sizeof(queue_entry_t), 0);

> +

> +       queue_tbl = odp_shm_addr(shm);

> +

> +       if (queue_tbl == NULL)

> +               return -1;

> +

> +       memset(queue_tbl, 0, sizeof(queue_table_t));

> +

> +       for (i = 0; i < ODP_CONFIG_QUEUES; i++) {

> +               /* init locks */

> +               queue_entry_t *queue;

> +

> +               queue = get_qentry(i);

> +               LOCK_INIT(&queue->s.lock);

> +               queue->s.index  = i;

> +               queue->s.handle = queue_from_id(i);

> +       }

> +

> +       ODP_DBG("done\n");

> +       ODP_DBG("Queue init global\n");

> +       ODP_DBG("  struct queue_entry_s size %zu\n",

> +               sizeof(struct queue_entry_s));

> +       ODP_DBG("  queue_entry_t size        %zu\n",

> +               sizeof(queue_entry_t));

> +       ODP_DBG("\n");

> +

> +       return 0;

> +}

> +

> +int odp_queue_term_global(void)

> +{

> +       int ret = 0;

> +       int rc = 0;

> +       queue_entry_t *queue;

> +       int i;

> +

> +       for (i = 0; i < ODP_CONFIG_QUEUES; i++) {

> +               queue = &queue_tbl->queue[i];

> +               if (__atomic_load_n(&queue->s.status,

> +                                   __ATOMIC_RELAXED) != QUEUE_STATUS_FREE) {

> +                       ODP_ERR("Not destroyed queue: %s\n", queue->s.name);

> +                       rc = -1;

> +               }

> +       }

> +

> +       ret = odp_shm_free(odp_shm_lookup("odp_queues"));

> +       if (ret < 0) {

> +               ODP_ERR("shm free failed for odp_queues");

> +               rc = -1;

> +       }

> +

> +       return rc;

> +}

> +

> +int odp_queue_capability(odp_queue_capability_t *capa)

> +{

> +       memset(capa, 0, sizeof(odp_queue_capability_t));

> +

> +       /* Reserve some queues for internal use */

> +       capa->max_queues        = ODP_CONFIG_QUEUES - NUM_INTERNAL_QUEUES;

> +       capa->max_ordered_locks = SCHEDULE_ORDERED_LOCKS_PER_QUEUE;

> +       capa->max_sched_groups  = sched_fn->num_grps();

> +       capa->sched_prios       = odp_schedule_num_prio();

> +

> +       return 0;

> +}

> +

> +odp_queue_type_t odp_queue_type(odp_queue_t handle)

> +{

> +       return queue_to_qentry(handle)->s.type;

> +}

> +

> +odp_schedule_sync_t odp_queue_sched_type(odp_queue_t handle)

> +{

> +       return queue_to_qentry(handle)->s.param.sched.sync;

> +}

> +

> +odp_schedule_prio_t odp_queue_sched_prio(odp_queue_t handle)

> +{

> +       return queue_to_qentry(handle)->s.param.sched.prio;

> +}

> +

> +odp_schedule_group_t odp_queue_sched_group(odp_queue_t handle)

> +{

> +       return queue_to_qentry(handle)->s.param.sched.group;

> +}

> +

> +int odp_queue_lock_count(odp_queue_t handle)

> +{

> +       queue_entry_t *queue = queue_to_qentry(handle);

> +

> +       return queue->s.param.sched.sync == ODP_SCHED_SYNC_ORDERED ?

> +               (int)queue->s.param.sched.lock_count : -1;

> +}

> +

> +odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)

> +{

> +       int queue_idx;

> +       odp_queue_t handle = ODP_QUEUE_INVALID;

> +       queue_entry_t *queue;

> +       odp_queue_param_t default_param;

> +

> +       if (param == NULL) {

> +               odp_queue_param_init(&default_param);

> +               param = &default_param;

> +       }

> +

> +       for (queue_idx = 0; queue_idx < ODP_CONFIG_QUEUES; queue_idx++) {

> +               queue = &queue_tbl->queue[queue_idx];

> +

> +               if (queue->s.status != QUEUE_STATUS_FREE)

> +                       continue;

> +

> +               LOCK(&queue->s.lock);

> +               if (queue->s.status == QUEUE_STATUS_FREE) {

> +                       if (queue_init(queue_idx, queue, name, param)) {

> +                               UNLOCK(&queue->s.lock);

> +                               return handle;

> +                       }

> +                       queue->s.status = QUEUE_STATUS_READY;

> +                       handle = queue->s.handle;

> +                       UNLOCK(&queue->s.lock);

> +                       break;

> +               }

> +               UNLOCK(&queue->s.lock);

> +       }

> +       return handle;

> +}

> +

> +int odp_queue_destroy(odp_queue_t handle)

> +{

> +       queue_entry_t *queue;

> +       sched_elem_t *q;

> +

> +       if (handle == ODP_QUEUE_INVALID)

> +               return -1;

> +

> +       queue = queue_to_qentry(handle);

> +       LOCK(&queue->s.lock);

> +       if (queue->s.status != QUEUE_STATUS_READY) {

> +               UNLOCK(&queue->s.lock);

> +               return -1;

> +       }

> +       q = &queue->s.sched_elem;

> +

> +#ifdef CONFIG_QSCHST_LOCK

> +       LOCK(&q->qschlock);

> +#endif

> +       if (_odp_queue_disable_enq(q)) {

> +               /* Producer side not empty */

> +#ifdef CONFIG_QSCHST_LOCK

> +               UNLOCK(&q->qschlock);

> +#endif

> +               UNLOCK(&queue->s.lock);

> +               return -1;

> +       }

> +       /* Enqueue is now disabled */

> +       if (q->cons_read != q->cons_write) {

> +               /* Consumer side is not empty

> +                * Roll back previous change, enable enqueue again.

> +                */

> +               uint32_t size;

> +

> +               size = q->prod_mask + 1;

> +               __atomic_fetch_sub(&q->prod_write, size, __ATOMIC_RELAXED);

> +#ifdef CONFIG_QSCHST_LOCK

> +               UNLOCK(&q->qschlock);

> +#endif

> +               UNLOCK(&queue->s.lock);

> +               return -1;

> +       }

> +#ifdef CONFIG_QSCHST_LOCK

> +       UNLOCK(&q->qschlock);

> +#endif

> +       /* Producer and consumer sides empty, enqueue disabled

> +        * Now wait until schedq state is empty and no outstanding tickets

> +        */

> +       while (__atomic_load_n(&q->qschst.numevts, __ATOMIC_RELAXED) != 0 ||

> +               __atomic_load_n(&q->qschst.cur_ticket, __ATOMIC_RELAXED) !=

> +               __atomic_load_n(&q->qschst.nxt_ticket, __ATOMIC_RELAXED)) {

> +               SEVL();

> +               while (WFE() && LDXR32((uint32_t *)&q->qschst.numevts,

> +                                      __ATOMIC_RELAXED) != 0)

> +                       DOZE();

> +       }

> +

> +       /* Adjust the spread factor for the queues in the schedule group */

> +       if (queue->s.type == ODP_QUEUE_TYPE_SCHED)

> +               sched_group_xcount_dec(queue->s.param.sched.group,

> +                                      queue->s.param.sched.prio);

> +

> +       if (odp_shm_free(queue->s.shm) < 0) {

> +               UNLOCK(&queue->s.lock);

> +               return -1;

> +       }

> +       if (queue->s.param.sched.sync == ODP_SCHED_SYNC_ORDERED) {

> +               if (odp_shm_free(queue->s.rwin_shm) < 0) {

> +                       ODP_ERR("Failed to free reorder window shm\n");

> +                       UNLOCK(&queue->s.lock);

> +                       return -1;

> +               }

> +       }

> +       queue->s.status = QUEUE_STATUS_FREE;

> +       UNLOCK(&queue->s.lock);

> +       return 0;

> +}

> +

> +int odp_queue_context_set(odp_queue_t handle, void *context,

> +                         uint32_t len ODP_UNUSED)

> +{

> +       odp_mb_full();

> +       queue_to_qentry(handle)->s.param.context = context;

> +       odp_mb_full();

> +       return 0;

> +}

> +

> +void *odp_queue_context(odp_queue_t handle)

> +{

> +       return queue_to_qentry(handle)->s.param.context;

> +}

> +

> +odp_queue_t odp_queue_lookup(const char *name)

> +{

> +       uint32_t i;

> +

> +       for (i = 0; i < ODP_CONFIG_QUEUES; i++) {

> +               queue_entry_t *queue = &queue_tbl->queue[i];

> +

> +               if (queue->s.status == QUEUE_STATUS_FREE ||

> +                   queue->s.status == QUEUE_STATUS_DESTROYED)

> +                       continue;

> +

> +               LOCK(&queue->s.lock);

> +               if (strcmp(name, queue->s.name) == 0) {

> +                       /* found it */

> +                       UNLOCK(&queue->s.lock);

> +                       return queue->s.handle;

> +               }

> +               UNLOCK(&queue->s.lock);

> +       }

> +

> +       return ODP_QUEUE_INVALID;

> +}

> +

> +static inline int _odp_queue_enq(sched_elem_t *q,

> +                                odp_buffer_hdr_t *buf_hdr[],

> +                                int num)

> +{

> +       ringidx_t old_read;

> +       ringidx_t old_write;

> +       ringidx_t new_write;

> +       int actual;

> +       uint32_t mask;

> +       odp_buffer_hdr_t **ring;

> +

> +       mask = q->prod_mask;

> +       ring = q->prod_ring;

> +

> +       /* Load producer ring state (read & write index) */

> +#ifndef ODP_CONFIG_USE_LLSC

> +       old_write = __atomic_load_n(&q->prod_write, __ATOMIC_RELAXED);

> +#endif

> +       do {

> +               /* Consumer does store-release prod_read, we need

> +                * load-acquire.

> +                */

> +               old_read = __atomic_load_n(&q->prod_read, __ATOMIC_ACQUIRE);

> +#ifdef ODP_CONFIG_USE_LLSC

> +               old_write = ll32(&q->prod_write, __ATOMIC_RELAXED);

> +#endif

> +

> +               actual = MIN(num, (int)((mask + 1) - (old_write - old_read)));

> +               if (odp_unlikely(actual <= 0))

> +                       return 0;

> +

> +               new_write = old_write + actual;

> +#ifdef ODP_CONFIG_USE_LLSC

> +       } while (odp_unlikely(sc32(&q->prod_write,

> +                                new_write,

> +                                __ATOMIC_RELAXED)));

> +#else

> +       } while (!__atomic_compare_exchange_n(&q->prod_write,

> +                                       &old_write, /* Updated on failure */

> +                                       new_write,

> +                                       true,

> +                                       __ATOMIC_RELAXED,

> +                                       __ATOMIC_RELAXED));

> +#endif

> +

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       __builtin_prefetch(&q->cons_write, 0, 0);

> +#endif

> +       /* Store our event(s) in the ring */

> +       do {

> +               ring[old_write & mask] = *buf_hdr++;

> +       } while (++old_write != new_write);

> +       old_write -= actual;

> +

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       __builtin_prefetch(&q->node, 1, 0);

> +#endif

> +       /* Wait for our turn to signal consumers */

> +       if (odp_unlikely(__atomic_load_n(&q->cons_write,

> +                                        __ATOMIC_RELAXED) != old_write)) {

> +               SEVL();

> +               while (WFE() && LDXR32(&q->cons_write,

> +                                      __ATOMIC_RELAXED) != old_write)

> +                       DOZE();

> +       }

> +

> +       /* Signal consumers that events are available (release events)

> +        * Enable other producers to continue

> +        */

> +#ifdef ODP_CONFIG_USE_DMB

> +       /* Wait for writes (to ring slots) to complete */

> +       __asm volatile("dmb ishst" ::: "memory");

> +       q->cons_write = new_write;

> +#else

> +       __atomic_store_n(&q->cons_write, new_write, __ATOMIC_RELEASE);

> +#endif

> +

> +       return actual;

> +}

> +

> +static inline int _odp_queue_enq_sp(sched_elem_t *q,

> +                                   odp_buffer_hdr_t *buf_hdr[],

> +                                   int num)

> +{

> +       ringidx_t old_read;

> +       ringidx_t old_write;

> +       ringidx_t new_write;

> +       int actual;

> +       uint32_t mask;

> +       odp_buffer_hdr_t **ring;

> +

> +       mask = q->prod_mask;

> +       ring = q->prod_ring;

> +

> +       /* Load producer ring state (read & write index) */

> +       old_write = q->prod_write;

> +       /* Consumer does store-release prod_read, we need load-acquire */

> +       old_read = __atomic_load_n(&q->prod_read, __ATOMIC_ACQUIRE);

> +       actual = MIN(num, (int)((mask + 1) - (old_write - old_read)));

> +       if (odp_unlikely(actual <= 0))

> +               return 0;

> +

> +       new_write = old_write + actual;

> +       q->prod_write = new_write;

> +

> +       /* Store our event(s) in the ring */

> +       do {

> +               ring[old_write & mask] = *buf_hdr++;

> +       } while (++old_write != new_write);

> +       old_write -= actual;

> +

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       __builtin_prefetch(&q->node, 1, 0);

> +#endif

> +

> +       /* Signal consumers that events are available (release events)

> +        * Enable other producers to continue

> +        */

> +#ifdef CONFIG_QSCHST_LOCK

> +       q->cons_write = new_write;

> +#else

> +#ifdef ODP_CONFIG_USE_DMB

> +       __asm volatile("dmb ishst" ::: "memory");

> +       q->cons_write = new_write;

> +#else

> +       __atomic_store_n(&q->cons_write, new_write, __ATOMIC_RELEASE);

> +#endif

> +#endif

> +

> +       return actual;

> +}

> +

> +int queue_enq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[], int num)

> +{

> +       int actual;

> +       int i;

> +       sched_scalable_thread_state_t *ts;

> +       reorder_context_t *first;

> +       reorder_context_t *cur;

> +       bitset_t next_idx;

> +

> +#ifdef CONFIG_QSCHST_LOCK

> +       LOCK(&queue->s.sched_elem.qschlock);

> +#endif

> +       ts = sched_ts;

> +       if (ts && odp_unlikely(ts->out_of_order)) {

> +               first = ts->rctx;

> +               ODP_ASSERT(ts->rctx != NULL);

> +               cur = &first[(int)first->cur_idx - (int)first->idx];

> +               for (i = 0; i < num; i++) {

> +                       if (odp_unlikely(cur->numevts == RC_EVT_SIZE)) {

> +                               /* No more space in current reorder context

> +                                * Try to allocate another.

> +                                */

> +                               if (odp_unlikely(

> +                                       bitset_is_null(ts->priv_rvec_free))) {

> +                                       ts->priv_rvec_free =

> +                                               atom_bitset_xchg(

> +                                                       &ts->rvec_free,

> +                                                       0,

> +                                                       __ATOMIC_RELAXED);

> +                                       if (odp_unlikely(bitset_is_null(

> +                                                       ts->priv_rvec_free)))

> +                                               /* Out of reorder contexts.

> +                                                * Return the number of events

> +                                                * stored so far.

> +                                                */

> +#ifdef CONFIG_QSCHST_LOCK

> +                                               UNLOCK(&queue->s.sched_elem.

> +                                                      qschlock);

> +#endif

> +                                               return i;

> +                               }

> +                               next_idx = bitset_ffs(ts->priv_rvec_free) - 1;

> +                               ts->priv_rvec_free =

> +                                       bitset_clr(ts->priv_rvec_free,

> +                                                  next_idx);

> +                               /* Link current to next (for eventual

> +                                * retiring)

> +                                */

> +                               cur->next_idx = next_idx;

> +                               /* Link first to next (for next call to

> +                               * queue_enq_multi())

> +                               */

> +                               first->cur_idx = next_idx;

> +                               /* Update current to next */

> +                               cur = &ts->rvec[next_idx];

> +                               rctx_init(cur, next_idx, NULL, 0);

> +                               /* The last rctx (so far) */

> +                               cur->next_idx = first->idx;

> +                       }

> +                       cur->events[cur->numevts] = buf_hdr[i];

> +                       cur->destq[cur->numevts] = queue;

> +                       cur->numevts++;

> +               }

> +               /* All events stored. */

> +#ifdef CONFIG_QSCHST_LOCK

> +               UNLOCK(&queue->s.sched_elem.qschlock);

> +#endif

> +               return num;

> +       }

> +

> +#ifdef CONFIG_QSCHST_LOCK

> +       actual = _odp_queue_enq_sp(&queue->s.sched_elem, buf_hdr, num);

> +#else

> +       actual = _odp_queue_enq(&queue->s.sched_elem, buf_hdr, num);

> +#endif

> +

> +       if (odp_likely(queue->s.sched_elem.schedq != NULL && actual != 0)) {

> +               /* Perform scheduler related updates. */

> +#ifdef CONFIG_QSCHST_LOCK

> +               sched_update_enq_sp(&queue->s.sched_elem, actual);

> +#else

> +               sched_update_enq(&queue->s.sched_elem, actual);

> +#endif

> +       }

> +

> +#ifdef CONFIG_QSCHST_LOCK

> +       UNLOCK(&queue->s.sched_elem.qschlock);

> +#endif

> +       return actual;

> +}

> +

> +int queue_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr)

> +{

> +       return odp_likely(

> +               queue_enq_multi(queue, &buf_hdr, 1) == 1) ? 0 : -1;

> +}

> +

> +int odp_queue_enq_multi(odp_queue_t handle, const odp_event_t ev[], int num)

> +{

> +       odp_buffer_hdr_t *buf_hdr[QUEUE_MULTI_MAX];

> +       queue_entry_t *queue;

> +       int i;

> +

> +       if (num > QUEUE_MULTI_MAX)

> +               num = QUEUE_MULTI_MAX;

> +

> +       queue = queue_to_qentry(handle);

> +

> +       for (i = 0; i < num; i++)

> +               buf_hdr[i] = (odp_buffer_hdr_t *)ev[i];

> +

> +       return queue->s.enqueue_multi(queue, buf_hdr, num);

> +}

> +

> +int odp_queue_enq(odp_queue_t handle, odp_event_t ev)

> +{

> +       queue_entry_t *queue;

> +

> +       queue = queue_to_qentry(handle);

> +       return queue->s.enqueue(queue, (odp_buffer_hdr_t *)ev);

> +}

> +

> +/* Single-consumer dequeue. */

> +int _odp_queue_deq_sc(sched_elem_t *q, odp_event_t *evp, int num)

> +{

> +       int actual;

> +       int i;

> +       ringidx_t old_read;

> +       ringidx_t old_write;

> +       ringidx_t new_read;

> +       uint32_t mask;

> +       odp_event_t *ring;

> +

> +       /* Load consumer ring state (read & write index). */

> +       old_read  = q->cons_read;

> +       /* Producer does store-release cons_write, we need load-acquire */

> +       old_write = __atomic_load_n(&q->cons_write, __ATOMIC_ACQUIRE);

> +       actual    = MIN(num, (int)(old_write - old_read));

> +

> +       if (odp_unlikely(actual <= 0))

> +               return 0;

> +

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       __builtin_prefetch(&q->node, 1, 0);

> +#endif

> +       new_read = old_read + actual;

> +       q->cons_read = new_read;

> +

> +       mask = q->cons_mask;

> +       ring = (odp_event_t *)q->cons_ring;

> +       do {

> +               *evp++ = ring[old_read & mask];

> +       } while (++old_read != new_read);

> +

> +       /* Signal producers that empty slots are available

> +        * (release ring slots). Enable other consumers to continue.

> +        */

> +#ifdef CONFIG_QSCHST_LOCK

> +       q->prod_read = new_read;

> +#else

> +#ifdef ODP_CONFIG_USE_DMB

> +       /* Wait for loads (from ring slots) to complete. */

> +       __asm volatile("dmb ishld" ::: "memory");

> +       q->prod_read = new_read;

> +#else

> +       __atomic_store_n(&q->prod_read, new_read, __ATOMIC_RELEASE);

> +#endif

> +#endif

> +       /* Prefetch events after we have release ring buffer slots */

> +       for (i = 0; i < actual; i++) {

> +               odp_event_t evt = *--evp;

> +

> +               __builtin_prefetch(

> +                       odp_buffer_addr(odp_buffer_from_event(evt)), 0, 0);

> +       }

> +       return actual;

> +}

> +

> +inline int _odp_queue_deq(sched_elem_t *q, odp_event_t *evp, int num)

> +{

> +       int actual;

> +       ringidx_t old_read;

> +       ringidx_t old_write;

> +       ringidx_t new_read;

> +       uint32_t mask;

> +       odp_buffer_hdr_t **ring;

> +       odp_buffer_hdr_t **p_buf_hdr;

> +

> +       mask = q->cons_mask;

> +       ring = q->cons_ring;

> +

> +       /* Load consumer ring state (read & write index) */

> +#ifndef ODP_CONFIG_USE_LLSC

> +       old_read = __atomic_load_n(&q->cons_read, __ATOMIC_RELAXED);

> +#endif

> +       do {

> +               /* Need __atomic_load to avoid compiler reordering

> +                * Producer does store-release cons_write, we need

> +                * load-acquire.

> +                */

> +               old_write = __atomic_load_n(&q->cons_write, __ATOMIC_ACQUIRE);

> +#ifdef ODP_CONFIG_USE_LLSC

> +               old_read = ll32(&q->cons_read, __ATOMIC_RELAXED);

> +#endif

> +               /* Prefetch ring buffer array */

> +               __builtin_prefetch(&q->cons_ring[old_read & mask], 0, 0);

> +

> +               actual = MIN(num, (int)(old_write - old_read));

> +               if (odp_unlikely(actual <= 0))

> +                       return 0;

> +

> +               /* Attempt to free ring slot(s) */

> +               new_read = old_read + actual;

> +#ifdef ODP_CONFIG_USE_LLSC

> +       } while (odp_unlikely(sc32(&q->cons_read, new_read, __ATOMIC_RELAXED)));

> +#else

> +       } while (!__atomic_compare_exchange_n(&q->cons_read,

> +                                       &old_read, /* Updated on failure */

> +                                       new_read,

> +                                       true,

> +                                       __ATOMIC_RELAXED,

> +                                       __ATOMIC_RELAXED));

> +#endif

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       __builtin_prefetch(&q->prod_read, 0, 0);

> +#endif

> +       p_buf_hdr = (odp_buffer_hdr_t **)evp;

> +       do {

> +               odp_buffer_hdr_t *p_buf;

> +

> +               p_buf = ring[old_read & mask];

> +               __builtin_prefetch(

> +                       odp_buffer_addr(

> +                               odp_buffer_from_event((odp_event_t)p_buf)),

> +                                                     0, 0);

> +               *p_buf_hdr++ = p_buf;

> +       } while (++old_read != new_read);

> +       old_read -= actual;

> +

> +#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS

> +       __builtin_prefetch(&q->node, 1, 0);

> +#endif

> +       /* Wait for our turn to signal producers */

> +       if (odp_unlikely(__atomic_load_n(&q->prod_read, __ATOMIC_RELAXED) !=

> +               old_read)) {

> +               SEVL();

> +               while (WFE() && LDXR32(&q->prod_read,

> +                                      __ATOMIC_RELAXED) != old_read)

> +                       DOZE();

> +       }

> +

> +       /* Signal producers that empty slots are available

> +        * (release ring slots)

> +        * Enable other consumers to continue

> +        */

> +#ifdef ODP_CONFIG_USE_DMB

> +       /* Wait for loads (from ring slots) to complete */

> +       __asm volatile("dmb ishld" ::: "memory");

> +       q->prod_read = new_read;

> +#else

> +       __atomic_store_n(&q->prod_read, new_read, __ATOMIC_RELEASE);

> +#endif

> +

> +       return actual;

> +}

> +

> +int queue_deq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[], int num)

> +{

> +       sched_elem_t *q;

> +

> +       q = &queue->s.sched_elem;

> +       return _odp_queue_deq(q, (odp_event_t *)buf_hdr, num);

> +}

> +

> +odp_buffer_hdr_t *queue_deq(queue_entry_t *queue)

> +{

> +       sched_elem_t *q;

> +       odp_buffer_hdr_t *buf_hdr;

> +

> +       q = &queue->s.sched_elem;

> +       if (_odp_queue_deq(q, (odp_event_t *)&buf_hdr, 1) == 1)

> +               return buf_hdr;

> +       else

> +               return BUFFER_HDR_INVALID;

> +}

> +

> +int odp_queue_deq_multi(odp_queue_t handle, odp_event_t events[], int num)

> +{

> +       queue_entry_t *queue;

> +

> +       queue = queue_to_qentry(handle);

> +       return queue->s.dequeue_multi(queue, (odp_buffer_hdr_t **)events, num);

> +}

> +

> +odp_event_t odp_queue_deq(odp_queue_t handle)

> +{

> +       queue_entry_t *queue;

> +

> +       queue = queue_to_qentry(handle);

> +       return (odp_event_t)queue->s.dequeue(queue);

> +}

> +

> +void odp_queue_param_init(odp_queue_param_t *params)

> +{

> +       memset(params, 0, sizeof(odp_queue_param_t));

> +       params->type = ODP_QUEUE_TYPE_PLAIN;

> +       params->enq_mode = ODP_QUEUE_OP_MT;

> +       params->deq_mode = ODP_QUEUE_OP_MT;

> +       params->sched.prio = ODP_SCHED_PRIO_DEFAULT;

> +       params->sched.sync = ODP_SCHED_SYNC_PARALLEL;

> +       params->sched.group = ODP_SCHED_GROUP_ALL;

> +}

> +

> +int odp_queue_info(odp_queue_t handle, odp_queue_info_t *info)

> +{

> +       uint32_t queue_id;

> +       queue_entry_t *queue;

> +       int status;

> +

> +       if (odp_unlikely(info == NULL)) {

> +               ODP_ERR("Unable to store info, NULL ptr given\n");

> +               return -1;

> +       }

> +

> +       queue_id = queue_to_id(handle);

> +

> +       if (odp_unlikely(queue_id >= ODP_CONFIG_QUEUES)) {

> +               ODP_ERR("Invalid queue handle:%" PRIu64 "\n",

> +                       odp_queue_to_u64(handle));

> +               return -1;

> +       }

> +

> +       queue = get_qentry(queue_id);

> +

> +       LOCK(&queue->s.lock);

> +       status = queue->s.status;

> +

> +       if (odp_unlikely(status == QUEUE_STATUS_FREE ||

> +                        status == QUEUE_STATUS_DESTROYED)) {

> +               UNLOCK(&queue->s.lock);

> +               ODP_ERR("Invalid queue status:%d\n", status);

> +               return -1;

> +       }

> +

> +       info->name = queue->s.name;

> +       info->param = queue->s.param;

> +

> +       UNLOCK(&queue->s.lock);

> +

> +       return 0;

> +}

> +

> +uint64_t odp_queue_to_u64(odp_queue_t hdl)

> +{

> +       return _odp_pri(hdl);

> +}

> diff --git a/platform/linux-generic/odp_schedule_if.c b/platform/linux-generic/odp_schedule_if.c

> index a9ede98d..bf92333e 100644

> --- a/platform/linux-generic/odp_schedule_if.c

> +++ b/platform/linux-generic/odp_schedule_if.c

> @@ -6,24 +6,38 @@

>

>  #include <odp_schedule_if.h>

>

> -extern const schedule_fn_t schedule_sp_fn;

> -extern const schedule_api_t schedule_sp_api;

> +#if defined(ODP_SCHEDULE_SCALABLE)

>

> -extern const schedule_fn_t schedule_default_fn;

> -extern const schedule_api_t schedule_default_api;

> +extern const schedule_fn_t  schedule_scalable_fn;

> +extern const schedule_api_t schedule_scalable_api;

>

> -extern const schedule_fn_t schedule_iquery_fn;

> -extern const schedule_api_t schedule_iquery_api;

> +const schedule_fn_t  *sched_fn  = &schedule_scalable_fn;

> +const schedule_api_t *sched_api = &schedule_scalable_api;

>

> -#ifdef ODP_SCHEDULE_SP

> -const schedule_fn_t *sched_fn   = &schedule_sp_fn;

> -const schedule_api_t *sched_api = &schedule_sp_api;

>  #elif defined(ODP_SCHEDULE_IQUERY)

> -const schedule_fn_t *sched_fn   = &schedule_iquery_fn;

> +

> +extern const schedule_fn_t  schedule_iquery_fn;

> +extern const schedule_api_t schedule_iquery_api;

> +

> +const schedule_fn_t  *sched_fn  = &schedule_iquery_fn;

>  const schedule_api_t *sched_api = &schedule_iquery_api;

> -#else

> +

> +#elif defined(ODP_SCHEDULE_SP)

> +

> +extern const schedule_fn_t  schedule_sp_fn;

> +extern const schedule_api_t schedule_sp_api;

> +

> +const schedule_fn_t  *sched_fn  = &schedule_sp_fn;

> +const schedule_api_t *sched_api = &schedule_sp_api;

> +

> +#else /* default scheduler */

> +

> +extern const schedule_fn_t  schedule_default_fn;

> +extern const schedule_api_t schedule_default_api;

> +

>  const schedule_fn_t  *sched_fn  = &schedule_default_fn;

>  const schedule_api_t *sched_api = &schedule_default_api;

> +

>  #endif

>

>  uint64_t odp_schedule_wait_time(uint64_t ns)

> diff --git a/platform/linux-generic/odp_schedule_scalable.c b/platform/linux-generic/odp_schedule_scalable.c

> new file mode 100644

> index 00000000..1e503f5e

> --- /dev/null

> +++ b/platform/linux-generic/odp_schedule_scalable.c

> @@ -0,0 +1,1959 @@

> +/* Copyright (c) 2017, ARM Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#include <odp/api/align.h>

> +#include <odp/api/atomic.h>

> +#include <odp/api/cpu.h>

> +#include <odp/api/hints.h>

> +#include <odp/api/schedule.h>

> +#include <odp/api/shared_memory.h>

> +#include <odp/api/sync.h>

> +#include <odp/api/thread.h>

> +#include <odp/api/thrmask.h>

> +#include <odp/api/time.h>

> +

> +#include <odp_internal.h>

> +#include <odp_config_internal.h>

> +#include <odp_debug_internal.h>

> +

> +#include <odp_align_internal.h>

> +#include <odp_buffer_inlines.h>

> +#include <odp_llqueue.h>

> +#include <odp_queue_internal.h>

> +#include <odp_schedule_if.h>

> +#include <odp_llsc.h>

> +#include <odp_bitset.h>

> +#include <odp_atomic16.h>

> +#include <odp_packet_io_internal.h>

> +

> +#include <limits.h>

> +#include <stdbool.h>

> +#include <string.h>

> +

> +#include <odp/api/plat/ticketlock_inlines.h>

> +#define LOCK(a) _odp_ticketlock_lock((a))

> +#define UNLOCK(a) _odp_ticketlock_unlock((a))

> +

> +#define TAG_EMPTY 0U

> +#define TAG_USED (1U << 15)

> +#define TAG_BUSY (1U << 31)

> +#define PKTIO_QUEUE_2_TAG(p, q) ((p) << 16 | (q) | TAG_USED)

> +#define TAG_2_PKTIO(t) (((t) >> 16) & 0x7FFF)

> +#define TAG_2_QUEUE(t) ((t) & 0x7FFF)

> +#define TAG_IS_READY(t) (((t) & (TAG_USED | TAG_BUSY)) == TAG_USED)

> +#define PKTIN_MAX (ODP_CONFIG_PKTIO_ENTRIES * PKTIO_MAX_QUEUES)

> +#define MAXTHREADS ATOM_BITSET_SIZE

> +

> +static uint32_t pktin_num;

> +static uint32_t pktin_hi;

> +static uint16_t pktin_count[ODP_CONFIG_PKTIO_ENTRIES];

> +static uint32_t pktin_tags[PKTIN_MAX] ODP_ALIGNED_CACHE;

> +

> +#define __atomic_fetch_max(var, v, mo) do { \

> +               /* Evalulate 'v' once */ \

> +               __typeof__(v) tmp_v = (v); \

> +               __typeof__(*var) old_var = \

> +                       __atomic_load_n((var), __ATOMIC_RELAXED); \

> +               while (tmp_v > old_var) { \

> +                       /* Attempt to store 'v' in '*var' */ \

> +                       if (__atomic_compare_exchange_n((var), &old_var, \

> +                                                       tmp_v, true, (mo), \

> +                                                       (mo))) \

> +                               break; \

> +                       /* Else failure, try again (with updated value of \

> +                        * old_var). \

> +                        */ \

> +               } \

> +               /* v <= old_var, nothing to do */ \

> +       } while (0)

> +

> +ODP_STATIC_ASSERT(ODP_SCHED_PRIO_LOWEST == (ODP_SCHED_PRIO_NUM - 1),

> +                 "lowest_prio_does_not_match_with_num_prios");

> +

> +ODP_STATIC_ASSERT((ODP_SCHED_PRIO_NORMAL > 0) &&

> +                 (ODP_SCHED_PRIO_NORMAL < (ODP_SCHED_PRIO_NUM - 1)),

> +                 "normal_prio_is_not_between_highest_and_lowest");

> +

> +ODP_STATIC_ASSERT(IS_POWER_TWO(ODP_CONFIG_QUEUES),

> +                 "Number_of_queues_is_not_power_of_two");

> +

> +/*

> + * Scheduler group related variables.

> + */

> +/* Currently used scheduler groups */

> +static sched_group_mask_t sg_free;

> +static sched_group_t *sg_vec[MAX_SCHED_GROUP];

> +/* Group lock for MT-safe APIs */

> +odp_spinlock_t sched_grp_lock;

> +

> +#define SCHED_GROUP_JOIN 0

> +#define SCHED_GROUP_LEAVE 1

> +

> +/*

> + * Per thread state

> + */

> +static sched_scalable_thread_state_t thread_state[MAXTHREADS];

> +__thread sched_scalable_thread_state_t *sched_ts;

> +

> +/*

> + * Forward declarations.

> + */

> +static int thread_state_init(int tidx)

> +{

> +       sched_scalable_thread_state_t *ts;

> +       uint32_t i;

> +

> +       ODP_ASSERT(tidx < MAXTHREADS);

> +       ts = &thread_state[tidx];

> +       ts->atomq = NULL;

> +       ts->rctx = NULL;

> +       ts->pause = false;

> +       ts->out_of_order = false;

> +       ts->tidx = tidx;

> +       ts->dequeued = 0;

> +       ts->pktin_next = 0;

> +       ts->pktin_poll_cnts = 0;

> +       ts->ticket = TICKET_INVALID;

> +       ts->priv_rvec_free = 0;

> +       ts->rvec_free = (1ULL << TS_RVEC_SIZE) - 1;

> +       ts->num_schedq = 0;

> +       ts->sg_sem = 1; /* Start with sched group semaphore changed */

> +       memset(ts->sg_actual, 0, sizeof(ts->sg_actual));

> +       for (i = 0; i < TS_RVEC_SIZE; i++) {

> +               ts->rvec[i].rvec_free = &ts->rvec_free;

> +               ts->rvec[i].idx = i;

> +       }

> +       sched_ts = ts;

> +

> +       return 0;

> +}

> +

> +static void insert_schedq_in_list(sched_scalable_thread_state_t *ts,

> +                                 sched_queue_t *schedq)

> +{

> +       /* Find slot for schedq */

> +       for (uint32_t i = 0; i < ts->num_schedq; i++) {

> +               /* Lower value is higher priority and closer to start of list */

> +               if (schedq->prio <= ts->schedq_list[i]->prio) {

> +                       /* This is the slot! */

> +                       sched_queue_t *tmp;

> +

> +                       tmp = ts->schedq_list[i];

> +                       ts->schedq_list[i] = schedq;

> +                       schedq = tmp;

> +                       /* Continue the insertion procedure with the

> +                        * new schedq.

> +                        */

> +               }

> +       }

> +       if (ts->num_schedq == SCHEDQ_PER_THREAD)

> +               ODP_ABORT("Too many schedqs\n");

> +       ts->schedq_list[ts->num_schedq++] = schedq;

> +}

> +

> +static void remove_schedq_from_list(sched_scalable_thread_state_t *ts,

> +                                   sched_queue_t *schedq)

> +{

> +       /* Find schedq */

> +       for (uint32_t i = 0; i < ts->num_schedq; i++)

> +               if (ts->schedq_list[i] == schedq) {

> +                       /* Move remaining schedqs */

> +                       for (uint32_t j = i + 1; j < ts->num_schedq; j++)

> +                               ts->schedq_list[j - 1] = ts->schedq_list[j];

> +                       ts->num_schedq--;

> +                       return;

> +               }

> +       ODP_ABORT("Cannot find schedq\n");

> +}

> +

> +/*******************************************************************************

> + * Scheduler queues

> + ******************************************************************************/

> +#ifndef odp_container_of

> +#define odp_container_of(pointer, type, member) \

> +       ((type *)(void *)(((char *)pointer) - offsetof(type, member)))

> +#endif

> +

> +static inline void schedq_init(sched_queue_t *schedq, uint32_t prio)

> +{

> +       llqueue_init(&schedq->llq);

> +       schedq->prio = prio;

> +}

> +

> +static inline sched_elem_t *schedq_peek(sched_queue_t *schedq)

> +{

> +       struct llnode *ptr;

> +

> +       ptr = llq_head(&schedq->llq);

> +       return odp_container_of(ptr, sched_elem_t, node);

> +}

> +

> +static inline odp_bool_t schedq_cond_pop(sched_queue_t *schedq,

> +                                        sched_elem_t *elem)

> +{

> +       return llq_dequeue_cond(&schedq->llq, &elem->node);

> +}

> +

> +static inline void schedq_push(sched_queue_t *schedq, sched_elem_t *elem)

> +{

> +       llq_enqueue(&schedq->llq, &elem->node);

> +}

> +

> +static inline odp_bool_t schedq_cond_rotate(sched_queue_t *schedq,

> +                                           sched_elem_t *elem)

> +{

> +       return llq_cond_rotate(&schedq->llq, &elem->node);

> +}

> +

> +static inline bool schedq_elem_on_queue(sched_elem_t *elem)

> +{

> +       return elem->node.next != NULL;

> +}

> +

> +/*******************************************************************************

> + * Shared metadata btwn scheduler and queue

> + ******************************************************************************/

> +

> +void sched_update_enq(sched_elem_t *q, uint32_t actual)

> +{

> +       union {

> +               qschedstate_t ss;

> +               uint64_t ui;

> +       } oss, nss;

> +       uint32_t ticket;

> +

> +#ifndef ODP_CONFIG_USE_LLSC

> +       oss.ss = q->qschst;

> +#endif

> +       /* Update event counter, optionally taking a ticket. */

> +       do {

> +               ticket = TICKET_INVALID;

> +#ifdef ODP_CONFIG_USE_LLSC

> +               oss.ui = ll64((uint64_t *)&q->qschst, __ATOMIC_RELAXED);

> +#endif

> +               nss = oss;

> +               nss.ss.numevts += actual;

> +               if (odp_unlikely(oss.ss.numevts <= 0 && nss.ss.numevts > 0))

> +                       /* E -> NE transition */

> +                       if (q->qschst_type != ODP_SCHED_SYNC_ATOMIC ||

> +                           oss.ss.cur_ticket == oss.ss.nxt_ticket)

> +                               /* Parallel or ordered queues: always take

> +                                * ticket.

> +                                * Atomic queue: only take ticket if one is

> +                                * immediately available.

> +                                * Otherwise ticket already taken => queue

> +                                * processed by some thread.

> +                                */

> +                               ticket = nss.ss.nxt_ticket++;

> +               /* Else queue already was non-empty. */

> +       /* Attempt to update numevts counter and optionally take ticket. */

> +#ifdef ODP_CONFIG_USE_LLSC

> +       } while (odp_unlikely(

> +                      sc64((uint64_t *)&q->qschst, nss.ui, __ATOMIC_RELAXED)));

> +#else

> +       } while (!__atomic_compare_exchange(

> +                      &q->qschst, &oss.ss, &nss.ss,

> +                      true, __ATOMIC_RELAXED, __ATOMIC_RELAXED));

> +#endif

> +

> +       if (odp_unlikely(ticket != TICKET_INVALID)) {

> +               /* Wait for our turn to update schedq. */

> +               if (odp_unlikely(

> +                           __atomic_load_n(&q->qschst.cur_ticket,

> +                                           __ATOMIC_ACQUIRE) != ticket)) {

> +                       SEVL();

> +                       while (WFE() &&

> +                              LDXR8(&q->qschst.cur_ticket,

> +                                     __ATOMIC_ACQUIRE) != ticket)

> +                               DOZE();

> +               }

> +               /* Enqueue at end of scheduler queue */

> +               /* We are here because of empty-to-non-empty transition

> +                * This means queue must be pushed to schedq if possible

> +                * but we can't do that if it already is on the schedq

> +                */

> +               if (odp_likely(!schedq_elem_on_queue(q) &&

> +                              q->pop_deficit == 0)) {

> +                       /* Queue not already on schedq and no pop deficit means

> +                        * we can push queue to schedq */

> +                       schedq_push(q->schedq, q);

> +               } else {

> +                       /* Missed push => cancels one missed pop */

> +                       q->pop_deficit--;

> +               }

> +#ifdef ODP_CONFIG_USE_DMB

> +               __atomic_thread_fence(__ATOMIC_RELEASE);

> +               __atomic_store_n(&q->qschst.cur_ticket, ticket + 1,

> +                                __ATOMIC_RELAXED);

> +#else

> +               __atomic_store_n(&q->qschst.cur_ticket, ticket + 1,

> +                                __ATOMIC_RELEASE);

> +#endif

> +       }

> +       /* Else queue was not empty or atomic queue already busy. */

> +}

> +

> +void sched_update_enq_sp(sched_elem_t *q, uint32_t actual)

> +{

> +       qschedstate_t oss, nss;

> +       uint32_t ticket;

> +

> +       oss = q->qschst;

> +       /* Update event counter, optionally taking a ticket. */

> +       ticket = TICKET_INVALID;

> +       nss = oss;

> +       nss.numevts += actual;

> +       if (odp_unlikely(oss.numevts <= 0 && nss.numevts > 0)) {

> +               /* E -> NE transition */

> +               if (q->qschst_type != ODP_SCHED_SYNC_ATOMIC ||

> +                   oss.cur_ticket == oss.nxt_ticket) {

> +                       /* Parallel or ordered queues: always take

> +                        * ticket.

> +                        * Atomic queue: only take ticket if one is

> +                        * immediately available. Otherwise ticket already

> +                        * taken => queue owned/processed by some thread

> +                        */

> +                       ticket = nss.nxt_ticket++;

> +               }

> +       }

> +       /* Else queue already was non-empty. */

> +       /* Attempt to update numevts counter and optionally take ticket. */

> +       q->qschst = nss;

> +

> +       if (odp_unlikely(ticket != TICKET_INVALID)) {

> +               /* Enqueue at end of scheduler queue */

> +               /* We are here because of empty-to-non-empty transition

> +                * This means queue must be pushed to schedq if possible

> +                * but we can't do that if it already is on the schedq

> +                */

> +               if (odp_likely(!schedq_elem_on_queue(q) &&

> +                              q->pop_deficit == 0)) {

> +                       /* Queue not already on schedq and no pop deficit means

> +                        * we can push queue to schedq */

> +                       schedq_push(q->schedq, q);

> +               } else {

> +                       /* Missed push => cancels one missed pop */

> +                       q->pop_deficit--;

> +               }

> +               q->qschst.cur_ticket = ticket + 1;

> +       }

> +       /* Else queue was not empty or atomic queue already busy. */

> +}

> +

> +/* The scheduler is the only entity that performs the dequeue from a queue. */

> +static void sched_update_deq(sched_elem_t *q,

> +               uint32_t actual, bool atomic) __attribute__((always_inline));

> +static inline void sched_update_deq(sched_elem_t *q,

> +               uint32_t actual, bool atomic)

> +{

> +       union {

> +               qschedstate_t ss;

> +               uint64_t ui;

> +       } oss, nss;

> +       uint32_t ticket;

> +

> +       if (atomic) {

> +               qschedstate_t oss, nss;

> +               bool pushed = false;

> +

> +               /* We own this atomic queue, only we can dequeue from it and

> +                * thus decrease numevts. Other threads may enqueue and thus

> +                * increase numevts.

> +                * This means that numevts can't unexpectedly become 0 and

> +                * invalidate a push operation already performed

> +                */

> +               oss = q->qschst;

> +               do {

> +                       ODP_ASSERT(oss.cur_ticket == sched_ts->ticket);

> +                       nss = oss;

> +                       nss.numevts -= actual;

> +                       if (nss.numevts > 0 && !pushed) {

> +                               schedq_push(q->schedq, q);

> +                               pushed = true;

> +                       }

> +                       /* Attempt to release ticket expecting our view of

> +                        * numevts to be correct

> +                        * Unfortunately nxt_ticket will also be included in

> +                        * the CAS operation

> +                        */

> +                       nss.cur_ticket = sched_ts->ticket + 1;

> +               } while (odp_unlikely(!__atomic_compare_exchange(

> +                                                         &q->qschst,

> +                                                         &oss, &nss,

> +                                                         true,

> +                                                         __ATOMIC_RELEASE,

> +                                                         __ATOMIC_RELAXED)));

> +               return;

> +       }

> +

> +#ifndef ODP_CONFIG_USE_LLSC

> +       oss.ss = q->qschst;

> +#endif

> +       do {

> +               ticket = TICKET_INVALID;

> +#ifdef ODP_CONFIG_USE_LLSC

> +               oss.ui = ll64((uint64_t *)&q->qschst, __ATOMIC_RELAXED);

> +#endif

> +               nss = oss;

> +               nss.ss.numevts -= actual;

> +               nss.ss.wrr_budget -= actual;

> +               if ((oss.ss.numevts > 0 && nss.ss.numevts <= 0) ||

> +                   oss.ss.wrr_budget <= actual) {

> +                       /* If we have emptied parallel/ordered queue or

> +                        * exchausted its WRR budget, we need a ticket

> +                        * for a later pop.

> +                        */

> +                       ticket = nss.ss.nxt_ticket++;

> +                       /* Reset wrr_budget as we might also push the

> +                        * queue to the schedq.

> +                        */

> +                       nss.ss.wrr_budget = CONFIG_WRR_WEIGHT;

> +               }

> +       /* Attempt to update numevts and optionally take ticket. */

> +#ifdef ODP_CONFIG_USE_LLSC

> +       } while (odp_unlikely(

> +                      sc64((uint64_t *)&q->qschst, nss.ui, __ATOMIC_RELAXED)));

> +#else

> +       } while (!__atomic_compare_exchange(

> +                      &q->qschst, &oss.ss, &nss.ss,

> +                      true, __ATOMIC_RELAXED, __ATOMIC_RELAXED));

> +#endif

> +

> +       if (odp_unlikely(ticket != TICKET_INVALID)) {

> +               ODP_ASSERT(q->qschst_type != ODP_SCHED_SYNC_ATOMIC);

> +               /* Wait for our turn to update schedq. */

> +               if (odp_unlikely(

> +                           __atomic_load_n(&q->qschst.cur_ticket,

> +                                           __ATOMIC_ACQUIRE) != ticket)) {

> +                       SEVL();

> +                       while (WFE() &&

> +                              LDXR8(&q->qschst.cur_ticket,

> +                                     __ATOMIC_ACQUIRE) != ticket)

> +                               DOZE();

> +               }

> +               /* We are here because of non-empty-to-empty transition or

> +                * WRR budget exhausted

> +                * This means the queue must be popped from the schedq, now or

> +                * later

> +                * If there was no NE->E transition but instead the WRR budget

> +                * was exhausted, the queue needs to be moved (popped and

> +                * pushed) to the tail of the schedq

> +                */

> +               if (oss.ss.numevts > 0 && nss.ss.numevts <= 0) {

> +                       /* NE->E transition, need to pop */

> +                       if (!schedq_elem_on_queue(q) ||

> +                           !schedq_cond_pop(q->schedq, q)) {

> +                               /* Queue not at head, failed to dequeue

> +                                * Missed a pop.

> +                                */

> +                               q->pop_deficit++;

> +                       }

> +               } else {

> +                       /* WRR budget exhausted

> +                        * Need to move queue to tail of schedq if possible

> +                        */

> +                       if (odp_likely(schedq_elem_on_queue(q))) {

> +                               /* Queue is on schedq, try to move it to

> +                                * the tail

> +                                */

> +                               (void)schedq_cond_rotate(q->schedq, q);

> +                       }

> +                       /* Else queue not on schedq or not at head of schedq

> +                        * No pop => no push

> +                        */

> +               }

> +#ifdef ODP_CONFIG_USE_DMB

> +               __atomic_thread_fence(__ATOMIC_RELEASE);

> +               __atomic_store_n(&q->qschst.cur_ticket, ticket + 1,

> +                                __ATOMIC_RELAXED);

> +#else

> +               __atomic_store_n(&q->qschst.cur_ticket, ticket + 1,

> +                                __ATOMIC_RELEASE);

> +#endif

> +       }

> +}

> +

> +static void sched_update_deq_sc(sched_elem_t *q,

> +               uint32_t actual, bool atomic) __attribute__((always_inline));

> +static inline void sched_update_deq_sc(sched_elem_t *q,

> +               uint32_t actual, bool atomic)

> +{

> +       qschedstate_t oss, nss;

> +       uint32_t ticket;

> +

> +       if (atomic) {

> +               ODP_ASSERT(q->qschst.cur_ticket == sched_ts->ticket);

> +               ODP_ASSERT(q->qschst.cur_ticket != q->qschst.nxt_ticket);

> +               q->qschst.numevts -= actual;

> +               q->qschst.cur_ticket = sched_ts->ticket + 1;

> +               if (q->qschst.numevts > 0)

> +                       schedq_push(q->schedq, q);

> +               return;

> +       }

> +

> +       oss = q->qschst;

> +       ticket = TICKET_INVALID;

> +       nss = oss;

> +       nss.numevts -= actual;

> +       nss.wrr_budget -= actual;

> +       if ((oss.numevts > 0 && nss.numevts <= 0) || oss.wrr_budget <= actual) {

> +               /* If we emptied the queue or

> +                * if we have served the maximum number of events

> +                * then we need a ticket for a later pop.

> +                */

> +               ticket = nss.nxt_ticket++;

> +               /* Also reset wrr_budget as we might also push the

> +                * queue to the schedq.

> +                */

> +               nss.wrr_budget = CONFIG_WRR_WEIGHT;

> +       }

> +       q->qschst = nss;

> +

> +       if (ticket != TICKET_INVALID) {

> +               if (oss.numevts > 0 && nss.numevts <= 0) {

> +                       /* NE->E transition, need to pop */

> +                       if (!schedq_elem_on_queue(q) ||

> +                           !schedq_cond_pop(q->schedq, q)) {

> +                               /* Queue not at head, failed to dequeue.

> +                                * Missed a pop.

> +                                */

> +                               q->pop_deficit++;

> +                       }

> +               } else {

> +                       /* WRR budget exhausted

> +                        * Need to move queue to tail of schedq if possible

> +                        */

> +                       if (odp_likely(schedq_elem_on_queue(q))) {

> +                               /* Queue is on schedq, try to move it to

> +                                * the tail

> +                                */

> +                               (void)schedq_cond_rotate(q->schedq, q);

> +                       }

> +                       /* Else queue not on schedq or not at head of schedq

> +                        * No pop => no push

> +                        */

> +               }

> +               q->qschst.cur_ticket = ticket + 1;

> +       }

> +}

> +

> +static inline void sched_update_popd_sc(sched_elem_t *elem)

> +{

> +       if (elem->pop_deficit != 0 &&

> +           schedq_elem_on_queue(elem) &&

> +           schedq_cond_pop(elem->schedq, elem))

> +               elem->pop_deficit--;

> +}

> +

> +static inline void sched_update_popd(sched_elem_t *elem)

> +{

> +       uint32_t ticket = __atomic_fetch_add(&elem->qschst.nxt_ticket,

> +                                           1,

> +                                           __ATOMIC_RELAXED);

> +       if (odp_unlikely(__atomic_load_n(&elem->qschst.cur_ticket,

> +                                        __ATOMIC_ACQUIRE) != ticket)) {

> +               SEVL();

> +               while (WFE() && LDXR8(&elem->qschst.cur_ticket,

> +                                     __ATOMIC_ACQUIRE) != ticket)

> +                       DOZE();

> +       }

> +       sched_update_popd_sc(elem);

> +#ifdef ODP_CONFIG_USE_DMB

> +       __atomic_thread_fence(__ATOMIC_RELEASE);

> +       __atomic_store_n(&elem->qschst.cur_ticket,

> +                        ticket + 1,

> +                        __ATOMIC_RELAXED);

> +#else

> +       __atomic_store_n(&elem->qschst.cur_ticket,

> +                        ticket + 1,

> +                        __ATOMIC_RELEASE);

> +#endif

> +}

> +

> +sched_queue_t *schedq_from_sched_group(odp_schedule_group_t grp, uint32_t prio)

> +{

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       uint32_t x;

> +

> +       ODP_ASSERT(grp >= 0 && grp <= (odp_schedule_group_t)MAX_SCHED_GROUP);

> +       ODP_ASSERT((sg_free & (1ULL << grp)) == 0);

> +       ODP_ASSERT(prio < ODP_SCHED_PRIO_NUM);

> +

> +       sgi = grp;

> +       sg = sg_vec[sgi];

> +

> +       /* Use xcount to spread queues over the xfactor schedq's

> +        * per priority.

> +        */

> +       x = __atomic_fetch_add(&sg->xcount[prio], 1, __ATOMIC_RELAXED);

> +       if (x == 0) {

> +               /* First ODP queue for this priority

> +                * Notify all threads in sg->thr_wanted that they

> +                * should join.

> +                */

> +               sched_group_mask_t thrds = sg->thr_wanted;

> +

> +               while (!bitset_is_null(thrds)) {

> +                       uint32_t thr;

> +

> +                       thr = bitset_ffs(thrds) - 1;

> +                       thrds = bitset_clr(thrds, thr);

> +                       /* Notify the thread about membership in this

> +                        * group/priority.

> +                        */

> +                       atom_bitset_set(&thread_state[thr].sg_wanted[prio],

> +                                       sgi, __ATOMIC_RELEASE);

> +                       __atomic_store_n(&thread_state[thr].sg_sem, 1,

> +                                        __ATOMIC_RELEASE);

> +               }

> +       }

> +       return &sg->schedq[prio * sg->xfactor + x % sg->xfactor];

> +}

> +

> +void sched_group_xcount_dec(odp_schedule_group_t grp, uint32_t prio)

> +{

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       uint32_t x;

> +

> +       ODP_ASSERT(grp >= 0 && grp <= (odp_schedule_group_t)MAX_SCHED_GROUP);

> +       ODP_ASSERT((sg_free & (1ULL << grp)) == 0);

> +       ODP_ASSERT(prio < ODP_SCHED_PRIO_NUM);

> +

> +       sgi = grp;

> +       sg = sg_vec[sgi];

> +       x = __atomic_sub_fetch(&sg->xcount[prio], 1, __ATOMIC_RELAXED);

> +

> +       if (x == 0) {

> +               /* Last ODP queue for this priority

> +                * Notify all threads in sg->thr_wanted that they

> +                * should leave.

> +                */

> +               sched_group_mask_t thrds = sg->thr_wanted;

> +

> +               while (!bitset_is_null(thrds)) {

> +                       uint32_t thr;

> +

> +                       thr = bitset_ffs(thrds) - 1;

> +                       thrds = bitset_clr(thrds, thr);

> +                       /* Notify the thread about membership in this

> +                        * group/priority.

> +                        */

> +                       atom_bitset_clr(&thread_state[thr].sg_wanted[prio],

> +                                       sgi, __ATOMIC_RELEASE);

> +                       __atomic_store_n(&thread_state[thr].sg_sem, 1,

> +                                        __ATOMIC_RELEASE);

> +               }

> +       }

> +}

> +

> +static void update_sg_membership(sched_scalable_thread_state_t *ts)

> +{

> +       uint32_t p;

> +       sched_group_mask_t sg_wanted;

> +       sched_group_mask_t added;

> +       sched_group_mask_t removed;

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       uint32_t x;

> +

> +       for (p = 0; p < ODP_SCHED_PRIO_NUM; p++) {

> +               sg_wanted = __atomic_load_n(&ts->sg_wanted[p],

> +                                               __ATOMIC_ACQUIRE);

> +               if (!bitset_is_eql(ts->sg_actual[p], sg_wanted)) {

> +                       /* Our sched_group membership has changed */

> +                       added = bitset_andn(sg_wanted, ts->sg_actual[p]);

> +                       while (!bitset_is_null(added)) {

> +                               sgi = bitset_ffs(added) - 1;

> +                               sg = sg_vec[sgi];

> +                               for (x = 0; x < sg->xfactor; x++) {

> +                                       /* Include our thread index to shift

> +                                        * (rotate) the order of schedq's

> +                                        */

> +                                       insert_schedq_in_list(ts,

> +                                               &sg->schedq[p * sg->xfactor +

> +                                               (x + ts->tidx) % sg->xfactor]);

> +                               }

> +                               atom_bitset_set(&sg->thr_actual[p], ts->tidx,

> +                                               __ATOMIC_RELAXED);

> +                               added = bitset_clr(added, sgi);

> +                       }

> +                       removed = bitset_andn(ts->sg_actual[p], sg_wanted);

> +                       while (!bitset_is_null(removed)) {

> +                               sgi = bitset_ffs(removed) - 1;

> +                               sg = sg_vec[sgi];

> +                               for (x = 0; x < sg->xfactor; x++) {

> +                                       remove_schedq_from_list(ts,

> +                                           &sg->schedq[p * sg->xfactor + x]);

> +                               }

> +                               atom_bitset_clr(&sg->thr_actual[p], ts->tidx,

> +                                               __ATOMIC_RELAXED);

> +                               removed = bitset_clr(removed, sgi);

> +                       }

> +                       ts->sg_actual[p] = sg_wanted;

> +               }

> +       }

> +}

> +

> +/*******************************************************************************

> + * Scheduler

> + ******************************************************************************/

> +

> +static inline void _schedule_release_atomic(sched_scalable_thread_state_t *ts)

> +{

> +#ifdef CONFIG_QSCHST_LOCK

> +       sched_update_deq_sc(ts->atomq, ts->dequeued, true);

> +       ODP_ASSERT(ts->atomq->qschst.cur_ticket != ts->ticket);

> +       ODP_ASSERT(ts->atomq->qschst.cur_ticket ==

> +                       ts->atomq->qschst.nxt_ticket);

> +#else

> +       sched_update_deq(ts->atomq, ts->dequeued, true);

> +#endif

> +       ts->atomq = NULL;

> +       ts->ticket = TICKET_INVALID;

> +}

> +

> +static inline void _schedule_release_ordered(sched_scalable_thread_state_t *ts)

> +{

> +       ts->out_of_order = false;

> +       rctx_release(ts->rctx);

> +       ts->rctx = NULL;

> +}

> +

> +static void pktin_poll(sched_scalable_thread_state_t *ts)

> +{

> +       uint32_t i, tag, hi, npolls = 0;

> +       int pktio_index, queue_index;

> +

> +       hi = __atomic_load_n(&pktin_hi, __ATOMIC_RELAXED);

> +       if (hi == 0)

> +               return;

> +

> +       for (i = ts->pktin_next; npolls != hi; i = (i + 1) % hi, npolls++) {

> +               tag = __atomic_load_n(&pktin_tags[i], __ATOMIC_RELAXED);

> +               if (!TAG_IS_READY(tag))

> +                       continue;

> +               if (!__atomic_compare_exchange_n(&pktin_tags[i], &tag,

> +                                                tag | TAG_BUSY,

> +                                                true,

> +                                                __ATOMIC_ACQUIRE,

> +                                                __ATOMIC_RELAXED))

> +                       continue;

> +               /* Tag grabbed */

> +               pktio_index = TAG_2_PKTIO(tag);

> +               queue_index = TAG_2_QUEUE(tag);

> +               if (odp_unlikely(sched_cb_pktin_poll(pktio_index,

> +                                                    1, &queue_index))) {

> +                       /* Pktio stopped or closed

> +                        * Remove tag from pktin_tags

> +                        */

> +                       __atomic_store_n(&pktin_tags[i],

> +                                        TAG_EMPTY, __ATOMIC_RELAXED);

> +                       __atomic_fetch_sub(&pktin_num,

> +                                          1, __ATOMIC_RELEASE);

> +                       /* Call stop_finalize when all queues

> +                        * of the pktio have been removed

> +                        */

> +                       if (__atomic_sub_fetch(&pktin_count[pktio_index], 1,

> +                                              __ATOMIC_RELAXED) == 0)

> +                               sched_cb_pktio_stop_finalize(pktio_index);

> +               } else {

> +                   /* We don't know whether any packets were found and enqueued

> +                    * Write back original tag value to release pktin queue

> +                    */

> +                   __atomic_store_n(&pktin_tags[i], tag, __ATOMIC_RELAXED);

> +                   /* Do not iterate through all pktin queues every time */

> +                   if ((ts->pktin_poll_cnts & 0xf) != 0)

> +                       break;

> +               }

> +       }

> +       ODP_ASSERT(i < hi);

> +       ts->pktin_poll_cnts++;

> +       ts->pktin_next = i;

> +}

> +

> +static int _schedule(odp_queue_t *from, odp_event_t ev[], int num_evts)

> +{

> +       sched_scalable_thread_state_t *ts;

> +       sched_elem_t *atomq;

> +       int num;

> +       uint32_t i;

> +

> +       ts = sched_ts;

> +       atomq = ts->atomq;

> +

> +       /* Once an atomic queue has been scheduled to a thread, it will stay

> +        * on that thread until empty or 'rotated' by WRR

> +        */

> +       if (atomq != NULL) {

> +               ODP_ASSERT(ts->ticket != TICKET_INVALID);

> +#ifdef CONFIG_QSCHST_LOCK

> +               LOCK(&atomq->qschlock);

> +#endif

> +dequeue_atomic:

> +               ODP_ASSERT(ts->ticket == atomq->qschst.cur_ticket);

> +               ODP_ASSERT(ts->ticket != atomq->qschst.nxt_ticket);

> +               /* Atomic queues can be dequeued without lock since this thread

> +                * has the only reference to the atomic queue being processed.

> +                */

> +               if (ts->dequeued < atomq->qschst.wrr_budget) {

> +                       num = _odp_queue_deq_sc(atomq, ev, num_evts);

> +                       if (odp_likely(num != 0)) {

> +#ifdef CONFIG_QSCHST_LOCK

> +                               UNLOCK(&atomq->qschlock);

> +#endif

> +                               ts->dequeued += num;

> +                               /* Allow this thread to continue to 'own' this

> +                                * atomic queue until all events have been

> +                                * processed and the thread re-invokes the

> +                                * scheduler.

> +                                */

> +                               if (from)

> +                                       *from = queue_get_handle(

> +                                                       (queue_entry_t *)atomq);

> +                               return num;

> +                       }

> +               }

> +               /* Atomic queue was empty or interrupted by WRR, release it. */

> +               _schedule_release_atomic(ts);

> +#ifdef CONFIG_QSCHST_LOCK

> +               UNLOCK(&atomq->qschlock);

> +#endif

> +       }

> +

> +       /* Release any previous reorder context. */

> +       if (ts->rctx != NULL)

> +               _schedule_release_ordered(ts);

> +

> +       /* Check for and perform any scheduler group updates. */

> +       if (odp_unlikely(__atomic_load_n(&ts->sg_sem, __ATOMIC_RELAXED) != 0)) {

> +               (void)__atomic_load_n(&ts->sg_sem, __ATOMIC_ACQUIRE);

> +               ts->sg_sem = 0;

> +               update_sg_membership(ts);

> +       }

> +

> +       /* Scan our schedq list from beginning to end */

> +       for (i = 0; i < ts->num_schedq; i++) {

> +               sched_queue_t *schedq = ts->schedq_list[i];

> +               sched_elem_t *elem;

> +restart_same:

> +               elem = schedq_peek(schedq);

> +               if (odp_unlikely(elem == NULL)) {

> +                       /* Schedq empty, look at next one. */

> +                       continue;

> +               }

> +

> +               if (elem->cons_type == ODP_SCHED_SYNC_ATOMIC) {

> +                       /* Dequeue element only if it is still at head

> +                        * of schedq.

> +                        */

> +                       if (odp_unlikely(!schedq_cond_pop(schedq, elem))) {

> +                               /* Queue not at head of schedq anymore, some

> +                                * other thread popped it.

> +                                */

> +                               goto restart_same;

> +                       }

> +                       ts->atomq = atomq = elem;

> +                       ts->dequeued = 0;

> +#ifdef CONFIG_QSCHST_LOCK

> +                       LOCK(&atomq->qschlock);

> +                       ts->ticket = atomq->qschst.nxt_ticket++;

> +                       ODP_ASSERT(atomq->qschst.cur_ticket == ts->ticket);

> +#else

> +                       /* Dequeued atomic queue from the schedq, only we

> +                        * can process it and any qschst updates are our

> +                        * responsibility.

> +                        */

> +                       /* The ticket taken below will signal producers */

> +                       ts->ticket = __atomic_fetch_add(

> +                               &atomq->qschst.nxt_ticket, 1, __ATOMIC_RELAXED);

> +                       while (__atomic_load_n(

> +                                       &atomq->qschst.cur_ticket,

> +                                       __ATOMIC_ACQUIRE) != ts->ticket) {

> +                               /* No need to use WFE, spinning here seems

> +                                * very infrequent.

> +                                */

> +                               odp_cpu_pause();

> +                       }

> +#endif

> +                       goto dequeue_atomic;

> +               } else if (elem->cons_type == ODP_SCHED_SYNC_PARALLEL) {

> +#ifdef CONFIG_QSCHST_LOCK

> +                       LOCK(&elem->qschlock);

> +                       num = _odp_queue_deq_sc(elem, ev, num_evts);

> +                       if (odp_likely(num != 0)) {

> +                               sched_update_deq_sc(elem, num, false);

> +                               UNLOCK(&elem->qschlock);

> +                               if (from)

> +                                       *from =

> +                                       queue_get_handle((queue_entry_t *)elem);

> +                               return num;

> +                       }

> +                       UNLOCK(&elem->qschlock);

> +#else

> +                       num = _odp_queue_deq(elem, ev, num_evts);

> +                       if (odp_likely(num != 0)) {

> +                               sched_update_deq(elem, num, false);

> +                               if (from)

> +                                       *from =

> +                                       queue_get_handle((queue_entry_t *)elem);

> +                               return num;

> +                       }

> +#endif

> +               } else if (elem->cons_type == ODP_SCHED_SYNC_ORDERED) {

> +                       reorder_window_t *rwin;

> +                       reorder_context_t *rctx;

> +                       uint32_t sn;

> +                       uint32_t idx;

> +                       int ret;

> +

> +                       /* The ordered queue has a reorder window so requires

> +                        * order restoration. We must use a reorder context to

> +                        * collect all outgoing events. Ensure there is at least

> +                        * one available reorder context.

> +                        */

> +                       if (odp_unlikely(bitset_is_null(ts->priv_rvec_free))) {

> +                               ts->priv_rvec_free = atom_bitset_xchg(

> +                                                       &ts->rvec_free, 0,

> +                                                       __ATOMIC_RELAXED);

> +                               if (odp_unlikely(bitset_is_null(

> +                                               ts->priv_rvec_free))) {

> +                                       /* No free reorder contexts for

> +                                        * this thread. Look at next schedq,

> +                                        * hope we find non-ordered queue.

> +                                        */

> +                                       continue;

> +                               }

> +                       }

> +                       /* rwin_reserve and odp_queue_deq must be atomic or

> +                        * there will be a potential race condition.

> +                        * Allocate a slot in the reorder window.

> +                        */

> +                       rwin = queue_get_rwin((queue_entry_t *)elem);

> +                       ODP_ASSERT(rwin != NULL);

> +                       if (odp_unlikely(!rwin_reserve(rwin, &sn))) {

> +                               /* Reorder window full */

> +                               /* Look at next schedq, find other queue */

> +                               continue;

> +                       }

> +                       /* Wait for our turn to dequeue */

> +                       if (odp_unlikely(__atomic_load_n(&rwin->turn,

> +                                        __ATOMIC_ACQUIRE) != sn)) {

> +                               SEVL();

> +                               while (WFE() &&

> +                                      LDXR32(&rwin->turn, __ATOMIC_ACQUIRE)

> +                                               != sn)

> +                                       DOZE();

> +                       }

> +#ifdef CONFIG_QSCHST_LOCK

> +                       LOCK(&elem->qschlock);

> +#endif

> +                       ret = _odp_queue_deq_sc(elem, ev, num_evts);

> +#ifdef ODP_CONFIG_USE_DMB

> +                       /* Wait for prod_read write in _odp_queue_dequeue_sc()

> +                        * to complete.

> +                        */

> +                       __asm volatile("dmb ishst" ::: "memory");

> +                       /* before we signal the next consumer */

> +                       rwin->turn = sn + 1;

> +#else

> +                       __atomic_store_n(&rwin->turn, sn + 1, __ATOMIC_RELEASE);

> +#endif

> +                       /* Find and initialise an unused reorder context. */

> +                       idx = bitset_ffs(ts->priv_rvec_free) - 1;

> +                       ts->priv_rvec_free =

> +                               bitset_clr(ts->priv_rvec_free, idx);

> +                       rctx = &ts->rvec[idx];

> +                       /* Need to initialise reorder context or we can't

> +                        * release it later.

> +                        */

> +                       rctx_init(rctx, idx, rwin, sn);

> +

> +                       /* Was dequeue successful? */

> +                       if (odp_likely(ret != 0)) {

> +                               /* Perform scheduler related updates */

> +#ifdef CONFIG_QSCHST_LOCK

> +                               sched_update_deq_sc(elem, ret,

> +                                                   /*atomic=*/false);

> +                               UNLOCK(&elem->qschlock);

> +#else

> +                               sched_update_deq(elem, ret, /*atomic=*/false);

> +#endif

> +

> +                               /* Are we in-order or out-of-order? */

> +                               ts->out_of_order = sn != rwin->hc.head;

> +

> +                               ts->rctx = rctx;

> +                               if (from)

> +                                       *from = queue_get_handle(

> +                                               (queue_entry_t *)elem);

> +                               return ret;

> +                       }

> +#ifdef CONFIG_QSCHST_LOCK

> +                       UNLOCK(&elem->qschlock);

> +#endif

> +                       /* Since a slot was reserved in the reorder window,

> +                        * the reorder context needs to be released and

> +                        * inserted into the reorder window.

> +                        */

> +                       rctx_release(rctx);

> +                       ODP_ASSERT(ts->rctx == NULL);

> +               }

> +               /* Dequeue from parallel/ordered queue failed

> +                * Check if we have a queue at the head of the schedq that needs

> +                * to be popped

> +                */

> +               if (odp_unlikely(__atomic_load_n(&elem->pop_deficit,

> +                                                __ATOMIC_RELAXED) != 0)) {

> +#ifdef CONFIG_QSCHST_LOCK

> +                       LOCK(&elem->qschlock);

> +                       sched_update_popd_sc(elem);

> +                       UNLOCK(&elem->qschlock);

> +#else

> +                       sched_update_popd(elem);

> +#endif

> +               }

> +       }

> +

> +       pktin_poll(ts);

> +       return 0;

> +}

> +

> +/******************************************************************************/

> +

> +static void schedule_order_lock(unsigned lock_index)

> +{

> +       struct reorder_context *rctx = sched_ts->rctx;

> +

> +       if (odp_unlikely(rctx == NULL ||

> +                        rctx->rwin == NULL ||

> +                        lock_index >= rctx->rwin->lock_count)) {

> +               ODP_ERR("Invalid call to odp_schedule_order_lock\n");

> +               return;

> +       }

> +       if (odp_unlikely(__atomic_load_n(&rctx->rwin->olock[lock_index],

> +                                        __ATOMIC_ACQUIRE) != rctx->sn)) {

> +               SEVL();

> +               while (WFE() &&

> +                      LDXR32(&rctx->rwin->olock[lock_index],

> +                             __ATOMIC_ACQUIRE) != rctx->sn)

> +                       DOZE();

> +       }

> +}

> +

> +static void schedule_order_unlock(unsigned lock_index)

> +{

> +       struct reorder_context *rctx;

> +

> +       rctx = sched_ts->rctx;

> +       if (odp_unlikely(rctx == NULL ||

> +                        rctx->rwin == NULL ||

> +                        lock_index >= rctx->rwin->lock_count ||

> +                        rctx->rwin->olock[lock_index] != rctx->sn)) {

> +               ODP_ERR("Invalid call to odp_schedule_order_unlock\n");

> +               return;

> +       }

> +#ifdef ODP_CONFIG_USE_DMB

> +       __atomic_thread_fence(__ATOMIC_RELEASE);

> +       __atomic_store_n(&rctx->rwin->olock[lock_index],

> +                        rctx->sn + 1,

> +                        __ATOMIC_RELAXED);

> +#else

> +       __atomic_store_n(&rctx->rwin->olock[lock_index],

> +                        rctx->sn + 1,

> +                        __ATOMIC_RELEASE);

> +#endif

> +       rctx->olock_flags |= 1U << lock_index;

> +}

> +

> +static void schedule_release_atomic(void)

> +{

> +       sched_scalable_thread_state_t *ts;

> +

> +       ts = sched_ts;

> +       if (odp_likely(ts->atomq != NULL)) {

> +#ifdef CONFIG_QSCHST_LOCK

> +               sched_elem_t *atomq;

> +

> +               atomq = ts->atomq;

> +               LOCK(&atomq->qschlock);

> +#endif

> +               _schedule_release_atomic(ts);

> +#ifdef CONFIG_QSCHST_LOCK

> +               UNLOCK(&atomq->qschlock);

> +#endif

> +       }

> +}

> +

> +static void schedule_release_ordered(void)

> +{

> +       sched_scalable_thread_state_t *ts;

> +

> +       ts = sched_ts;

> +       if (ts->rctx != NULL)

> +               _schedule_release_ordered(ts);

> +}

> +

> +static int schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t ev[],

> +                         int num)

> +{

> +       sched_scalable_thread_state_t *ts;

> +       int n;

> +       odp_time_t start;

> +       odp_time_t delta;

> +       odp_time_t deadline;

> +

> +       ts = sched_ts;

> +       if (odp_unlikely(ts->pause)) {

> +               if (ts->atomq != NULL) {

> +#ifdef CONFIG_QSCHST_LOCK

> +                       sched_elem_t *atomq;

> +

> +                       atomq = ts->atomq;

> +                       LOCK(&atomq->qschlock);

> +#endif

> +                       _schedule_release_atomic(ts);

> +#ifdef CONFIG_QSCHST_LOCK

> +                       UNLOCK(&atomq->qschlock);

> +#endif

> +               } else if (ts->rctx != NULL) {

> +                       _schedule_release_ordered(ts);

> +               }

> +               return 0;

> +       }

> +

> +       if (wait == ODP_SCHED_NO_WAIT)

> +               return _schedule(from, ev, num);

> +

> +       if (wait == ODP_SCHED_WAIT) {

> +               for (;;) {

> +                       n = _schedule(from, ev, num);

> +                       if (odp_likely(n  > 0))

> +                               return n;

> +               }

> +       }

> +

> +       start = odp_time_local();

> +

> +       n = _schedule(from, ev, num);

> +       if (odp_likely(n > 0))

> +               return n;

> +

> +       delta = odp_time_local_from_ns(wait);

> +       deadline = odp_time_sum(start, delta);

> +

> +       while (odp_time_cmp(deadline, odp_time_local()) > 0) {

> +               n = _schedule(from, ev, num);

> +               if (odp_likely(n > 0))

> +                       return n;

> +       }

> +

> +       return 0;

> +}

> +

> +static odp_event_t schedule(odp_queue_t *from, uint64_t wait)

> +{

> +       odp_event_t ev = ODP_EVENT_INVALID;

> +       const int num = 1;

> +       sched_scalable_thread_state_t *ts;

> +       int n;

> +       odp_time_t start;

> +       odp_time_t delta;

> +       odp_time_t deadline;

> +

> +       ts = sched_ts;

> +       if (odp_unlikely(ts->pause)) {

> +               if (ts->atomq != NULL) {

> +#ifdef CONFIG_QSCHST_LOCK

> +                       sched_elem_t *atomq;

> +

> +                       atomq = ts->atomq;

> +                       LOCK(&atomq->qschlock);

> +#endif

> +                       _schedule_release_atomic(ts);

> +#ifdef CONFIG_QSCHST_LOCK

> +                       UNLOCK(&atomq->qschlock);

> +#endif

> +               } else if (ts->rctx != NULL) {

> +                       _schedule_release_ordered(ts);

> +               }

> +               return ev;

> +       }

> +

> +       if (wait == ODP_SCHED_NO_WAIT) {

> +               (void)_schedule(from, &ev, num);

> +               return ev;

> +       }

> +

> +       if (wait == ODP_SCHED_WAIT) {

> +               for (;;) {

> +                       n = _schedule(from, &ev, num);

> +                       if (odp_likely(n > 0))

> +                               return ev;

> +               }

> +       }

> +

> +       start = odp_time_local();

> +

> +       n = _schedule(from, &ev, num);

> +       if (odp_likely(n > 0))

> +               return ev;

> +

> +       delta = odp_time_local_from_ns(wait);

> +       deadline = odp_time_sum(start, delta);

> +

> +       while (odp_time_cmp(deadline, odp_time_local()) > 0) {

> +               n = _schedule(from, &ev, num);

> +               if (odp_likely(n > 0))

> +                       return ev;

> +       }

> +

> +       return ev;

> +}

> +

> +static void schedule_pause(void)

> +{

> +       sched_ts->pause = true;

> +}

> +

> +static void schedule_resume(void)

> +{

> +       sched_ts->pause = false;

> +}

> +

> +static uint64_t schedule_wait_time(uint64_t ns)

> +{

> +       return ns;

> +}

> +

> +static int schedule_num_prio(void)

> +{

> +       return ODP_SCHED_PRIO_NUM;

> +}

> +

> +static int schedule_group_update(sched_group_t *sg,

> +                                uint32_t sgi,

> +                                const odp_thrmask_t *mask,

> +                                int join_leave)

> +{

> +       int thr;

> +       uint32_t p;

> +

> +       /* Internal function, do not validate inputs */

> +

> +       /* Notify relevant threads about the change */

> +       thr = odp_thrmask_first(mask);

> +       while (0 <= thr) {

> +               /* Add thread to scheduler group's wanted thread mask */

> +               if (join_leave == SCHED_GROUP_JOIN)

> +                       atom_bitset_set(&sg->thr_wanted, thr, __ATOMIC_RELAXED);

> +               else

> +                       atom_bitset_clr(&sg->thr_wanted, thr, __ATOMIC_RELAXED);

> +               for (p = 0; p < ODP_SCHED_PRIO_NUM; p++) {

> +                       if (sg->xcount[p] != 0) {

> +                               /* This priority level has ODP queues

> +                                * Notify the thread about membership in

> +                                * this group/priority

> +                                */

> +                               if (join_leave == SCHED_GROUP_JOIN)

> +                                       atom_bitset_set(

> +                                               &thread_state[thr].sg_wanted[p],

> +                                               sgi,

> +                                               __ATOMIC_RELEASE);

> +                               else

> +                                       atom_bitset_clr(

> +                                               &thread_state[thr].sg_wanted[p],

> +                                               sgi,

> +                                               __ATOMIC_RELEASE);

> +                               __atomic_store_n(&thread_state[thr].sg_sem,

> +                                       1,

> +                                       __ATOMIC_RELEASE);

> +                       }

> +               }

> +               thr = odp_thrmask_next(mask, thr);

> +       }

> +

> +       return 0;

> +}

> +

> +static int _schedule_group_thrmask(sched_group_t *sg, odp_thrmask_t *mask)

> +{

> +       bitset_t bs;

> +       uint32_t bit;

> +

> +       /* Internal function, do not validate inputs */

> +

> +       odp_thrmask_zero(mask);

> +       bs = sg->thr_wanted;

> +       while (!bitset_is_null(bs)) {

> +               bit = bitset_ffs(bs) - 1;

> +               bs = bitset_clr(bs, bit);

> +               odp_thrmask_set(mask, bit);

> +       }

> +

> +       return 0;

> +}

> +

> +static odp_schedule_group_t schedule_group_create(const char *name,

> +                                                 const odp_thrmask_t *mask)

> +{

> +       odp_shm_t shm;

> +       uint32_t sgi;

> +       sched_group_mask_t free;

> +       uint32_t xfactor;

> +       sched_group_t *sg;

> +       uint32_t p;

> +       uint32_t x;

> +

> +       /* Validate inputs */

> +       if (mask == NULL)

> +               ODP_ABORT("mask is NULL\n");

> +

> +       odp_spinlock_lock(&sched_grp_lock);

> +

> +       /* Allocate a scheduler group */

> +       free = __atomic_load_n(&sg_free, __ATOMIC_RELAXED);

> +       do {

> +               /* All sched_groups in use */

> +               if (bitset_is_null(free))

> +                       goto no_free_sched_group;

> +

> +               sgi = bitset_ffs(free) - 1;

> +               /* All sched_groups in use */

> +               if (sgi >= MAX_SCHED_GROUP)

> +                       goto no_free_sched_group;

> +       } while (!__atomic_compare_exchange_n(&sg_free,

> +                                         &free,

> +                                         bitset_clr(free, sgi),

> +                                         true,

> +                                         __ATOMIC_ACQUIRE,

> +                                         __ATOMIC_ACQUIRE));

> +

> +       /* Compute xfactor (spread factor) from the number of threads

> +        * present in the thread mask. Preferable this would be an

> +        * explicit parameter.

> +        */

> +       xfactor = odp_thrmask_count(mask);

> +       if (xfactor < 1)

> +               xfactor = 1;

> +

> +       shm = odp_shm_reserve(name ? name : "",

> +                            (sizeof(sched_group_t) +

> +                            (ODP_SCHED_PRIO_NUM * xfactor - 1) *

> +                             sizeof(sched_queue_t)),

> +                             ODP_CACHE_LINE_SIZE,

> +                             ODP_SHM_PROC);

> +       if (ODP_SHM_INVALID == shm)

> +               goto shm_reserve_failed;

> +

> +       sg = (sched_group_t *) odp_shm_addr(shm);

> +       if (sg == NULL)

> +               goto shm_addr_failed;

> +

> +       strncpy(sg->name, name ? name : "", ODP_SCHED_GROUP_NAME_LEN - 1);

> +       sg->shm = shm;

> +       sg_vec[sgi] = sg;

> +       memset(sg->thr_actual, 0, sizeof(sg->thr_actual));

> +       sg->thr_wanted = bitset_null();

> +       sg->xfactor = xfactor;

> +       for (p = 0; p < ODP_SCHED_PRIO_NUM; p++) {

> +               sg->xcount[p] = 0;

> +               for (x = 0; x < xfactor; x++)

> +                       schedq_init(&sg->schedq[p * xfactor + x], p);

> +       }

> +       if (odp_thrmask_count(mask) != 0)

> +               schedule_group_update(sg, sgi, mask, SCHED_GROUP_JOIN);

> +

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return (odp_schedule_group_t) (sgi);

> +

> +shm_addr_failed:

> +       odp_shm_free(shm);

> +

> +shm_reserve_failed:

> +       /* Free the allocated group index */

> +       atom_bitset_set(&sg_free, sgi, __ATOMIC_RELAXED);

> +

> +no_free_sched_group:

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return ODP_SCHED_GROUP_INVALID;

> +}

> +

> +static int schedule_group_destroy(odp_schedule_group_t group)

> +{

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       uint32_t p;

> +       int ret = 0;

> +

> +       /* Validate inputs */

> +       if (group < 0 && group >= (odp_schedule_group_t)MAX_SCHED_GROUP) {

> +               ret = -1;

> +               goto invalid_group;

> +       }

> +

> +       if (sched_ts &&

> +           odp_unlikely(__atomic_load_n(&sched_ts->sg_sem,

> +                                        __ATOMIC_RELAXED) != 0)) {

> +               (void)__atomic_load_n(&sched_ts->sg_sem,

> +                                     __ATOMIC_ACQUIRE);

> +               sched_ts->sg_sem = 0;

> +               update_sg_membership(sched_ts);

> +       }

> +       odp_spinlock_lock(&sched_grp_lock);

> +

> +       sgi = (uint32_t)group;

> +       if (bitset_is_set(sg_free, sgi)) {

> +               ret = -1;

> +               goto group_not_found;

> +       }

> +

> +       sg = sg_vec[sgi];

> +       /* First ensure all threads have processed group_join/group_leave

> +        * requests.

> +        */

> +       for (p = 0; p < ODP_SCHED_PRIO_NUM; p++) {

> +               if (sg->xcount[p] != 0) {

> +                       bitset_t wanted = atom_bitset_load(

> +                               &sg->thr_wanted, __ATOMIC_RELAXED);

> +

> +                       SEVL();

> +                       while (WFE() &&

> +                              !bitset_is_eql(wanted,

> +                                             bitset_ldex(&sg->thr_actual[p],

> +                                                         __ATOMIC_RELAXED)))

> +                               DOZE();

> +               }

> +               /* Else ignore because no ODP queues on this prio */

> +       }

> +

> +       /* Check if all threads/queues have left the group */

> +       for (p = 0; p < ODP_SCHED_PRIO_NUM; p++) {

> +               if (!bitset_is_null(sg->thr_actual[p])) {

> +                       ODP_ERR("Group has threads\n");

> +                       ret = -1;

> +                       goto thrd_q_present_in_group;

> +               }

> +               if (sg->xcount[p] != 0) {

> +                       ODP_ERR("Group has queues\n");

> +                       ret = -1;

> +                       goto thrd_q_present_in_group;

> +               }

> +       }

> +

> +       odp_shm_free(sg->shm);

> +       sg_vec[sgi] = NULL;

> +       atom_bitset_set(&sg_free, sgi, __ATOMIC_RELEASE);

> +

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return ret;

> +

> +thrd_q_present_in_group:

> +

> +group_not_found:

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +invalid_group:

> +

> +       return ret;

> +}

> +

> +static odp_schedule_group_t schedule_group_lookup(const char *name)

> +{

> +       uint32_t sgi;

> +       odp_schedule_group_t group;

> +

> +       /* Validate inputs */

> +       if (name == NULL)

> +               ODP_ABORT("name or mask is NULL\n");

> +

> +       group = ODP_SCHED_GROUP_INVALID;

> +

> +       odp_spinlock_lock(&sched_grp_lock);

> +

> +       /* Scan through the schedule group array */

> +       for (sgi = 0; sgi < MAX_SCHED_GROUP; sgi++) {

> +               if ((sg_vec[sgi] != NULL) &&

> +                   (strncmp(name, sg_vec[sgi]->name,

> +                            ODP_SCHED_GROUP_NAME_LEN) == 0)) {

> +                       group = (odp_schedule_group_t)sgi;

> +                       break;

> +               }

> +       }

> +

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return group;

> +}

> +

> +static int schedule_group_join(odp_schedule_group_t group,

> +                              const odp_thrmask_t *mask)

> +{

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       int ret;

> +

> +       /* Validate inputs */

> +       if (group < 0 && group >= ((odp_schedule_group_t)MAX_SCHED_GROUP))

> +               return -1;

> +

> +       if (mask == NULL)

> +               ODP_ABORT("name or mask is NULL\n");

> +

> +       odp_spinlock_lock(&sched_grp_lock);

> +

> +       sgi = (uint32_t)group;

> +       if (bitset_is_set(sg_free, sgi)) {

> +               odp_spinlock_unlock(&sched_grp_lock);

> +               return -1;

> +       }

> +

> +       sg = sg_vec[sgi];

> +       ret = schedule_group_update(sg, sgi, mask, SCHED_GROUP_JOIN);

> +

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return ret;

> +}

> +

> +static int schedule_group_leave(odp_schedule_group_t group,

> +                               const odp_thrmask_t *mask)

> +{

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       int ret = 0;

> +

> +       /* Validate inputs */

> +       if (group < 0 && group >= (odp_schedule_group_t)MAX_SCHED_GROUP) {

> +               ret = -1;

> +               goto invalid_group;

> +       }

> +

> +       if (mask == NULL)

> +               ODP_ABORT("name or mask is NULL\n");

> +

> +       odp_spinlock_lock(&sched_grp_lock);

> +

> +       sgi = (uint32_t)group;

> +       if (bitset_is_set(sg_free, sgi)) {

> +               ret = -1;

> +               goto group_not_found;

> +       }

> +

> +       sg = sg_vec[sgi];

> +

> +       ret = schedule_group_update(sg, sgi, mask, SCHED_GROUP_LEAVE);

> +

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return ret;

> +

> +group_not_found:

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +invalid_group:

> +       return ret;

> +}

> +

> +static int schedule_group_thrmask(odp_schedule_group_t group,

> +                                 odp_thrmask_t *mask)

> +{

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       int ret = 0;

> +

> +       /* Validate inputs */

> +       if (group < 0 && group >= ((odp_schedule_group_t)MAX_SCHED_GROUP)) {

> +               ret = -1;

> +               goto invalid_group;

> +       }

> +

> +       if (mask == NULL)

> +               ODP_ABORT("name or mask is NULL\n");

> +

> +       odp_spinlock_lock(&sched_grp_lock);

> +

> +       sgi = (uint32_t)group;

> +       if (bitset_is_set(sg_free, sgi)) {

> +               ret = -1;

> +               goto group_not_found;

> +       }

> +

> +       sg = sg_vec[sgi];

> +       ret = _schedule_group_thrmask(sg, mask);

> +

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return ret;

> +

> +group_not_found:

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +invalid_group:

> +       return ret;

> +}

> +

> +static int schedule_group_info(odp_schedule_group_t group,

> +                              odp_schedule_group_info_t *info)

> +{

> +       uint32_t sgi;

> +       sched_group_t *sg;

> +       int ret = 0;

> +

> +       /* Validate inputs */

> +       if (group < 0 && group >= ((odp_schedule_group_t)MAX_SCHED_GROUP)) {

> +               ret = -1;

> +               goto invalid_group;

> +       }

> +

> +       if (info == NULL)

> +               ODP_ABORT("name or mask is NULL\n");

> +

> +       odp_spinlock_lock(&sched_grp_lock);

> +

> +       sgi = (uint32_t)group;

> +       if (bitset_is_set(sg_free, sgi)) {

> +               ret = -1;

> +               goto group_not_found;

> +       }

> +

> +       sg = sg_vec[sgi];

> +

> +       ret = _schedule_group_thrmask(sg, &info->thrmask);

> +

> +       info->name = sg->name;

> +

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +       return ret;

> +

> +group_not_found:

> +       odp_spinlock_unlock(&sched_grp_lock);

> +

> +invalid_group:

> +       return ret;

> +}

> +

> +static int schedule_init_global(void)

> +{

> +       odp_thrmask_t mask;

> +       odp_schedule_group_t tmp_all;

> +       odp_schedule_group_t tmp_wrkr;

> +       odp_schedule_group_t tmp_ctrl;

> +       uint32_t bits;

> +

> +       odp_spinlock_init(&sched_grp_lock);

> +

> +       bits = MAX_SCHED_GROUP;

> +       if (MAX_SCHED_GROUP == sizeof(sg_free) * CHAR_BIT)

> +               sg_free = ~0ULL;

> +       else

> +               sg_free = (1ULL << bits) - 1;

> +

> +       for (uint32_t i = 0; i < MAX_SCHED_GROUP; i++)

> +               sg_vec[i] = NULL;

> +       for (uint32_t i = 0; i < MAXTHREADS; i++) {

> +               thread_state[i].sg_sem = 0;

> +               for (uint32_t j = 0; j < ODP_SCHED_PRIO_NUM; j++)

> +                       thread_state[i].sg_wanted[j] = bitset_null();

> +       }

> +

> +       /* Create sched groups for default GROUP_ALL, GROUP_WORKER and

> +        * GROUP_CONTROL groups.

> +        */

> +       odp_thrmask_zero(&mask);

> +       tmp_all = odp_schedule_group_create("__group_all", &mask);

> +       if (tmp_all != ODP_SCHED_GROUP_ALL) {

> +               ODP_ERR("Could not create ODP_SCHED_GROUP_ALL()\n");

> +               goto failed_create_group_all;

> +       }

> +

> +       tmp_wrkr = odp_schedule_group_create("__group_worker", &mask);

> +       if (tmp_wrkr != ODP_SCHED_GROUP_WORKER) {

> +               ODP_ERR("Could not create ODP_SCHED_GROUP_WORKER()\n");

> +               goto failed_create_group_worker;

> +       }

> +

> +       tmp_ctrl = odp_schedule_group_create("__group_control", &mask);

> +       if (tmp_ctrl != ODP_SCHED_GROUP_CONTROL) {

> +               ODP_ERR("Could not create ODP_SCHED_GROUP_CONTROL()\n");

> +               goto failed_create_group_control;

> +       }

> +

> +       return 0;

> +

> +failed_create_group_control:

> +       if (tmp_ctrl != ODP_SCHED_GROUP_INVALID)

> +               odp_schedule_group_destroy(ODP_SCHED_GROUP_CONTROL);

> +

> +failed_create_group_worker:

> +       if (tmp_wrkr != ODP_SCHED_GROUP_INVALID)

> +               odp_schedule_group_destroy(ODP_SCHED_GROUP_WORKER);

> +

> +failed_create_group_all:

> +       if (tmp_all != ODP_SCHED_GROUP_INVALID)

> +               odp_schedule_group_destroy(ODP_SCHED_GROUP_ALL);

> +

> +       return -1;

> +}

> +

> +static int schedule_term_global(void)

> +{

> +       /* Destroy sched groups for default GROUP_ALL, GROUP_WORKER and

> +        * GROUP_CONTROL groups.

> +        */

> +       if (odp_schedule_group_destroy(ODP_SCHED_GROUP_ALL) != 0)

> +               ODP_ERR("Failed to destroy ODP_SCHED_GROUP_ALL\n");

> +       if (odp_schedule_group_destroy(ODP_SCHED_GROUP_WORKER) != 0)

> +               ODP_ERR("Failed to destroy ODP_SCHED_GROUP_WORKER\n");

> +       if (odp_schedule_group_destroy(ODP_SCHED_GROUP_CONTROL) != 0)

> +               ODP_ERR("Failed to destroy ODP_SCHED_GROUP_CONTROL\n");

> +

> +       return 0;

> +}

> +

> +static int schedule_init_local(void)

> +{

> +       int thr_id;

> +       odp_thread_type_t thr_type;

> +       odp_thrmask_t mask;

> +

> +       thr_id = odp_thread_id();

> +       if (thread_state_init(thr_id))

> +               goto failed_to_init_ts;

> +

> +       /* Add this thread to default schedule groups */

> +       thr_type = odp_thread_type();

> +       odp_thrmask_zero(&mask);

> +       odp_thrmask_set(&mask, thr_id);

> +

> +       if (odp_schedule_group_join(ODP_SCHED_GROUP_ALL, &mask) != 0) {

> +               ODP_ERR("Failed to join ODP_SCHED_GROUP_ALL\n");

> +               goto failed_to_join_grp_all;

> +       }

> +       if (thr_type == ODP_THREAD_CONTROL) {

> +               if (odp_schedule_group_join(ODP_SCHED_GROUP_CONTROL,

> +                                               &mask) != 0) {

> +                       ODP_ERR("Failed to join ODP_SCHED_GROUP_CONTROL\n");

> +                       goto failed_to_join_grp_ctrl;

> +               }

> +       } else {

> +               if (odp_schedule_group_join(ODP_SCHED_GROUP_WORKER,

> +                                               &mask) != 0) {

> +                       ODP_ERR("Failed to join ODP_SCHED_GROUP_WORKER\n");

> +                       goto failed_to_join_grp_wrkr;

> +               }

> +       }

> +

> +       return 0;

> +

> +failed_to_join_grp_wrkr:

> +

> +failed_to_join_grp_ctrl:

> +       odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &mask);

> +

> +failed_to_join_grp_all:

> +failed_to_init_ts:

> +

> +       return -1;

> +}

> +

> +static int schedule_term_local(void)

> +{

> +       int thr_id;

> +       odp_thread_type_t thr_type;

> +       odp_thrmask_t mask;

> +       int rc = 0;

> +

> +       /* Remove this thread from default schedule groups */

> +       thr_id = odp_thread_id();

> +       thr_type = odp_thread_type();

> +       odp_thrmask_zero(&mask);

> +       odp_thrmask_set(&mask, thr_id);

> +

> +       if (odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &mask) != 0)

> +               ODP_ERR("Failed to leave ODP_SCHED_GROUP_ALL\n");

> +       if (thr_type == ODP_THREAD_CONTROL) {

> +               if (odp_schedule_group_leave(ODP_SCHED_GROUP_CONTROL,

> +                                               &mask) != 0)

> +                       ODP_ERR("Failed to leave ODP_SCHED_GROUP_CONTROL\n");

> +       } else {

> +               if (odp_schedule_group_leave(ODP_SCHED_GROUP_WORKER,

> +                                               &mask) != 0)

> +                       ODP_ERR("Failed to leave ODP_SCHED_GROUP_WORKER\n");

> +       }

> +

> +       update_sg_membership(sched_ts);

> +

> +       /* Check if the thread is still part of any groups */

> +       if (sched_ts->num_schedq != 0) {

> +               ODP_ERR("Thread %d still part of scheduler group(s)\n",

> +                       sched_ts->tidx);

> +               rc = -1;

> +       }

> +

> +       return rc;

> +}

> +

> +int queue_tm_reorder(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr)

> +{

> +       (void)queue;

> +       (void)buf_hdr;

> +       return 0;

> +}

> +

> +static void pktio_start(int pktio_index, int num_in_queue, int in_queue_idx[])

> +{

> +       int i;

> +       uint32_t old, tag, j;

> +

> +       for (i = 0; i < num_in_queue; i++) {

> +               /* Try to reserve a slot */

> +               if (__atomic_fetch_add(&pktin_num,

> +                                      1, __ATOMIC_RELAXED) >= PKTIN_MAX) {

> +                       __atomic_fetch_sub(&pktin_num, 1, __ATOMIC_RELAXED);

> +                       ODP_ABORT("Too many pktio in queues for scheduler\n");

> +               }

> +               /* A slot has been reserved, now we need to find an empty one */

> +               for (j = 0; ; j = (j + 1) % PKTIN_MAX) {

> +                       if (__atomic_load_n(&pktin_tags[j],

> +                                           __ATOMIC_RELAXED) != TAG_EMPTY)

> +                               /* Slot used, continue with next */

> +                               continue;

> +                       /* Empty slot found */

> +                       old = TAG_EMPTY;

> +                       tag = PKTIO_QUEUE_2_TAG(pktio_index, in_queue_idx[i]);

> +                       if (__atomic_compare_exchange_n(&pktin_tags[j],

> +                                                       &old,

> +                                                       tag,

> +                                                       true,

> +                                                       __ATOMIC_RELEASE,

> +                                                       __ATOMIC_RELAXED)) {

> +                               /* Success grabbing slot,update high

> +                                * watermark

> +                                */

> +                               __atomic_fetch_max(&pktin_hi,

> +                                                  j + 1, __ATOMIC_RELAXED);

> +                               /* One more tag (queue) for this pktio

> +                                * instance

> +                                */

> +                               __atomic_fetch_add(&pktin_count[pktio_index],

> +                                                  1, __ATOMIC_RELAXED);

> +                               /* Continue with next RX queue */

> +                               break;

> +                       }

> +                       /* Failed to grab slot */

> +               }

> +       }

> +}

> +

> +static int num_grps(void)

> +{

> +       return MAX_SCHED_GROUP;

> +}

> +

> +/*

> + * Stubs for internal scheduler abstraction layer due to absence of NULL

> + * checking before calling the function pointer.

> + */

> +

> +static int thr_add(odp_schedule_group_t group, int thr)

> +{

> +       /* This function is a schedule_init_local duplicate. */

> +       (void)group;

> +       (void)thr;

> +       return 0;

> +}

> +static int thr_rem(odp_schedule_group_t group, int thr)

> +{

> +       /* This function is a schedule_term_local duplicate. */

> +       (void)group;

> +       (void)thr;

> +       return 0;

> +}

> +static int init_queue(uint32_t queue_index,

> +                     const odp_schedule_param_t *sched_param)

> +{

> +       /* Not used in scalable scheduler. */

> +       (void)queue_index;

> +       (void)sched_param;

> +       return 0;

> +}

> +static void destroy_queue(uint32_t queue_index)

> +{

> +       /* Not used in scalable scheduler. */

> +       (void)queue_index;

> +}

> +static int sched_queue(uint32_t queue_index)

> +{

> +       /* Not used in scalable scheduler. */

> +       (void)queue_index;

> +       return 0;

> +}

> +static int ord_enq_multi(uint32_t queue_index, void *p_buf_hdr[],

> +                        int num, int *ret)

> +{

> +       (void)queue_index;

> +       (void)p_buf_hdr;

> +       (void)num;

> +       (void)ret;

> +       return 0;

> +}

> +

> +static void schedule_prefetch(int num)

> +{

> +       (void)num;

> +}

> +

> +static void order_lock(void)

> +{

> +}

> +

> +static void order_unlock(void)

> +{

> +}

> +

> +const schedule_fn_t schedule_scalable_fn = {

> +       .pktio_start    = pktio_start,

> +       .thr_add        = thr_add,

> +       .thr_rem        = thr_rem,

> +       .num_grps       = num_grps,

> +       .init_queue     = init_queue,

> +       .destroy_queue  = destroy_queue,

> +       .sched_queue    = sched_queue,

> +       .ord_enq_multi  = ord_enq_multi,

> +       .init_global    = schedule_init_global,

> +       .term_global    = schedule_term_global,

> +       .init_local     = schedule_init_local,

> +       .term_local     = schedule_term_local,

> +       .order_lock     = order_lock,

> +       .order_unlock   = order_unlock,

> +};

> +

> +const schedule_api_t schedule_scalable_api = {

> +       .schedule_wait_time             = schedule_wait_time,

> +       .schedule                       = schedule,

> +       .schedule_multi                 = schedule_multi,

> +       .schedule_pause                 = schedule_pause,

> +       .schedule_resume                = schedule_resume,

> +       .schedule_release_atomic        = schedule_release_atomic,

> +       .schedule_release_ordered       = schedule_release_ordered,

> +       .schedule_prefetch              = schedule_prefetch,

> +       .schedule_num_prio              = schedule_num_prio,

> +       .schedule_group_create          = schedule_group_create,

> +       .schedule_group_destroy         = schedule_group_destroy,

> +       .schedule_group_lookup          = schedule_group_lookup,

> +       .schedule_group_join            = schedule_group_join,

> +       .schedule_group_leave           = schedule_group_leave,

> +       .schedule_group_thrmask         = schedule_group_thrmask,

> +       .schedule_group_info            = schedule_group_info,

> +       .schedule_order_lock            = schedule_order_lock,

> +       .schedule_order_unlock          = schedule_order_unlock,

> +};

> diff --git a/platform/linux-generic/odp_schedule_scalable_ordered.c b/platform/linux-generic/odp_schedule_scalable_ordered.c

> new file mode 100644

> index 00000000..ff4431b5

> --- /dev/null

> +++ b/platform/linux-generic/odp_schedule_scalable_ordered.c

> @@ -0,0 +1,298 @@

> +/* Copyright (c) 2017, ARM Limited

> + * All rights reserved.

> + *

> + * SPDX-License-Identifier:     BSD-3-Clause

> + */

> +

> +#include <odp/api/shared_memory.h>

> +#include <odp_queue_internal.h>

> +#include <odp_schedule_if.h>

> +#include <odp_schedule_ordered_internal.h>

> +#include <odp_llsc.h>

> +#include <odp_bitset.h>

> +

> +#include <string.h>

> +

> +extern __thread sched_scalable_thread_state_t *sched_ts;

> +

> +#define RWIN_NAME_SIZE 32

> +

> +reorder_window_t *rwin_alloc(int rwin_id, odp_shm_t *shm, unsigned lock_count)

> +{

> +       char rwin_name[RWIN_NAME_SIZE];

> +       reorder_window_t *rwin;

> +       uint32_t i;

> +

> +       strncpy(rwin_name, "rwin", RWIN_NAME_SIZE);

> +       i = strlen(rwin_name);

> +       snprintf(rwin_name + i,

> +                (RWIN_NAME_SIZE - i), "%d", rwin_id);

> +

> +       *shm = odp_shm_reserve(rwin_name,

> +                       sizeof(reorder_window_t),

> +                       ODP_CACHE_LINE_SIZE,

> +                       ODP_SHM_PROC);

> +       if (ODP_SHM_INVALID == *shm)

> +               goto shm_reserve_failed;

> +

> +       rwin = (reorder_window_t *) odp_shm_addr(*shm);

> +       if (rwin == NULL)

> +               goto shm_addr_failed;

> +

> +       rwin->hc.head = 0;

> +       rwin->hc.chgi = 0;

> +       rwin->winmask = RWIN_SIZE - 1;

> +       rwin->tail = 0;

> +       rwin->turn = 0;

> +       rwin->lock_count = (uint16_t)lock_count;

> +       memset(rwin->olock, 0, sizeof(rwin->olock));

> +       for (i = 0; i < RWIN_SIZE; i++)

> +               rwin->ring[i] = NULL;

> +

> +       return rwin;

> +

> +shm_addr_failed:

> +       odp_shm_free(*shm);

> +

> +shm_reserve_failed:

> +       return NULL;

> +}

> +

> +bool rwin_reserve(reorder_window_t *rwin, uint32_t *sn)

> +{

> +       uint32_t head;

> +       uint32_t oldt;

> +       uint32_t newt;

> +       uint32_t winmask;

> +

> +       /* Read head and tail separately */

> +#ifndef ODP_CONFIG_USE_LLSC

> +       oldt = rwin->tail;

> +#endif

> +       __builtin_prefetch(&rwin->tail, 1, 0);

> +       winmask = rwin->winmask;

> +       do {

> +               /* Need __atomic_load to avoid compiler reordering */

> +               head = __atomic_load_n(&rwin->hc.head, __ATOMIC_RELAXED);

> +#ifdef ODP_CONFIG_USE_LLSC

> +               oldt = ll32(&rwin->tail, __ATOMIC_RELAXED);

> +#endif

> +               if (odp_unlikely(oldt - head >= winmask))

> +                       return false;

> +

> +               newt = oldt + 1;

> +#ifdef ODP_CONFIG_USE_LLSC

> +       } while (odp_unlikely(sc32(&rwin->tail, newt, __ATOMIC_RELAXED)));

> +#else

> +       } while (!__atomic_compare_exchange(&rwin->tail,

> +               &oldt,

> +               &newt,

> +               true,

> +               __ATOMIC_RELAXED,

> +               __ATOMIC_RELAXED));

> +#endif

> +       *sn = oldt;

> +

> +       return true;

> +}

> +

> +void rwin_insert(reorder_window_t *rwin,

> +                reorder_context_t *rctx,

> +                uint32_t sn,

> +                void (*callback)(reorder_context_t *))

> +{

> +       /* Initialise to silence scan-build */

> +       hc_t old = {0, 0};

> +       hc_t new;

> +       uint32_t winmask;

> +

> +       __atomic_load(&rwin->hc, &old, __ATOMIC_ACQUIRE);

> +       winmask = rwin->winmask;

> +       if (old.head != sn) {

> +               /* We are out-of-order. Store context in reorder window,

> +                * releasing its content.

> +                */

> +               ODP_ASSERT(rwin->ring[sn & winmask] == NULL);

> +#ifdef ODP_CONFIG_USE_DMB

> +               __atomic_thread_fence(__ATOMIC_RELEASE);

> +               __atomic_store_n(&rwin->ring[sn & winmask], rctx,

> +                                __ATOMIC_RELAXED);

> +#else

> +               __atomic_store_n(&rwin->ring[sn & winmask], rctx,

> +                                __ATOMIC_RELEASE);

> +#endif

> +               rctx = NULL;

> +               do {

> +                       hc_t new;

> +

> +                       new.head = old.head;

> +                       new.chgi = old.chgi + 1; /* Changed value */

> +                       /* Update head & chgi, fail if any has changed */

> +                       if (__atomic_compare_exchange(&rwin->hc,

> +                               &old, /* Updated on failure */

> +                               &new,

> +                               true,

> +                               __ATOMIC_RELEASE, /* Release our ring update */

> +                               __ATOMIC_ACQUIRE))

> +                               /* CAS succeeded => head same (we are not

> +                                * in-order), chgi updated.

> +                                */

> +                               return;

> +                       /* CAS failed => head and/or chgi changed.

> +                        * We might not be out-of-order anymore.

> +                        */

> +               } while (old.head != sn);

> +       }

> +

> +       /* old.head == sn => we are now in-order! */

> +       ODP_ASSERT(old.head == sn);

> +       /* We are in-order so our responsibility to retire contexts */

> +       new.head = old.head;

> +       new.chgi = old.chgi + 1;

> +

> +       /* Retire our in-order context (if we still have it) */

> +       if (rctx != NULL) {

> +               callback(rctx);

> +               new.head++;

> +       }

> +

> +       /* Retire in-order contexts in the ring

> +        * The first context might actually be ours (if we were originally

> +        * out-of-order)

> +        */

> +       do {

> +               for (;;) {

> +                       rctx = __atomic_load_n(&rwin->ring[new.head & winmask],

> +                                              __ATOMIC_ACQUIRE);

> +                       if (rctx == NULL)

> +                               break;

> +                       /* We are the only thread that are in-order

> +                        * (until head updated) so don't have to use

> +                        * atomic load-and-clear (exchange)

> +                        */

> +                       rwin->ring[new.head & winmask] = NULL;

> +                       callback(rctx);

> +                       new.head++;

> +               }

> +       /* Update head&chgi, fail if chgi has changed (head cannot change) */

> +       } while (!__atomic_compare_exchange(&rwin->hc,

> +                       &old, /* Updated on failure */

> +                       &new,

> +                       false, /* weak */

> +                       __ATOMIC_RELEASE, /* Release our ring updates */

> +                       __ATOMIC_ACQUIRE));

> +}

> +

> +void rctx_init(reorder_context_t *rctx, uint16_t idx,

> +              reorder_window_t *rwin, uint32_t sn)

> +{

> +       /* rctx->rvec_free and rctx->idx already initialised in

> +        * thread_state_init function.

> +        */

> +       ODP_ASSERT(rctx->idx == idx);

> +       rctx->rwin = rwin;

> +       rctx->sn = sn;

> +       rctx->olock_flags = 0;

> +       /* First => no next reorder context */

> +       rctx->next_idx = idx;

> +       /* Where to store next event */

> +       rctx->cur_idx = idx;

> +       rctx->numevts = 0;

> +}

> +

> +inline void rctx_free(const reorder_context_t *rctx)

> +{

> +       const reorder_context_t *const base = &rctx[-(int)rctx->idx];

> +       const uint32_t first = rctx->idx;

> +       uint32_t next_idx;

> +

> +       next_idx = rctx->next_idx;

> +

> +       ODP_ASSERT(rctx->rwin != NULL);

> +       /* Set free bit */

> +       if (rctx->rvec_free == &sched_ts->rvec_free)

> +               /* Since it is our own reorder context, we can instead

> +                * perform a non-atomic and relaxed update on our private

> +                * rvec_free.

> +                */

> +               sched_ts->priv_rvec_free =

> +                       bitset_set(sched_ts->priv_rvec_free, rctx->idx);

> +       else

> +               atom_bitset_set(rctx->rvec_free, rctx->idx, __ATOMIC_RELEASE);

> +

> +       /* Can't dereference rctx after the corresponding free bit is set */

> +       while (next_idx != first) {

> +               rctx = &base[next_idx];

> +               next_idx = rctx->next_idx;

> +               /* Set free bit */

> +               if (rctx->rvec_free == &sched_ts->rvec_free)

> +                       sched_ts->priv_rvec_free =

> +                               bitset_set(sched_ts->priv_rvec_free, rctx->idx);

> +               else

> +                       atom_bitset_set(rctx->rvec_free, rctx->idx,

> +                                       __ATOMIC_RELEASE);

> +       }

> +}

> +

> +inline void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,

> +                        uint32_t lock_index)

> +{

> +       if ((rctx->olock_flags & (1U << lock_index)) == 0) {

> +               /* Use relaxed ordering, we are not releasing any updates */

> +               rwin->olock[lock_index] = rctx->sn + 1;

> +       }

> +}

> +

> +void olock_release(const reorder_context_t *rctx)

> +{

> +       reorder_window_t *rwin;

> +

> +       rwin = rctx->rwin;

> +

> +       switch (rwin->lock_count) {

> +       case 2:

> +               olock_unlock(rctx, rwin, 1);

> +       case 1:

> +               olock_unlock(rctx, rwin, 0);

> +       }

> +       ODP_STATIC_ASSERT(NUM_OLOCKS == 2, "Number of ordered locks != 2");

> +}

> +

> +void rctx_retire(reorder_context_t *first)

> +{

> +       reorder_context_t *rctx;

> +       queue_entry_t *q;

> +       uint32_t i;

> +       uint32_t j;

> +       uint32_t num;

> +       int rc;

> +

> +       rctx = first;

> +       do {

> +               /* Process all events in this reorder context */

> +               for (i = 0; i < rctx->numevts;) {

> +                       q = rctx->destq[i];

> +                       /* Find index of next different destq */

> +                       j = i + 1;

> +                       while (j < rctx->numevts && rctx->destq[j] == q)

> +                               j++;

> +                       num = j - i;

> +                       rc = q->s.enqueue_multi(q, &rctx->events[i], num);

> +                       if (odp_unlikely(rc != (int)num))

> +                               ODP_ERR("Failed to enqueue deferred events\n");

> +                       i += num;

> +               }

> +               /* Update rctx pointer to point to 'next_idx' element */

> +               rctx += (int)rctx->next_idx - (int)rctx->idx;

> +       } while (rctx != first);

> +       olock_release(first);

> +       rctx_free(first);

> +}

> +

> +void rctx_release(reorder_context_t *rctx)

> +{

> +       /* Insert reorder context into reorder window, potentially calling the

> +        * rctx_retire function for all pending reorder_contexts.

> +        */

> +       rwin_insert(rctx->rwin, rctx, rctx->sn, rctx_retire);

> +}

> diff --git a/platform/linux-generic/odp_traffic_mngr.c b/platform/linux-generic/odp_traffic_mngr.c

> index 4e9358b9..3244dfe3 100644

> --- a/platform/linux-generic/odp_traffic_mngr.c

> +++ b/platform/linux-generic/odp_traffic_mngr.c

> @@ -3918,9 +3918,10 @@ odp_tm_queue_t odp_tm_queue_create(odp_tm_t odp_tm,

>         tm_queue_obj->pkt = ODP_PACKET_INVALID;

>         odp_ticketlock_init(&tm_wred_node->tm_wred_node_lock);

>

> -       tm_queue_obj->tm_qentry.s.type = QUEUE_TYPE_TM;

> -       tm_queue_obj->tm_qentry.s.enqueue = queue_tm_reenq;

> -       tm_queue_obj->tm_qentry.s.enqueue_multi = queue_tm_reenq_multi;

> +       queue_set_type(&tm_queue_obj->tm_qentry, QUEUE_TYPE_TM);

> +       queue_set_enq_func(&tm_queue_obj->tm_qentry, queue_tm_reenq);

> +       queue_set_enq_multi_func(&tm_queue_obj->tm_qentry,

> +                                queue_tm_reenq_multi);

>

>         tm_system->queue_num_tbl[tm_queue_obj->queue_num - 1] = tm_queue_obj;

>         odp_ticketlock_lock(&tm_system->tm_system_lock);

> diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c

> index 70962839..1f2f16c1 100644

> --- a/platform/linux-generic/pktio/loop.c

> +++ b/platform/linux-generic/pktio/loop.c

> @@ -80,11 +80,13 @@ static int loopback_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,

>

>         for (i = 0; i < nbr; i++) {

>                 uint32_t pkt_len;

> -

> +#ifdef ODP_SCHEDULE_SCALABLE

> +               pkt = _odp_packet_from_buffer((odp_buffer_t)(hdr_tbl[i]));

> +#else

>                 pkt = _odp_packet_from_buffer(odp_hdr_to_buf(hdr_tbl[i]));

> +#endif

>                 pkt_len = odp_packet_len(pkt);

>

> -

>                 if (pktio_cls_enabled(pktio_entry)) {

>                         odp_packet_t new_pkt;

>                         odp_pool_t new_pool;

> @@ -162,7 +164,11 @@ static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,

>                 len = QUEUE_MULTI_MAX;

>

>         for (i = 0; i < len; ++i) {

> +#ifdef ODP_SCHEDULE_SCALABLE

> +               hdr_tbl[i] = _odp_packet_to_buf_hdr_ptr(pkt_tbl[i]);

> +#else

>                 hdr_tbl[i] = buf_hdl_to_hdr(_odp_packet_to_buffer(pkt_tbl[i]));

> +#endif

>                 bytes += odp_packet_len(pkt_tbl[i]);

>         }

>

> @@ -176,6 +182,7 @@ static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,

>                 pktio_entry->s.stats.out_octets += bytes;

>         } else {

>                 ODP_DBG("queue enqueue failed %i\n", ret);

> +               odp_ticketlock_unlock(&pktio_entry->s.txl);

>                 return -1;

>         }

>

> diff --git a/test/common_plat/performance/odp_sched_latency.c b/test/common_plat/performance/odp_sched_latency.c

> index 2b28cd7b..5e11a4f3 100644

> --- a/test/common_plat/performance/odp_sched_latency.c

> +++ b/test/common_plat/performance/odp_sched_latency.c

> @@ -28,7 +28,13 @@

>  #define MAX_WORKERS      64            /**< Maximum number of worker threads */

>  #define MAX_QUEUES       4096          /**< Maximum number of queues */

>  #define EVENT_POOL_SIZE          (1024 * 1024) /**< Event pool size */

> +

> +#ifdef ODP_SCHEDULE_SP

>  #define TEST_ROUNDS (4 * 1024 * 1024)  /**< Test rounds for each thread */

> +#else

> +#define TEST_ROUNDS (32 * 1024 * 1024) /**< Test rounds for each thread */

> +#endif

> +

>  #define MAIN_THREAD       1 /**< Thread ID performing maintenance tasks */

>

>  /* Default values for command line arguments */

> @@ -104,6 +110,9 @@ typedef union {

>  typedef struct {

>         core_stat_t      core_stat[MAX_WORKERS]; /**< Core specific stats */

>         odp_barrier_t    barrier; /**< Barrier for thread synchronization */

> +#ifdef ODP_SCHEDULE_SCALABLE

> +       odp_schedule_group_t schedule_group;

> +#endif

>         odp_pool_t       pool;    /**< Pool for allocating test events */

>         test_args_t      args;    /**< Parsed command line arguments */

>         odp_queue_t      queue[NUM_PRIOS][MAX_QUEUES]; /**< Scheduled queues */

> @@ -119,7 +128,11 @@ static void clear_sched_queues(void)

>         odp_event_t ev;

>

>         while (1) {

> -               ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT);

> +               /* Need a non-zero timeout to ensure we can observe

> +                * any non-empty queue made eligible for scheduling

> +                * by some other thread.

> +                */

> +               ev = odp_schedule(NULL, 1000);

>

>                 if (ev == ODP_EVENT_INVALID)

>                         break;

> @@ -428,6 +441,20 @@ static int run_thread(void *arg ODP_UNUSED)

>                 return -1;

>         }

>

> +#ifdef ODP_SCHEDULE_SCALABLE

> +       int err;

> +       odp_thrmask_t thrmask;

> +

> +       odp_thrmask_zero(&thrmask);

> +       odp_thrmask_set(&thrmask, thr);

> +

> +       err = odp_schedule_group_join(globals->schedule_group, &thrmask);

> +       if (err != 0) {

> +               LOG_ERR("odp_schedule_group_join failed\n");

> +               return -1;

> +       }

> +#endif

> +

>         if (thr == MAIN_THREAD) {

>                 args = &globals->args;

>

> @@ -452,6 +479,13 @@ static int run_thread(void *arg ODP_UNUSED)

>         if (test_schedule(thr, globals))

>                 return -1;

>

> +#ifdef ODP_SCHEDULE_SCALABLE

> +       err = odp_schedule_group_leave(globals->schedule_group, &thrmask);

> +       if (err != 0) {

> +               LOG_ERR("odp_schedule_group_leave failed\n");

> +               return -1;

> +       }

> +#endif

>         return 0;

>  }

>

> @@ -692,6 +726,31 @@ int main(int argc, char *argv[])

>         }

>         globals->pool = pool;

>

> +#ifdef ODP_SCHEDULE_SCALABLE

> +       /*

> +        * Create scheduler group

> +        */

> +       odp_thrmask_t expected_thrmask;

> +       int cpu;

> +       int thr;

> +

> +       odp_thrmask_zero(&expected_thrmask);

> +       /* This is a odp_thrmask_from_cpumask() */

> +       cpu = odp_cpumask_first(&cpumask);

> +       thr = 1;

> +       while (0 <= cpu) {

> +               odp_thrmask_set(&expected_thrmask, thr++);

> +               cpu = odp_cpumask_next(&cpumask, cpu);

> +       }

> +

> +       globals->schedule_group =

> +               odp_schedule_group_create("sg0", &expected_thrmask);

> +       if (globals->schedule_group == ODP_SCHED_GROUP_INVALID) {

> +               LOG_ERR("odp_schedule_group_create failed\n");

> +               return -1;

> +       }

> +#endif

> +

>         /*

>          * Create queues for schedule test

>          */

> @@ -713,7 +772,11 @@ int main(int argc, char *argv[])

>                 param.type        = ODP_QUEUE_TYPE_SCHED;

>                 param.sched.prio  = prio;

>                 param.sched.sync  = args.sync_type;

> +#ifdef ODP_SCHEDULE_SCALABLE

> +               param.sched.group = globals->schedule_group;

> +#else

>                 param.sched.group = ODP_SCHED_GROUP_ALL;

> +#endif

>

>                 for (j = 0; j < args.prio[i].queues; j++) {

>                         name[9]  = '0' + j / 10;

> @@ -758,6 +821,10 @@ int main(int argc, char *argv[])

>                 }

>         }

>

> +

> +#ifdef ODP_SCHEDULE_SCALABLE

> +       ret += odp_schedule_group_destroy(globals->schedule_group);

> +#endif

>         ret += odp_shm_free(shm);

>         ret += odp_pool_destroy(pool);

>         ret += odp_term_local();

> diff --git a/test/common_plat/performance/odp_scheduling.c b/test/common_plat/performance/odp_scheduling.c

> index c74a0713..38e76257 100644

> --- a/test/common_plat/performance/odp_scheduling.c

> +++ b/test/common_plat/performance/odp_scheduling.c

> @@ -273,7 +273,7 @@ static int test_plain_queue(int thr, test_globals_t *globals)

>         test_message_t *t_msg;

>         odp_queue_t queue;

>         uint64_t c1, c2, cycles;

> -       int i;

> +       int i, j;

>

>         /* Alloc test message */

>         buf = odp_buffer_alloc(globals->pool);

> @@ -307,7 +307,15 @@ static int test_plain_queue(int thr, test_globals_t *globals)

>                         return -1;

>                 }

>

> -               ev = odp_queue_deq(queue);

> +               /* When enqueue and dequeue are decoupled (e.g. not using a

> +                * common lock), an enqueued event may not be immediately

> +                * visible to dequeue. So we just try again for a while. */

> +               for (j = 0; j < 100; j++) {

> +                       ev = odp_queue_deq(queue);

> +                       if (ev != ODP_EVENT_INVALID)

> +                               break;

> +                       odp_cpu_pause();

> +               }

>

>                 buf = odp_buffer_from_event(ev);

>

> diff --git a/test/common_plat/validation/api/classification/odp_classification_basic.c b/test/common_plat/validation/api/classification/odp_classification_basic.c

> index 9817287e..b5b92851 100644

> --- a/test/common_plat/validation/api/classification/odp_classification_basic.c

> +++ b/test/common_plat/validation/api/classification/odp_classification_basic.c

> @@ -93,10 +93,10 @@ void classification_test_create_pmr_match(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("pmr_match", true);

> +       queue = queue_create("pmr_match_queue", true);

>         CU_ASSERT(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("pmr_match");

> +       pool = pool_create("pmr_match_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         odp_cls_cos_param_init(&cls_param);

> @@ -277,10 +277,10 @@ void classification_test_pmr_composite_create(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("pmr_match", true);

> +       queue = queue_create("pmr_match_queue", true);

>         CU_ASSERT(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("pmr_match");

> +       pool = pool_create("pmr_match_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         odp_cls_cos_param_init(&cls_param);

> diff --git a/test/common_plat/validation/api/classification/odp_classification_test_pmr.c b/test/common_plat/validation/api/classification/odp_classification_test_pmr.c

> index d9524205..c1da5159 100644

> --- a/test/common_plat/validation/api/classification/odp_classification_test_pmr.c

> +++ b/test/common_plat/validation/api/classification/odp_classification_test_pmr.c

> @@ -121,10 +121,10 @@ void classification_test_pmr_term_tcp_dport(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("tcp_dport1", true);

> +       queue = queue_create("tcp_dport1_queue", true);

>         CU_ASSERT(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("tcp_dport1");

> +       pool = pool_create("tcp_dport1_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "tcp_dport");

> @@ -235,10 +235,10 @@ void classification_test_pmr_term_tcp_sport(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("tcp_sport", true);

> +       queue = queue_create("tcp_sport_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("tcp_sport");

> +       pool = pool_create("tcp_sport_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "tcp_sport");

> @@ -348,10 +348,10 @@ void classification_test_pmr_term_udp_dport(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("udp_dport", true);

> +       queue = queue_create("udp_dport_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("udp_dport");

> +       pool = pool_create("udp_dport_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "udp_dport");

> @@ -464,10 +464,10 @@ void classification_test_pmr_term_udp_sport(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("udp_sport", true);

> +       queue = queue_create("udp_sport_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("udp_sport");

> +       pool = pool_create("udp_sport_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "udp_sport");

> @@ -578,10 +578,10 @@ void classification_test_pmr_term_ipproto(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("ipproto", true);

> +       queue = queue_create("ipproto_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("ipproto");

> +       pool = pool_create("ipproto_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "ipproto");

> @@ -687,10 +687,10 @@ void classification_test_pmr_term_dmac(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("dmac", true);

> +       queue = queue_create("dmac_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("dmac");

> +       pool = pool_create("dmac_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "dmac");

> @@ -794,10 +794,10 @@ void classification_test_pmr_term_packet_len(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("packet_len", true);

> +       queue = queue_create("packet_len_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("packet_len");

> +       pool = pool_create("packet_len_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "packet_len");

> @@ -1355,10 +1355,10 @@ static void classification_test_pmr_pool_set(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("ipproto1", true);

> +       queue = queue_create("ipproto1_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("ipproto1");

> +       pool = pool_create("ipproto1_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "ipproto1");

> @@ -1454,10 +1454,10 @@ static void classification_test_pmr_queue_set(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("ipproto1", true);

> +       queue = queue_create("ipproto1_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("ipproto1");

> +       pool = pool_create("ipproto1_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "ipproto1");

> @@ -1469,7 +1469,7 @@ static void classification_test_pmr_queue_set(void)

>         cos = odp_cls_cos_create(cosname, &cls_param);

>         CU_ASSERT_FATAL(cos != ODP_COS_INVALID);

>

> -       queue_new = queue_create("ipproto2", true);

> +       queue_new = queue_create("ipproto2_queue", true);

>         CU_ASSERT_FATAL(queue_new != ODP_QUEUE_INVALID);

>

>         /* new queue is set on CoS */

> @@ -1546,10 +1546,10 @@ static void classification_test_pmr_term_daddr(void)

>         configure_default_cos(pktio, &default_cos,

>                               &default_queue, &default_pool);

>

> -       queue = queue_create("daddr", true);

> +       queue = queue_create("daddr_queue", true);

>         CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);

>

> -       pool = pool_create("daddr");

> +       pool = pool_create("daddr_pool");

>         CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);

>

>         sprintf(cosname, "daddr");

> diff --git a/test/common_plat/validation/api/scheduler/scheduler.c b/test/common_plat/validation/api/scheduler/scheduler.c

> index 952561cd..bc486192 100644

> --- a/test/common_plat/validation/api/scheduler/scheduler.c

> +++ b/test/common_plat/validation/api/scheduler/scheduler.c

> @@ -251,7 +251,10 @@ void scheduler_test_queue_destroy(void)

>                 CU_ASSERT_FATAL(u32[0] == MAGIC);

>

>                 odp_buffer_free(buf);

> -               odp_schedule_release_ordered();

> +               if (qp.sched.sync == ODP_SCHED_SYNC_ATOMIC)

> +                       odp_schedule_release_atomic();

> +               else if (qp.sched.sync == ODP_SCHED_SYNC_ORDERED)

> +                       odp_schedule_release_ordered();

>

>                 CU_ASSERT_FATAL(odp_queue_destroy(queue) == 0);

>         }

> @@ -478,6 +481,11 @@ void scheduler_test_groups(void)

>                 odp_schedule_group_leave(mygrp1, &mymask);

>                 odp_schedule_group_leave(mygrp2, &mymask);

>

> +               if (qp.sched.sync == ODP_SCHED_SYNC_ATOMIC)

> +                       odp_schedule_release_atomic();

> +               else if (qp.sched.sync == ODP_SCHED_SYNC_ORDERED)

> +                       odp_schedule_release_ordered();

> +

>                 /* Done with queues for this round */

>                 CU_ASSERT_FATAL(odp_queue_destroy(queue_grp1) == 0);

>                 CU_ASSERT_FATAL(odp_queue_destroy(queue_grp2) == 0);

> @@ -959,7 +967,6 @@ static void fill_queues(thread_args_t *args)

>                                 }

>

>                                 ret = odp_queue_enq(queue, ev);

> -                               CU_ASSERT_FATAL(ret == 0);

>

>                                 if (ret)

>                                         odp_buffer_free(buf);

> diff --git a/test/common_plat/validation/api/timer/timer.c b/test/common_plat/validation/api/timer/timer.c

> index b7d84c64..362f33c8 100644

> --- a/test/common_plat/validation/api/timer/timer.c

> +++ b/test/common_plat/validation/api/timer/timer.c

> @@ -297,8 +297,11 @@ static int worker_entrypoint(void *arg TEST_UNUSED)

>         struct timespec ts;

>         uint32_t nstale;

>         odp_timer_set_t timer_rc;

> +       char name[32];

>

> -       queue = odp_queue_create("timer_queue", NULL);

> +       snprintf(name, sizeof(name), "timer_queue_%d", thr);

> +

> +       queue = odp_queue_create(name, NULL);

>         if (queue == ODP_QUEUE_INVALID)

>                 CU_FAIL_FATAL("Queue create failed");

>

> --

> 2.12.1

>
Bill Fischofer March 29, 2017, 12:18 a.m. UTC | #2
On Tue, Mar 28, 2017 at 2:23 PM, Brian Brooks <brian.brooks@arm.com> wrote:
> Signed-off-by: Brian Brooks <brian.brooks@arm.com>

> ---

>  include/odp/api/spec/queue.h | 5 +++++

>  1 file changed, 5 insertions(+)

>

> diff --git a/include/odp/api/spec/queue.h b/include/odp/api/spec/queue.h

> index 7972feac..1cec4773 100644

> --- a/include/odp/api/spec/queue.h

> +++ b/include/odp/api/spec/queue.h

> @@ -124,6 +124,11 @@ typedef struct odp_queue_param_t {

>           * the queue type. */

>         odp_queue_type_t type;

>

> +       /** Queue size

> +         *

> +         * Indicates the max ring size of the ring buffer. */

> +       uint32_t ring_size;


ODP queues have historically been of unspecified size. If we're going
to introduce the notion of explicitly limited sized queues this has
additional implications.

First, ring_size is an inappropriate choice of name here since a ring
is an implementation model, not a specification. The documentation
says "Queue size", so

uint32_t size;

is sufficient here. We should document that size = 0 requests a queue
of default size (which may be unbounded).

Second, if we're going to allow a queue size to be specified then this
needs to be added as an output to odp_queue_capability() so the
application knows the max_size supported (again 0 = unbounded).

A larger question, however, is why is this being introduced at all
since this field is only used in the modified
odph_cuckoo_table_create() helper routine and this, in turn, is only
used within the cuckootable test module? This seems an extraneous and
unnecessary change and has no relationship to the rest of this patch
series.

So Parts 1 and 3 of this series don't seem to have anything to do with
the scalable scheduler. As a minor point, the order of these needs to
be reversed to preserve bisectability since Part 1 can't reference the
new field before Part 3 defines it.

> +

>         /** Enqueue mode

>           *

>           * Default value for both queue types is ODP_QUEUE_OP_MT. Application

> --

> 2.12.1

>
Brian Brooks March 29, 2017, 1:55 a.m. UTC | #3
On 03/28 19:18:37, Bill Fischofer wrote:
> <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">


It is infinitely better to do patch review in plain text rather
than HTML. I thought this was a plain text mailing list?

> <meta name="Generator" content="Microsoft Exchange Server">

> <!-- converted from text -->

> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style></head>

> <body>

> <font size="2"><span style="font-size:10pt;"><div class="PlainText">On Tue, Mar 28, 2017 at 2:23 PM, Brian Brooks &lt;brian.brooks@arm.com&gt; wrote:<br>

> &gt; Signed-off-by: Brian Brooks &lt;brian.brooks@arm.com&gt;<br>

> &gt; ---<br>

> &gt;&nbsp; include/odp/api/spec/queue.h | 5 &#43;&#43;&#43;&#43;&#43;<br>

> &gt;&nbsp; 1 file changed, 5 insertions(&#43;)<br>

> &gt;<br>

> &gt; diff --git a/include/odp/api/spec/queue.h b/include/odp/api/spec/queue.h<br>

> &gt; index 7972feac..1cec4773 100644<br>

> &gt; --- a/include/odp/api/spec/queue.h<br>

> &gt; &#43;&#43;&#43; b/include/odp/api/spec/queue.h<br>

> &gt; @@ -124,6 &#43;124,11 @@ typedef struct odp_queue_param_t {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the queue type. */<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_type_t type;<br>

> &gt;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Queue size<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Indicates the max ring size of the ring buffer. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ring_size;<br>

> <br>

> ODP queues have historically been of unspecified size. If we're going<br>

> to introduce the notion of explicitly limited sized queues this has<br>

> additional implications.<br>

>

> First, ring_size is an inappropriate choice of name here since a ring<br>

> is an implementation model, not a specification. The documentation<br>

> says &quot;Queue size&quot;, so<br>

> <br>

> uint32_t size;<br>

> <br>

> is sufficient here.


Agree, will change 'ring_size' to a better name.

> We should document that size = 0 requests a queue<br>

> of default size (which may be unbounded).<br>


Unbounded size is not practical or possible. Can we agree that 0 means
that the default aka ODP_CONFIG_QUEUE_SIZE is used? Should we allow for
greater than ODP_CONFIG_QUEUE_SIZE? E.g. 10,000 queue depth is also not
practical or possible. Perhaps we need a max which also acts as the default.

> <br>

> Second, if we're going to allow a queue size to be specified then this<br>

> needs to be added as an output to odp_queue_capability()


OK, will look into that.

> so the<br>

> application knows the max_size supported (again 0 = unbounded).<br>

> <br>

> A larger question, however, is why is this being introduced at all<br>

> since this field is only used in the modified<br>

> odph_cuckoo_table_create() helper routine and this, in turn, is only<br>

> used within the cuckootable test module? This seems an extraneous and<br>

> unnecessary change and has no relationship to the rest of this patch<br>

> series.<br>


AFAIK, the cuckoo unit test enqueues too many events (millions) to a queue.
That sounds like it makes no sense, but is an example of how anything is
possible.

> <br>

> So Parts 1 and 3 of this series don't seem to have anything to do with<br>

> the scalable scheduler. As a minor point, the order of these needs to<br>

> be reversed to preserve bisectability since Part 1 can't reference the<br>

> new field before Part 3 defines it.<br>


Agree that there are 2 independent sets of patches, but the order is needed
in order to get a sane `make check' on ARM-based chips. Without these fixes
going in first, we have no way of knowing whether the scalable scheduler patches
caused the issue or not. I can break these into 2 separate sets of patches.

> <br>

> &gt; &#43;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Enqueue mode<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Default value for both queue types is ODP_QUEUE_OP_MT. Application<br>

> &gt; --<br>

> &gt; 2.12.1<br>

> &gt;<br>

> </div></span></font>

> </body>

> </html>
Brian Brooks March 29, 2017, 2:18 a.m. UTC | #4
On 03/28 18:50:32, Bill Fischofer wrote:
> <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">

> <meta name="Generator" content="Microsoft Exchange Server">

> <!-- converted from text -->

> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style></head>

> <body>

> <font size="2"><span style="font-size:10pt;"><div class="PlainText">This part generates numerous checkpatch warnings and errors. Please<br>

> run checkpatch and correct for v2.<br>


We ran checkpatch.pl and corrected the issues that made sense. We all know that
checkpatch.pl is not perfect. Please point out the checkpatch.pl issues that
are generated from this patch which are not false positives or not destructive
to programmer readability.

> <br>

> Also, this part introduces a number of errors that result in failure<br>

> to compile using clang.


This is likely true. Is compilation with Clang a blocker?

> Please test with both gcc and clang to ensure<br>

> that it compiles cleanly for both (gcc looks fine)<br>

> <br>

> Specific clang issues:<br>

> &nbsp; CC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_packet.lo<br>

> odp_packet.c:656:9: error: cast from 'odp_buffer_t' (aka<br>

> '_odp_abi_buffer_t *') to 'odp_buffer_hdr_t *' (aka 'struct<br>

> odp_buffer_hdr_t *') increases required alignment from 1 to 8<br>

> [-Werror,-Wcast-align]<br>

> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (odp_buffer_hdr_t *)(_odp_packet_to_buffer(pkt));<br>

> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>

> <br>

> clang requires an intermediate cast to (void *) to avoid these warnings.<br>

> <br>

> 1 error generated.<br>

> Makefile:1004: recipe for target 'odp_packet.lo' failed<br>

> <br>

> <br>

> clang also generates numerous link errors:<br>

> <br>

> &nbsp; CC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_bench_packet-odp_bench_packet.o<br>

> make[3]: *** No rule to make target '../../../lib/libodp-linux.la',<br>

> needed by 'odp_bench_packet'.<br>

> <br>

> .&nbsp; CC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atomic_main.o<br>

> make[5]: *** No rule to make target<br>

> '../../../../../lib/libodp-linux.la', needed by 'atomic_main'.<br>

> <br>

> &nbsp; CC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classification_main.o<br>

> make[5]: *** No rule to make target<br>

> '../../../../../lib/libodp-linux.la', needed by 'classification_main'.<br>

> <br>

> ...and many others like this.<br>

> <br>


I cannot tell if there are any other comments in this response because
it is not in plain text. Did you have more comments?

> On Tue, Mar 28, 2017 at 2:23 PM, Brian Brooks &lt;brian.brooks@arm.com&gt; wrote:<br>

> &gt; This work derives from Ola Liljedahl's prototype [1] which introduced a<br>

> &gt; scalable scheduler design based on primarily lock-free algorithms and<br>

> &gt; data structures designed to decrease contention. A thread searches<br>

> &gt; through a data structure containing only queues that are both non-empty<br>

> &gt; and allowed to be scheduled to that thread. Strict priority scheduling is<br>

> &gt; respected, and (W)RR scheduling may be used within queues of the same priority.<br>

> &gt; Lastly, pre-scheduling or stashing is not employed since it is optional<br>

> &gt; functionality that can be implemented in the application.<br>

> &gt;<br>

> &gt; In addition to scalable ring buffers, the algorithm also uses unbounded<br>

> &gt; concurrent queues. LL/SC and CAS variants exist in cases where absense of<br>

> &gt; ABA problem cannot be proved, and also in cases where the compiler's atomic<br>

> &gt; built-ins may not be lowered to the desired instruction(s). Finally, a version<br>

> &gt; of the algorithm that uses locks is also provided.<br>

> &gt;<br>

> &gt; See platform/linux-generic/include/odp_config_internal.h for further build<br>

> &gt; time configuration.<br>

> &gt;<br>

> &gt; Use --enable-schedule-scalable to conditionally compile this scheduler<br>

> &gt; into the library.<br>

> &gt;<br>

> &gt; [1] <a href="https://lists.linaro.org/pipermail/lng-odp/2016-September/025682.html">https://lists.linaro.org/pipermail/lng-odp/2016-September/025682.html</a><br>

> &gt;<br>

> &gt; Signed-off-by: Brian Brooks &lt;brian.brooks@arm.com&gt;<br>

> &gt; Signed-off-by: Kevin Wang &lt;kevin.wang@arm.com&gt;<br>

> &gt; Signed-off-by: Honnappa Nagarahalli &lt;honnappa.nagarahalli@arm.com&gt;<br>

> &gt; Signed-off-by: Ola Liljedahl &lt;ola.liljedahl@arm.com&gt;<br>

> &gt; ---<br>

> &gt;&nbsp; platform/linux-generic/Makefile.am&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 21 &#43;-<br>

> &gt;&nbsp; .../include/odp/api/plat/schedule_types.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 20 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/include/odp_atomic16.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 244 &#43;&#43;&#43;<br>

> &gt;&nbsp; platform/linux-generic/include/odp_bitset.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 155 &#43;&#43;<br>

> &gt;&nbsp; .../linux-generic/include/odp_config_internal.h&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 90 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/include/odp_internal.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 2 &#43;<br>

> &gt;&nbsp; platform/linux-generic/include/odp_llqueue.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 386 &#43;&#43;&#43;&#43;<br>

> &gt;&nbsp; platform/linux-generic/include/odp_llsc.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 325 &#43;&#43;&#43;&#43;<br>

> &gt;&nbsp; .../linux-generic/include/odp_packet_internal.h&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 3 &#43;<br>

> &gt;&nbsp; .../linux-generic/include/odp_queue_internal.h&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 122 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/include/odp_schedule_if.h&nbsp;&nbsp; |&nbsp; 166 &#43;-<br>

> &gt;&nbsp; .../include/odp_schedule_ordered_internal.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 150 &#43;&#43;<br>

> &gt;&nbsp; platform/linux-generic/m4/odp_schedule.m4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 55 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/odp_classification.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 4 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/odp_packet.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 5 &#43;<br>

> &gt;&nbsp; platform/linux-generic/odp_packet_io.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 88 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/odp_queue.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 2 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/odp_queue_scalable.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 944 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;<br>

> &gt;&nbsp; platform/linux-generic/odp_schedule_if.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 36 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/odp_schedule_scalable.c&nbsp;&nbsp;&nbsp;&nbsp; | 1959 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;<br>

> &gt;&nbsp; .../linux-generic/odp_schedule_scalable_ordered.c&nbsp; |&nbsp; 298 &#43;&#43;&#43;<br>

> &gt;&nbsp; platform/linux-generic/odp_traffic_mngr.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 7 &#43;-<br>

> &gt;&nbsp; platform/linux-generic/pktio/loop.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 11 &#43;-<br>

> &gt;&nbsp; test/common_plat/performance/odp_sched_latency.c&nbsp;&nbsp; |&nbsp;&nbsp; 69 &#43;-<br>

> &gt;&nbsp; test/common_plat/performance/odp_scheduling.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 12 &#43;-<br>

> &gt;&nbsp; .../api/classification/odp_classification_basic.c&nbsp; |&nbsp;&nbsp;&nbsp; 8 &#43;-<br>

> &gt;&nbsp; .../classification/odp_classification_test_pmr.c&nbsp;&nbsp; |&nbsp;&nbsp; 42 &#43;-<br>

> &gt;&nbsp; .../validation/api/scheduler/scheduler.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 11 &#43;-<br>

> &gt;&nbsp; test/common_plat/validation/api/timer/timer.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp; 5 &#43;-<br>

> &gt;&nbsp; 29 files changed, 5123 insertions(&#43;), 117 deletions(-)<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/include/odp_atomic16.h<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/include/odp_bitset.h<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/include/odp_llqueue.h<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/include/odp_llsc.h<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/include/odp_schedule_ordered_internal.h<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/odp_queue_scalable.c<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/odp_schedule_scalable.c<br>

> &gt;&nbsp; create mode 100644 platform/linux-generic/odp_schedule_scalable_ordered.c<br>

> &gt;<br>

> &gt; diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am<br>

> &gt; index 70683cac..8c263b99 100644<br>

> &gt; --- a/platform/linux-generic/Makefile.am<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/Makefile.am<br>

> &gt; @@ -151,6 &#43;151,8 @@ noinst_HEADERS = \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_debug_internal.h \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_forward_typedefs_internal.h \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_internal.h \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_llqueue.h \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_llsc.h \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_name_table_internal.h \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_packet_internal.h \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${srcdir}/include/odp_packet_io_internal.h \<br>

> &gt; @@ -219,13 &#43;221,9 @@ __LIB__libodp_linux_la_SOURCES = \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pktio/ring.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pkt_queue.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pool.c \<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_rwlock.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_rwlock_recursive.c \<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_if.c \<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_sp.c \<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_iquery.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shared_memory.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_sorted_list.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock.c \<br>

> &gt; @@ -250,6 &#43;248,21 @@ __LIB__libodp_linux_la_SOURCES = \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arch/@ARCH_DIR@/odp_cpu_arch.c \<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arch/@ARCH_DIR@/odp_sysinfo_parse.c<br>

> &gt;<br>

> &gt; &#43;if ODP_SCHEDULE_SP<br>

> &gt; &#43;__LIB__libodp_linux_la_SOURCES &#43;= odp_schedule_sp.c<br>

> &gt; &#43;endif<br>

> &gt; &#43;<br>

> &gt; &#43;if ODP_SCHEDULE_IQUERY<br>

> &gt; &#43;__LIB__libodp_linux_la_SOURCES &#43;= odp_schedule_iquery.c<br>

> &gt; &#43;endif<br>

> &gt; &#43;<br>

> &gt; &#43;if ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;__LIB__libodp_linux_la_SOURCES &#43;= odp_queue_scalable.c odp_schedule_scalable.c \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_scalable_ordered.c<br>

> &gt; &#43;else<br>

> &gt; &#43;__LIB__libodp_linux_la_SOURCES &#43;= odp_queue.c odp_schedule.c<br>

> &gt; &#43;endif<br>

> &gt; &#43;<br>

> &gt;&nbsp; if HAVE_PCAP<br>

> &gt;&nbsp; __LIB__libodp_linux_la_SOURCES &#43;= pktio/pcap.c<br>

> &gt;&nbsp; endif<br>

> &gt; diff --git a/platform/linux-generic/include/odp/api/plat/schedule_types.h b/platform/linux-generic/include/odp/api/plat/schedule_types.h<br>

> &gt; index 535fd6d0..d9bb39a6 100644<br>

> &gt; --- a/platform/linux-generic/include/odp/api/plat/schedule_types.h<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp/api/plat/schedule_types.h<br>

> &gt; @@ -18,6 &#43;18,8 @@<br>

> &gt;&nbsp; extern &quot;C&quot; {<br>

> &gt;&nbsp; #endif<br>

> &gt;<br>

> &gt; &#43;#include &lt;odp/api/std_types.h&gt;<br>

> &gt; &#43;<br>

> &gt;&nbsp; /** @addtogroup odp_scheduler<br>

> &gt;&nbsp;&nbsp; *&nbsp; @{<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt; @@ -27,6 &#43;29,20 @@ extern &quot;C&quot; {<br>

> &gt;<br>

> &gt;&nbsp; typedef int odp_schedule_prio_t;<br>

> &gt;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;<br>

> &gt; &#43;#define ODP_SCHED_PRIO_NUM&nbsp; 8<br>

> &gt; &#43;<br>

> &gt; &#43;#define ODP_SCHED_PRIO_HIGHEST 0<br>

> &gt; &#43;<br>

> &gt; &#43;#define ODP_SCHED_PRIO_LOWEST (ODP_SCHED_PRIO_NUM - 1)<br>

> &gt; &#43;<br>

> &gt; &#43;#define ODP_SCHED_PRIO_DEFAULT (ODP_SCHED_PRIO_NUM / 2)<br>

> &gt; &#43;<br>

> &gt; &#43;#define ODP_SCHED_PRIO_NORMAL ODP_SCHED_PRIO_DEFAULT<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;<br>

> &gt;&nbsp; #define ODP_SCHED_PRIO_HIGHEST&nbsp; 0<br>

> &gt;<br>

> &gt;&nbsp; #define ODP_SCHED_PRIO_NORMAL&nbsp;&nbsp; 4<br>

> &gt; @@ -35,6 &#43;51,8 @@ typedef int odp_schedule_prio_t;<br>

> &gt;<br>

> &gt;&nbsp; #define ODP_SCHED_PRIO_DEFAULT&nbsp; ODP_SCHED_PRIO_NORMAL<br>

> &gt;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt;&nbsp; typedef int odp_schedule_sync_t;<br>

> &gt;<br>

> &gt;&nbsp; #define ODP_SCHED_SYNC_PARALLEL 0<br>

> &gt; @@ -44,7 &#43;62,7 @@ typedef int odp_schedule_sync_t;<br>

> &gt;&nbsp; typedef int odp_schedule_group_t;<br>

> &gt;<br>

> &gt;&nbsp; /* These must be kept in sync with thread_globals_t in odp_thread.c */<br>

> &gt; -#define ODP_SCHED_GROUP_INVALID -1<br>

> &gt; &#43;#define ODP_SCHED_GROUP_INVALID ((odp_schedule_group_t) -1)<br>

> &gt;&nbsp; #define ODP_SCHED_GROUP_ALL&nbsp;&nbsp;&nbsp;&nbsp; 0<br>

> &gt;&nbsp; #define ODP_SCHED_GROUP_WORKER&nbsp; 1<br>

> &gt;&nbsp; #define ODP_SCHED_GROUP_CONTROL 2<br>

> &gt; diff --git a/platform/linux-generic/include/odp_atomic16.h b/platform/linux-generic/include/odp_atomic16.h<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..5afd66c5<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_atomic16.h<br>

> &gt; @@ -0,0 &#43;1,244 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited.<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef _ODP_ATOMIC16_H_<br>

> &gt; &#43;#define _ODP_ATOMIC16_H_<br>

> &gt; &#43;<br>

> &gt; &#43;#include &quot;odp_llsc.h&quot;<br>

> &gt; &#43;<br>

> &gt; &#43;#if defined __ARM_ARCH &amp;&amp; __ARM_ARCH == 8<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */<br>

> &gt; &#43;static inline __int128 casp(__int128 *var, __int128 old, __int128 neu, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mo == __ATOMIC_RELAXED) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;casp %0, %H0, %1, %H1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;&#43;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (mo == __ATOMIC_ACQUIRE) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;caspa %0, %H0, %1, %H1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;&#43;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (mo == __ATOMIC_ACQ_REL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;caspal %0, %H0, %1, %H1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;&#43;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (mo == __ATOMIC_RELEASE) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;caspl %0, %H0, %1, %H1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;&#43;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; abort();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bool __atomic_compare_exchange_16(register __int128 *var,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 *exp, register __int128 neu,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool weak, int mo_success, int mo_failure)<br>

> &gt; &#43;{<br>

> &gt; &#43;#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)weak;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)mo_failure;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 old;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 expected;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected = *exp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = casp(var, expected, neu, mo_success);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *exp = old; /* Always update, atomically read value */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old == expected;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)weak; /* Always do strong CAS or we can't perform atomic read */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Ignore memory ordering for failure, memory order for<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * success must be stronger or equal<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)mo_failure;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ll_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sc_mo;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register __int128 old;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register __int128 expected;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ll_mo = mo_success == __ATOMIC_ACQUIRE ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mo_success == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc_mo = mo_success == __ATOMIC_RELEASE ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mo_success == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE : __ATOMIC_RELAXED;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected = *exp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomicity of LLD is not guaranteed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = lld(var, ll_mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Must write back neu or old to verify atomicity of LLD */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(scd(var, old == expected ? neu : old, sc_mo)));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *exp = old; /* Always update, atomically read value */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old == expected;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bool __atomic_compare_exchange_16_frail(register __int128 *var,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 *exp, register __int128 neu, bool weak,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int mo_success, int mo_failure)<br>

> &gt; &#43;{<br>

> &gt; &#43;#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)weak;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)mo_failure;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 old;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 expected;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected = *exp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = casp(var, expected, neu, mo_success);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *exp = old; /* Always update, atomically read value */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old == expected;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)weak; /* Weak CAS and non-atomic load on failure */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)mo_failure; /* Ignore memory ordering for failure */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ll_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sc_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register __int128 expected;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register __int128 old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* memory order for success must be stronger or equal */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ll_mo = mo_success == __ATOMIC_ACQUIRE ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mo_success == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc_mo = mo_success == __ATOMIC_RELEASE ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mo_success == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected = *exp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomicity of LLD is not guaranteed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = lld(var, ll_mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(old == expected &amp;&amp; !scd(var, neu, sc_mo))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Right value and SC succeeded */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm __volatile(&quot;&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wrong value or SC failed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *exp = old; /* Old possibly torn value */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0; /* Failure, *exp updated */<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline __int128 __atomic_load_16(__int128 *var, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 old = *var; /* Possibly torn read */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Do CAS to ensure atomicity<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Either CAS succeeds (writing back the same value)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Or CAS fails and returns the old value (atomic read)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)__atomic_compare_exchange_n(var,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false, /* weak= */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mo,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline __int128 __atomic_exchange_16(__int128 *var,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 neu, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 old;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 expected;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected = *var;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = casp(var, expected, neu, mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (old != expected);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ll_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sc_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register __int128 old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ll_mo = mo == __ATOMIC_ACQUIRE || mo == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc_mo = mo == __ATOMIC_RELEASE || mo == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomicity of LLD is not guaranteed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = lld(var, ll_mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Must successfully write back to verify atomicity of LLD */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(scd(var, neu, sc_mo)));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline __int128 __atomic_fetch_and_16(__int128 *var,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 mask, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 old;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 expected;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected = *var;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = casp(var, expected, expected &amp; mask, mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (old != expected);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ll_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sc_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register __int128 old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ll_mo = mo == __ATOMIC_ACQUIRE || mo == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc_mo = mo == __ATOMIC_RELEASE || mo == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomicity of LLD is not guaranteed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = lld(var, ll_mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Must successfully write back to verify atomicity of LLD */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(scd(var, old &amp; mask, sc_mo)));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline __int128 __atomic_fetch_or_16(__int128 *var,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 mask,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;#ifdef __ARM_FEATURE_QRDMX /* Feature only available in v8.1a and beyond */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 old;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 expected;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expected = *var;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = casp(var, expected, expected | mask, mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (old != expected);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ll_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sc_mo;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register __int128 old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ll_mo = mo == __ATOMIC_ACQUIRE || mo == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc_mo = mo == __ATOMIC_RELEASE || mo == __ATOMIC_ACQ_REL ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE : __ATOMIC_RELAXED;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomicity of LLD is not guaranteed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = lld(var, ll_mo);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Must successfully write back to verify atomicity of LLD */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(scd(var, old | mask, sc_mo)));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#endif<br>

> &gt; diff --git a/platform/linux-generic/include/odp_bitset.h b/platform/linux-generic/include/odp_bitset.h<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..db004267<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_bitset.h<br>

> &gt; @@ -0,0 &#43;1,155 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef _ODP_BITSET_H_<br>

> &gt; &#43;#define _ODP_BITSET_H_<br>

> &gt; &#43;<br>

> &gt; &#43;/******************************************************************************<br>

> &gt; &#43; * bitset abstract data type<br>

> &gt; &#43; *****************************************************************************/<br>

> &gt; &#43;/* This could be a struct of scalars to support larger bit sets */<br>

> &gt; &#43;<br>

> &gt; &#43;#if ATOM_BITSET_SIZE &lt;= 32<br>

> &gt; &#43;<br>

> &gt; &#43;typedef uint32_t bitset_t;<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bitset_t bitset_mask(uint32_t bit)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1UL &lt;&lt; bit;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return first-bit-set with StdC ffs() semantics */<br>

> &gt; &#43;static inline uint32_t bitset_ffs(bitset_t b)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __builtin_ffsl(b);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Load-exclusive with memory ordering */<br>

> &gt; &#43;static inline bitset_t bitset_ldex(bitset_t *bs, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return LDXR32(bs, mo);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#elif ATOM_BITSET_SIZE &lt;= 64<br>

> &gt; &#43;<br>

> &gt; &#43;typedef uint64_t bitset_t;<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bitset_t bitset_mask(uint32_t bit)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1ULL &lt;&lt; bit;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return first-bit-set with StdC ffs() semantics */<br>

> &gt; &#43;static inline uint32_t bitset_ffs(bitset_t b)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __builtin_ffsll(b);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Load-exclusive with memory ordering */<br>

> &gt; &#43;static inline bitset_t bitset_ldex(bitset_t *bs, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return LDXR64(bs, mo);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#elif ATOM_BITSET_SIZE &lt;= 128<br>

> &gt; &#43;<br>

> &gt; &#43;#if __SIZEOF_INT128__ == 16<br>

> &gt; &#43;typedef unsigned __int128 bitset_t;<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bitset_t bitset_mask(uint32_t bit)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bit &lt; 64)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1ULL &lt;&lt; bit;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (unsigned __int128)(1ULL &lt;&lt; (bit - 64)) &lt;&lt; 64;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return first-bit-set with StdC ffs() semantics */<br>

> &gt; &#43;static inline uint32_t bitset_ffs(bitset_t b)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((uint64_t)b != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __builtin_ffsll((uint64_t)b);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if ((b &gt;&gt; 64) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __builtin_ffsll((uint64_t)(b &gt;&gt; 64)) &#43; 64;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Load-exclusive with memory ordering */<br>

> &gt; &#43;static inline bitset_t bitset_ldex(bitset_t *bs, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return LDXR128(bs, mo);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;#error __int128 not supported by compiler<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;#error Unsupported size of bit sets (ATOM_BITSET_SIZE)<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;/* Atomic load with memory ordering */<br>

> &gt; &#43;static inline bitset_t atom_bitset_load(bitset_t *bs, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __atomic_load_n(bs, mo);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Atomic bit set with memory ordering */<br>

> &gt; &#43;static inline void atom_bitset_set(bitset_t *bs, uint32_t bit, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)__atomic_fetch_or(bs, bitset_mask(bit), mo);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Atomic bit clear with memory ordering */<br>

> &gt; &#43;static inline void atom_bitset_clr(bitset_t *bs, uint32_t bit, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)__atomic_fetch_and(bs, ~bitset_mask(bit), mo);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Atomic exchange with memory ordering */<br>

> &gt; &#43;static inline bitset_t atom_bitset_xchg(bitset_t *bs, bitset_t neu, int mo)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __atomic_exchange_n(bs, neu, mo);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return a &amp; ~b */<br>

> &gt; &#43;static inline bitset_t bitset_andn(bitset_t a, bitset_t b)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return a &amp; ~b;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bool bitset_is_eql(bitset_t a, bitset_t b)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return a == b;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bitset_t bitset_clr(bitset_t bs, uint32_t bit)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return bs &amp; ~bitset_mask(bit);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bitset_t bitset_set(bitset_t bs, uint32_t bit)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return bs | bitset_mask(bit);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bitset_t bitset_null(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0U;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bool bitset_is_null(bitset_t a)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return a == 0U;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bool bitset_is_set(bitset_t a, uint32_t bit)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (a &amp; bitset_mask(bit)) != 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; diff --git a/platform/linux-generic/include/odp_config_internal.h b/platform/linux-generic/include/odp_config_internal.h<br>

> &gt; index dadd59e7..b1ee48f2 100644<br>

> &gt; --- a/platform/linux-generic/include/odp_config_internal.h<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_config_internal.h<br>

> &gt; @@ -22,6 &#43;22,13 @@ extern &quot;C&quot; {<br>

> &gt;&nbsp; #define ODP_CONFIG_QUEUES 1024<br>

> &gt;<br>

> &gt;&nbsp; /*<br>

> &gt; &#43; * Maximum queue depth. Maximum number of elements that can be stored in a<br>

> &gt; &#43; * queue. This value is used only when the size is not explicitly provided<br>

> &gt; &#43; * during queue creation.<br>

> &gt; &#43; */<br>

> &gt; &#43;#define ODP_CONFIG_QUEUE_SIZE 4096<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt;&nbsp;&nbsp; * Maximum number of ordered locks per queue<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt;&nbsp; #define CONFIG_QUEUE_MAX_ORD_LOCKS 4<br>

> &gt; @@ -104,7 &#43;111,7 @@ extern &quot;C&quot; {<br>

> &gt;&nbsp;&nbsp; *<br>

> &gt;&nbsp;&nbsp; * This the the number of separate SHM areas that can be reserved concurrently<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt; -#define ODP_CONFIG_SHM_BLOCKS (ODP_CONFIG_POOLS &#43; 48)<br>

> &gt; &#43;#define ODP_CONFIG_SHM_BLOCKS (ODP_CONFIG_POOLS &#43; ODP_CONFIG_QUEUES &#43; 48)<br>

> &gt;<br>

> &gt;&nbsp; /*<br>

> &gt;&nbsp;&nbsp; * Size of the virtual address space pre-reserver for ISHM<br>

> &gt; @@ -120,7 &#43;127,7 @@ extern &quot;C&quot; {<br>

> &gt;&nbsp;&nbsp; *<br>

> &gt;&nbsp;&nbsp; * This the the number of separate SHM areas that can be reserved concurrently<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt; -#define ODPDRV_CONFIG_SHM_BLOCKS 48<br>

> &gt; &#43;#define ODPDRV_CONFIG_SHM_BLOCKS ODP_CONFIG_SHM_BLOCKS<br>

> &gt;<br>

> &gt;&nbsp; /* Maximum event burst size<br>

> &gt;&nbsp;&nbsp; *<br>

> &gt; @@ -129,6 &#43;136,21 @@ extern &quot;C&quot; {<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt;&nbsp; #define CONFIG_BURST_SIZE 16<br>

> &gt;<br>

> &gt; &#43;/* Default weight (in events) for WRR in scalable scheduler<br>

> &gt; &#43; *<br>

> &gt; &#43; * This controls the per-queue weight for WRR between queues of the same<br>

> &gt; &#43; * priority in the scalable scheduler<br>

> &gt; &#43; * A higher value improves throughput while a lower value increases fairness<br>

> &gt; &#43; * and thus likely decreases latency<br>

> &gt; &#43; *<br>

> &gt; &#43; * If WRR is undesired, set the value to ~0 which will use the largest possible<br>

> &gt; &#43; * weight<br>

> &gt; &#43; *<br>

> &gt; &#43; * Note: an API for specifying this on a per-queue basis would be useful but is<br>

> &gt; &#43; * not yet available<br>

> &gt; &#43; */<br>

> &gt; &#43;#define CONFIG_WRR_WEIGHT 64<br>

> &gt; &#43;<br>

> &gt;&nbsp; /*<br>

> &gt;&nbsp;&nbsp; * Maximum number of events in a pool<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt; @@ -139,6 &#43;161,70 @@ extern &quot;C&quot; {<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt;&nbsp; #define CONFIG_POOL_CACHE_SIZE 256<br>

> &gt;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Split queue producer/consumer metadata into separate cache lines.<br>

> &gt; &#43; * This is beneficial on e.g. Cortex-A57 but not so much on A53.<br>

> &gt; &#43; */<br>

> &gt; &#43;#define ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Split queue read/write metadata into separate cache lines.<br>

> &gt; &#43; * This enhances scalability even further on Cortex-A57.<br>

> &gt; &#43; */<br>

> &gt; &#43;#define ODP_CONFIG_USE_SPLIT_READWRITE<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Use locks to protect queue (ring buffer) and scheduler state updates<br>

> &gt; &#43; * On x86, this decreases overhead but also degrades scalability<br>

> &gt; &#43; */<br>

> &gt; &#43;#ifndef __ARM_ARCH<br>

> &gt; &#43;#define CONFIG_QSCHST_LOCK<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;/* Keep all ring buffer/qschst data together when using locks<br>

> &gt; &#43; */<br>

> &gt; &#43;#undef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;#undef ODP_CONFIG_USE_SPLIT_READWRITE<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Use spin lock instead of (lock-free) atomic operations in llqueue<br>

> &gt; &#43; * This is recommended on architectures which implement CAS instead<br>

> &gt; &#43; * of LL/SC as CAS is susceptible to the ABA problem<br>

> &gt; &#43; */<br>

> &gt; &#43;#ifndef __ARM_ARCH<br>

> &gt; &#43;#define ODP_CONFIG_LLQ_LOCK<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Size of atomic bit set. This limits the max number of threads,<br>

> &gt; &#43; * scheduler groups and reorder windows. On ARMv8/64-bit and x86-64, the<br>

> &gt; &#43; * (lock-free) max is 128<br>

> &gt; &#43; */<br>

> &gt; &#43;#define ATOM_BITSET_SIZE 64<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Use LL/SC atomic primitives instead of __atomic_compare_exchange built-ins<br>

> &gt; &#43; */<br>

> &gt; &#43;#ifdef __ARM_ARCH<br>

> &gt; &#43;#define ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Use DMB;STR instead of STRL on ARM<br>

> &gt; &#43; */<br>

> &gt; &#43;#ifdef __ARM_ARCH<br>

> &gt; &#43;#define ODP_CONFIG_USE_DMB<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Use ARM event signalling mechanism<br>

> &gt; &#43; */<br>

> &gt; &#43;#ifdef __ARM_ARCH<br>

> &gt; &#43;#define ODP_CONFIG_USE_WFE<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt;&nbsp; #ifdef __cplusplus<br>

> &gt;&nbsp; }<br>

> &gt;&nbsp; #endif<br>

> &gt; diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h<br>

> &gt; index 05c8a422..60eb9daa 100644<br>

> &gt; --- a/platform/linux-generic/include/odp_internal.h<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_internal.h<br>

> &gt; @@ -28,6 &#43;28,8 @@ extern __thread int __odp_errno;<br>

> &gt;<br>

> &gt;&nbsp; #define MAX_CPU_NUMBER 128<br>

> &gt;<br>

> &gt; &#43;#define IS_POWER_TWO(x) ((((x) - 1) &amp; (x)) == 0)<br>

> &gt; &#43;<br>

> &gt;&nbsp; typedef struct {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t cpu_hz_max[MAX_CPU_NUMBER];<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t page_size;<br>

> &gt; diff --git a/platform/linux-generic/include/odp_llqueue.h b/platform/linux-generic/include/odp_llqueue.h<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..6f20c641<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_llqueue.h<br>

> &gt; @@ -0,0 &#43;1,386 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited.<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_LLQUEUE_H_<br>

> &gt; &#43;#define ODP_LLQUEUE_H_<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp/api/cpu.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/hints.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/spinlock.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_config_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_debug_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_llsc.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;stdint.h&gt;<br>

> &gt; &#43;#include &lt;stdlib.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;/******************************************************************************<br>

> &gt; &#43; * Linked list queues<br>

> &gt; &#43; *****************************************************************************/<br>

> &gt; &#43;<br>

> &gt; &#43;#if defined(__ARM_ARCH) &amp;&amp; !defined(ODP_CONFIG_USE_LLSC) &amp;&amp; \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !defined(ODP_CONFIG_LLQ_LOCK)<br>

> &gt; &#43;#error ODP_CONFIG_USE_LLSC required on ARM for double-word atomics if not \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; using spinlock<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;/* The scalar equivalent of a double pointer */<br>

> &gt; &#43;#if __SIZEOF_PTRDIFF_T__ == 4<br>

> &gt; &#43;typedef uint64_t dintptr_t;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#if __SIZEOF_PTRDIFF_T__ == 8<br>

> &gt; &#43;typedef __int128 dintptr_t;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#define SENTINEL ((void *)~(uintptr_t)0)<br>

> &gt; &#43;<br>

> &gt; &#43;struct llnode {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *next;<br>

> &gt; &#43;};<br>

> &gt; &#43;<br>

> &gt; &#43;union llht {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *head, *tail;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } st;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dintptr_t ui;<br>

> &gt; &#43;};<br>

> &gt; &#43;<br>

> &gt; &#43;struct llqueue {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht u;<br>

> &gt; &#43;#ifdef ODP_CONFIG_LLQ_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_t lock;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;};<br>

> &gt; &#43;<br>

> &gt; &#43;static inline struct llnode *llq_head(struct llqueue *llq)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return __atomic_load_n(&amp;llq-&gt;u.st.head, __ATOMIC_RELAXED);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void llqueue_init(struct llqueue *llq)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.head = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.tail = NULL;<br>

> &gt; &#43;#ifdef ODP_CONFIG_LLQ_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_init(&amp;llq-&gt;lock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_CONFIG_LLQ_LOCK<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void llq_enqueue(struct llqueue *llq, struct llnode *node)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht old;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht neu;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(node-&gt;next == NULL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node-&gt;next = SENTINEL;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Prefetch for store for faster LL/SC execution */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;llq-&gt;u.ui, 1, 0);<br>

> &gt; &#43;retry: /* Failed SC requires new LL */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old.ui = lld(&amp;llq-&gt;u.ui, __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load(&amp;llq-&gt;u, &amp;old, __ATOMIC_RELAXED);<br>

> &gt; &#43;retry: /* Failed CAS returns existing value */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)0; /* Need statement after label */<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.head = old.st.head == NULL ? node : old.st.head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.tail = node;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(scd(&amp;llq-&gt;u.ui, neu.ui, __ATOMIC_RELEASE))) {<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(!__atomic_compare_exchange(&amp;llq-&gt;u,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;neu,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false, /* weak= */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto retry;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (old.st.tail != NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* List was not empty */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(old.st.tail-&gt;next == SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old.st.tail-&gt;next = node;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void llq_enqueue(struct llqueue *llq, struct llnode *node)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(node-&gt;next == NULL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node-&gt;next = SENTINEL;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;llq-&gt;lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (llq-&gt;u.st.head == NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.head = llq-&gt;u.st.tail = node;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.tail-&gt;next = node;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.tail = node;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;llq-&gt;lock);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_CONFIG_LLQ_LOCK<br>

> &gt; &#43;<br>

> &gt; &#43;static inline struct llnode *llq_dequeue(struct llqueue *llq)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* llq_dequeue() may be used in a busy-waiting fashion<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Read head using plain load to avoid disturbing remote LL/SC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = __atomic_load_n(&amp;llq-&gt;u.st.head, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (head == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Read head-&gt;next before LL to minimize cache miss latency<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * in LL/SC below<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)__atomic_load_n(&amp;head-&gt;next, __ATOMIC_RELAXED);<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Prefetch for store for faster LL/SC execution */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;llq-&gt;u.ui, 1, 0);<br>

> &gt; &#43;retry: /* Failed SC requires new LL */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old.ui = lld(&amp;llq-&gt;u.ui, __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load(&amp;llq-&gt;u, &amp;old, __ATOMIC_RELAXED);<br>

> &gt; &#43;retry: /* Failed CAS returns existing value */<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(old.st.head == NULL)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Empty list */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (odp_unlikely(old.st.head == old.st.tail)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Single-element in list */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht neu;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.head = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.tail = NULL;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(scd(&amp;llq-&gt;u.ui, neu.ui, __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(!__atomic_compare_exchange(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;llq-&gt;u,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;neu,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false, /* weak= */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Failed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto retry;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(old.st.head-&gt;next == SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Multi-element list, dequeue head */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *next;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht neu;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait until llq_enqueue() has written true next pointer */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((next = __atomic_load_n(&amp;old.st.head-&gt;next,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED)) == SENTINEL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.head = next;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.tail = old.st.tail;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(scd(&amp;llq-&gt;u.ui, neu.ui, __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(!__atomic_compare_exchange(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;llq-&gt;u,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;neu,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false, /* weak= */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Failed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto retry;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(old.st.head-&gt;next != SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old.st.head-&gt;next = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old.st.head;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;<br>

> &gt; &#43;static inline struct llnode *llq_dequeue(struct llqueue *llq)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *node = NULL;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = __atomic_load_n(&amp;llq-&gt;u.st.head, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (head == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;llq-&gt;lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (llq-&gt;u.st.head != NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node = llq-&gt;u.st.head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (llq-&gt;u.st.head == llq-&gt;u.st.tail) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(node-&gt;next == SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.head = llq-&gt;u.st.tail = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(node-&gt;next != SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.head = node-&gt;next;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node-&gt;next = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;llq-&gt;lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return node;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_CONFIG_LLQ_LOCK<br>

> &gt; &#43;<br>

> &gt; &#43;static inline odp_bool_t llq_dequeue_cond(struct llqueue *llq,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *exp)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht old;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Prefetch for store for faster LL/SC execution */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;llq-&gt;u.ui, 1, 0);<br>

> &gt; &#43;retry: /* Failed SC requires new LL */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old.ui = lld(&amp;llq-&gt;u.ui, __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load(&amp;llq-&gt;u, &amp;old, __ATOMIC_RELAXED);<br>

> &gt; &#43;retry: /* Failed CAS returns existing value */<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(old.st.head == NULL || old.st.head != exp)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Empty list or wrong head */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (odp_unlikely(old.st.head == old.st.tail)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Single-element in list */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht neu;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.head = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.tail = NULL;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(scd(&amp;llq-&gt;u.ui, neu.ui, __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(!__atomic_compare_exchange(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;llq-&gt;u,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;neu,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false, /* weak= */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Failed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto retry;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(old.st.head-&gt;next == SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Multi-element list, dequeue head */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *next;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union llht neu;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait until llq_enqueue() has written true next pointer */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((next = __atomic_load_n(&amp;old.st.head-&gt;next,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED)) == SENTINEL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.head = next;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; neu.st.tail = old.st.tail;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(scd(&amp;llq-&gt;u.ui, neu.ui, __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(!__atomic_compare_exchange(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;llq-&gt;u,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;neu,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false, /* weak= */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED))) {<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Failed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto retry;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(old.st.head-&gt;next != SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old.st.head-&gt;next = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;<br>

> &gt; &#43;static inline odp_bool_t llq_dequeue_cond(struct llqueue *llq,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *node)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_bool_t success = false;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;llq-&gt;lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(llq-&gt;u.st.head != NULL &amp;&amp; llq-&gt;u.st.head == node)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; success = true;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (llq-&gt;u.st.head == llq-&gt;u.st.tail) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(node-&gt;next == SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.head = llq-&gt;u.st.tail = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(node-&gt;next != SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.head = node-&gt;next;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node-&gt;next = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;llq-&gt;lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return success;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_CONFIG_LLQ_LOCK<br>

> &gt; &#43;<br>

> &gt; &#43;/* If 'node' is a head of llq then move it to tail */<br>

> &gt; &#43;static inline odp_bool_t llq_cond_rotate(struct llqueue *llq,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *node)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Difficult to make this into a single atomic operation<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Instead use existing primitives.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(llq_dequeue_cond(llq, node))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq_enqueue(llq, node);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;<br>

> &gt; &#43;/* If 'node' is a head of llq then move it to tail */<br>

> &gt; &#43;static inline odp_bool_t llq_cond_rotate(struct llqueue *llq,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *node)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_bool_t success = false;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;llq-&gt;lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(llq-&gt;u.st.head == node)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; success = true;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (llq-&gt;u.st.tail != node) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(node-&gt;next != SENTINEL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.head = node-&gt;next;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.tail-&gt;next = node;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq-&gt;u.st.tail = node;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node-&gt;next = SENTINEL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else 'node' is only element on list =&gt; nothing to do */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;llq-&gt;lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return success;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; diff --git a/platform/linux-generic/include/odp_llsc.h b/platform/linux-generic/include/odp_llsc.h<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..a7b6166e<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_llsc.h<br>

> &gt; @@ -0,0 &#43;1,325 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_LLSC_H_<br>

> &gt; &#43;#define ODP_LLSC_H_<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_config_internal.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;/******************************************************************************<br>

> &gt; &#43; * LL/SC primitives<br>

> &gt; &#43; *****************************************************************************/<br>

> &gt; &#43;<br>

> &gt; &#43;#if defined __ARM_ARCH<br>

> &gt; &#43;#if __ARM_ARCH == 7 || (__ARM_ARCH == 8 &amp;&amp; __ARM_64BIT_STATE == 0)<br>

> &gt; &#43;static inline void dmb(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;dmb&quot; : : : &quot;memory&quot;);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline uint32_t ll8(uint8_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldrexb %0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Barrier after an acquiring load */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dmb();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline uint32_t ll16(uint16_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldrexh %0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Barrier after an acquiring load */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dmb();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline uint32_t ll(uint32_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldrex %0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Barrier after an acquiring load */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dmb();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;#define ll32(a, b) ll((a), (b))<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return 0 on success, 1 on failure */<br>

> &gt; &#43;static inline uint32_t sc(uint32_t *var, uint32_t neu, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ret;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Barrier before a releasing store */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_RELEASE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dmb();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;strex %0, %1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;#define sc32(a, b, c) sc((a), (b), (c))<br>

> &gt; &#43;<br>

> &gt; &#43;static inline uint64_t lld(uint64_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldrexd %0, %H0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Barrier after an acquiring load */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dmb();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;#define ll64(a, b) lld((a), (b))<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return 0 on success, 1 on failure */<br>

> &gt; &#43;static inline uint32_t scd(uint64_t *var, uint64_t neu, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ret;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Barrier before a releasing store */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_RELEASE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dmb();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;strexd %0, %1, %H1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;#define sc64(a, b, c) scd((a), (b), (c))<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#if __ARM_ARCH == 8 &amp;&amp; __ARM_64BIT_STATE == 1<br>

> &gt; &#43;static inline uint16_t ll8(uint8_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldaxrb %w0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldxrb %w0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline uint16_t ll16(uint16_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldaxrh %w0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldxrh %w0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline uint32_t ll32(uint32_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldaxr %w0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldxr %w0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return 0 on success, 1 on failure */<br>

> &gt; &#43;static inline uint32_t sc32(uint32_t *var, uint32_t neu, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ret;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_RELEASE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;stlxr %w0, %w1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;stxr %w0, %w1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline uint64_t ll(uint64_t *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldaxr %0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldxr %0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;#define ll64(a, b) ll((a), (b))<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return 0 on success, 1 on failure */<br>

> &gt; &#43;static inline uint32_t sc(uint64_t *var, uint64_t neu, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ret;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_RELEASE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;stlxr %w0, %1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;stxr %w0, %1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;#define sc64(a, b, c) sc((a), (b), (c))<br>

> &gt; &#43;static inline __int128 lld(__int128 *var, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __int128 old;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldaxp %0, %H0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;ldxp %0, %H0, [%1]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (old)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return old;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Return 0 on success, 1 on failure */<br>

> &gt; &#43;static inline uint32_t scd(__int128 *var, __int128 neu, int mm)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ret;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mm == __ATOMIC_RELEASE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;stlxp %w0, %1, %H1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (mm == __ATOMIC_RELAXED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;stxp %w0, %1, %H1, [%2]&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;=&amp;r&quot; (ret)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : &quot;r&quot; (neu), &quot;r&quot; (var)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : );<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void sevl(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;#if defined __ARM_ARCH<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;sevl&quot; : : : );<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void sev(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;#if defined __ARM_ARCH<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;sev&quot; : : : &quot;memory&quot;);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline int wfe(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;#if defined __ARM_ARCH<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;wfe&quot; : : : &quot;memory&quot;);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_WFE<br>

> &gt; &#43;#define SEVL() sevl()<br>

> &gt; &#43;#define WFE() wfe()<br>

> &gt; &#43;#define SEV() do { __asm volatile(&quot;dsb ish&quot; ::: &quot;memory&quot;); sev(); } while (0)<br>

> &gt; &#43;#if defined __ARM_ARCH &amp;&amp; __ARM_ARCH == 8 &amp;&amp; __ARM_64BIT_STATE == 1<br>

> &gt; &#43;#define LDXR128(addr, mo) lld((addr), (mo))<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#define LDXR64(addr, mo) ll64((addr), (mo))<br>

> &gt; &#43;#define LDXR32(addr, mo) ll32((addr), (mo))<br>

> &gt; &#43;#define LDXR16(addr, mo) ll16((addr), (mo))<br>

> &gt; &#43;#define LDXR8(addr, mo) ll8((addr), (mo))<br>

> &gt; &#43;/* When using WFE do not stall the pipeline using other means */<br>

> &gt; &#43;#define DOZE() (void)0<br>

> &gt; &#43;#else<br>

> &gt; &#43;#define SEVL() (void)0<br>

> &gt; &#43;#define WFE() 1<br>

> &gt; &#43;#define SEV() (void)0<br>

> &gt; &#43;#define LDXR128(addr, mo) __atomic_load_n((addr), (mo))<br>

> &gt; &#43;#define LDXR64(addr, mo) __atomic_load_n((addr), (mo))<br>

> &gt; &#43;#define LDXR32(addr, mo) __atomic_load_n((addr), (mo))<br>

> &gt; &#43;#define LDXR16(addr, mo) __atomic_load_n((addr), (mo))<br>

> &gt; &#43;#define LDXR8(addr, mo) __atomic_load_n((addr), (mo))<br>

> &gt; &#43;#if defined __ARM_ARCH<br>

> &gt; &#43;#define DOZE() __asm volatile(&quot;isb&quot; ::: &quot;memory&quot;)<br>

> &gt; &#43;#else<br>

> &gt; &#43;#define DOZE() __asm volatile(&quot;pause&quot; ::: &quot;memory&quot;)<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h<br>

> &gt; index 0a9f1779..c9d14766 100644<br>

> &gt; --- a/platform/linux-generic/include/odp_packet_internal.h<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_packet_internal.h<br>

> &gt; @@ -235,6 &#43;235,9 @@ odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt);<br>

> &gt;&nbsp; /* Convert a buffer handle to a packet handle */<br>

> &gt;&nbsp; odp_packet_t _odp_packet_from_buffer(odp_buffer_t buf);<br>

> &gt;<br>

> &gt; &#43;/* Convert a packet handle to a buffer hdr handle pointer */<br>

> &gt; &#43;odp_buffer_hdr_t *_odp_packet_to_buf_hdr_ptr(odp_packet_t pkt);<br>

> &gt; &#43;<br>

> &gt;&nbsp; static inline int packet_hdr_has_l2(odp_packet_hdr_t *pkt_hdr)<br>

> &gt;&nbsp; {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pkt_hdr-&gt;p.input_flags.l2;<br>

> &gt; diff --git a/platform/linux-generic/include/odp_queue_internal.h b/platform/linux-generic/include/odp_queue_internal.h<br>

> &gt; index 560f826e..ebfc0f76 100644<br>

> &gt; --- a/platform/linux-generic/include/odp_queue_internal.h<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_queue_internal.h<br>

> &gt; @@ -19,16 &#43;19,24 @@ extern &quot;C&quot; {<br>

> &gt;&nbsp; #endif<br>

> &gt;<br>

> &gt;&nbsp; #include &lt;odp/api/queue.h&gt;<br>

> &gt; -#include &lt;odp_forward_typedefs_internal.h&gt;<br>

> &gt; -#include &lt;odp_schedule_if.h&gt;<br>

> &gt; -#include &lt;odp_buffer_internal.h&gt;<br>

> &gt; -#include &lt;odp_align_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/std_types.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/buffer.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/packet_io.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/align.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/hints.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/ticketlock.h&gt;<br>

> &gt; &#43;<br>

> &gt;&nbsp; #include &lt;odp_config_internal.h&gt;<br>

> &gt;<br>

> &gt; &#43;#include &lt;odp_align_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_buffer_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_forward_typedefs_internal.h&gt;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;#include &lt;odp_llsc.h&gt;<br>

> &gt; &#43;#include &lt;odp_schedule_ordered_internal.h&gt;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#include &lt;odp_schedule_if.h&gt;<br>

> &gt; &#43;<br>

> &gt;&nbsp; #define QUEUE_MULTI_MAX CONFIG_BURST_SIZE<br>

> &gt;<br>

> &gt;&nbsp; #define QUEUE_STATUS_FREE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br>

> &gt; @@ -37,8 &#43;45,6 @@ extern &quot;C&quot; {<br>

> &gt;&nbsp; #define QUEUE_STATUS_NOTSCHED&nbsp;&nbsp;&nbsp;&nbsp; 3<br>

> &gt;&nbsp; #define QUEUE_STATUS_SCHED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4<br>

> &gt;<br>

> &gt; -<br>

> &gt; -/* forward declaration */<br>

> &gt;&nbsp; union queue_entry_u;<br>

> &gt;<br>

> &gt;&nbsp; typedef int (*enq_func_t)(union queue_entry_u *, odp_buffer_hdr_t *);<br>

> &gt; @@ -49,6 &#43;55,37 @@ typedef int (*enq_multi_func_t)(union queue_entry_u *,<br>

> &gt;&nbsp; typedef&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*deq_multi_func_t)(union queue_entry_u *,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **, int);<br>

> &gt;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;#define BUFFER_HDR_INVALID ((odp_buffer_hdr_t *)ODP_EVENT_INVALID)<br>

> &gt; &#43;<br>

> &gt; &#43;struct queue_entry_s {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t&nbsp;&nbsp;&nbsp;&nbsp; sched_elem;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shm;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin_shm;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_ticketlock_t lock ODP_ALIGNED_CACHE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enq_func_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enqueue ODP_ALIGNED_CACHE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deq_func_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dequeue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enq_multi_func_t enqueue_multi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deq_multi_func_t dequeue_multi;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; index;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handle;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_type_t&nbsp;&nbsp; type;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_param_t&nbsp; param;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pktin_queue_t&nbsp; pktin;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pktout_queue_t pktout;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name[ODP_QUEUE_NAME_LEN];<br>

> &gt; &#43;};<br>

> &gt; &#43;<br>

> &gt; &#43;int _odp_queue_deq(sched_elem_t *q, odp_event_t *evp, int num);<br>

> &gt; &#43;int _odp_queue_deq_sc(sched_elem_t *q, odp_event_t *evp, int num);<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;#define BUFFER_HDR_INVALID NULL<br>

> &gt; &#43;<br>

> &gt;&nbsp; struct queue_entry_s {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_ticketlock_t&nbsp; lock ODP_ALIGNED_CACHE;<br>

> &gt;<br>

> &gt; @@ -77,6 &#43;114,8 @@ struct queue_entry_s {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name[ODP_QUEUE_NAME_LEN];<br>

> &gt;&nbsp; };<br>

> &gt;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt;&nbsp; union queue_entry_u {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct queue_entry_s s;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t pad[ROUNDUP_CACHE_LINE(sizeof(struct queue_entry_s))];<br>

> &gt; @@ -94,6 &#43;133,12 @@ int queue_deq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[], int num);<br>

> &gt;&nbsp; void queue_lock(queue_entry_t *queue);<br>

> &gt;&nbsp; void queue_unlock(queue_entry_t *queue);<br>

> &gt;<br>

> &gt; &#43;int queue_pktout_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr);<br>

> &gt; &#43;int queue_pktout_enq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num);<br>

> &gt; &#43;<br>

> &gt; &#43;int queue_tm_reorder(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr);<br>

> &gt; &#43;<br>

> &gt;&nbsp; static inline uint32_t queue_to_id(odp_queue_t handle)<br>

> &gt;&nbsp; {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _odp_typeval(handle) - 1;<br>

> &gt; @@ -107,6 &#43;152,71 @@ static inline queue_entry_t *queue_to_qentry(odp_queue_t handle)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return get_qentry(queue_id);<br>

> &gt;&nbsp; }<br>

> &gt;<br>

> &gt; &#43;static inline odp_queue_t queue_get_handle(queue_entry_t *queue)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.handle;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline odp_pktout_queue_t queue_get_pktout(queue_entry_t *queue)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.pktout;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void queue_set_pktout(queue_entry_t *queue,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pktio_t pktio,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int index)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.pktout.pktio = pktio;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.pktout.index = index;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline odp_pktin_queue_t queue_get_pktin(queue_entry_t *queue)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.pktin;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void queue_set_pktin(queue_entry_t *queue,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pktio_t pktio,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int index)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.pktin.pktio = pktio;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.pktin.index = index;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void queue_set_enq_func(queue_entry_t *queue, enq_func_t func)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.enqueue = func;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void queue_set_enq_multi_func(queue_entry_t *queue,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enq_multi_func_t func)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.enqueue_multi = func;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void queue_set_deq_func(queue_entry_t *queue, deq_func_t func)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.dequeue = func;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void queue_set_deq_multi_func(queue_entry_t *queue,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deq_multi_func_t func)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.dequeue_multi = func;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void queue_set_type(queue_entry_t *queue, odp_queue_type_t type)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.type = type;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;static inline reorder_window_t *queue_get_rwin(queue_entry_t *queue)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.sched_elem.rwin;<br>

> &gt; &#43;}<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt;&nbsp; #ifdef __cplusplus<br>

> &gt;&nbsp; }<br>

> &gt;&nbsp; #endif<br>

> &gt; diff --git a/platform/linux-generic/include/odp_schedule_if.h b/platform/linux-generic/include/odp_schedule_if.h<br>

> &gt; index 530d157f..41998833 100644<br>

> &gt; --- a/platform/linux-generic/include/odp_schedule_if.h<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_schedule_if.h<br>

> &gt; @@ -4,6 &#43;4,12 @@<br>

> &gt;&nbsp;&nbsp; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt;<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt;&nbsp; #ifndef ODP_SCHEDULE_IF_H_<br>

> &gt;&nbsp; #define ODP_SCHEDULE_IF_H_<br>

> &gt;<br>

> &gt; @@ -11,18 &#43;17,168 @@<br>

> &gt;&nbsp; extern &quot;C&quot; {<br>

> &gt;&nbsp; #endif<br>

> &gt;<br>

> &gt; &#43;#include &lt;odp/api/align.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/queue.h&gt;<br>

> &gt; -#include &lt;odp_queue_internal.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/schedule.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/ticketlock.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_forward_typedefs_internal.h&gt;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;#include &lt;odp_config_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_llqueue.h&gt;<br>

> &gt; &#43;#include &lt;odp_schedule_ordered_internal.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;limits.h&gt;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;/* Number of ordered locks per queue */<br>

> &gt; &#43;#define SCHEDULE_ORDERED_LOCKS_PER_QUEUE 2<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llqueue llq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t prio;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char line[ODP_CACHE_LINE_SIZE];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br>

> &gt; &#43;} sched_queue_t ODP_ALIGNED_CACHE;<br>

> &gt; &#43;<br>

> &gt; &#43;#define TICKET_INVALID (uint16_t)(~0U)<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int32_t numevts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t wrr_budget;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t cur_ticket;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t nxt_ticket;<br>

> &gt; &#43;} qschedstate_t ODP_ALIGNED(sizeof(uint64_t));<br>

> &gt; &#43;<br>

> &gt; &#43;typedef uint32_t ringidx_t;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;#define SPLIT_PC ODP_ALIGNED_CACHE<br>

> &gt; &#43;#else<br>

> &gt; &#43;#define SPLIT_PC<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_READWRITE<br>

> &gt; &#43;#define SPLIT_RW ODP_ALIGNED_CACHE<br>

> &gt; &#43;#else<br>

> &gt; &#43;#define SPLIT_RW<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#define ODP_NO_SCHED_QUEUE (ODP_SCHED_SYNC_ORDERED &#43; 1)<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* (ll)node must be first */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode node;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 8:&nbsp; 0.. 7 */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_queue_t *schedq;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 8:&nbsp; 8..15 */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_ticketlock_t qschlock;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qschedstate_t qschst;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 8: 16..23 */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t pop_deficit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 2: 24..25 */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t qschst_type;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 2: 26..27 */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t prod_read SPLIT_PC; /* 4: 28..31 */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t prod_write SPLIT_RW;/* 4: 32..35 */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t prod_mask;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 4: 36..39 */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **prod_ring; /* 8: 40..47 */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t cons_write SPLIT_PC;/* 4: 48..51 */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t cons_read SPLIT_RW; /* 4: 52..55 */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_window_t *rwin;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 8: 56..63 */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *user_ctx;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 8: 64..71 */<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **cons_ring;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t cons_mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t cons_type;<br>

> &gt; &#43;#else<br>

> &gt; &#43;#define cons_mask prod_mask<br>

> &gt; &#43;#define cons_ring prod_ring<br>

> &gt; &#43;#define cons_type qschst_type<br>

> &gt; &#43;#endif<br>

> &gt; &#43;} sched_elem_t ODP_ALIGNED_CACHE;<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Scheduler group related declarations.<br>

> &gt; &#43; */<br>

> &gt; &#43;typedef bitset_t sched_group_mask_t;<br>

> &gt; &#43;<br>

> &gt; &#43;/* Number of scheduling groups */<br>

> &gt; &#43;#define MAX_SCHED_GROUP (sizeof(sched_group_mask_t) * CHAR_BIT)<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Threads currently associated with the sched group */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t thr_actual[ODP_SCHED_PRIO_NUM] ODP_ALIGNED_CACHE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t thr_wanted;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Used to spread queues over schedq's */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t xcount[ODP_SCHED_PRIO_NUM];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Number of schedq's per prio */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t xfactor;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char name[ODP_SCHED_GROUP_NAME_LEN];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* shm handle for the group */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_t shm;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* ODP_SCHED_PRIO_NUM * xfactor.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Must be the last memember in this struct.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_queue_t schedq[1] ODP_ALIGNED_CACHE;<br>

> &gt; &#43;} sched_group_t;<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Per thread state<br>

> &gt; &#43; */<br>

> &gt; &#43;/* Number of reorder contexts per thread */<br>

> &gt; &#43;#define TS_RVEC_SIZE 16<br>

> &gt; &#43;typedef struct {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomic queue currently being processed or NULL */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *atomq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Current reorder context or NULL */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *rctx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t pause;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t out_of_order;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t tidx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t pad;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t dequeued; /* Number of events dequeued from atomic queue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t pktin_next;/* Next pktin tag to poll */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t pktin_poll_cnts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t ticket; /* Ticket for atomic queue or TICKET_INVALID */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t num_schedq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t sg_sem; /* Set when sg_wanted is modified by other thread */<br>

> &gt; &#43;#define SCHEDQ_PER_THREAD (MAX_SCHED_GROUP * ODP_SCHED_PRIO_NUM)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_queue_t *schedq_list[SCHEDQ_PER_THREAD];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Current sched_group membership */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t sg_actual[ODP_SCHED_PRIO_NUM];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Future sched_group membership. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t sg_wanted[ODP_SCHED_PRIO_NUM];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t priv_rvec_free;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Bitset of free entries in rvec[] */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t rvec_free ODP_ALIGNED_CACHE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Reordering contexts to allocate from */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t rvec[TS_RVEC_SIZE] ODP_ALIGNED_CACHE;<br>

> &gt; &#43;} sched_scalable_thread_state_t ODP_ALIGNED_CACHE;<br>

> &gt; &#43;<br>

> &gt; &#43;void sched_update_enq(sched_elem_t *q, uint32_t actual);<br>

> &gt; &#43;void sched_update_enq_sp(sched_elem_t *q, uint32_t actual);<br>

> &gt; &#43;sched_queue_t *schedq_from_sched_group(odp_schedule_group_t grp, uint32_t prio);<br>

> &gt; &#43;void sched_group_xcount_dec(odp_schedule_group_t grp, uint32_t prio);<br>

> &gt; &#43;<br>

> &gt; &#43;#endif&nbsp; /* ODP_SCHEDULE_SCALABLE */<br>

> &gt;<br>

> &gt;&nbsp; typedef void (*schedule_pktio_start_fn_t)(int pktio_index, int num_in_queue,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int in_queue_idx[]);<br>

> &gt;&nbsp; typedef int (*schedule_thr_add_fn_t)(odp_schedule_group_t group, int thr);<br>

> &gt;&nbsp; typedef int (*schedule_thr_rem_fn_t)(odp_schedule_group_t group, int thr);<br>

> &gt;&nbsp; typedef int (*schedule_num_grps_fn_t)(void);<br>

> &gt; -typedef int (*schedule_init_queue_fn_t)(uint32_t queue_index,<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const odp_schedule_param_t *sched_param<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br>

> &gt; &#43;typedef int (*schedule_init_queue_fn_t)(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t queue_index, const odp_schedule_param_t *sched_param);<br>

> &gt;&nbsp; typedef void (*schedule_destroy_queue_fn_t)(uint32_t queue_index);<br>

> &gt;&nbsp; typedef int (*schedule_sched_queue_fn_t)(uint32_t queue_index);<br>

> &gt;&nbsp; typedef int (*schedule_unsched_queue_fn_t)(uint32_t queue_index);<br>

> &gt; @@ -64,6 &#43;220,7 @@ extern const schedule_fn_t *sched_fn;<br>

> &gt;&nbsp; int sched_cb_pktin_poll(int pktio_index, int num_queue, int index[]);<br>

> &gt;&nbsp; void sched_cb_pktio_stop_finalize(int pktio_index);<br>

> &gt;&nbsp; int sched_cb_num_pktio(void);<br>

> &gt; &#43;#ifndef ODP_SCHEDULE_SCALABLE<br>

> &gt;&nbsp; int sched_cb_num_queues(void);<br>

> &gt;&nbsp; int sched_cb_queue_prio(uint32_t queue_index);<br>

> &gt;&nbsp; int sched_cb_queue_grp(uint32_t queue_index);<br>

> &gt; @@ -73,6 &#43;230,7 @@ odp_queue_t sched_cb_queue_handle(uint32_t queue_index);<br>

> &gt;&nbsp; void sched_cb_queue_destroy_finalize(uint32_t queue_index);<br>

> &gt;&nbsp; int sched_cb_queue_deq_multi(uint32_t queue_index, odp_event_t ev[], int num);<br>

> &gt;&nbsp; int sched_cb_queue_empty(uint32_t queue_index);<br>

> &gt; &#43;#endif<br>

> &gt;<br>

> &gt;&nbsp; /* API functions */<br>

> &gt;&nbsp; typedef struct {<br>

> &gt; diff --git a/platform/linux-generic/include/odp_schedule_ordered_internal.h b/platform/linux-generic/include/odp_schedule_ordered_internal.h<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..a16deca8<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/include/odp_schedule_ordered_internal.h<br>

> &gt; @@ -0,0 &#43;1,150 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_SCHEDULE_ORDERED_INTERNAL_H_<br>

> &gt; &#43;#define ODP_SCHEDULE_ORDERED_INTERNAL_H_<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef __cplusplus<br>

> &gt; &#43;extern &quot;C&quot; {<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp/api/shared_memory.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_internal.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_align_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_bitset.h&gt;<br>

> &gt; &#43;#include &lt;odp_llsc.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;/* High level functioning of reordering<br>

> &gt; &#43; * Datastructures -<br>

> &gt; &#43; * Reorder Window - Every ordered queue is associated with a reorder window.<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Reorder window stores reorder contexts from threads that<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; have completed processing out-of-order.<br>

> &gt; &#43; * Reorder Context - Reorder context consists of events that a thread<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wants to enqueue while processing a batch of events<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from an ordered queue.<br>

> &gt; &#43; *<br>

> &gt; &#43; * Algorithm -<br>

> &gt; &#43; * 1) Thread identifies the ordered queue.<br>

> &gt; &#43; * 2) It 'reserves a slot in the reorder window and dequeues the<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp; events' atomically. Atomicity is achieved by using a ticket-lock<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp; like design where the reorder window slot is the ticket.<br>

> &gt; &#43; * 3a) Upon order-release/next schedule call, the thread<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; checks if it's slot (ticket) equals the head of the reorder window.<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; If yes, enqueues the events to the destination queue till<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i) the reorder window is empty or<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ii) there is a gap in the reorder window<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; If no, the reorder context is stored in the reorder window at<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; the reserved slot.<br>

> &gt; &#43; * 3b) Upon the first enqueue, the thread checks if it's slot (ticket)<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; equals the head of the reorder window.<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; If yes, enqueues the events immediately to the destination queue<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; If no, these (and subsequent) events are stored in the reorder context<br>

> &gt; &#43; *&nbsp;&nbsp;&nbsp;&nbsp; (in the application given order)<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;/* Head and change indicator variables are used to synchronise between<br>

> &gt; &#43; * concurrent insert operations in the reorder window. A thread performing<br>

> &gt; &#43; * an in-order insertion must be notified about the newly inserted<br>

> &gt; &#43; * reorder contexts so that it doesn’t halt the retire process too early.<br>

> &gt; &#43; * A thread performing an out-of-order insertion must correspondingly<br>

> &gt; &#43; * notify the thread doing in-order insertion of the new waiting reorder<br>

> &gt; &#43; * context, which may need to be handled by that thread.<br>

> &gt; &#43; *<br>

> &gt; &#43; * Also, an out-of-order insertion may become an in-order insertion if the<br>

> &gt; &#43; * thread doing an in-order insertion completes before this thread completes.<br>

> &gt; &#43; * We need a point of synchronisation where this knowledge and potential state<br>

> &gt; &#43; * change can be transferred between threads.<br>

> &gt; &#43; */<br>

> &gt; &#43;typedef struct hc {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* First missing context */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Change indicator */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t chgi;<br>

> &gt; &#43;} hc_t ODP_ALIGNED(sizeof(uint64_t));<br>

> &gt; &#43;<br>

> &gt; &#43;/* Number of reorder contects in the reorder window.<br>

> &gt; &#43; * Should be at least one per CPU.<br>

> &gt; &#43; */<br>

> &gt; &#43;#define RWIN_SIZE 32<br>

> &gt; &#43;ODP_STATIC_ASSERT(IS_POWER_TWO(RWIN_SIZE), &quot;RWIN_SIZE is not a power of 2&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;#define NUM_OLOCKS 2<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct reorder_context reorder_context_t;<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct reorder_window {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* head and change indicator */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hc_t hc;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t winmask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t tail;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t turn;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t olock[NUM_OLOCKS];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t lock_count;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Reorder contexts in this window */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *ring[RWIN_SIZE];<br>

> &gt; &#43;} reorder_window_t;<br>

> &gt; &#43;<br>

> &gt; &#43;/* Number of events that can be stored in a reorder context.<br>

> &gt; &#43; * This size is chosen so that there is no space left unused at the end<br>

> &gt; &#43; * of the last cache line (for 64b architectures and 64b handles).<br>

> &gt; &#43; */<br>

> &gt; &#43;#define RC_EVT_SIZE 18<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct reorder_context {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Reorder window to which this context belongs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_window_t *rwin;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Pointer to TS-&gt;rvec_free */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t *rvec_free;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Our slot number in the reorder window */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sn;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t olock_flags;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Our index in thread_state rvec array */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Use to link reorder contexts together */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t next_idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Current reorder context to save events in */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t cur_idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Number of events stored in this reorder context */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t numevts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Events stored in this context */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *events[RC_EVT_SIZE];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *destq[RC_EVT_SIZE];<br>

> &gt; &#43;} reorder_context_t ODP_ALIGNED_CACHE;<br>

> &gt; &#43;<br>

> &gt; &#43;reorder_window_t *rwin_alloc(int rwin_id, odp_shm_t *shm, unsigned lock_count);<br>

> &gt; &#43;bool rwin_reserve(reorder_window_t *rwin, uint32_t *sn);<br>

> &gt; &#43;void rwin_insert(reorder_window_t *rwin,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *rctx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sn,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (*callback)(reorder_context_t *));<br>

> &gt; &#43;void rctx_init(reorder_context_t *rctx, uint16_t idx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_window_t *rwin, uint32_t sn);<br>

> &gt; &#43;void rctx_free(const reorder_context_t *rctx);<br>

> &gt; &#43;void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t lock_index);<br>

> &gt; &#43;void olock_release(const reorder_context_t *rctx);<br>

> &gt; &#43;void rctx_retire(reorder_context_t *first);<br>

> &gt; &#43;void rctx_release(reorder_context_t *rctx);<br>

> &gt; &#43;<br>

> &gt; &#43;#else<br>

> &gt; &#43;<br>

> &gt; &#43;#define SUSTAIN_ORDER 1<br>

> &gt; &#43;<br>

> &gt; &#43;int schedule_ordered_queue_enq(uint32_t queue_index, void *p_buf_hdr,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int sustain, int *ret);<br>

> &gt; &#43;int schedule_ordered_queue_enq_multi(uint32_t queue_index, void *p_buf_hdr[],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num, int sustain, int *ret);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef __cplusplus<br>

> &gt; &#43;}<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#endif<br>

> &gt; diff --git a/platform/linux-generic/m4/odp_schedule.m4 b/platform/linux-generic/m4/odp_schedule.m4<br>

> &gt; index 91c19f21..d862b8b2 100644<br>

> &gt; --- a/platform/linux-generic/m4/odp_schedule.m4<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/m4/odp_schedule.m4<br>

> &gt; @@ -1,13 &#43;1,44 @@<br>

> &gt; -AC_ARG_ENABLE([schedule-sp],<br>

> &gt; -&nbsp;&nbsp;&nbsp; [&nbsp; --enable-schedule-sp&nbsp;&nbsp;&nbsp; enable strict priority scheduler],<br>

> &gt; -&nbsp;&nbsp;&nbsp; [if test x$enableval = xyes; then<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_sp_enabled=yes<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CFLAGS=&quot;$ODP_CFLAGS -DODP_SCHEDULE_SP&quot;<br>

> &gt; -&nbsp;&nbsp;&nbsp; fi])<br>

> &gt; &#43;# Checks for --enable-schedule-sp and defines ODP_SCHEDULE_SP and adds<br>

> &gt; &#43;# -DODP_SCHEDULE_SP to CFLAGS.<br>

> &gt; &#43;AC_ARG_ENABLE(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [schedule_sp],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [AC_HELP_STRING([--enable-schedule-sp],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [enable strict priority scheduler])],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [if test &quot;x$enableval&quot; = xyes; then<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_sp=true<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CFLAGS=&quot;$ODP_CFLAGS -DODP_SCHEDULE_SP&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_sp=false<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; fi],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [schedule_sp=false])<br>

> &gt; &#43;AM_CONDITIONAL([ODP_SCHEDULE_SP], [test x$schedule_sp = xtrue])<br>

> &gt;<br>

> &gt; -AC_ARG_ENABLE([schedule-iquery],<br>

> &gt; -&nbsp;&nbsp;&nbsp; [&nbsp; --enable-schedule-iquery&nbsp;&nbsp;&nbsp; enable interests query (sparse bitmap) scheduler],<br>

> &gt; -&nbsp;&nbsp;&nbsp; [if test x$enableval = xyes; then<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_iquery_enabled=yes<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CFLAGS=&quot;$ODP_CFLAGS -DODP_SCHEDULE_IQUERY&quot;<br>

> &gt; -&nbsp;&nbsp;&nbsp; fi])<br>

> &gt; &#43;# Checks for --enable-schedule-iquery and defines ODP_SCHEDULE_IQUERY and adds<br>

> &gt; &#43;# -DODP_SCHEDULE_IQUERY to CFLAGS.<br>

> &gt; &#43;AC_ARG_ENABLE(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [schedule_iquery],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [AC_HELP_STRING([--enable-schedule-iquery],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [enable interests query (sparse bitmap) scheduler])],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [if test &quot;x$enableval&quot; = xyes; then<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_iquery=true<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CFLAGS=&quot;$ODP_CFLAGS -DODP_SCHEDULE_IQUERY&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_iquery=false<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; fi],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [schedule_iquery=false])<br>

> &gt; &#43;AM_CONDITIONAL([ODP_SCHEDULE_IQUERY], [test x$schedule_iquery = xtrue])<br>

> &gt; &#43;<br>

> &gt; &#43;# Checks for --enable-schedule-scalable and defines ODP_SCHEDULE_SCALABLE and<br>

> &gt; &#43;# adds -DODP_SCHEDULE_SCALABLE to CFLAGS.<br>

> &gt; &#43;AC_ARG_ENABLE(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [schedule_scalable],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [AC_HELP_STRING([--enable-schedule-scalable],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [enable scalable scheduler])],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [if test &quot;x$enableval&quot; = xyes; then<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_scalable=true<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CFLAGS=&quot;$ODP_CFLAGS -DODP_SCHEDULE_SCALABLE&quot;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_scalable=false<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; fi],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp; [schedule_scalable=false])<br>

> &gt; &#43;AM_CONDITIONAL([ODP_SCHEDULE_SCALABLE], [test x$schedule_scalable = xtrue])<br>

> &gt; diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c<br>

> &gt; index 5d96b00b..8fb5c32f 100644<br>

> &gt; --- a/platform/linux-generic/odp_classification.c<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_classification.c<br>

> &gt; @@ -282,7 &#43;282,7 @@ odp_queue_t odp_cos_queue(odp_cos_t cos_id)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!cos-&gt;s.queue)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ODP_QUEUE_INVALID;<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return cos-&gt;s.queue-&gt;s.handle;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue_get_handle(cos-&gt;s.queue);<br>

> &gt;&nbsp; }<br>

> &gt;<br>

> &gt;&nbsp; int odp_cos_drop_set(odp_cos_t cos_id, odp_cls_drop_t drop_policy)<br>

> &gt; @@ -849,7 &#43;849,7 @@ int cls_classify_packet(pktio_entry_t *entry, const uint8_t *base,<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pool = cos-&gt;s.pool;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt_hdr-&gt;p.input_flags.dst_queue = 1;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt_hdr-&gt;dst_queue = cos-&gt;s.queue-&gt;s.handle;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt_hdr-&gt;dst_queue = queue_get_handle(cos-&gt;s.queue);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt;&nbsp; }<br>

> &gt; diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c<br>

> &gt; index b8aac6bf..8ae35867 100644<br>

> &gt; --- a/platform/linux-generic/odp_packet.c<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_packet.c<br>

> &gt; @@ -651,6 &#43;651,11 @@ odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return buffer_handle(packet_hdr(pkt));<br>

> &gt;&nbsp; }<br>

> &gt;<br>

> &gt; &#43;odp_buffer_hdr_t *_odp_packet_to_buf_hdr_ptr(odp_packet_t pkt)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (odp_buffer_hdr_t *)(_odp_packet_to_buffer(pkt));<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt;&nbsp; odp_packet_t odp_packet_from_event(odp_event_t ev)<br>

> &gt;&nbsp; {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(ev == ODP_EVENT_INVALID))<br>

> &gt; diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c<br>

> &gt; index 5e783d83..a267ee97 100644<br>

> &gt; --- a/platform/linux-generic/odp_packet_io.c<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_packet_io.c<br>

> &gt; @@ -5,23 &#43;5,25 @@<br>

> &gt;&nbsp;&nbsp; */<br>

> &gt;&nbsp; #include &lt;odp_posix_extensions.h&gt;<br>

> &gt;<br>

> &gt; -#include &lt;odp/api/packet_io.h&gt;<br>

> &gt; -#include &lt;odp_packet_io_internal.h&gt;<br>

> &gt; -#include &lt;odp_packet_io_queue.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/packet.h&gt;<br>

> &gt; -#include &lt;odp_packet_internal.h&gt;<br>

> &gt; -#include &lt;odp_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/packet_io.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/spinlock.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/ticketlock.h&gt;<br>

> &gt;&nbsp; #include &lt;odp/api/shared_memory.h&gt;<br>

> &gt; -#include &lt;odp_packet_socket.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/time.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_internal.h&gt;<br>

> &gt;&nbsp; #include &lt;odp_config_internal.h&gt;<br>

> &gt; -#include &lt;odp_queue_internal.h&gt;<br>

> &gt; -#include &lt;odp_schedule_if.h&gt;<br>

> &gt; -#include &lt;odp_classification_internal.h&gt;<br>

> &gt;&nbsp; #include &lt;odp_debug_internal.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_classification_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_queue_internal.h&gt;<br>

> &gt;&nbsp; #include &lt;odp_packet_io_ipc_internal.h&gt;<br>

> &gt; -#include &lt;odp/api/time.h&gt;<br>

> &gt; &#43;#include &lt;odp_packet_io_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_packet_io_queue.h&gt;<br>

> &gt; &#43;#include &lt;odp_packet_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_packet_socket.h&gt;<br>

> &gt; &#43;#include &lt;odp_schedule_if.h&gt;<br>

> &gt;<br>

> &gt;&nbsp; #include &lt;string.h&gt;<br>

> &gt;&nbsp; #include &lt;inttypes.h&gt;<br>

> &gt; @@ -470,7 &#43;472,6 @@ int odp_pktio_start(odp_pktio_t hdl)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; -<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_fn-&gt;pktio_start(pktio_to_id(hdl), num, index);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt; @@ -552,7 &#43;553,6 @@ static inline int pktin_recv_buf(odp_pktin_queue_t queue,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_packet_t packets[num];<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_packet_hdr_t *pkt_hdr;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *buf_hdr;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_t buf;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int pkts;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num_rx = 0;<br>

> &gt; @@ -562,9 &#43;562,11 @@ static inline int pktin_recv_buf(odp_pktin_queue_t queue,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; pkts; i&#43;&#43;) {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt = packets[i];<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt_hdr = odp_packet_hdr(pkt);<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf = _odp_packet_to_buffer(pkt);<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf_hdr = buf_hdl_to_hdr(buf);<br>

> &gt; -<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf_hdr = _odp_packet_to_buf_hdr_ptr(pkt);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf_hdr = buf_hdl_to_hdr(_odp_packet_to_buffer(pkt));<br>

> &gt; &#43;#endif<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pkt_hdr-&gt;p.input_flags.dst_queue) {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *dst_queue;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret;<br>

> &gt; @@ -582,11 &#43;584,17 @@ static inline int pktin_recv_buf(odp_pktin_queue_t queue,<br>

> &gt;<br>

> &gt;&nbsp; int pktout_enqueue(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr)<br>

> &gt;&nbsp; {<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_packet_t pkt = _odp_packet_from_buffer(buf_hdr-&gt;handle.handle);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_packet_t pkt;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt = _odp_packet_from_buffer((odp_buffer_t)buf_hdr);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt = _odp_packet_from_buffer(buf_hdr-&gt;handle.handle);<br>

> &gt; &#43;#endif<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int len = 1;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int nbr;<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nbr = odp_pktout_send(qentry-&gt;s.pktout, &amp;pkt, len);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nbr = odp_pktout_send(queue_get_pktout(qentry), &amp;pkt, len);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (nbr == len ? 0 : -1);<br>

> &gt;&nbsp; }<br>

> &gt;<br>

> &gt; @@ -604,9 &#43;612,13 @@ int pktout_enq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[],<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; num; &#43;&#43;i)<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt_tbl[i] = _odp_packet_from_buffer((odp_buffer_t)buf_hdr[i]);<br>

> &gt; &#43;#else<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt_tbl[i] = _odp_packet_from_buffer(buf_hdr[i]-&gt;handle.handle);<br>

> &gt; &#43;#endif<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nbr = odp_pktout_send(qentry-&gt;s.pktout, pkt_tbl, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nbr = odp_pktout_send(queue_get_pktout(qentry), pkt_tbl, num);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return nbr;<br>

> &gt;&nbsp; }<br>

> &gt;<br>

> &gt; @@ -632,13 &#43;644,14 @@ odp_buffer_hdr_t *pktin_dequeue(queue_entry_t *qentry)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int pkts;<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf_hdr = queue_deq(qentry);<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (buf_hdr != NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (buf_hdr != BUFFER_HDR_INVALID)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return buf_hdr;<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkts = pktin_recv_buf(qentry-&gt;s.pktin, hdr_tbl, QUEUE_MULTI_MAX);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkts = pktin_recv_buf(queue_get_pktin(qentry),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hdr_tbl, QUEUE_MULTI_MAX);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pkts &lt;= 0)<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return BUFFER_HDR_INVALID;<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pkts &gt; 1)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_enq_multi(qentry, &amp;hdr_tbl[1], pkts - 1);<br>

> &gt; @@ -669,7 &#43;682,8 @@ int pktin_deq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[], int num)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nbr == num)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return nbr;<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkts = pktin_recv_buf(qentry-&gt;s.pktin, hdr_tbl, QUEUE_MULTI_MAX);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkts = pktin_recv_buf(queue_get_pktin(qentry),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hdr_tbl, QUEUE_MULTI_MAX);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pkts &lt;= 0)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return nbr;<br>

> &gt;<br>

> &gt; @@ -684,7 &#43;698,6 @@ int pktin_deq_multi(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr[], int num)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_enq_multi(qentry, hdr_tbl, j);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return nbr;<br>

> &gt;&nbsp; }<br>

> &gt; -<br>

> &gt;&nbsp; int sched_cb_pktin_poll(int pktio_index, int num_queue, int index[])<br>

> &gt;&nbsp; {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX];<br>

> &gt; @@ -1266,13 &#43;1279,14 @@ int odp_pktin_queue_config(odp_pktio_t pktio,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *qentry;<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry = queue_to_qentry(queue);<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.pktin.index&nbsp; = i;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.pktin.pktio&nbsp; = pktio;<br>

> &gt; -<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.enqueue = pktin_enqueue;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.dequeue = pktin_dequeue;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.enqueue_multi = pktin_enq_multi;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.dequeue_multi = pktin_deq_multi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_pktin(qentry, pktio, i);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_enq_func(qentry, pktin_enqueue);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_deq_func(qentry, pktin_dequeue);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_enq_multi_func(qentry,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pktin_enq_multi);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_deq_multi_func(qentry,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pktin_deq_multi);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; entry-&gt;s.in_queue[i].queue = queue;<br>

> &gt; @@ -1390,14 &#43;1404,12 @@ int odp_pktout_queue_config(odp_pktio_t pktio,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry = queue_to_qentry(queue);<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.pktout.index&nbsp; = i;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.pktout.pktio&nbsp; = pktio;<br>

> &gt; -<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Override default enqueue / dequeue functions */<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.enqueue&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = pktout_enqueue;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.dequeue&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = pktout_dequeue;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.enqueue_multi = pktout_enq_multi;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qentry-&gt;s.dequeue_multi = pktout_deq_multi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_pktout(qentry, pktio, i);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_enq_func(qentry, pktout_enqueue);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_deq_func(qentry, pktout_dequeue);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_enq_multi_func(qentry, pktout_enq_multi);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_deq_multi_func(qentry, pktout_deq_multi);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; entry-&gt;s.out_queue[i].queue = queue;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; diff --git a/platform/linux-generic/odp_queue.c b/platform/linux-generic/odp_queue.c<br>

> &gt; index fcf4bf5b..42b58c44 100644<br>

> &gt; --- a/platform/linux-generic/odp_queue.c<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_queue.c<br>

> &gt; @@ -291,11 &#43;291,11 @@ void sched_cb_queue_destroy_finalize(uint32_t queue_index)<br>

> &gt;&nbsp; int odp_queue_destroy(odp_queue_t handle)<br>

> &gt;&nbsp; {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_to_qentry(handle);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (handle == ODP_QUEUE_INVALID)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_to_qentry(handle);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;queue-&gt;s.lock);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.status == QUEUE_STATUS_FREE) {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; diff --git a/platform/linux-generic/odp_queue_scalable.c b/platform/linux-generic/odp_queue_scalable.c<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..c08dd06a<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_queue_scalable.c<br>

> &gt; @@ -0,0 &#43;1,944 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp/api/hints.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/plat/ticketlock_inlines.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/queue.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/schedule.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/shared_memory.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/sync.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/traffic_mngr.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_config_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_debug_internal.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_buffer_inlines.h&gt;<br>

> &gt; &#43;#include &lt;odp_packet_io_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_packet_io_queue.h&gt;<br>

> &gt; &#43;#include &lt;odp_pool_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_queue_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_schedule_if.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;string.h&gt;<br>

> &gt; &#43;#include &lt;inttypes.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#define NUM_INTERNAL_QUEUES 64<br>

> &gt; &#43;<br>

> &gt; &#43;#define MIN(a, b) \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ({ \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __typeof__(a) tmp_a = (a); \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __typeof__(b) tmp_b = (b); \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_a &lt; tmp_b ? tmp_a : tmp_b; \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; })<br>

> &gt; &#43;<br>

> &gt; &#43;#define LOCK(a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _odp_ticketlock_lock(a)<br>

> &gt; &#43;#define UNLOCK(a)&nbsp;&nbsp;&nbsp; _odp_ticketlock_unlock(a)<br>

> &gt; &#43;#define LOCK_INIT(a) odp_ticketlock_init(a)<br>

> &gt; &#43;<br>

> &gt; &#43;extern __thread sched_scalable_thread_state_t *sched_ts;<br>

> &gt; &#43;<br>

> &gt; &#43;typedef struct queue_table_t {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t&nbsp; queue[ODP_CONFIG_QUEUES];<br>

> &gt; &#43;} queue_table_t;<br>

> &gt; &#43;<br>

> &gt; &#43;static queue_table_t *queue_tbl;<br>

> &gt; &#43;<br>

> &gt; &#43;static inline odp_queue_t queue_from_id(uint32_t queue_id)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _odp_cast_scalar(odp_queue_t, queue_id &#43; 1);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;queue_entry_t *get_qentry(uint32_t queue_id)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &amp;queue_tbl-&gt;queue[queue_id];<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int _odp_queue_disable_enq(sched_elem_t *q)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_read, old_write, new_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t size;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write = q-&gt;prod_write;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size = q-&gt;prod_mask &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Need __atomic_load to avoid compiler reordering */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read = __atomic_load_n(&amp;q-&gt;prod_read, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write = ll32(&amp;q-&gt;prod_write, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (old_write != old_read) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue is not empty, cannot claim all elements<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Cannot disable enqueue.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Claim all elements in ring */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_write = old_write &#43; size;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(sc32(&amp;q-&gt;prod_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED)));<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange_n(&amp;q-&gt;prod_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old_write, /* Updated on failure */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED));<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* All remaining elements claimed, noone else can enqueue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static uint32_t roundup_pow2(uint32_t v)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Check if already power of 2 */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((v &amp; (v - 1)) == 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return v;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; (i &lt; (sizeof(v) * CHAR_BIT)) &amp;&amp; (v != 0); i&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v = v &gt;&gt; 1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1&lt;&lt;i;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int queue_init(int queue_idx, queue_entry_t *queue, const char *name,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const odp_queue_param_t *param)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t ring_idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *sched_elem;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_t shm;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ring_size;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **ring;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem = &amp;queue-&gt;s.sched_elem;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring_size = param-&gt;ring_size &gt; 0 ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; roundup_pow2(param-&gt;ring_size) :<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CONFIG_QUEUE_SIZE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strncpy(queue-&gt;s.name, name ? name : &quot;&quot;, ODP_QUEUE_NAME_LEN - 1);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.name[ODP_QUEUE_NAME_LEN - 1] = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memcpy(&amp;queue-&gt;s.param, param, sizeof(odp_queue_param_t));<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shm = odp_shm_reserve(name,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring_size * sizeof(odp_buffer_hdr_t *),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CACHE_LINE_SIZE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_SHM_PROC);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ODP_SHM_INVALID == shm)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring = (odp_buffer_hdr_t **)odp_shm_addr(shm);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (ring_idx = 0; ring_idx &lt; ring_size; ring_idx&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring[ring_idx] = NULL;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.shm = shm;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.type = queue-&gt;s.param.type;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.enqueue = queue_enq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.dequeue = queue_deq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.enqueue_multi = queue_enq_multi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.dequeue_multi = queue_deq_multi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.pktin = PKTIN_INVALID;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;node.next = NULL;<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK_INIT(&amp;sched_elem-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;qschst.numevts = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;qschst.wrr_budget = CONFIG_WRR_WEIGHT;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;qschst.cur_ticket = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;qschst.nxt_ticket = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;pop_deficit = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.type == ODP_QUEUE_TYPE_SCHED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;qschst_type = queue-&gt;s.param.sched.sync;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;qschst_type = ODP_NO_SCHED_QUEUE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 2nd cache line - enqueue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;prod_read = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;prod_write = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;prod_ring = ring;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;prod_mask = ring_size - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 3rd cache line - dequeue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;cons_read = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;cons_write = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;rwin = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;schedq = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;user_ctx = queue-&gt;s.param.context;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;cons_ring = ring;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;cons_mask = ring_size - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;cons_type = sched_elem-&gt;qschst_type;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue initialized successfully, add it to the sched group */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.type == ODP_QUEUE_TYPE_SCHED) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.param.sched.sync == ODP_SCHED_SYNC_ORDERED) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;rwin =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin_alloc(queue_idx, &amp;queue-&gt;s.rwin_shm,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.param.sched.lock_count);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sched_elem-&gt;rwin == NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Reorder window not created\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto rwin_create_failed;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem-&gt;schedq =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_from_sched_group(param-&gt;sched.group,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param-&gt;sched.prio);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;<br>

> &gt; &#43;rwin_create_failed:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_free(queue-&gt;s.shm);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_init_global(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_t shm;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_DBG(&quot;Queue init ... &quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shm = odp_shm_reserve(&quot;odp_queues&quot;,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(queue_table_t),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(queue_entry_t), 0);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_tbl = odp_shm_addr(shm);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue_tbl == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(queue_tbl, 0, sizeof(queue_table_t));<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; ODP_CONFIG_QUEUES; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* init locks */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = get_qentry(i);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK_INIT(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.index&nbsp; = i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.handle = queue_from_id(i);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_DBG(&quot;done\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_DBG(&quot;Queue init global\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_DBG(&quot;&nbsp; struct queue_entry_s size %zu\n&quot;,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(struct queue_entry_s));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_DBG(&quot;&nbsp; queue_entry_t size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %zu\n&quot;,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(queue_entry_t));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_DBG(&quot;\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_term_global(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int rc = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; ODP_CONFIG_QUEUES; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = &amp;queue_tbl-&gt;queue[i];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__atomic_load_n(&amp;queue-&gt;s.status,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != QUEUE_STATUS_FREE) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Not destroyed queue: %s\n&quot;, queue-&gt;s.name);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rc = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = odp_shm_free(odp_shm_lookup(&quot;odp_queues&quot;));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret &lt; 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;shm free failed for odp_queues&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rc = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return rc;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_capability(odp_queue_capability_t *capa)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(capa, 0, sizeof(odp_queue_capability_t));<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Reserve some queues for internal use */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capa-&gt;max_queues&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = ODP_CONFIG_QUEUES - NUM_INTERNAL_QUEUES;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capa-&gt;max_ordered_locks = SCHEDULE_ORDERED_LOCKS_PER_QUEUE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capa-&gt;max_sched_groups&nbsp; = sched_fn-&gt;num_grps();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capa-&gt;sched_prios&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = odp_schedule_num_prio();<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_queue_type_t odp_queue_type(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue_to_qentry(handle)-&gt;s.type;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_schedule_sync_t odp_queue_sched_type(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue_to_qentry(handle)-&gt;s.param.sched.sync;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_schedule_prio_t odp_queue_sched_prio(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue_to_qentry(handle)-&gt;s.param.sched.prio;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_schedule_group_t odp_queue_sched_group(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue_to_qentry(handle)-&gt;s.param.sched.group;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_lock_count(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue = queue_to_qentry(handle);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.param.sched.sync == ODP_SCHED_SYNC_ORDERED ?<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (int)queue-&gt;s.param.sched.lock_count : -1;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int queue_idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_t handle = ODP_QUEUE_INVALID;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_param_t default_param;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (param == NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_param_init(&amp;default_param);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param = &amp;default_param;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (queue_idx = 0; queue_idx &lt; ODP_CONFIG_QUEUES; queue_idx&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = &amp;queue_tbl-&gt;queue[queue_idx];<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.status != QUEUE_STATUS_FREE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.status == QUEUE_STATUS_FREE) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue_init(queue_idx, queue, name, param)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return handle;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.status = QUEUE_STATUS_READY;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handle = queue-&gt;s.handle;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return handle;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_destroy(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *q;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (handle == ODP_QUEUE_INVALID)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_to_qentry(handle);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.status != QUEUE_STATUS_READY) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = &amp;queue-&gt;s.sched_elem;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;q-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_odp_queue_disable_enq(q)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Producer side not empty */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;q-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Enqueue is now disabled */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (q-&gt;cons_read != q-&gt;cons_write) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Consumer side is not empty<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Roll back previous change, enable enqueue again.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t size;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size = q-&gt;prod_mask &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_fetch_sub(&amp;q-&gt;prod_write, size, __ATOMIC_RELAXED);<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;q-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;q-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Producer and consumer sides empty, enqueue disabled<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Now wait until schedq state is empty and no outstanding tickets<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (__atomic_load_n(&amp;q-&gt;qschst.numevts, __ATOMIC_RELAXED) != 0 ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load_n(&amp;q-&gt;qschst.cur_ticket, __ATOMIC_RELAXED) !=<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load_n(&amp;q-&gt;qschst.nxt_ticket, __ATOMIC_RELAXED)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp; LDXR32((uint32_t *)&amp;q-&gt;qschst.numevts,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Adjust the spread factor for the queues in the schedule group */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.type == ODP_QUEUE_TYPE_SCHED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_xcount_dec(queue-&gt;s.param.sched.group,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.param.sched.prio);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_shm_free(queue-&gt;s.shm) &lt; 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.param.sched.sync == ODP_SCHED_SYNC_ORDERED) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_shm_free(queue-&gt;s.rwin_shm) &lt; 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to free reorder window shm\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.status = QUEUE_STATUS_FREE;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_context_set(odp_queue_t handle, void *context,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t len ODP_UNUSED)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_mb_full();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_to_qentry(handle)-&gt;s.param.context = context;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_mb_full();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void *odp_queue_context(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue_to_qentry(handle)-&gt;s.param.context;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_queue_t odp_queue_lookup(const char *name)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; ODP_CONFIG_QUEUES; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue = &amp;queue_tbl-&gt;queue[i];<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue-&gt;s.status == QUEUE_STATUS_FREE ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue-&gt;s.status == QUEUE_STATUS_DESTROYED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (strcmp(name, queue-&gt;s.name) == 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* found it */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.handle;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ODP_QUEUE_INVALID;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline int _odp_queue_enq(sched_elem_t *q,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *buf_hdr[],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_read;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t new_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **ring;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mask = q-&gt;prod_mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring = q-&gt;prod_ring;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Load producer ring state (read &amp; write index) */<br>

> &gt; &#43;#ifndef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write = __atomic_load_n(&amp;q-&gt;prod_write, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Consumer does store-release prod_read, we need<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * load-acquire.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read = __atomic_load_n(&amp;q-&gt;prod_read, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write = ll32(&amp;q-&gt;prod_write, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actual = MIN(num, (int)((mask &#43; 1) - (old_write - old_read)));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(actual &lt;= 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_write = old_write &#43; actual;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(sc32(&amp;q-&gt;prod_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED)));<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange_n(&amp;q-&gt;prod_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old_write, /* Updated on failure */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED));<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;q-&gt;cons_write, 0, 0);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Store our event(s) in the ring */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring[old_write &amp; mask] = *buf_hdr&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (&#43;&#43;old_write != new_write);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write -= actual;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;q-&gt;node, 1, 0);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for our turn to signal consumers */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(__atomic_load_n(&amp;q-&gt;cons_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != old_write)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp; LDXR32(&amp;q-&gt;cons_write,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != old_write)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Signal consumers that events are available (release events)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Enable other producers to continue<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for writes (to ring slots) to complete */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;dmb ishst&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;cons_write = new_write;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;cons_write, new_write, __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return actual;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline int _odp_queue_enq_sp(sched_elem_t *q,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *buf_hdr[],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_read;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t new_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **ring;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mask = q-&gt;prod_mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring = q-&gt;prod_ring;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Load producer ring state (read &amp; write index) */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write = q-&gt;prod_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Consumer does store-release prod_read, we need load-acquire */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read = __atomic_load_n(&amp;q-&gt;prod_read, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actual = MIN(num, (int)((mask &#43; 1) - (old_write - old_read)));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(actual &lt;= 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_write = old_write &#43; actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;prod_write = new_write;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Store our event(s) in the ring */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring[old_write &amp; mask] = *buf_hdr&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (&#43;&#43;old_write != new_write);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write -= actual;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;q-&gt;node, 1, 0);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Signal consumers that events are available (release events)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Enable other producers to continue<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;cons_write = new_write;<br>

> &gt; &#43;#else<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;dmb ishst&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;cons_write = new_write;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;cons_write, new_write, __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return actual;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int queue_enq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[], int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_scalable_thread_state_t *ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *first;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *cur;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t next_idx;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;queue-&gt;s.sched_elem.qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts = sched_ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts &amp;&amp; odp_unlikely(ts-&gt;out_of_order)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; first = ts-&gt;rctx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(ts-&gt;rctx != NULL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur = &amp;first[(int)first-&gt;cur_idx - (int)first-&gt;idx];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; num; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(cur-&gt;numevts == RC_EVT_SIZE)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* No more space in current reorder context<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Try to allocate another.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_is_null(ts-&gt;priv_rvec_free))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;priv_rvec_free =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_xchg(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;ts-&gt;rvec_free,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(bitset_is_null(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;priv_rvec_free)))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Out of reorder contexts.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Return the number of events<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * stored so far.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.sched_elem.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; next_idx = bitset_ffs(ts-&gt;priv_rvec_free) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;priv_rvec_free =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_clr(ts-&gt;priv_rvec_free,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; next_idx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Link current to next (for eventual<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * retiring)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur-&gt;next_idx = next_idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Link first to next (for next call to<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * queue_enq_multi())<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; first-&gt;cur_idx = next_idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Update current to next */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur = &amp;ts-&gt;rvec[next_idx];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx_init(cur, next_idx, NULL, 0);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* The last rctx (so far) */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur-&gt;next_idx = first-&gt;idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur-&gt;events[cur-&gt;numevts] = buf_hdr[i];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur-&gt;destq[cur-&gt;numevts] = queue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cur-&gt;numevts&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* All events stored. */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.sched_elem.qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actual = _odp_queue_enq_sp(&amp;queue-&gt;s.sched_elem, buf_hdr, num);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actual = _odp_queue_enq(&amp;queue-&gt;s.sched_elem, buf_hdr, num);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(queue-&gt;s.sched_elem.schedq != NULL &amp;&amp; actual != 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Perform scheduler related updates. */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_enq_sp(&amp;queue-&gt;s.sched_elem, actual);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_enq(&amp;queue-&gt;s.sched_elem, actual);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.sched_elem.qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return actual;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int queue_enq(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return odp_likely(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_enq_multi(queue, &amp;buf_hdr, 1) == 1) ? 0 : -1;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_enq_multi(odp_queue_t handle, const odp_event_t ev[], int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *buf_hdr[QUEUE_MULTI_MAX];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (num &gt; QUEUE_MULTI_MAX)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num = QUEUE_MULTI_MAX;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_to_qentry(handle);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; num; i&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf_hdr[i] = (odp_buffer_hdr_t *)ev[i];<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.enqueue_multi(queue, buf_hdr, num);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_enq(odp_queue_t handle, odp_event_t ev)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_to_qentry(handle);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.enqueue(queue, (odp_buffer_hdr_t *)ev);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* Single-consumer dequeue. */<br>

> &gt; &#43;int _odp_queue_deq_sc(sched_elem_t *q, odp_event_t *evp, int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_read;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t new_read;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_event_t *ring;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Load consumer ring state (read &amp; write index). */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read&nbsp; = q-&gt;cons_read;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Producer does store-release cons_write, we need load-acquire */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write = __atomic_load_n(&amp;q-&gt;cons_write, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actual&nbsp;&nbsp;&nbsp; = MIN(num, (int)(old_write - old_read));<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(actual &lt;= 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;q-&gt;node, 1, 0);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_read = old_read &#43; actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;cons_read = new_read;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mask = q-&gt;cons_mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring = (odp_event_t *)q-&gt;cons_ring;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *evp&#43;&#43; = ring[old_read &amp; mask];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (&#43;&#43;old_read != new_read);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Signal producers that empty slots are available<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (release ring slots). Enable other consumers to continue.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;prod_read = new_read;<br>

> &gt; &#43;#else<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for loads (from ring slots) to complete. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;dmb ishld&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;prod_read = new_read;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;prod_read, new_read, __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Prefetch events after we have release ring buffer slots */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; actual; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_event_t evt = *--evp;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_addr(odp_buffer_from_event(evt)), 0, 0);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return actual;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;inline int _odp_queue_deq(sched_elem_t *q, odp_event_t *evp, int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_read;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t old_write;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ringidx_t new_read;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **ring;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t **p_buf_hdr;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mask = q-&gt;cons_mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ring = q-&gt;cons_ring;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Load consumer ring state (read &amp; write index) */<br>

> &gt; &#43;#ifndef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read = __atomic_load_n(&amp;q-&gt;cons_read, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Need __atomic_load to avoid compiler reordering<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Producer does store-release cons_write, we need<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * load-acquire.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_write = __atomic_load_n(&amp;q-&gt;cons_write, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read = ll32(&amp;q-&gt;cons_read, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Prefetch ring buffer array */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;q-&gt;cons_ring[old_read &amp; mask], 0, 0);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actual = MIN(num, (int)(old_write - old_read));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(actual &lt;= 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Attempt to free ring slot(s) */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_read = old_read &#43; actual;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(sc32(&amp;q-&gt;cons_read, new_read, __ATOMIC_RELAXED)));<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange_n(&amp;q-&gt;cons_read,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old_read, /* Updated on failure */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new_read,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED));<br>

> &gt; &#43;#endif<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;q-&gt;prod_read, 0, 0);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p_buf_hdr = (odp_buffer_hdr_t **)evp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *p_buf;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p_buf = ring[old_read &amp; mask];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_addr(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_from_event((odp_event_t)p_buf)),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0, 0);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *p_buf_hdr&#43;&#43; = p_buf;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (&#43;&#43;old_read != new_read);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read -= actual;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_SPLIT_PRODCONS<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;q-&gt;node, 1, 0);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for our turn to signal producers */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(__atomic_load_n(&amp;q-&gt;prod_read, __ATOMIC_RELAXED) !=<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old_read)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp; LDXR32(&amp;q-&gt;prod_read,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != old_read)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Signal producers that empty slots are available<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (release ring slots)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Enable other consumers to continue<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for loads (from ring slots) to complete */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;dmb ishld&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;prod_read = new_read;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;prod_read, new_read, __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return actual;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int queue_deq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[], int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *q;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = &amp;queue-&gt;s.sched_elem;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _odp_queue_deq(q, (odp_event_t *)buf_hdr, num);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_buffer_hdr_t *queue_deq(queue_entry_t *queue)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *q;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_hdr_t *buf_hdr;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = &amp;queue-&gt;s.sched_elem;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_odp_queue_deq(q, (odp_event_t *)&amp;buf_hdr, 1) == 1)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return buf_hdr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return BUFFER_HDR_INVALID;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_deq_multi(odp_queue_t handle, odp_event_t events[], int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_to_qentry(handle);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return queue-&gt;s.dequeue_multi(queue, (odp_buffer_hdr_t **)events, num);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;odp_event_t odp_queue_deq(odp_queue_t handle)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_to_qentry(handle);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (odp_event_t)queue-&gt;s.dequeue(queue);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void odp_queue_param_init(odp_queue_param_t *params)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(params, 0, sizeof(odp_queue_param_t));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params-&gt;type = ODP_QUEUE_TYPE_PLAIN;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params-&gt;enq_mode = ODP_QUEUE_OP_MT;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params-&gt;deq_mode = ODP_QUEUE_OP_MT;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params-&gt;sched.prio = ODP_SCHED_PRIO_DEFAULT;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params-&gt;sched.sync = ODP_SCHED_SYNC_PARALLEL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params-&gt;sched.group = ODP_SCHED_GROUP_ALL;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int odp_queue_info(odp_queue_t handle, odp_queue_info_t *info)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t queue_id;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *queue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int status;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(info == NULL)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Unable to store info, NULL ptr given\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_id = queue_to_id(handle);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(queue_id &gt;= ODP_CONFIG_QUEUES)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Invalid queue handle:%&quot; PRIu64 &quot;\n&quot;,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_to_u64(handle));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = get_qentry(queue_id);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status = queue-&gt;s.status;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(status == QUEUE_STATUS_FREE ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status == QUEUE_STATUS_DESTROYED)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Invalid queue status:%d\n&quot;, status);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info-&gt;name = queue-&gt;s.name;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info-&gt;param = queue-&gt;s.param;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;queue-&gt;s.lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;uint64_t odp_queue_to_u64(odp_queue_t hdl)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _odp_pri(hdl);<br>

> &gt; &#43;}<br>

> &gt; diff --git a/platform/linux-generic/odp_schedule_if.c b/platform/linux-generic/odp_schedule_if.c<br>

> &gt; index a9ede98d..bf92333e 100644<br>

> &gt; --- a/platform/linux-generic/odp_schedule_if.c<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_schedule_if.c<br>

> &gt; @@ -6,24 &#43;6,38 @@<br>

> &gt;<br>

> &gt;&nbsp; #include &lt;odp_schedule_if.h&gt;<br>

> &gt;<br>

> &gt; -extern const schedule_fn_t schedule_sp_fn;<br>

> &gt; -extern const schedule_api_t schedule_sp_api;<br>

> &gt; &#43;#if defined(ODP_SCHEDULE_SCALABLE)<br>

> &gt;<br>

> &gt; -extern const schedule_fn_t schedule_default_fn;<br>

> &gt; -extern const schedule_api_t schedule_default_api;<br>

> &gt; &#43;extern const schedule_fn_t&nbsp; schedule_scalable_fn;<br>

> &gt; &#43;extern const schedule_api_t schedule_scalable_api;<br>

> &gt;<br>

> &gt; -extern const schedule_fn_t schedule_iquery_fn;<br>

> &gt; -extern const schedule_api_t schedule_iquery_api;<br>

> &gt; &#43;const schedule_fn_t&nbsp; *sched_fn&nbsp; = &amp;schedule_scalable_fn;<br>

> &gt; &#43;const schedule_api_t *sched_api = &amp;schedule_scalable_api;<br>

> &gt;<br>

> &gt; -#ifdef ODP_SCHEDULE_SP<br>

> &gt; -const schedule_fn_t *sched_fn&nbsp;&nbsp; = &amp;schedule_sp_fn;<br>

> &gt; -const schedule_api_t *sched_api = &amp;schedule_sp_api;<br>

> &gt;&nbsp; #elif defined(ODP_SCHEDULE_IQUERY)<br>

> &gt; -const schedule_fn_t *sched_fn&nbsp;&nbsp; = &amp;schedule_iquery_fn;<br>

> &gt; &#43;<br>

> &gt; &#43;extern const schedule_fn_t&nbsp; schedule_iquery_fn;<br>

> &gt; &#43;extern const schedule_api_t schedule_iquery_api;<br>

> &gt; &#43;<br>

> &gt; &#43;const schedule_fn_t&nbsp; *sched_fn&nbsp; = &amp;schedule_iquery_fn;<br>

> &gt;&nbsp; const schedule_api_t *sched_api = &amp;schedule_iquery_api;<br>

> &gt; -#else<br>

> &gt; &#43;<br>

> &gt; &#43;#elif defined(ODP_SCHEDULE_SP)<br>

> &gt; &#43;<br>

> &gt; &#43;extern const schedule_fn_t&nbsp; schedule_sp_fn;<br>

> &gt; &#43;extern const schedule_api_t schedule_sp_api;<br>

> &gt; &#43;<br>

> &gt; &#43;const schedule_fn_t&nbsp; *sched_fn&nbsp; = &amp;schedule_sp_fn;<br>

> &gt; &#43;const schedule_api_t *sched_api = &amp;schedule_sp_api;<br>

> &gt; &#43;<br>

> &gt; &#43;#else /* default scheduler */<br>

> &gt; &#43;<br>

> &gt; &#43;extern const schedule_fn_t&nbsp; schedule_default_fn;<br>

> &gt; &#43;extern const schedule_api_t schedule_default_api;<br>

> &gt; &#43;<br>

> &gt;&nbsp; const schedule_fn_t&nbsp; *sched_fn&nbsp; = &amp;schedule_default_fn;<br>

> &gt;&nbsp; const schedule_api_t *sched_api = &amp;schedule_default_api;<br>

> &gt; &#43;<br>

> &gt;&nbsp; #endif<br>

> &gt;<br>

> &gt;&nbsp; uint64_t odp_schedule_wait_time(uint64_t ns)<br>

> &gt; diff --git a/platform/linux-generic/odp_schedule_scalable.c b/platform/linux-generic/odp_schedule_scalable.c<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..1e503f5e<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_schedule_scalable.c<br>

> &gt; @@ -0,0 &#43;1,1959 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp/api/align.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/atomic.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/cpu.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/hints.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/schedule.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/shared_memory.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/sync.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/thread.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/thrmask.h&gt;<br>

> &gt; &#43;#include &lt;odp/api/time.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_config_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_debug_internal.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp_align_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_buffer_inlines.h&gt;<br>

> &gt; &#43;#include &lt;odp_llqueue.h&gt;<br>

> &gt; &#43;#include &lt;odp_queue_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_schedule_if.h&gt;<br>

> &gt; &#43;#include &lt;odp_llsc.h&gt;<br>

> &gt; &#43;#include &lt;odp_bitset.h&gt;<br>

> &gt; &#43;#include &lt;odp_atomic16.h&gt;<br>

> &gt; &#43;#include &lt;odp_packet_io_internal.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;limits.h&gt;<br>

> &gt; &#43;#include &lt;stdbool.h&gt;<br>

> &gt; &#43;#include &lt;string.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp/api/plat/ticketlock_inlines.h&gt;<br>

> &gt; &#43;#define LOCK(a) _odp_ticketlock_lock((a))<br>

> &gt; &#43;#define UNLOCK(a) _odp_ticketlock_unlock((a))<br>

> &gt; &#43;<br>

> &gt; &#43;#define TAG_EMPTY 0U<br>

> &gt; &#43;#define TAG_USED (1U &lt;&lt; 15)<br>

> &gt; &#43;#define TAG_BUSY (1U &lt;&lt; 31)<br>

> &gt; &#43;#define PKTIO_QUEUE_2_TAG(p, q) ((p) &lt;&lt; 16 | (q) | TAG_USED)<br>

> &gt; &#43;#define TAG_2_PKTIO(t) (((t) &gt;&gt; 16) &amp; 0x7FFF)<br>

> &gt; &#43;#define TAG_2_QUEUE(t) ((t) &amp; 0x7FFF)<br>

> &gt; &#43;#define TAG_IS_READY(t) (((t) &amp; (TAG_USED | TAG_BUSY)) == TAG_USED)<br>

> &gt; &#43;#define PKTIN_MAX (ODP_CONFIG_PKTIO_ENTRIES * PKTIO_MAX_QUEUES)<br>

> &gt; &#43;#define MAXTHREADS ATOM_BITSET_SIZE<br>

> &gt; &#43;<br>

> &gt; &#43;static uint32_t pktin_num;<br>

> &gt; &#43;static uint32_t pktin_hi;<br>

> &gt; &#43;static uint16_t pktin_count[ODP_CONFIG_PKTIO_ENTRIES];<br>

> &gt; &#43;static uint32_t pktin_tags[PKTIN_MAX] ODP_ALIGNED_CACHE;<br>

> &gt; &#43;<br>

> &gt; &#43;#define __atomic_fetch_max(var, v, mo) do { \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Evalulate 'v' once */ \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __typeof__(v) tmp_v = (v); \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __typeof__(*var) old_var = \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load_n((var), __ATOMIC_RELAXED); \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (tmp_v &gt; old_var) { \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Attempt to store 'v' in '*var' */ \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__atomic_compare_exchange_n((var), &amp;old_var, \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_v, true, (mo), \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (mo))) \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else failure, try again (with updated value of \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * old_var). \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */ \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* v &lt;= old_var, nothing to do */ \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (0)<br>

> &gt; &#43;<br>

> &gt; &#43;ODP_STATIC_ASSERT(ODP_SCHED_PRIO_LOWEST == (ODP_SCHED_PRIO_NUM - 1),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;lowest_prio_does_not_match_with_num_prios&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;ODP_STATIC_ASSERT((ODP_SCHED_PRIO_NORMAL &gt; 0) &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (ODP_SCHED_PRIO_NORMAL &lt; (ODP_SCHED_PRIO_NUM - 1)),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;normal_prio_is_not_between_highest_and_lowest&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;ODP_STATIC_ASSERT(IS_POWER_TWO(ODP_CONFIG_QUEUES),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;Number_of_queues_is_not_power_of_two&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Scheduler group related variables.<br>

> &gt; &#43; */<br>

> &gt; &#43;/* Currently used scheduler groups */<br>

> &gt; &#43;static sched_group_mask_t sg_free;<br>

> &gt; &#43;static sched_group_t *sg_vec[MAX_SCHED_GROUP];<br>

> &gt; &#43;/* Group lock for MT-safe APIs */<br>

> &gt; &#43;odp_spinlock_t sched_grp_lock;<br>

> &gt; &#43;<br>

> &gt; &#43;#define SCHED_GROUP_JOIN 0<br>

> &gt; &#43;#define SCHED_GROUP_LEAVE 1<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Per thread state<br>

> &gt; &#43; */<br>

> &gt; &#43;static sched_scalable_thread_state_t thread_state[MAXTHREADS];<br>

> &gt; &#43;__thread sched_scalable_thread_state_t *sched_ts;<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Forward declarations.<br>

> &gt; &#43; */<br>

> &gt; &#43;static int thread_state_init(int tidx)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_scalable_thread_state_t *ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(tidx &lt; MAXTHREADS);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts = &amp;thread_state[tidx];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;atomq = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;rctx = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;pause = false;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;out_of_order = false;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;tidx = tidx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;dequeued = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;pktin_next = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;pktin_poll_cnts = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;ticket = TICKET_INVALID;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;priv_rvec_free = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;rvec_free = (1ULL &lt;&lt; TS_RVEC_SIZE) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;num_schedq = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;sg_sem = 1; /* Start with sched group semaphore changed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(ts-&gt;sg_actual, 0, sizeof(ts-&gt;sg_actual));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; TS_RVEC_SIZE; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;rvec[i].rvec_free = &amp;ts-&gt;rvec_free;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;rvec[i].idx = i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_ts = ts;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void insert_schedq_in_list(sched_scalable_thread_state_t *ts,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_queue_t *schedq)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Find slot for schedq */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (uint32_t i = 0; i &lt; ts-&gt;num_schedq; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Lower value is higher priority and closer to start of list */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (schedq-&gt;prio &lt;= ts-&gt;schedq_list[i]-&gt;prio) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* This is the slot! */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_queue_t *tmp;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp = ts-&gt;schedq_list[i];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;schedq_list[i] = schedq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq = tmp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Continue the insertion procedure with the<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * new schedq.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts-&gt;num_schedq == SCHEDQ_PER_THREAD)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;Too many schedqs\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;schedq_list[ts-&gt;num_schedq&#43;&#43;] = schedq;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void remove_schedq_from_list(sched_scalable_thread_state_t *ts,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_queue_t *schedq)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Find schedq */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (uint32_t i = 0; i &lt; ts-&gt;num_schedq; i&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts-&gt;schedq_list[i] == schedq) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Move remaining schedqs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (uint32_t j = i &#43; 1; j &lt; ts-&gt;num_schedq; j&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;schedq_list[j - 1] = ts-&gt;schedq_list[j];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;num_schedq--;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;Cannot find schedq\n&quot;);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/*******************************************************************************<br>

> &gt; &#43; * Scheduler queues<br>

> &gt; &#43; ******************************************************************************/<br>

> &gt; &#43;#ifndef odp_container_of<br>

> &gt; &#43;#define odp_container_of(pointer, type, member) \<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((type *)(void *)(((char *)pointer) - offsetof(type, member)))<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void schedq_init(sched_queue_t *schedq, uint32_t prio)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llqueue_init(&amp;schedq-&gt;llq);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq-&gt;prio = prio;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline sched_elem_t *schedq_peek(sched_queue_t *schedq)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct llnode *ptr;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ptr = llq_head(&amp;schedq-&gt;llq);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return odp_container_of(ptr, sched_elem_t, node);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline odp_bool_t schedq_cond_pop(sched_queue_t *schedq,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *elem)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return llq_dequeue_cond(&amp;schedq-&gt;llq, &amp;elem-&gt;node);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void schedq_push(sched_queue_t *schedq, sched_elem_t *elem)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; llq_enqueue(&amp;schedq-&gt;llq, &amp;elem-&gt;node);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline odp_bool_t schedq_cond_rotate(sched_queue_t *schedq,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *elem)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return llq_cond_rotate(&amp;schedq-&gt;llq, &amp;elem-&gt;node);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline bool schedq_elem_on_queue(sched_elem_t *elem)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return elem-&gt;node.next != NULL;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/*******************************************************************************<br>

> &gt; &#43; * Shared metadata btwn scheduler and queue<br>

> &gt; &#43; ******************************************************************************/<br>

> &gt; &#43;<br>

> &gt; &#43;void sched_update_enq(sched_elem_t *q, uint32_t actual)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qschedstate_t ss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t ui;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } oss, nss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ticket;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss.ss = q-&gt;qschst;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Update event counter, optionally taking a ticket. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = TICKET_INVALID;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss.ui = ll64((uint64_t *)&amp;q-&gt;qschst, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss = oss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.ss.numevts &#43;= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(oss.ss.numevts &lt;= 0 &amp;&amp; nss.ss.numevts &gt; 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* E -&gt; NE transition */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (q-&gt;qschst_type != ODP_SCHED_SYNC_ATOMIC ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss.ss.cur_ticket == oss.ss.nxt_ticket)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Parallel or ordered queues: always take<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ticket.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Atomic queue: only take ticket if one is<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * immediately available.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Otherwise ticket already taken =&gt; queue<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * processed by some thread.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = nss.ss.nxt_ticket&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else queue already was non-empty. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Attempt to update numevts counter and optionally take ticket. */<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc64((uint64_t *)&amp;q-&gt;qschst, nss.ui, __ATOMIC_RELAXED)));<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;q-&gt;qschst, &amp;oss.ss, &amp;nss.ss,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true, __ATOMIC_RELAXED, __ATOMIC_RELAXED));<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(ticket != TICKET_INVALID)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for our turn to update schedq. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load_n(&amp;q-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != ticket)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDXR8(&amp;q-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != ticket)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Enqueue at end of scheduler queue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We are here because of empty-to-non-empty transition<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * This means queue must be pushed to schedq if possible<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * but we can't do that if it already is on the schedq<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(!schedq_elem_on_queue(q) &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;pop_deficit == 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue not already on schedq and no pop deficit means<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * we can push queue to schedq */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_push(q-&gt;schedq, q);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Missed push =&gt; cancels one missed pop */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;pop_deficit--;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_thread_fence(__ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;qschst.cur_ticket, ticket &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;qschst.cur_ticket, ticket &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else queue was not empty or atomic queue already busy. */<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void sched_update_enq_sp(sched_elem_t *q, uint32_t actual)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qschedstate_t oss, nss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ticket;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss = q-&gt;qschst;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Update event counter, optionally taking a ticket. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = TICKET_INVALID;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss = oss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.numevts &#43;= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(oss.numevts &lt;= 0 &amp;&amp; nss.numevts &gt; 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* E -&gt; NE transition */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (q-&gt;qschst_type != ODP_SCHED_SYNC_ATOMIC ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss.cur_ticket == oss.nxt_ticket) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Parallel or ordered queues: always take<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ticket.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Atomic queue: only take ticket if one is<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * immediately available. Otherwise ticket already<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * taken =&gt; queue owned/processed by some thread<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = nss.nxt_ticket&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else queue already was non-empty. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Attempt to update numevts counter and optionally take ticket. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;qschst = nss;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(ticket != TICKET_INVALID)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Enqueue at end of scheduler queue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We are here because of empty-to-non-empty transition<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * This means queue must be pushed to schedq if possible<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * but we can't do that if it already is on the schedq<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(!schedq_elem_on_queue(q) &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;pop_deficit == 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue not already on schedq and no pop deficit means<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * we can push queue to schedq */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_push(q-&gt;schedq, q);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Missed push =&gt; cancels one missed pop */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;pop_deficit--;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;qschst.cur_ticket = ticket &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else queue was not empty or atomic queue already busy. */<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/* The scheduler is the only entity that performs the dequeue from a queue. */<br>

> &gt; &#43;static void sched_update_deq(sched_elem_t *q,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t actual, bool atomic) __attribute__((always_inline));<br>

> &gt; &#43;static inline void sched_update_deq(sched_elem_t *q,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t actual, bool atomic)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; union {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qschedstate_t ss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t ui;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } oss, nss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ticket;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (atomic) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qschedstate_t oss, nss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool pushed = false;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We own this atomic queue, only we can dequeue from it and<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * thus decrease numevts. Other threads may enqueue and thus<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * increase numevts.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * This means that numevts can't unexpectedly become 0 and<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * invalidate a push operation already performed<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss = q-&gt;qschst;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(oss.cur_ticket == sched_ts-&gt;ticket);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss = oss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.numevts -= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nss.numevts &gt; 0 &amp;&amp; !pushed) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_push(q-&gt;schedq, q);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushed = true;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Attempt to release ticket expecting our view of<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * numevts to be correct<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Unfortunately nxt_ticket will also be included in<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the CAS operation<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.cur_ticket = sched_ts-&gt;ticket &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(!__atomic_compare_exchange(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;q-&gt;qschst,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;oss, &amp;nss,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED)));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;#ifndef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss.ss = q-&gt;qschst;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = TICKET_INVALID;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss.ui = ll64((uint64_t *)&amp;q-&gt;qschst, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss = oss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.ss.numevts -= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.ss.wrr_budget -= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((oss.ss.numevts &gt; 0 &amp;&amp; nss.ss.numevts &lt;= 0) ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss.ss.wrr_budget &lt;= actual) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* If we have emptied parallel/ordered queue or<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * exchausted its WRR budget, we need a ticket<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * for a later pop.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = nss.ss.nxt_ticket&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Reset wrr_budget as we might also push the<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * queue to the schedq.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.ss.wrr_budget = CONFIG_WRR_WEIGHT;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Attempt to update numevts and optionally take ticket. */<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc64((uint64_t *)&amp;q-&gt;qschst, nss.ui, __ATOMIC_RELAXED)));<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;q-&gt;qschst, &amp;oss.ss, &amp;nss.ss,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true, __ATOMIC_RELAXED, __ATOMIC_RELAXED));<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(ticket != TICKET_INVALID)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(q-&gt;qschst_type != ODP_SCHED_SYNC_ATOMIC);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for our turn to update schedq. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load_n(&amp;q-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != ticket)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDXR8(&amp;q-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != ticket)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We are here because of non-empty-to-empty transition or<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * WRR budget exhausted<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * This means the queue must be popped from the schedq, now or<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * later<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * If there was no NE-&gt;E transition but instead the WRR budget<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * was exhausted, the queue needs to be moved (popped and<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * pushed) to the tail of the schedq<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (oss.ss.numevts &gt; 0 &amp;&amp; nss.ss.numevts &lt;= 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* NE-&gt;E transition, need to pop */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!schedq_elem_on_queue(q) ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !schedq_cond_pop(q-&gt;schedq, q)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue not at head, failed to dequeue<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Missed a pop.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;pop_deficit&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* WRR budget exhausted<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Need to move queue to tail of schedq if possible<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(schedq_elem_on_queue(q))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue is on schedq, try to move it to<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the tail<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)schedq_cond_rotate(q-&gt;schedq, q);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else queue not on schedq or not at head of schedq<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * No pop =&gt; no push<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_thread_fence(__ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;qschst.cur_ticket, ticket &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;q-&gt;qschst.cur_ticket, ticket &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void sched_update_deq_sc(sched_elem_t *q,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t actual, bool atomic) __attribute__((always_inline));<br>

> &gt; &#43;static inline void sched_update_deq_sc(sched_elem_t *q,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t actual, bool atomic)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; qschedstate_t oss, nss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ticket;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (atomic) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(q-&gt;qschst.cur_ticket == sched_ts-&gt;ticket);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(q-&gt;qschst.cur_ticket != q-&gt;qschst.nxt_ticket);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;qschst.numevts -= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;qschst.cur_ticket = sched_ts-&gt;ticket &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (q-&gt;qschst.numevts &gt; 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_push(q-&gt;schedq, q);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oss = q-&gt;qschst;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = TICKET_INVALID;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss = oss;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.numevts -= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.wrr_budget -= actual;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((oss.numevts &gt; 0 &amp;&amp; nss.numevts &lt;= 0) || oss.wrr_budget &lt;= actual) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* If we emptied the queue or<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * if we have served the maximum number of events<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * then we need a ticket for a later pop.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket = nss.nxt_ticket&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Also reset wrr_budget as we might also push the<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * queue to the schedq.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nss.wrr_budget = CONFIG_WRR_WEIGHT;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;qschst = nss;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ticket != TICKET_INVALID) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (oss.numevts &gt; 0 &amp;&amp; nss.numevts &lt;= 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* NE-&gt;E transition, need to pop */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!schedq_elem_on_queue(q) ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !schedq_cond_pop(q-&gt;schedq, q)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue not at head, failed to dequeue.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Missed a pop.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;pop_deficit&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* WRR budget exhausted<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Need to move queue to tail of schedq if possible<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(schedq_elem_on_queue(q))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue is on schedq, try to move it to<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the tail<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)schedq_cond_rotate(q-&gt;schedq, q);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else queue not on schedq or not at head of schedq<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * No pop =&gt; no push<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q-&gt;qschst.cur_ticket = ticket &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void sched_update_popd_sc(sched_elem_t *elem)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (elem-&gt;pop_deficit != 0 &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_elem_on_queue(elem) &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_cond_pop(elem-&gt;schedq, elem))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elem-&gt;pop_deficit--;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void sched_update_popd(sched_elem_t *elem)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ticket = __atomic_fetch_add(&amp;elem-&gt;qschst.nxt_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(__atomic_load_n(&amp;elem-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != ticket)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp; LDXR8(&amp;elem-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != ticket)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_popd_sc(elem);<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_thread_fence(__ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;elem-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;elem-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ticket &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;sched_queue_t *schedq_from_sched_group(odp_schedule_group_t grp, uint32_t prio)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t x;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(grp &gt;= 0 &amp;&amp; grp &lt;= (odp_schedule_group_t)MAX_SCHED_GROUP);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT((sg_free &amp; (1ULL &lt;&lt; grp)) == 0);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(prio &lt; ODP_SCHED_PRIO_NUM);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = grp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Use xcount to spread queues over the xfactor schedq's<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * per priority.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = __atomic_fetch_add(&amp;sg-&gt;xcount[prio], 1, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (x == 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* First ODP queue for this priority<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Notify all threads in sg-&gt;thr_wanted that they<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * should join.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t thrds = sg-&gt;thr_wanted;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!bitset_is_null(thrds)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t thr;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr = bitset_ffs(thrds) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thrds = bitset_clr(thrds, thr);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Notify the thread about membership in this<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * group/priority.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(&amp;thread_state[thr].sg_wanted[prio],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi, __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;thread_state[thr].sg_sem, 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &amp;sg-&gt;schedq[prio * sg-&gt;xfactor &#43; x % sg-&gt;xfactor];<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void sched_group_xcount_dec(odp_schedule_group_t grp, uint32_t prio)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t x;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(grp &gt;= 0 &amp;&amp; grp &lt;= (odp_schedule_group_t)MAX_SCHED_GROUP);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT((sg_free &amp; (1ULL &lt;&lt; grp)) == 0);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(prio &lt; ODP_SCHED_PRIO_NUM);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = grp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = __atomic_sub_fetch(&amp;sg-&gt;xcount[prio], 1, __ATOMIC_RELAXED);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (x == 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Last ODP queue for this priority<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Notify all threads in sg-&gt;thr_wanted that they<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * should leave.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t thrds = sg-&gt;thr_wanted;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!bitset_is_null(thrds)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t thr;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr = bitset_ffs(thrds) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thrds = bitset_clr(thrds, thr);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Notify the thread about membership in this<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * group/priority.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_clr(&amp;thread_state[thr].sg_wanted[prio],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi, __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;thread_state[thr].sg_sem, 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void update_sg_membership(sched_scalable_thread_state_t *ts)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t p;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t sg_wanted;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t added;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t removed;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t x;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (p = 0; p &lt; ODP_SCHED_PRIO_NUM; p&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg_wanted = __atomic_load_n(&amp;ts-&gt;sg_wanted[p],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!bitset_is_eql(ts-&gt;sg_actual[p], sg_wanted)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Our sched_group membership has changed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; added = bitset_andn(sg_wanted, ts-&gt;sg_actual[p]);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!bitset_is_null(added)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = bitset_ffs(added) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (x = 0; x &lt; sg-&gt;xfactor; x&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Include our thread index to shift<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (rotate) the order of schedq's<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insert_schedq_in_list(ts,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;sg-&gt;schedq[p * sg-&gt;xfactor &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (x &#43; ts-&gt;tidx) % sg-&gt;xfactor]);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(&amp;sg-&gt;thr_actual[p], ts-&gt;tidx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; added = bitset_clr(added, sgi);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; removed = bitset_andn(ts-&gt;sg_actual[p], sg_wanted);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!bitset_is_null(removed)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = bitset_ffs(removed) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (x = 0; x &lt; sg-&gt;xfactor; x&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove_schedq_from_list(ts,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;sg-&gt;schedq[p * sg-&gt;xfactor &#43; x]);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_clr(&amp;sg-&gt;thr_actual[p], ts-&gt;tidx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; removed = bitset_clr(removed, sgi);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;sg_actual[p] = sg_wanted;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/*******************************************************************************<br>

> &gt; &#43; * Scheduler<br>

> &gt; &#43; ******************************************************************************/<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void _schedule_release_atomic(sched_scalable_thread_state_t *ts)<br>

> &gt; &#43;{<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_deq_sc(ts-&gt;atomq, ts-&gt;dequeued, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(ts-&gt;atomq-&gt;qschst.cur_ticket != ts-&gt;ticket);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(ts-&gt;atomq-&gt;qschst.cur_ticket ==<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;atomq-&gt;qschst.nxt_ticket);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_deq(ts-&gt;atomq, ts-&gt;dequeued, true);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;atomq = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;ticket = TICKET_INVALID;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static inline void _schedule_release_ordered(sched_scalable_thread_state_t *ts)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;out_of_order = false;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx_release(ts-&gt;rctx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;rctx = NULL;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void pktin_poll(sched_scalable_thread_state_t *ts)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i, tag, hi, npolls = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int pktio_index, queue_index;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hi = __atomic_load_n(&amp;pktin_hi, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (hi == 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = ts-&gt;pktin_next; npolls != hi; i = (i &#43; 1) % hi, npolls&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tag = __atomic_load_n(&amp;pktin_tags[i], __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!TAG_IS_READY(tag))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!__atomic_compare_exchange_n(&amp;pktin_tags[i], &amp;tag,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tag | TAG_BUSY,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Tag grabbed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pktio_index = TAG_2_PKTIO(tag);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_index = TAG_2_QUEUE(tag);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(sched_cb_pktin_poll(pktio_index,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1, &amp;queue_index))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Pktio stopped or closed<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Remove tag from pktin_tags<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;pktin_tags[i],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TAG_EMPTY, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_fetch_sub(&amp;pktin_num,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1, __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Call stop_finalize when all queues<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * of the pktio have been removed<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__atomic_sub_fetch(&amp;pktin_count[pktio_index], 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) == 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_cb_pktio_stop_finalize(pktio_index);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We don't know whether any packets were found and enqueued<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Write back original tag value to release pktin queue<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;pktin_tags[i], tag, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Do not iterate through all pktin queues every time */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((ts-&gt;pktin_poll_cnts &amp; 0xf) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(i &lt; hi);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;pktin_poll_cnts&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;pktin_next = i;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int _schedule(odp_queue_t *from, odp_event_t ev[], int num_evts)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_scalable_thread_state_t *ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *atomq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts = sched_ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atomq = ts-&gt;atomq;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Once an atomic queue has been scheduled to a thread, it will stay<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * on that thread until empty or 'rotated' by WRR<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (atomq != NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(ts-&gt;ticket != TICKET_INVALID);<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;dequeue_atomic:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(ts-&gt;ticket == atomq-&gt;qschst.cur_ticket);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(ts-&gt;ticket != atomq-&gt;qschst.nxt_ticket);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomic queues can be dequeued without lock since this thread<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * has the only reference to the atomic queue being processed.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts-&gt;dequeued &lt; atomq-&gt;qschst.wrr_budget) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num = _odp_queue_deq_sc(atomq, ev, num_evts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(num != 0)) {<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;dequeued &#43;= num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Allow this thread to continue to 'own' this<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * atomic queue until all events have been<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * processed and the thread re-invokes the<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * scheduler.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (from)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *from = queue_get_handle(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (queue_entry_t *)atomq);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Atomic queue was empty or interrupted by WRR, release it. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_atomic(ts);<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Release any previous reorder context. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts-&gt;rctx != NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_ordered(ts);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Check for and perform any scheduler group updates. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(__atomic_load_n(&amp;ts-&gt;sg_sem, __ATOMIC_RELAXED) != 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)__atomic_load_n(&amp;ts-&gt;sg_sem, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;sg_sem = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; update_sg_membership(ts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Scan our schedq list from beginning to end */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; ts-&gt;num_schedq; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_queue_t *schedq = ts-&gt;schedq_list[i];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *elem;<br>

> &gt; &#43;restart_same:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elem = schedq_peek(schedq);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(elem == NULL)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Schedq empty, look at next one. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (elem-&gt;cons_type == ODP_SCHED_SYNC_ATOMIC) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Dequeue element only if it is still at head<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * of schedq.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(!schedq_cond_pop(schedq, elem))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Queue not at head of schedq anymore, some<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * other thread popped it.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto restart_same;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;atomq = atomq = elem;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;dequeued = 0;<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;ticket = atomq-&gt;qschst.nxt_ticket&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(atomq-&gt;qschst.cur_ticket == ts-&gt;ticket);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Dequeued atomic queue from the schedq, only we<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * can process it and any qschst updates are our<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * responsibility.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* The ticket taken below will signal producers */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;ticket = __atomic_fetch_add(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;atomq-&gt;qschst.nxt_ticket, 1, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (__atomic_load_n(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;atomq-&gt;qschst.cur_ticket,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != ts-&gt;ticket) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* No need to use WFE, spinning here seems<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * very infrequent.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto dequeue_atomic;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (elem-&gt;cons_type == ODP_SCHED_SYNC_PARALLEL) {<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num = _odp_queue_deq_sc(elem, ev, num_evts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(num != 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_deq_sc(elem, num, false);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (from)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *from =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_get_handle((queue_entry_t *)elem);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num = _odp_queue_deq(elem, ev, num_evts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(num != 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_deq(elem, num, false);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (from)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *from =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_get_handle((queue_entry_t *)elem);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (elem-&gt;cons_type == ODP_SCHED_SYNC_ORDERED) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_window_t *rwin;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *rctx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sn;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* The ordered queue has a reorder window so requires<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * order restoration. We must use a reorder context to<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * collect all outgoing events. Ensure there is at least<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * one available reorder context.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(bitset_is_null(ts-&gt;priv_rvec_free))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;priv_rvec_free = atom_bitset_xchg(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;ts-&gt;rvec_free, 0,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(bitset_is_null(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;priv_rvec_free))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* No free reorder contexts for<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * this thread. Look at next schedq,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * hope we find non-ordered queue.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* rwin_reserve and odp_queue_deq must be atomic or<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * there will be a potential race condition.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Allocate a slot in the reorder window.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin = queue_get_rwin((queue_entry_t *)elem);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(rwin != NULL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(!rwin_reserve(rwin, &amp;sn))) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Reorder window full */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Look at next schedq, find other queue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for our turn to dequeue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(__atomic_load_n(&amp;rwin-&gt;turn,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != sn)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDXR32(&amp;rwin-&gt;turn, __ATOMIC_ACQUIRE)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; != sn)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = _odp_queue_deq_sc(elem, ev, num_evts);<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Wait for prod_read write in _odp_queue_dequeue_sc()<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * to complete.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm volatile(&quot;dmb ishst&quot; ::: &quot;memory&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* before we signal the next consumer */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;turn = sn &#43; 1;<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;rwin-&gt;turn, sn &#43; 1, __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Find and initialise an unused reorder context. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; idx = bitset_ffs(ts-&gt;priv_rvec_free) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;priv_rvec_free =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_clr(ts-&gt;priv_rvec_free, idx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx = &amp;ts-&gt;rvec[idx];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Need to initialise reorder context or we can't<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * release it later.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx_init(rctx, idx, rwin, sn);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Was dequeue successful? */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(ret != 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Perform scheduler related updates */<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_deq_sc(elem, ret,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*atomic=*/false);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_deq(elem, ret, /*atomic=*/false);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Are we in-order or out-of-order? */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;out_of_order = sn != rwin-&gt;hc.head;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts-&gt;rctx = rctx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (from)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *from = queue_get_handle(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (queue_entry_t *)elem);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Since a slot was reserved in the reorder window,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the reorder context needs to be released and<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * inserted into the reorder window.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx_release(rctx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(ts-&gt;rctx == NULL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Dequeue from parallel/ordered queue failed<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Check if we have a queue at the head of the schedq that needs<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * to be popped<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(__atomic_load_n(&amp;elem-&gt;pop_deficit,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != 0)) {<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_popd_sc(elem);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;elem-&gt;qschlock);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_update_popd(elem);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pktin_poll(ts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/******************************************************************************/<br>

> &gt; &#43;<br>

> &gt; &#43;static void schedule_order_lock(unsigned lock_index)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct reorder_context *rctx = sched_ts-&gt;rctx;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(rctx == NULL ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;rwin == NULL ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock_index &gt;= rctx-&gt;rwin-&gt;lock_count)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Invalid call to odp_schedule_order_lock\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(__atomic_load_n(&amp;rctx-&gt;rwin-&gt;olock[lock_index],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != rctx-&gt;sn)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LDXR32(&amp;rctx-&gt;rwin-&gt;olock[lock_index],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE) != rctx-&gt;sn)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void schedule_order_unlock(unsigned lock_index)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct reorder_context *rctx;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx = sched_ts-&gt;rctx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(rctx == NULL ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;rwin == NULL ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock_index &gt;= rctx-&gt;rwin-&gt;lock_count ||<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;rwin-&gt;olock[lock_index] != rctx-&gt;sn)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Invalid call to odp_schedule_order_unlock\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_thread_fence(__ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;rctx-&gt;rwin-&gt;olock[lock_index],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;sn &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;rctx-&gt;rwin-&gt;olock[lock_index],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;sn &#43; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;olock_flags |= 1U &lt;&lt; lock_index;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void schedule_release_atomic(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_scalable_thread_state_t *ts;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts = sched_ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(ts-&gt;atomq != NULL)) {<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *atomq;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atomq = ts-&gt;atomq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_atomic(ts);<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void schedule_release_ordered(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_scalable_thread_state_t *ts;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts = sched_ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts-&gt;rctx != NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_ordered(ts);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t ev[],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_scalable_thread_state_t *ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int n;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_time_t start;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_time_t delta;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_time_t deadline;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts = sched_ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(ts-&gt;pause)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts-&gt;atomq != NULL) {<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *atomq;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atomq = ts-&gt;atomq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_atomic(ts);<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (ts-&gt;rctx != NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_ordered(ts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (wait == ODP_SCHED_NO_WAIT)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return _schedule(from, ev, num);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (wait == ODP_SCHED_WAIT) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (;;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = _schedule(from, ev, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(n&nbsp; &gt; 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return n;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; start = odp_time_local();<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = _schedule(from, ev, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(n &gt; 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return n;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delta = odp_time_local_from_ns(wait);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deadline = odp_time_sum(start, delta);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (odp_time_cmp(deadline, odp_time_local()) &gt; 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = _schedule(from, ev, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(n &gt; 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return n;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static odp_event_t schedule(odp_queue_t *from, uint64_t wait)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_event_t ev = ODP_EVENT_INVALID;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const int num = 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_scalable_thread_state_t *ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int n;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_time_t start;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_time_t delta;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_time_t deadline;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts = sched_ts;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(ts-&gt;pause)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ts-&gt;atomq != NULL) {<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_elem_t *atomq;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atomq = ts-&gt;atomq;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_atomic(ts);<br>

> &gt; &#43;#ifdef CONFIG_QSCHST_LOCK<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UNLOCK(&amp;atomq-&gt;qschlock);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (ts-&gt;rctx != NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _schedule_release_ordered(ts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ev;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (wait == ODP_SCHED_NO_WAIT) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)_schedule(from, &amp;ev, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ev;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (wait == ODP_SCHED_WAIT) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (;;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = _schedule(from, &amp;ev, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(n &gt; 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ev;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; start = odp_time_local();<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = _schedule(from, &amp;ev, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(n &gt; 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ev;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delta = odp_time_local_from_ns(wait);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deadline = odp_time_sum(start, delta);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (odp_time_cmp(deadline, odp_time_local()) &gt; 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = _schedule(from, &amp;ev, num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_likely(n &gt; 0))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ev;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ev;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void schedule_pause(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_ts-&gt;pause = true;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void schedule_resume(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_ts-&gt;pause = false;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static uint64_t schedule_wait_time(uint64_t ns)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ns;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_num_prio(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ODP_SCHED_PRIO_NUM;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_group_update(sched_group_t *sg,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const odp_thrmask_t *mask,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int join_leave)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int thr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t p;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Internal function, do not validate inputs */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Notify relevant threads about the change */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr = odp_thrmask_first(mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (0 &lt;= thr) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Add thread to scheduler group's wanted thread mask */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (join_leave == SCHED_GROUP_JOIN)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(&amp;sg-&gt;thr_wanted, thr, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_clr(&amp;sg-&gt;thr_wanted, thr, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (p = 0; p &lt; ODP_SCHED_PRIO_NUM; p&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sg-&gt;xcount[p] != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* This priority level has ODP queues<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Notify the thread about membership in<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * this group/priority<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (join_leave == SCHED_GROUP_JOIN)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;thread_state[thr].sg_wanted[p],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_clr(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;thread_state[thr].sg_wanted[p],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;thread_state[thr].sg_sem,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr = odp_thrmask_next(mask, thr);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int _schedule_group_thrmask(sched_group_t *sg, odp_thrmask_t *mask)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t bs;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t bit;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Internal function, do not validate inputs */<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_zero(mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bs = sg-&gt;thr_wanted;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!bitset_is_null(bs)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit = bitset_ffs(bs) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bs = bitset_clr(bs, bit);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_set(mask, bit);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static odp_schedule_group_t schedule_group_create(const char *name,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const odp_thrmask_t *mask)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_t shm;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_mask_t free;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t xfactor;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t p;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t x;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Validate inputs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mask == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;mask is NULL\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Allocate a scheduler group */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free = __atomic_load_n(&amp;sg_free, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* All sched_groups in use */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bitset_is_null(free))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto no_free_sched_group;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = bitset_ffs(free) - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* All sched_groups in use */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sgi &gt;= MAX_SCHED_GROUP)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto no_free_sched_group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange_n(&amp;sg_free,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;free,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_clr(free, sgi),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE));<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Compute xfactor (spread factor) from the number of threads<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * present in the thread mask. Preferable this would be an<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * explicit parameter.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xfactor = odp_thrmask_count(mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (xfactor &lt; 1)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xfactor = 1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shm = odp_shm_reserve(name ? name : &quot;&quot;,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (sizeof(sched_group_t) &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (ODP_SCHED_PRIO_NUM * xfactor - 1) *<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(sched_queue_t)),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CACHE_LINE_SIZE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_SHM_PROC);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ODP_SHM_INVALID == shm)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto shm_reserve_failed;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = (sched_group_t *) odp_shm_addr(shm);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sg == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto shm_addr_failed;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strncpy(sg-&gt;name, name ? name : &quot;&quot;, ODP_SCHED_GROUP_NAME_LEN - 1);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg-&gt;shm = shm;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg_vec[sgi] = sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(sg-&gt;thr_actual, 0, sizeof(sg-&gt;thr_actual));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg-&gt;thr_wanted = bitset_null();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg-&gt;xfactor = xfactor;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (p = 0; p &lt; ODP_SCHED_PRIO_NUM; p&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg-&gt;xcount[p] = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (x = 0; x &lt; xfactor; x&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedq_init(&amp;sg-&gt;schedq[p * xfactor &#43; x], p);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_thrmask_count(mask) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; schedule_group_update(sg, sgi, mask, SCHED_GROUP_JOIN);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (odp_schedule_group_t) (sgi);<br>

> &gt; &#43;<br>

> &gt; &#43;shm_addr_failed:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_free(shm);<br>

> &gt; &#43;<br>

> &gt; &#43;shm_reserve_failed:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Free the allocated group index */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(&amp;sg_free, sgi, __ATOMIC_RELAXED);<br>

> &gt; &#43;<br>

> &gt; &#43;no_free_sched_group:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ODP_SCHED_GROUP_INVALID;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_group_destroy(odp_schedule_group_t group)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t p;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret = 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Validate inputs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (group &lt; 0 &amp;&amp; group &gt;= (odp_schedule_group_t)MAX_SCHED_GROUP) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto invalid_group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sched_ts &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_unlikely(__atomic_load_n(&amp;sched_ts-&gt;sg_sem,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)__atomic_load_n(&amp;sched_ts-&gt;sg_sem,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_ts-&gt;sg_sem = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; update_sg_membership(sched_ts);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = (uint32_t)group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bitset_is_set(sg_free, sgi)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto group_not_found;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* First ensure all threads have processed group_join/group_leave<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * requests.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (p = 0; p &lt; ODP_SCHED_PRIO_NUM; p&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sg-&gt;xcount[p] != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_t wanted = atom_bitset_load(<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;sg-&gt;thr_wanted, __ATOMIC_RELAXED);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SEVL();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (WFE() &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !bitset_is_eql(wanted,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_ldex(&amp;sg-&gt;thr_actual[p],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED)))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DOZE();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Else ignore because no ODP queues on this prio */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Check if all threads/queues have left the group */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (p = 0; p &lt; ODP_SCHED_PRIO_NUM; p&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!bitset_is_null(sg-&gt;thr_actual[p])) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Group has threads\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto thrd_q_present_in_group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sg-&gt;xcount[p] != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Group has queues\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto thrd_q_present_in_group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_free(sg-&gt;shm);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg_vec[sgi] = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(&amp;sg_free, sgi, __ATOMIC_RELEASE);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;<br>

> &gt; &#43;thrd_q_present_in_group:<br>

> &gt; &#43;<br>

> &gt; &#43;group_not_found:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;invalid_group:<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static odp_schedule_group_t schedule_group_lookup(const char *name)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_t group;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Validate inputs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (name == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;name or mask is NULL\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; group = ODP_SCHED_GROUP_INVALID;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Scan through the schedule group array */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (sgi = 0; sgi &lt; MAX_SCHED_GROUP; sgi&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((sg_vec[sgi] != NULL) &amp;&amp;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (strncmp(name, sg_vec[sgi]-&gt;name,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_SCHED_GROUP_NAME_LEN) == 0)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; group = (odp_schedule_group_t)sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return group;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_group_join(odp_schedule_group_t group,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const odp_thrmask_t *mask)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Validate inputs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (group &lt; 0 &amp;&amp; group &gt;= ((odp_schedule_group_t)MAX_SCHED_GROUP))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mask == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;name or mask is NULL\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = (uint32_t)group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bitset_is_set(sg_free, sgi)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = schedule_group_update(sg, sgi, mask, SCHED_GROUP_JOIN);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_group_leave(odp_schedule_group_t group,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const odp_thrmask_t *mask)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret = 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Validate inputs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (group &lt; 0 &amp;&amp; group &gt;= (odp_schedule_group_t)MAX_SCHED_GROUP) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto invalid_group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mask == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;name or mask is NULL\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = (uint32_t)group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bitset_is_set(sg_free, sgi)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto group_not_found;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = schedule_group_update(sg, sgi, mask, SCHED_GROUP_LEAVE);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;<br>

> &gt; &#43;group_not_found:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;invalid_group:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_group_thrmask(odp_schedule_group_t group,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_t *mask)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret = 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Validate inputs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (group &lt; 0 &amp;&amp; group &gt;= ((odp_schedule_group_t)MAX_SCHED_GROUP)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto invalid_group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mask == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;name or mask is NULL\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = (uint32_t)group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bitset_is_set(sg_free, sgi)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto group_not_found;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = _schedule_group_thrmask(sg, mask);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;<br>

> &gt; &#43;group_not_found:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;invalid_group:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_group_info(odp_schedule_group_t group,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_info_t *info)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sgi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_group_t *sg;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret = 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Validate inputs */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (group &lt; 0 &amp;&amp; group &gt;= ((odp_schedule_group_t)MAX_SCHED_GROUP)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto invalid_group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (info == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;name or mask is NULL\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_lock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sgi = (uint32_t)group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bitset_is_set(sg_free, sgi)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto group_not_found;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg = sg_vec[sgi];<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = _schedule_group_thrmask(sg, &amp;info-&gt;thrmask);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; info-&gt;name = sg-&gt;name;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;<br>

> &gt; &#43;group_not_found:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_unlock(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;invalid_group:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_init_global(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_t mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_t tmp_all;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_t tmp_wrkr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_t tmp_ctrl;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t bits;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_spinlock_init(&amp;sched_grp_lock);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bits = MAX_SCHED_GROUP;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (MAX_SCHED_GROUP == sizeof(sg_free) * CHAR_BIT)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg_free = ~0ULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg_free = (1ULL &lt;&lt; bits) - 1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (uint32_t i = 0; i &lt; MAX_SCHED_GROUP; i&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sg_vec[i] = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (uint32_t i = 0; i &lt; MAXTHREADS; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread_state[i].sg_sem = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (uint32_t j = 0; j &lt; ODP_SCHED_PRIO_NUM; j&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread_state[i].sg_wanted[j] = bitset_null();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Create sched groups for default GROUP_ALL, GROUP_WORKER and<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * GROUP_CONTROL groups.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_zero(&amp;mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_all = odp_schedule_group_create(&quot;__group_all&quot;, &amp;mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmp_all != ODP_SCHED_GROUP_ALL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Could not create ODP_SCHED_GROUP_ALL()\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto failed_create_group_all;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_wrkr = odp_schedule_group_create(&quot;__group_worker&quot;, &amp;mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmp_wrkr != ODP_SCHED_GROUP_WORKER) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Could not create ODP_SCHED_GROUP_WORKER()\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto failed_create_group_worker;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_ctrl = odp_schedule_group_create(&quot;__group_control&quot;, &amp;mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmp_ctrl != ODP_SCHED_GROUP_CONTROL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Could not create ODP_SCHED_GROUP_CONTROL()\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto failed_create_group_control;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;<br>

> &gt; &#43;failed_create_group_control:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmp_ctrl != ODP_SCHED_GROUP_INVALID)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_destroy(ODP_SCHED_GROUP_CONTROL);<br>

> &gt; &#43;<br>

> &gt; &#43;failed_create_group_worker:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmp_wrkr != ODP_SCHED_GROUP_INVALID)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_destroy(ODP_SCHED_GROUP_WORKER);<br>

> &gt; &#43;<br>

> &gt; &#43;failed_create_group_all:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tmp_all != ODP_SCHED_GROUP_INVALID)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_destroy(ODP_SCHED_GROUP_ALL);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_term_global(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Destroy sched groups for default GROUP_ALL, GROUP_WORKER and<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * GROUP_CONTROL groups.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_destroy(ODP_SCHED_GROUP_ALL) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to destroy ODP_SCHED_GROUP_ALL\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_destroy(ODP_SCHED_GROUP_WORKER) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to destroy ODP_SCHED_GROUP_WORKER\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_destroy(ODP_SCHED_GROUP_CONTROL) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to destroy ODP_SCHED_GROUP_CONTROL\n&quot;);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_init_local(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int thr_id;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thread_type_t thr_type;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_t mask;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr_id = odp_thread_id();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (thread_state_init(thr_id))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto failed_to_init_ts;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Add this thread to default schedule groups */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr_type = odp_thread_type();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_zero(&amp;mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_set(&amp;mask, thr_id);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_join(ODP_SCHED_GROUP_ALL, &amp;mask) != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to join ODP_SCHED_GROUP_ALL\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto failed_to_join_grp_all;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (thr_type == ODP_THREAD_CONTROL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_join(ODP_SCHED_GROUP_CONTROL,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;mask) != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to join ODP_SCHED_GROUP_CONTROL\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto failed_to_join_grp_ctrl;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_join(ODP_SCHED_GROUP_WORKER,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;mask) != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to join ODP_SCHED_GROUP_WORKER\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto failed_to_join_grp_wrkr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;<br>

> &gt; &#43;failed_to_join_grp_wrkr:<br>

> &gt; &#43;<br>

> &gt; &#43;failed_to_join_grp_ctrl:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &amp;mask);<br>

> &gt; &#43;<br>

> &gt; &#43;failed_to_join_grp_all:<br>

> &gt; &#43;failed_to_init_ts:<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int schedule_term_local(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int thr_id;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thread_type_t thr_type;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_t mask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int rc = 0;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Remove this thread from default schedule groups */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr_id = odp_thread_id();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr_type = odp_thread_type();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_zero(&amp;mask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_set(&amp;mask, thr_id);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_leave(ODP_SCHED_GROUP_ALL, &amp;mask) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to leave ODP_SCHED_GROUP_ALL\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (thr_type == ODP_THREAD_CONTROL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_leave(ODP_SCHED_GROUP_CONTROL,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;mask) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to leave ODP_SCHED_GROUP_CONTROL\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_schedule_group_leave(ODP_SCHED_GROUP_WORKER,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;mask) != 0)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to leave ODP_SCHED_GROUP_WORKER\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; update_sg_membership(sched_ts);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Check if the thread is still part of any groups */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sched_ts-&gt;num_schedq != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Thread %d still part of scheduler group(s)\n&quot;,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_ts-&gt;tidx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rc = -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return rc;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;int queue_tm_reorder(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)queue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)buf_hdr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void pktio_start(int pktio_index, int num_in_queue, int in_queue_idx[])<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t old, tag, j;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; num_in_queue; i&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Try to reserve a slot */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__atomic_fetch_add(&amp;pktin_num,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1, __ATOMIC_RELAXED) &gt;= PKTIN_MAX) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_fetch_sub(&amp;pktin_num, 1, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ABORT(&quot;Too many pktio in queues for scheduler\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* A slot has been reserved, now we need to find an empty one */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (j = 0; ; j = (j &#43; 1) % PKTIN_MAX) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__atomic_load_n(&amp;pktin_tags[j],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED) != TAG_EMPTY)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Slot used, continue with next */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Empty slot found */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; old = TAG_EMPTY;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tag = PKTIO_QUEUE_2_TAG(pktio_index, in_queue_idx[i]);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__atomic_compare_exchange_n(&amp;pktin_tags[j],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tag,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED)) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Success grabbing slot,update high<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * watermark<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_fetch_max(&amp;pktin_hi,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j &#43; 1, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* One more tag (queue) for this pktio<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * instance<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_fetch_add(&amp;pktin_count[pktio_index],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1, __ATOMIC_RELAXED);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Continue with next RX queue */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Failed to grab slot */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static int num_grps(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return MAX_SCHED_GROUP;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;/*<br>

> &gt; &#43; * Stubs for internal scheduler abstraction layer due to absence of NULL<br>

> &gt; &#43; * checking before calling the function pointer.<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;static int thr_add(odp_schedule_group_t group, int thr)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* This function is a schedule_init_local duplicate. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)thr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;static int thr_rem(odp_schedule_group_t group, int thr)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* This function is a schedule_term_local duplicate. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)group;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)thr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;static int init_queue(uint32_t queue_index,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const odp_schedule_param_t *sched_param)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Not used in scalable scheduler. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)queue_index;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)sched_param;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;static void destroy_queue(uint32_t queue_index)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Not used in scalable scheduler. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)queue_index;<br>

> &gt; &#43;}<br>

> &gt; &#43;static int sched_queue(uint32_t queue_index)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Not used in scalable scheduler. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)queue_index;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;static int ord_enq_multi(uint32_t queue_index, void *p_buf_hdr[],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int num, int *ret)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)queue_index;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)p_buf_hdr;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)ret;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void schedule_prefetch(int num)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (void)num;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void order_lock(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;static void order_unlock(void)<br>

> &gt; &#43;{<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;const schedule_fn_t schedule_scalable_fn = {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .pktio_start&nbsp;&nbsp;&nbsp; = pktio_start,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .thr_add&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = thr_add,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .thr_rem&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = thr_rem,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .num_grps&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = num_grps,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .init_queue&nbsp;&nbsp;&nbsp;&nbsp; = init_queue,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .destroy_queue&nbsp; = destroy_queue,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .sched_queue&nbsp;&nbsp;&nbsp; = sched_queue,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ord_enq_multi&nbsp; = ord_enq_multi,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .init_global&nbsp;&nbsp;&nbsp; = schedule_init_global,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .term_global&nbsp;&nbsp;&nbsp; = schedule_term_global,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .init_local&nbsp;&nbsp;&nbsp;&nbsp; = schedule_init_local,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .term_local&nbsp;&nbsp;&nbsp;&nbsp; = schedule_term_local,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .order_lock&nbsp;&nbsp;&nbsp;&nbsp; = order_lock,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .order_unlock&nbsp;&nbsp; = order_unlock,<br>

> &gt; &#43;};<br>

> &gt; &#43;<br>

> &gt; &#43;const schedule_api_t schedule_scalable_api = {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_wait_time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_wait_time,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_multi&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_multi,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_pause&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_pause,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_resume&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_resume,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_release_atomic&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_release_atomic,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_release_ordered&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_release_ordered,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_prefetch&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_prefetch,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_num_prio&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_num_prio,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_group_create&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_group_create,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_group_destroy&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_group_destroy,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_group_lookup&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_group_lookup,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_group_join&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_group_join,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_group_leave&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_group_leave,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_group_thrmask&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_group_thrmask,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_group_info&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_group_info,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_order_lock&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_order_lock,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .schedule_order_unlock&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = schedule_order_unlock,<br>

> &gt; &#43;};<br>

> &gt; diff --git a/platform/linux-generic/odp_schedule_scalable_ordered.c b/platform/linux-generic/odp_schedule_scalable_ordered.c<br>

> &gt; new file mode 100644<br>

> &gt; index 00000000..ff4431b5<br>

> &gt; --- /dev/null<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_schedule_scalable_ordered.c<br>

> &gt; @@ -0,0 &#43;1,298 @@<br>

> &gt; &#43;/* Copyright (c) 2017, ARM Limited<br>

> &gt; &#43; * All rights reserved.<br>

> &gt; &#43; *<br>

> &gt; &#43; * SPDX-License-Identifier:&nbsp;&nbsp;&nbsp;&nbsp; BSD-3-Clause<br>

> &gt; &#43; */<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;odp/api/shared_memory.h&gt;<br>

> &gt; &#43;#include &lt;odp_queue_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_schedule_if.h&gt;<br>

> &gt; &#43;#include &lt;odp_schedule_ordered_internal.h&gt;<br>

> &gt; &#43;#include &lt;odp_llsc.h&gt;<br>

> &gt; &#43;#include &lt;odp_bitset.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#include &lt;string.h&gt;<br>

> &gt; &#43;<br>

> &gt; &#43;extern __thread sched_scalable_thread_state_t *sched_ts;<br>

> &gt; &#43;<br>

> &gt; &#43;#define RWIN_NAME_SIZE 32<br>

> &gt; &#43;<br>

> &gt; &#43;reorder_window_t *rwin_alloc(int rwin_id, odp_shm_t *shm, unsigned lock_count)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char rwin_name[RWIN_NAME_SIZE];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_window_t *rwin;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strncpy(rwin_name, &quot;rwin&quot;, RWIN_NAME_SIZE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = strlen(rwin_name);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snprintf(rwin_name &#43; i,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (RWIN_NAME_SIZE - i), &quot;%d&quot;, rwin_id);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *shm = odp_shm_reserve(rwin_name,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(reorder_window_t),<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_CACHE_LINE_SIZE,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_SHM_PROC);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ODP_SHM_INVALID == *shm)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto shm_reserve_failed;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin = (reorder_window_t *) odp_shm_addr(*shm);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rwin == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto shm_addr_failed;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;hc.head = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;hc.chgi = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;winmask = RWIN_SIZE - 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;tail = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;turn = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;lock_count = (uint16_t)lock_count;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(rwin-&gt;olock, 0, sizeof(rwin-&gt;olock));<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; RWIN_SIZE; i&#43;&#43;)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;ring[i] = NULL;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return rwin;<br>

> &gt; &#43;<br>

> &gt; &#43;shm_addr_failed:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_shm_free(*shm);<br>

> &gt; &#43;<br>

> &gt; &#43;shm_reserve_failed:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NULL;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;bool rwin_reserve(reorder_window_t *rwin, uint32_t *sn)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t oldt;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t newt;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t winmask;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Read head and tail separately */<br>

> &gt; &#43;#ifndef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oldt = rwin-&gt;tail;<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __builtin_prefetch(&amp;rwin-&gt;tail, 1, 0);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; winmask = rwin-&gt;winmask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Need __atomic_load to avoid compiler reordering */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = __atomic_load_n(&amp;rwin-&gt;hc.head, __ATOMIC_RELAXED);<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oldt = ll32(&amp;rwin-&gt;tail, __ATOMIC_RELAXED);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(oldt - head &gt;= winmask))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newt = oldt &#43; 1;<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_LLSC<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (odp_unlikely(sc32(&amp;rwin-&gt;tail, newt, __ATOMIC_RELAXED)));<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange(&amp;rwin-&gt;tail,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;oldt,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;newt,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED));<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *sn = oldt;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void rwin_insert(reorder_window_t *rwin,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *rctx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t sn,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (*callback)(reorder_context_t *))<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Initialise to silence scan-build */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hc_t old = {0, 0};<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hc_t new;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t winmask;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_load(&amp;rwin-&gt;hc, &amp;old, __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; winmask = rwin-&gt;winmask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (old.head != sn) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We are out-of-order. Store context in reorder window,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * releasing its content.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(rwin-&gt;ring[sn &amp; winmask] == NULL);<br>

> &gt; &#43;#ifdef ODP_CONFIG_USE_DMB<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_thread_fence(__ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;rwin-&gt;ring[sn &amp; winmask], rctx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELAXED);<br>

> &gt; &#43;#else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __atomic_store_n(&amp;rwin-&gt;ring[sn &amp; winmask], rctx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;#endif<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hc_t new;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new.head = old.head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new.chgi = old.chgi &#43; 1; /* Changed value */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Update head &amp; chgi, fail if any has changed */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__atomic_compare_exchange(&amp;rwin-&gt;hc,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old, /* Updated on failure */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;new,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE, /* Release our ring update */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* CAS succeeded =&gt; head same (we are not<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * in-order), chgi updated.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* CAS failed =&gt; head and/or chgi changed.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * We might not be out-of-order anymore.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (old.head != sn);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* old.head == sn =&gt; we are now in-order! */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(old.head == sn);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We are in-order so our responsibility to retire contexts */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new.head = old.head;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new.chgi = old.chgi &#43; 1;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Retire our in-order context (if we still have it) */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rctx != NULL) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; callback(rctx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new.head&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Retire in-order contexts in the ring<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * The first context might actually be ours (if we were originally<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * out-of-order)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (;;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx = __atomic_load_n(&amp;rwin-&gt;ring[new.head &amp; winmask],<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rctx == NULL)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* We are the only thread that are in-order<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (until head updated) so don't have to use<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * atomic load-and-clear (exchange)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;ring[new.head &amp; winmask] = NULL;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; callback(rctx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new.head&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Update head&amp;chgi, fail if chgi has changed (head cannot change) */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (!__atomic_compare_exchange(&amp;rwin-&gt;hc,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;old, /* Updated on failure */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;new,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false, /* weak */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE, /* Release our ring updates */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_ACQUIRE));<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void rctx_init(reorder_context_t *rctx, uint16_t idx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_window_t *rwin, uint32_t sn)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* rctx-&gt;rvec_free and rctx-&gt;idx already initialised in<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * thread_state_init function.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(rctx-&gt;idx == idx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;rwin = rwin;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;sn = sn;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;olock_flags = 0;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* First =&gt; no next reorder context */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;next_idx = idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Where to store next event */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;cur_idx = idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx-&gt;numevts = 0;<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;inline void rctx_free(const reorder_context_t *rctx)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const reorder_context_t *const base = &amp;rctx[-(int)rctx-&gt;idx];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const uint32_t first = rctx-&gt;idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t next_idx;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; next_idx = rctx-&gt;next_idx;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ASSERT(rctx-&gt;rwin != NULL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Set free bit */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rctx-&gt;rvec_free == &amp;sched_ts-&gt;rvec_free)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Since it is our own reorder context, we can instead<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * perform a non-atomic and relaxed update on our private<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * rvec_free.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_ts-&gt;priv_rvec_free =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_set(sched_ts-&gt;priv_rvec_free, rctx-&gt;idx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(rctx-&gt;rvec_free, rctx-&gt;idx, __ATOMIC_RELEASE);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Can't dereference rctx after the corresponding free bit is set */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (next_idx != first) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx = &amp;base[next_idx];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; next_idx = rctx-&gt;next_idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Set free bit */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (rctx-&gt;rvec_free == &amp;sched_ts-&gt;rvec_free)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sched_ts-&gt;priv_rvec_free =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitset_set(sched_ts-&gt;priv_rvec_free, rctx-&gt;idx);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atom_bitset_set(rctx-&gt;rvec_free, rctx-&gt;idx,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __ATOMIC_RELEASE);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;inline void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t lock_index)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((rctx-&gt;olock_flags &amp; (1U &lt;&lt; lock_index)) == 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Use relaxed ordering, we are not releasing any updates */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin-&gt;olock[lock_index] = rctx-&gt;sn &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void olock_release(const reorder_context_t *rctx)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_window_t *rwin;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin = rctx-&gt;rwin;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch (rwin-&gt;lock_count) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 2:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; olock_unlock(rctx, rwin, 1);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 1:<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; olock_unlock(rctx, rwin, 0);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_STATIC_ASSERT(NUM_OLOCKS == 2, &quot;Number of ordered locks != 2&quot;);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void rctx_retire(reorder_context_t *first)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reorder_context_t *rctx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_entry_t *q;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t j;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int rc;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx = first;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Process all events in this reorder context */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; rctx-&gt;numevts;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = rctx-&gt;destq[i];<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Find index of next different destq */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j = i &#43; 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (j &lt; rctx-&gt;numevts &amp;&amp; rctx-&gt;destq[j] == q)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j&#43;&#43;;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num = j - i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rc = q-&gt;s.enqueue_multi(q, &amp;rctx-&gt;events[i], num);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (odp_unlikely(rc != (int)num))<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_ERR(&quot;Failed to enqueue deferred events\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i &#43;= num;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Update rctx pointer to point to 'next_idx' element */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx &#43;= (int)rctx-&gt;next_idx - (int)rctx-&gt;idx;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (rctx != first);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; olock_release(first);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rctx_free(first);<br>

> &gt; &#43;}<br>

> &gt; &#43;<br>

> &gt; &#43;void rctx_release(reorder_context_t *rctx)<br>

> &gt; &#43;{<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Insert reorder context into reorder window, potentially calling the<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * rctx_retire function for all pending reorder_contexts.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rwin_insert(rctx-&gt;rwin, rctx, rctx-&gt;sn, rctx_retire);<br>

> &gt; &#43;}<br>

> &gt; diff --git a/platform/linux-generic/odp_traffic_mngr.c b/platform/linux-generic/odp_traffic_mngr.c<br>

> &gt; index 4e9358b9..3244dfe3 100644<br>

> &gt; --- a/platform/linux-generic/odp_traffic_mngr.c<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/odp_traffic_mngr.c<br>

> &gt; @@ -3918,9 &#43;3918,10 @@ odp_tm_queue_t odp_tm_queue_create(odp_tm_t odp_tm,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tm_queue_obj-&gt;pkt = ODP_PACKET_INVALID;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_ticketlock_init(&amp;tm_wred_node-&gt;tm_wred_node_lock);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tm_queue_obj-&gt;tm_qentry.s.type = QUEUE_TYPE_TM;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tm_queue_obj-&gt;tm_qentry.s.enqueue = queue_tm_reenq;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tm_queue_obj-&gt;tm_qentry.s.enqueue_multi = queue_tm_reenq_multi;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_type(&amp;tm_queue_obj-&gt;tm_qentry, QUEUE_TYPE_TM);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_enq_func(&amp;tm_queue_obj-&gt;tm_qentry, queue_tm_reenq);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_set_enq_multi_func(&amp;tm_queue_obj-&gt;tm_qentry,<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_tm_reenq_multi);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tm_system-&gt;queue_num_tbl[tm_queue_obj-&gt;queue_num - 1] = tm_queue_obj;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_ticketlock_lock(&amp;tm_system-&gt;tm_system_lock);<br>

> &gt; diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c<br>

> &gt; index 70962839..1f2f16c1 100644<br>

> &gt; --- a/platform/linux-generic/pktio/loop.c<br>

> &gt; &#43;&#43;&#43; b/platform/linux-generic/pktio/loop.c<br>

> &gt; @@ -80,11 &#43;80,13 @@ static int loopback_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; nbr; i&#43;&#43;) {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t pkt_len;<br>

> &gt; -<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt = _odp_packet_from_buffer((odp_buffer_t)(hdr_tbl[i]));<br>

> &gt; &#43;#else<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt = _odp_packet_from_buffer(odp_hdr_to_buf(hdr_tbl[i]));<br>

> &gt; &#43;#endif<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pkt_len = odp_packet_len(pkt);<br>

> &gt;<br>

> &gt; -<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pktio_cls_enabled(pktio_entry)) {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_packet_t new_pkt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pool_t new_pool;<br>

> &gt; @@ -162,7 &#43;164,11 @@ static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; len = QUEUE_MULTI_MAX;<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt; len; &#43;&#43;i) {<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hdr_tbl[i] = _odp_packet_to_buf_hdr_ptr(pkt_tbl[i]);<br>

> &gt; &#43;#else<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hdr_tbl[i] = buf_hdl_to_hdr(_odp_packet_to_buffer(pkt_tbl[i]));<br>

> &gt; &#43;#endif<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bytes &#43;= odp_packet_len(pkt_tbl[i]);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt; @@ -176,6 &#43;182,7 @@ static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pktio_entry-&gt;s.stats.out_octets &#43;= bytes;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ODP_DBG(&quot;queue enqueue failed %i\n&quot;, ret);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_ticketlock_unlock(&amp;pktio_entry-&gt;s.txl);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt; diff --git a/test/common_plat/performance/odp_sched_latency.c b/test/common_plat/performance/odp_sched_latency.c<br>

> &gt; index 2b28cd7b..5e11a4f3 100644<br>

> &gt; --- a/test/common_plat/performance/odp_sched_latency.c<br>

> &gt; &#43;&#43;&#43; b/test/common_plat/performance/odp_sched_latency.c<br>

> &gt; @@ -28,7 &#43;28,13 @@<br>

> &gt;&nbsp; #define MAX_WORKERS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**&lt; Maximum number of worker threads */<br>

> &gt;&nbsp; #define MAX_QUEUES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**&lt; Maximum number of queues */<br>

> &gt;&nbsp; #define EVENT_POOL_SIZE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1024 * 1024) /**&lt; Event pool size */<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SP<br>

> &gt;&nbsp; #define TEST_ROUNDS (4 * 1024 * 1024)&nbsp; /**&lt; Test rounds for each thread */<br>

> &gt; &#43;#else<br>

> &gt; &#43;#define TEST_ROUNDS (32 * 1024 * 1024) /**&lt; Test rounds for each thread */<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt;&nbsp; #define MAIN_THREAD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 /**&lt; Thread ID performing maintenance tasks */<br>

> &gt;<br>

> &gt;&nbsp; /* Default values for command line arguments */<br>

> &gt; @@ -104,6 &#43;110,9 @@ typedef union {<br>

> &gt;&nbsp; typedef struct {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; core_stat_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; core_stat[MAX_WORKERS]; /**&lt; Core specific stats */<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_barrier_t&nbsp;&nbsp;&nbsp; barrier; /**&lt; Barrier for thread synchronization */<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_t schedule_group;<br>

> &gt; &#43;#endif<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_pool_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool;&nbsp;&nbsp;&nbsp; /**&lt; Pool for allocating test events */<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test_args_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; args;&nbsp;&nbsp;&nbsp; /**&lt; Parsed command line arguments */<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue[NUM_PRIOS][MAX_QUEUES]; /**&lt; Scheduled queues */<br>

> &gt; @@ -119,7 &#43;128,11 @@ static void clear_sched_queues(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_event_t ev;<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (1) {<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ev = odp_schedule(NULL, ODP_SCHED_NO_WAIT);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Need a non-zero timeout to ensure we can observe<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * any non-empty queue made eligible for scheduling<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * by some other thread.<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ev = odp_schedule(NULL, 1000);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ev == ODP_EVENT_INVALID)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>

> &gt; @@ -428,6 &#43;441,20 @@ static int run_thread(void *arg ODP_UNUSED)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int err;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_t thrmask;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_zero(&amp;thrmask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_set(&amp;thrmask, thr);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = odp_schedule_group_join(globals-&gt;schedule_group, &amp;thrmask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (err != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOG_ERR(&quot;odp_schedule_group_join failed\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (thr == MAIN_THREAD) {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; args = &amp;globals-&gt;args;<br>

> &gt;<br>

> &gt; @@ -452,6 &#43;479,13 @@ static int run_thread(void *arg ODP_UNUSED)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (test_schedule(thr, globals))<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = odp_schedule_group_leave(globals-&gt;schedule_group, &amp;thrmask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (err != 0) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOG_ERR(&quot;odp_schedule_group_leave failed\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#endif<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>

> &gt;&nbsp; }<br>

> &gt;<br>

> &gt; @@ -692,6 &#43;726,31 @@ int main(int argc, char *argv[])<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; globals-&gt;pool = pool;<br>

> &gt;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Create scheduler group<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_t expected_thrmask;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int cpu;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int thr;<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_zero(&amp;expected_thrmask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* This is a odp_thrmask_from_cpumask() */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cpu = odp_cpumask_first(&amp;cpumask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thr = 1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (0 &lt;= cpu) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_thrmask_set(&amp;expected_thrmask, thr&#43;&#43;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cpu = odp_cpumask_next(&amp;cpumask, cpu);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; globals-&gt;schedule_group =<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_create(&quot;sg0&quot;, &amp;expected_thrmask);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (globals-&gt;schedule_group == ODP_SCHED_GROUP_INVALID) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOG_ERR(&quot;odp_schedule_group_create failed\n&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; &#43;#endif<br>

> &gt; &#43;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Create queues for schedule test<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>

> &gt; @@ -713,7 &#43;772,11 @@ int main(int argc, char *argv[])<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param.type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = ODP_QUEUE_TYPE_SCHED;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param.sched.prio&nbsp; = prio;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param.sched.sync&nbsp; = args.sync_type;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param.sched.group = globals-&gt;schedule_group;<br>

> &gt; &#43;#else<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; param.sched.group = ODP_SCHED_GROUP_ALL;<br>

> &gt; &#43;#endif<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (j = 0; j &lt; args.prio[i].queues; j&#43;&#43;) {<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name[9]&nbsp; = '0' &#43; j / 10;<br>

> &gt; @@ -758,6 &#43;821,10 @@ int main(int argc, char *argv[])<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt; &#43;<br>

> &gt; &#43;#ifdef ODP_SCHEDULE_SCALABLE<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret &#43;= odp_schedule_group_destroy(globals-&gt;schedule_group);<br>

> &gt; &#43;#endif<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret &#43;= odp_shm_free(shm);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret &#43;= odp_pool_destroy(pool);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret &#43;= odp_term_local();<br>

> &gt; diff --git a/test/common_plat/performance/odp_scheduling.c b/test/common_plat/performance/odp_scheduling.c<br>

> &gt; index c74a0713..38e76257 100644<br>

> &gt; --- a/test/common_plat/performance/odp_scheduling.c<br>

> &gt; &#43;&#43;&#43; b/test/common_plat/performance/odp_scheduling.c<br>

> &gt; @@ -273,7 &#43;273,7 @@ static int test_plain_queue(int thr, test_globals_t *globals)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test_message_t *t_msg;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_t queue;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t c1, c2, cycles;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i, j;<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Alloc test message */<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf = odp_buffer_alloc(globals-&gt;pool);<br>

> &gt; @@ -307,7 &#43;307,15 @@ static int test_plain_queue(int thr, test_globals_t *globals)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ev = odp_queue_deq(queue);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* When enqueue and dequeue are decoupled (e.g. not using a<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * common lock), an enqueued event may not be immediately<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * visible to dequeue. So we just try again for a while. */<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (j = 0; j &lt; 100; j&#43;&#43;) {<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ev = odp_queue_deq(queue);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ev != ODP_EVENT_INVALID)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cpu_pause();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf = odp_buffer_from_event(ev);<br>

> &gt;<br>

> &gt; diff --git a/test/common_plat/validation/api/classification/odp_classification_basic.c b/test/common_plat/validation/api/classification/odp_classification_basic.c<br>

> &gt; index 9817287e..b5b92851 100644<br>

> &gt; --- a/test/common_plat/validation/api/classification/odp_classification_basic.c<br>

> &gt; &#43;&#43;&#43; b/test/common_plat/validation/api/classification/odp_classification_basic.c<br>

> &gt; @@ -93,10 &#43;93,10 @@ void classification_test_create_pmr_match(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;pmr_match&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;pmr_match_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;pmr_match&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;pmr_match_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cls_cos_param_init(&amp;cls_param);<br>

> &gt; @@ -277,10 &#43;277,10 @@ void classification_test_pmr_composite_create(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;pmr_match&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;pmr_match_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;pmr_match&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;pmr_match_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_cls_cos_param_init(&amp;cls_param);<br>

> &gt; diff --git a/test/common_plat/validation/api/classification/odp_classification_test_pmr.c b/test/common_plat/validation/api/classification/odp_classification_test_pmr.c<br>

> &gt; index d9524205..c1da5159 100644<br>

> &gt; --- a/test/common_plat/validation/api/classification/odp_classification_test_pmr.c<br>

> &gt; &#43;&#43;&#43; b/test/common_plat/validation/api/classification/odp_classification_test_pmr.c<br>

> &gt; @@ -121,10 &#43;121,10 @@ void classification_test_pmr_term_tcp_dport(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;tcp_dport1&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;tcp_dport1_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;tcp_dport1&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;tcp_dport1_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;tcp_dport&quot;);<br>

> &gt; @@ -235,10 &#43;235,10 @@ void classification_test_pmr_term_tcp_sport(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;tcp_sport&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;tcp_sport_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;tcp_sport&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;tcp_sport_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;tcp_sport&quot;);<br>

> &gt; @@ -348,10 &#43;348,10 @@ void classification_test_pmr_term_udp_dport(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;udp_dport&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;udp_dport_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;udp_dport&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;udp_dport_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;udp_dport&quot;);<br>

> &gt; @@ -464,10 &#43;464,10 @@ void classification_test_pmr_term_udp_sport(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;udp_sport&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;udp_sport_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;udp_sport&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;udp_sport_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;udp_sport&quot;);<br>

> &gt; @@ -578,10 &#43;578,10 @@ void classification_test_pmr_term_ipproto(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;ipproto&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;ipproto_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;ipproto&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;ipproto_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;ipproto&quot;);<br>

> &gt; @@ -687,10 &#43;687,10 @@ void classification_test_pmr_term_dmac(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;dmac&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;dmac_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;dmac&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;dmac_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;dmac&quot;);<br>

> &gt; @@ -794,10 &#43;794,10 @@ void classification_test_pmr_term_packet_len(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;packet_len&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;packet_len_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;packet_len&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;packet_len_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;packet_len&quot;);<br>

> &gt; @@ -1355,10 &#43;1355,10 @@ static void classification_test_pmr_pool_set(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;ipproto1&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;ipproto1_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;ipproto1&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;ipproto1_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;ipproto1&quot;);<br>

> &gt; @@ -1454,10 &#43;1454,10 @@ static void classification_test_pmr_queue_set(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;ipproto1&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;ipproto1_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;ipproto1&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;ipproto1_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;ipproto1&quot;);<br>

> &gt; @@ -1469,7 &#43;1469,7 @@ static void classification_test_pmr_queue_set(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cos = odp_cls_cos_create(cosname, &amp;cls_param);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(cos != ODP_COS_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_new = queue_create(&quot;ipproto2&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue_new = queue_create(&quot;ipproto2_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue_new != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* new queue is set on CoS */<br>

> &gt; @@ -1546,10 &#43;1546,10 @@ static void classification_test_pmr_term_daddr(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; configure_default_cos(pktio, &amp;default_cos,<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;default_queue, &amp;default_pool);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;daddr&quot;, true);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = queue_create(&quot;daddr_queue&quot;, true);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(queue != ODP_QUEUE_INVALID);<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;daddr&quot;);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool = pool_create(&quot;daddr_pool&quot;);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(cosname, &quot;daddr&quot;);<br>

> &gt; diff --git a/test/common_plat/validation/api/scheduler/scheduler.c b/test/common_plat/validation/api/scheduler/scheduler.c<br>

> &gt; index 952561cd..bc486192 100644<br>

> &gt; --- a/test/common_plat/validation/api/scheduler/scheduler.c<br>

> &gt; &#43;&#43;&#43; b/test/common_plat/validation/api/scheduler/scheduler.c<br>

> &gt; @@ -251,7 &#43;251,10 @@ void scheduler_test_queue_destroy(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(u32[0] == MAGIC);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_free(buf);<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_release_ordered();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (qp.sched.sync == ODP_SCHED_SYNC_ATOMIC)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_release_atomic();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (qp.sched.sync == ODP_SCHED_SYNC_ORDERED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_release_ordered();<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(odp_queue_destroy(queue) == 0);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt; @@ -478,6 &#43;481,11 @@ void scheduler_test_groups(void)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_leave(mygrp1, &amp;mymask);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_group_leave(mygrp2, &amp;mymask);<br>

> &gt;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (qp.sched.sync == ODP_SCHED_SYNC_ATOMIC)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_release_atomic();<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (qp.sched.sync == ODP_SCHED_SYNC_ORDERED)<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_schedule_release_ordered();<br>

> &gt; &#43;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Done with queues for this round */<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(odp_queue_destroy(queue_grp1) == 0);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(odp_queue_destroy(queue_grp2) == 0);<br>

> &gt; @@ -959,7 &#43;967,6 @@ static void fill_queues(thread_args_t *args)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = odp_queue_enq(queue, ev);<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_ASSERT_FATAL(ret == 0);<br>

> &gt;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_buffer_free(buf);<br>

> &gt; diff --git a/test/common_plat/validation/api/timer/timer.c b/test/common_plat/validation/api/timer/timer.c<br>

> &gt; index b7d84c64..362f33c8 100644<br>

> &gt; --- a/test/common_plat/validation/api/timer/timer.c<br>

> &gt; &#43;&#43;&#43; b/test/common_plat/validation/api/timer/timer.c<br>

> &gt; @@ -297,8 &#43;297,11 @@ static int worker_entrypoint(void *arg TEST_UNUSED)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct timespec ts;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t nstale;<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_timer_set_t timer_rc;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char name[32];<br>

> &gt;<br>

> &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = odp_queue_create(&quot;timer_queue&quot;, NULL);<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snprintf(name, sizeof(name), &quot;timer_queue_%d&quot;, thr);<br>

> &gt; &#43;<br>

> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue = odp_queue_create(name, NULL);<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (queue == ODP_QUEUE_INVALID)<br>

> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CU_FAIL_FATAL(&quot;Queue create failed&quot;);<br>

> &gt;<br>

> &gt; --<br>

> &gt; 2.12.1<br>

> &gt;<br>

> </div></span></font>

> </body>

> </html>
Bill Fischofer March 29, 2017, 3:01 a.m. UTC | #5
First off, I'm not sure why you're seeing HTML since Gmail is set to plain
text mode for me.

On Tue, Mar 28, 2017 at 9:18 PM, Brian Brooks <brian.brooks@arm.com> wrote:

> On 03/28 18:50:32, Bill Fischofer wrote:

> > <html><head><meta http-equiv="Content-Type" content="text/html;

> charset=utf-8">

> > <meta name="Generator" content="Microsoft Exchange Server">

> > <!-- converted from text -->

> > <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt;

> border-left: #800000 2px solid; } --></style></head>

> > <body>

> > <font size="2"><span style="font-size:10pt;"><div class="PlainText">This

> part generates numerous checkpatch warnings and errors. Please<br>

> > run checkpatch and correct for v2.<br>

>

> We ran checkpatch.pl and corrected the issues that made sense. We all

> know that

> checkpatch.pl is not perfect. Please point out the checkpatch.pl issues

> that

> are generated from this patch which are not false positives or not

> destructive

> to programmer readability.

>


Checkpatch does issue a number of spurious warnings relating to the use of
volatile, etc. but the following seem legit:

WARNING: Possible unwrapped commit description (prefer a maximum 75 chars
per line)
#11:
respected, and (W)RR scheduling may be used within queues of the same
priority.

WARNING: 'absense' may be misspelled - perhaps 'absence'?
#16:
concurrent queues. LL/SC and CAS variants exist in cases where absense of

CHECK: No space is necessary after a cast
#171: FILE: platform/linux-generic/include/odp/api/plat/schedule_types.h:65:
+#define ODP_SCHED_GROUP_INVALID ((odp_schedule_group_t) -1)

CHECK: Alignment should match open parenthesis
#225: FILE: platform/linux-generic/include/odp_atomic16.h:45:
+static inline bool __atomic_compare_exchange_16(register __int128 *var,
+ __int128 *exp, register __int128 neu,

CHECK: Alignment should match open parenthesis
#271: FILE: platform/linux-generic/include/odp_atomic16.h:91:
+static inline bool __atomic_compare_exchange_16_frail(register __int128
*var,
+ __int128 *exp, register __int128 neu, bool weak,

CHECK: Alignment should match open parenthesis
#393: FILE: platform/linux-generic/include/odp_atomic16.h:213:
+static inline __int128 __atomic_fetch_or_16(__int128 *var,
+ __int128 mask,

CHECK: multiple assignments should be avoided
#856: FILE: platform/linux-generic/include/odp_llqueue.h:123:
+ llq->u.st.head = llq->u.st.tail = node;

CHECK: multiple assignments should be avoided
#965: FILE: platform/linux-generic/include/odp_llqueue.h:232:
+ llq->u.st.head = llq->u.st.tail = NULL;

CHECK: multiple assignments should be avoided
#1064: FILE: platform/linux-generic/include/odp_llqueue.h:331:
+ llq->u.st.head = llq->u.st.tail = NULL;


CHECK: Please use a blank line after function/struct/union/enum declarations
#1189: FILE: platform/linux-generic/include/odp_llsc.h:64:
+}
+#define ll32(a, b) ll((a), (b))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1205: FILE: platform/linux-generic/include/odp_llsc.h:80:
+}
+#define sc32(a, b, c) sc((a), (b), (c))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1220: FILE: platform/linux-generic/include/odp_llsc.h:95:
+}
+#define ll64(a, b) lld((a), (b))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1236: FILE: platform/linux-generic/include/odp_llsc.h:111:
+}
+#define sc64(a, b, c) scd((a), (b), (c))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1336: FILE: platform/linux-generic/include/odp_llsc.h:211:
+}
+#define ll64(a, b) ll((a), (b))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1357: FILE: platform/linux-generic/include/odp_llsc.h:232:
+}
+#define sc64(a, b, c) sc((a), (b), (c))


CHECK: Alignment should match open parenthesis
#1981: FILE:
platform/linux-generic/include/odp_schedule_ordered_internal.h:131:
+void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,
+ uint32_t lock_index);


WARNING: 'noone' may be misspelled - perhaps 'no one'?
#2402: FILE: platform/linux-generic/odp_queue_scalable.c:95:
+ /* All remaining elements claimed, noone else can enqueue */

CHECK: spaces preferred around that '<<' (ctx:VxV)
#2417: FILE: platform/linux-generic/odp_queue_scalable.c:110:
+ return 1<<i;
         ^

CHECK: Alignment should match open parenthesis
#2438: FILE: platform/linux-generic/odp_queue_scalable.c:131:
+ shm = odp_shm_reserve(name,
+ ring_size * sizeof(odp_buffer_hdr_t *),

CHECK: Alignment should match open parenthesis
#2698: FILE: platform/linux-generic/odp_queue_scalable.c:391:
+ while (__atomic_load_n(&q->qschst.numevts, __ATOMIC_RELAXED) != 0 ||
+ __atomic_load_n(&q->qschst.cur_ticket, __ATOMIC_RELAXED) !=


WARNING: macros should not use a trailing semicolon
#3366: FILE: platform/linux-generic/odp_schedule_scalable.c:55:
+#define __atomic_fetch_max(var, v, mo) do { \
+ /* Evalulate 'v' once */ \
+ __typeof__(v) tmp_v = (v); \
+ __typeof__(*var) old_var = \
+ __atomic_load_n((var), __ATOMIC_RELAXED); \
+ while (tmp_v > old_var) { \
+ /* Attempt to store 'v' in '*var' */ \
+ if (__atomic_compare_exchange_n((var), &old_var, \
+ tmp_v, true, (mo), \
+ (mo))) \
+ break; \
+ /* Else failure, try again (with updated value of \

WARNING: Avoid unnecessary line continuations
#3379: FILE: platform/linux-generic/odp_schedule_scalable.c:68:
+ */ \

CHECK: Alignment should match open parenthesis
#3581: FILE: platform/linux-generic/odp_schedule_scalable.c:270:
+       LDXR8(&q->qschst.cur_ticket,
+      __ATOMIC_ACQUIRE) != ticket)

CHECK: Alignment should match open parenthesis
#3659: FILE: platform/linux-generic/odp_schedule_scalable.c:348:
+static void sched_update_deq(sched_elem_t *q,
+ uint32_t actual, bool atomic) __attribute__((always_inline));

CHECK: Alignment should match open parenthesis
#3661: FILE: platform/linux-generic/odp_schedule_scalable.c:350:
+static inline void sched_update_deq(sched_elem_t *q,
+ uint32_t actual, bool atomic)

CHECK: Alignment should match open parenthesis
#3745: FILE: platform/linux-generic/odp_schedule_scalable.c:434:
+       LDXR8(&q->qschst.cur_ticket,
+      __ATOMIC_ACQUIRE) != ticket)

CHECK: Alignment should match open parenthesis
#3791: FILE: platform/linux-generic/odp_schedule_scalable.c:480:
+static void sched_update_deq_sc(sched_elem_t *q,
+ uint32_t actual, bool atomic) __attribute__((always_inline));

CHECK: Alignment should match open parenthesis
#3793: FILE: platform/linux-generic/odp_schedule_scalable.c:482:
+static inline void sched_update_deq_sc(sched_elem_t *q,
+ uint32_t actual, bool atomic)

CHECK: Alignment should match open parenthesis
#3977: FILE: platform/linux-generic/odp_schedule_scalable.c:666:
+ sg_wanted = __atomic_load_n(&ts->sg_wanted[p],
+ __ATOMIC_ACQUIRE);

CHECK: Alignment should match open parenthesis
#3989: FILE: platform/linux-generic/odp_schedule_scalable.c:678:
+ insert_schedq_in_list(ts,
+ &sg->schedq[p * sg->xfactor +

CHECK: Alignment should match open parenthesis
#4002: FILE: platform/linux-generic/odp_schedule_scalable.c:691:
+ remove_schedq_from_list(ts,
+    &sg->schedq[p * sg->xfactor + x]);

CHECK: multiple assignments should be avoided
#4171: FILE: platform/linux-generic/odp_schedule_scalable.c:860:
+ ts->atomq = atomq = elem;

CHECK: Alignment should match open parenthesis
#4256: FILE: platform/linux-generic/odp_schedule_scalable.c:945:
+ if (odp_unlikely(__atomic_load_n(&rwin->turn,
+ __ATOMIC_ACQUIRE) != sn)) {


CHECK: Alignment should match open parenthesis
#4584: FILE: platform/linux-generic/odp_schedule_scalable.c:1273:
+ __atomic_store_n(&thread_state[thr].sg_sem,
+ 1,

CHECK: Alignment should match open parenthesis
#4656: FILE: platform/linux-generic/odp_schedule_scalable.c:1345:
+ shm = odp_shm_reserve(name ? name : "",
+     (sizeof(sched_group_t) +

CHECK: No space is necessary after a cast
#4664: FILE: platform/linux-generic/odp_schedule_scalable.c:1353:
+ sg = (sched_group_t *) odp_shm_addr(shm);

CHECK: No space is necessary after a cast
#4684: FILE: platform/linux-generic/odp_schedule_scalable.c:1373:
+ return (odp_schedule_group_t) (sgi);

CHECK: Alignment should match open parenthesis
#5054: FILE: platform/linux-generic/odp_schedule_scalable.c:1743:
+ if (odp_schedule_group_join(ODP_SCHED_GROUP_CONTROL,
+ &mask) != 0) {

CHECK: Alignment should match open parenthesis
#5060: FILE: platform/linux-generic/odp_schedule_scalable.c:1749:
+ if (odp_schedule_group_join(ODP_SCHED_GROUP_WORKER,
+ &mask) != 0) {

CHECK: Alignment should match open parenthesis
#5096: FILE: platform/linux-generic/odp_schedule_scalable.c:1785:
+ if (odp_schedule_group_leave(ODP_SCHED_GROUP_CONTROL,
+ &mask) != 0)

CHECK: Alignment should match open parenthesis
#5100: FILE: platform/linux-generic/odp_schedule_scalable.c:1789:
+ if (odp_schedule_group_leave(ODP_SCHED_GROUP_WORKER,
+ &mask) != 0)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5185: FILE: platform/linux-generic/odp_schedule_scalable.c:1874:
+}
+static int thr_rem(odp_schedule_group_t group, int thr)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5192: FILE: platform/linux-generic/odp_schedule_scalable.c:1881:
+}
+static int init_queue(uint32_t queue_index,

CHECK: Please use a blank line after function/struct/union/enum declarations
#5200: FILE: platform/linux-generic/odp_schedule_scalable.c:1889:
+}
+static void destroy_queue(uint32_t queue_index)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5205: FILE: platform/linux-generic/odp_schedule_scalable.c:1894:
+}
+static int sched_queue(uint32_t queue_index)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5211: FILE: platform/linux-generic/odp_schedule_scalable.c:1900:
+}
+static int ord_enq_multi(uint32_t queue_index, void *p_buf_hdr[],


CHECK: No space is necessary after a cast
#5314: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:38:
+ rwin = (reorder_window_t *) odp_shm_addr(*shm);

CHECK: Alignment should match open parenthesis
#5408: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:132:
+ if (__atomic_compare_exchange(&rwin->hc,
+ &old, /* Updated on failure */

CHECK: Please don't use multiple blank lines
#5757: FILE: test/common_plat/performance/odp_sched_latency.c:824:

+

total: 0 errors, 54 warnings, 44 checks, 5742 lines checked

NOTE: Ignored message types: BIT_MACRO COMPARISON_TO_NULL
DEPRECATED_VARIABLE NEW_TYPEDEFS SPLIT_STRING SSCANF_TO_KSTRTO

0004-A-scalable-software-scheduler.patch has style problems, please review.

If any of these errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.


> > <br>

> > Also, this part introduces a number of errors that result in failure<br>

> > to compile using clang.

>

> This is likely true. Is compilation with Clang a blocker?

>


Yes, it is. We require ODP modules to be compilable with either GCC or
clang.


>

>
Honnappa Nagarahalli March 29, 2017, 3:28 a.m. UTC | #6
I had run the checkpatch.pl, but I did not see these issues. May be it was to do with the way I generated the patch. I will address the ones that make sense.

Do we have to compile for 32b with gcc?

From: Bill Fischofer [mailto:bill.fischofer@linaro.org]

Sent: Tuesday, March 28, 2017 10:01 PM
To: Brian Brooks
Cc: lng-odp-forward; Ola Liljedahl; Kevin Wang; Honnappa Nagarahalli
Subject: Re: [lng-odp] [API-NEXT 4/4] A scalable software scheduler

First off, I'm not sure why you're seeing HTML since Gmail is set to plain text mode for me.

On Tue, Mar 28, 2017 at 9:18 PM, Brian Brooks <brian.brooks@arm.com> wrote:
On 03/28 18:50:32, Bill Fischofer wrote:
> <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">

> <meta name="Generator" content="Microsoft Exchange Server">

> <!-- converted from text -->

> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style></head>

> <body>

> <font size="2"><span style="font-size:10pt;"><div class="PlainText">This part generates numerous checkpatch warnings and errors. Please<br>

> run checkpatch and correct for v2.<br>


We ran checkpatch.pl and corrected the issues that made sense. We all know that
checkpatch.pl is not perfect. Please point out the checkpatch.pl issues that
are generated from this patch which are not false positives or not destructive
to programmer readability.

Checkpatch does issue a number of spurious warnings relating to the use of volatile, etc. but the following seem legit:

WARNING: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#11:
respected, and (W)RR scheduling may be used within queues of the same priority.

WARNING: 'absense' may be misspelled - perhaps 'absence'?
#16:
concurrent queues. LL/SC and CAS variants exist in cases where absense of

CHECK: No space is necessary after a cast
#171: FILE: platform/linux-generic/include/odp/api/plat/schedule_types.h:65:
+#define ODP_SCHED_GROUP_INVALID ((odp_schedule_group_t) -1)

CHECK: Alignment should match open parenthesis
#225: FILE: platform/linux-generic/include/odp_atomic16.h:45:
+static inline bool __atomic_compare_exchange_16(register __int128 *var,
+__int128 *exp, register __int128 neu,

CHECK: Alignment should match open parenthesis
#271: FILE: platform/linux-generic/include/odp_atomic16.h:91:
+static inline bool __atomic_compare_exchange_16_frail(register __int128 *var,
+__int128 *exp, register __int128 neu, bool weak,

CHECK: Alignment should match open parenthesis
#393: FILE: platform/linux-generic/include/odp_atomic16.h:213:
+static inline __int128 __atomic_fetch_or_16(__int128 *var,
+__int128 mask,

CHECK: multiple assignments should be avoided
#856: FILE: platform/linux-generic/include/odp_llqueue.h:123:
+llq->u.st.head = llq->u.st.tail = node;

CHECK: multiple assignments should be avoided
#965: FILE: platform/linux-generic/include/odp_llqueue.h:232:
+llq->u.st.head = llq->u.st.tail = NULL;

CHECK: multiple assignments should be avoided
#1064: FILE: platform/linux-generic/include/odp_llqueue.h:331:
+llq->u.st.head = llq->u.st.tail = NULL;


CHECK: Please use a blank line after function/struct/union/enum declarations
#1189: FILE: platform/linux-generic/include/odp_llsc.h:64:
+}
+#define ll32(a, b) ll((a), (b))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1205: FILE: platform/linux-generic/include/odp_llsc.h:80:
+}
+#define sc32(a, b, c) sc((a), (b), (c))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1220: FILE: platform/linux-generic/include/odp_llsc.h:95:
+}
+#define ll64(a, b) lld((a), (b))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1236: FILE: platform/linux-generic/include/odp_llsc.h:111:
+}
+#define sc64(a, b, c) scd((a), (b), (c))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1336: FILE: platform/linux-generic/include/odp_llsc.h:211:
+}
+#define ll64(a, b) ll((a), (b))


CHECK: Please use a blank line after function/struct/union/enum declarations
#1357: FILE: platform/linux-generic/include/odp_llsc.h:232:
+}
+#define sc64(a, b, c) sc((a), (b), (c))


CHECK: Alignment should match open parenthesis
#1981: FILE: platform/linux-generic/include/odp_schedule_ordered_internal.h:131:
+void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,
+ uint32_t lock_index);


WARNING: 'noone' may be misspelled - perhaps 'no one'?
#2402: FILE: platform/linux-generic/odp_queue_scalable.c:95:
+/* All remaining elements claimed, noone else can enqueue */

CHECK: spaces preferred around that '<<' (ctx:VxV)
#2417: FILE: platform/linux-generic/odp_queue_scalable.c:110:
+return 1<<i;
         ^

CHECK: Alignment should match open parenthesis
#2438: FILE: platform/linux-generic/odp_queue_scalable.c:131:
+shm = odp_shm_reserve(name,
+ring_size * sizeof(odp_buffer_hdr_t *),

CHECK: Alignment should match open parenthesis
#2698: FILE: platform/linux-generic/odp_queue_scalable.c:391:
+while (__atomic_load_n(&q->qschst.numevts, __ATOMIC_RELAXED) != 0 ||
+__atomic_load_n(&q->qschst.cur_ticket, __ATOMIC_RELAXED) !=


WARNING: macros should not use a trailing semicolon
#3366: FILE: platform/linux-generic/odp_schedule_scalable.c:55:
+#define __atomic_fetch_max(var, v, mo) do { \
+/* Evalulate 'v' once */ \
+__typeof__(v) tmp_v = (v); \
+__typeof__(*var) old_var = \
+__atomic_load_n((var), __ATOMIC_RELAXED); \
+while (tmp_v > old_var) { \
+/* Attempt to store 'v' in '*var' */ \
+if (__atomic_compare_exchange_n((var), &old_var, \
+tmp_v, true, (mo), \
+(mo))) \
+break; \
+/* Else failure, try again (with updated value of \

WARNING: Avoid unnecessary line continuations
#3379: FILE: platform/linux-generic/odp_schedule_scalable.c:68:
+ */ \

CHECK: Alignment should match open parenthesis
#3581: FILE: platform/linux-generic/odp_schedule_scalable.c:270:
+       LDXR8(&q->qschst.cur_ticket,
+      __ATOMIC_ACQUIRE) != ticket)

CHECK: Alignment should match open parenthesis
#3659: FILE: platform/linux-generic/odp_schedule_scalable.c:348:
+static void sched_update_deq(sched_elem_t *q,
+uint32_t actual, bool atomic) __attribute__((always_inline));

CHECK: Alignment should match open parenthesis
#3661: FILE: platform/linux-generic/odp_schedule_scalable.c:350:
+static inline void sched_update_deq(sched_elem_t *q,
+uint32_t actual, bool atomic)

CHECK: Alignment should match open parenthesis
#3745: FILE: platform/linux-generic/odp_schedule_scalable.c:434:
+       LDXR8(&q->qschst.cur_ticket,
+      __ATOMIC_ACQUIRE) != ticket)

CHECK: Alignment should match open parenthesis
#3791: FILE: platform/linux-generic/odp_schedule_scalable.c:480:
+static void sched_update_deq_sc(sched_elem_t *q,
+uint32_t actual, bool atomic) __attribute__((always_inline));

CHECK: Alignment should match open parenthesis
#3793: FILE: platform/linux-generic/odp_schedule_scalable.c:482:
+static inline void sched_update_deq_sc(sched_elem_t *q,
+uint32_t actual, bool atomic)

CHECK: Alignment should match open parenthesis
#3977: FILE: platform/linux-generic/odp_schedule_scalable.c:666:
+sg_wanted = __atomic_load_n(&ts->sg_wanted[p],
+__ATOMIC_ACQUIRE);

CHECK: Alignment should match open parenthesis
#3989: FILE: platform/linux-generic/odp_schedule_scalable.c:678:
+insert_schedq_in_list(ts,
+&sg->schedq[p * sg->xfactor +

CHECK: Alignment should match open parenthesis
#4002: FILE: platform/linux-generic/odp_schedule_scalable.c:691:
+remove_schedq_from_list(ts,
+    &sg->schedq[p * sg->xfactor + x]);

CHECK: multiple assignments should be avoided
#4171: FILE: platform/linux-generic/odp_schedule_scalable.c:860:
+ts->atomq = atomq = elem;

CHECK: Alignment should match open parenthesis
#4256: FILE: platform/linux-generic/odp_schedule_scalable.c:945:
+if (odp_unlikely(__atomic_load_n(&rwin->turn,
+ __ATOMIC_ACQUIRE) != sn)) {


CHECK: Alignment should match open parenthesis
#4584: FILE: platform/linux-generic/odp_schedule_scalable.c:1273:
+__atomic_store_n(&thread_state[thr].sg_sem,
+1,

CHECK: Alignment should match open parenthesis
#4656: FILE: platform/linux-generic/odp_schedule_scalable.c:1345:
+shm = odp_shm_reserve(name ? name : "",
+     (sizeof(sched_group_t) +

CHECK: No space is necessary after a cast
#4664: FILE: platform/linux-generic/odp_schedule_scalable.c:1353:
+sg = (sched_group_t *) odp_shm_addr(shm);

CHECK: No space is necessary after a cast
#4684: FILE: platform/linux-generic/odp_schedule_scalable.c:1373:
+return (odp_schedule_group_t) (sgi);

CHECK: Alignment should match open parenthesis
#5054: FILE: platform/linux-generic/odp_schedule_scalable.c:1743:
+if (odp_schedule_group_join(ODP_SCHED_GROUP_CONTROL,
+&mask) != 0) {

CHECK: Alignment should match open parenthesis
#5060: FILE: platform/linux-generic/odp_schedule_scalable.c:1749:
+if (odp_schedule_group_join(ODP_SCHED_GROUP_WORKER,
+&mask) != 0) {

CHECK: Alignment should match open parenthesis
#5096: FILE: platform/linux-generic/odp_schedule_scalable.c:1785:
+if (odp_schedule_group_leave(ODP_SCHED_GROUP_CONTROL,
+&mask) != 0)

CHECK: Alignment should match open parenthesis
#5100: FILE: platform/linux-generic/odp_schedule_scalable.c:1789:
+if (odp_schedule_group_leave(ODP_SCHED_GROUP_WORKER,
+&mask) != 0)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5185: FILE: platform/linux-generic/odp_schedule_scalable.c:1874:
+}
+static int thr_rem(odp_schedule_group_t group, int thr)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5192: FILE: platform/linux-generic/odp_schedule_scalable.c:1881:
+}
+static int init_queue(uint32_t queue_index,

CHECK: Please use a blank line after function/struct/union/enum declarations
#5200: FILE: platform/linux-generic/odp_schedule_scalable.c:1889:
+}
+static void destroy_queue(uint32_t queue_index)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5205: FILE: platform/linux-generic/odp_schedule_scalable.c:1894:
+}
+static int sched_queue(uint32_t queue_index)

CHECK: Please use a blank line after function/struct/union/enum declarations
#5211: FILE: platform/linux-generic/odp_schedule_scalable.c:1900:
+}
+static int ord_enq_multi(uint32_t queue_index, void *p_buf_hdr[],


CHECK: No space is necessary after a cast
#5314: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:38:
+rwin = (reorder_window_t *) odp_shm_addr(*shm);

CHECK: Alignment should match open parenthesis
#5408: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:132:
+if (__atomic_compare_exchange(&rwin->hc,
+&old, /* Updated on failure */

CHECK: Please don't use multiple blank lines
#5757: FILE: test/common_plat/performance/odp_sched_latency.c:824:

+

total: 0 errors, 54 warnings, 44 checks, 5742 lines checked

NOTE: Ignored message types: BIT_MACRO COMPARISON_TO_NULL DEPRECATED_VARIABLE NEW_TYPEDEFS SPLIT_STRING SSCANF_TO_KSTRTO

0004-A-scalable-software-scheduler.patch has style problems, please review.

If any of these errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.


> <br>

> Also, this part introduces a number of errors that result in failure<br>

> to compile using clang.


This is likely true. Is compilation with Clang a blocker?

Yes, it is. We require ODP modules to be compilable with either GCC or clang.


IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
Bill Fischofer March 29, 2017, 3:30 a.m. UTC | #7
On Tue, Mar 28, 2017 at 10:28 PM, Honnappa Nagarahalli <
Honnappa.Nagarahalli@arm.com> wrote:

> I had run the checkpatch.pl, but I did not see these issues. May be it

> was to do with the way I generated the patch. I will address the ones that

> make sense.

>


I did a git am for your patches and then regenerated them for checkpatch
testing via:
git format-patch origin/api-next --subject-prefix="API-NEXT PATCH"


>

> Do we have to compile for 32b with gcc?

>


Yes, we require that ODP code compile and run in both 32-bit and 64-bit
mode.


>

> From: Bill Fischofer [mailto:bill.fischofer@linaro.org]

> Sent: Tuesday, March 28, 2017 10:01 PM

> To: Brian Brooks

> Cc: lng-odp-forward; Ola Liljedahl; Kevin Wang; Honnappa Nagarahalli

> Subject: Re: [lng-odp] [API-NEXT 4/4] A scalable software scheduler

>

> First off, I'm not sure why you're seeing HTML since Gmail is set to plain

> text mode for me.

>

> On Tue, Mar 28, 2017 at 9:18 PM, Brian Brooks <brian.brooks@arm.com>

> wrote:

> On 03/28 18:50:32, Bill Fischofer wrote:

> > <html><head><meta http-equiv="Content-Type" content="text/html;

> charset=utf-8">

> > <meta name="Generator" content="Microsoft Exchange Server">

> > <!-- converted from text -->

> > <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt;

> border-left: #800000 2px solid; } --></style></head>

> > <body>

> > <font size="2"><span style="font-size:10pt;"><div class="PlainText">This

> part generates numerous checkpatch warnings and errors. Please<br>

> > run checkpatch and correct for v2.<br>

>

> We ran checkpatch.pl and corrected the issues that made sense. We all

> know that

> checkpatch.pl is not perfect. Please point out the checkpatch.pl issues

> that

> are generated from this patch which are not false positives or not

> destructive

> to programmer readability.

>

> Checkpatch does issue a number of spurious warnings relating to the use of

> volatile, etc. but the following seem legit:

>

> WARNING: Possible unwrapped commit description (prefer a maximum 75 chars

> per line)

> #11:

> respected, and (W)RR scheduling may be used within queues of the same

> priority.

>

> WARNING: 'absense' may be misspelled - perhaps 'absence'?

> #16:

> concurrent queues. LL/SC and CAS variants exist in cases where absense of

>

> CHECK: No space is necessary after a cast

> #171: FILE: platform/linux-generic/include/odp/api/plat/schedule_

> types.h:65:

> +#define ODP_SCHED_GROUP_INVALID ((odp_schedule_group_t) -1)

>

> CHECK: Alignment should match open parenthesis

> #225: FILE: platform/linux-generic/include/odp_atomic16.h:45:

> +static inline bool __atomic_compare_exchange_16(register __int128 *var,

> +__int128 *exp, register __int128 neu,

>

> CHECK: Alignment should match open parenthesis

> #271: FILE: platform/linux-generic/include/odp_atomic16.h:91:

> +static inline bool __atomic_compare_exchange_16_frail(register __int128

> *var,

> +__int128 *exp, register __int128 neu, bool weak,

>

> CHECK: Alignment should match open parenthesis

> #393: FILE: platform/linux-generic/include/odp_atomic16.h:213:

> +static inline __int128 __atomic_fetch_or_16(__int128 *var,

> +__int128 mask,

>

> CHECK: multiple assignments should be avoided

> #856: FILE: platform/linux-generic/include/odp_llqueue.h:123:

> +llq->u.st.head = llq->u.st.tail = node;

>

> CHECK: multiple assignments should be avoided

> #965: FILE: platform/linux-generic/include/odp_llqueue.h:232:

> +llq->u.st.head = llq->u.st.tail = NULL;

>

> CHECK: multiple assignments should be avoided

> #1064: FILE: platform/linux-generic/include/odp_llqueue.h:331:

> +llq->u.st.head = llq->u.st.tail = NULL;

>

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #1189: FILE: platform/linux-generic/include/odp_llsc.h:64:

> +}

> +#define ll32(a, b) ll((a), (b))

>

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #1205: FILE: platform/linux-generic/include/odp_llsc.h:80:

> +}

> +#define sc32(a, b, c) sc((a), (b), (c))

>

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #1220: FILE: platform/linux-generic/include/odp_llsc.h:95:

> +}

> +#define ll64(a, b) lld((a), (b))

>

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #1236: FILE: platform/linux-generic/include/odp_llsc.h:111:

> +}

> +#define sc64(a, b, c) scd((a), (b), (c))

>

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #1336: FILE: platform/linux-generic/include/odp_llsc.h:211:

> +}

> +#define ll64(a, b) ll((a), (b))

>

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #1357: FILE: platform/linux-generic/include/odp_llsc.h:232:

> +}

> +#define sc64(a, b, c) sc((a), (b), (c))

>

>

> CHECK: Alignment should match open parenthesis

> #1981: FILE: platform/linux-generic/include/odp_schedule_ordered_

> internal.h:131:

> +void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,

> + uint32_t lock_index);

>

>

> WARNING: 'noone' may be misspelled - perhaps 'no one'?

> #2402: FILE: platform/linux-generic/odp_queue_scalable.c:95:

> +/* All remaining elements claimed, noone else can enqueue */

>

> CHECK: spaces preferred around that '<<' (ctx:VxV)

> #2417: FILE: platform/linux-generic/odp_queue_scalable.c:110:

> +return 1<<i;

>          ^

>

> CHECK: Alignment should match open parenthesis

> #2438: FILE: platform/linux-generic/odp_queue_scalable.c:131:

> +shm = odp_shm_reserve(name,

> +ring_size * sizeof(odp_buffer_hdr_t *),

>

> CHECK: Alignment should match open parenthesis

> #2698: FILE: platform/linux-generic/odp_queue_scalable.c:391:

> +while (__atomic_load_n(&q->qschst.numevts, __ATOMIC_RELAXED) != 0 ||

> +__atomic_load_n(&q->qschst.cur_ticket, __ATOMIC_RELAXED) !=

>

>

> WARNING: macros should not use a trailing semicolon

> #3366: FILE: platform/linux-generic/odp_schedule_scalable.c:55:

> +#define __atomic_fetch_max(var, v, mo) do { \

> +/* Evalulate 'v' once */ \

> +__typeof__(v) tmp_v = (v); \

> +__typeof__(*var) old_var = \

> +__atomic_load_n((var), __ATOMIC_RELAXED); \

> +while (tmp_v > old_var) { \

> +/* Attempt to store 'v' in '*var' */ \

> +if (__atomic_compare_exchange_n((var), &old_var, \

> +tmp_v, true, (mo), \

> +(mo))) \

> +break; \

> +/* Else failure, try again (with updated value of \

>

> WARNING: Avoid unnecessary line continuations

> #3379: FILE: platform/linux-generic/odp_schedule_scalable.c:68:

> + */ \

>

> CHECK: Alignment should match open parenthesis

> #3581: FILE: platform/linux-generic/odp_schedule_scalable.c:270:

> +       LDXR8(&q->qschst.cur_ticket,

> +      __ATOMIC_ACQUIRE) != ticket)

>

> CHECK: Alignment should match open parenthesis

> #3659: FILE: platform/linux-generic/odp_schedule_scalable.c:348:

> +static void sched_update_deq(sched_elem_t *q,

> +uint32_t actual, bool atomic) __attribute__((always_inline));

>

> CHECK: Alignment should match open parenthesis

> #3661: FILE: platform/linux-generic/odp_schedule_scalable.c:350:

> +static inline void sched_update_deq(sched_elem_t *q,

> +uint32_t actual, bool atomic)

>

> CHECK: Alignment should match open parenthesis

> #3745: FILE: platform/linux-generic/odp_schedule_scalable.c:434:

> +       LDXR8(&q->qschst.cur_ticket,

> +      __ATOMIC_ACQUIRE) != ticket)

>

> CHECK: Alignment should match open parenthesis

> #3791: FILE: platform/linux-generic/odp_schedule_scalable.c:480:

> +static void sched_update_deq_sc(sched_elem_t *q,

> +uint32_t actual, bool atomic) __attribute__((always_inline));

>

> CHECK: Alignment should match open parenthesis

> #3793: FILE: platform/linux-generic/odp_schedule_scalable.c:482:

> +static inline void sched_update_deq_sc(sched_elem_t *q,

> +uint32_t actual, bool atomic)

>

> CHECK: Alignment should match open parenthesis

> #3977: FILE: platform/linux-generic/odp_schedule_scalable.c:666:

> +sg_wanted = __atomic_load_n(&ts->sg_wanted[p],

> +__ATOMIC_ACQUIRE);

>

> CHECK: Alignment should match open parenthesis

> #3989: FILE: platform/linux-generic/odp_schedule_scalable.c:678:

> +insert_schedq_in_list(ts,

> +&sg->schedq[p * sg->xfactor +

>

> CHECK: Alignment should match open parenthesis

> #4002: FILE: platform/linux-generic/odp_schedule_scalable.c:691:

> +remove_schedq_from_list(ts,

> +    &sg->schedq[p * sg->xfactor + x]);

>

> CHECK: multiple assignments should be avoided

> #4171: FILE: platform/linux-generic/odp_schedule_scalable.c:860:

> +ts->atomq = atomq = elem;

>

> CHECK: Alignment should match open parenthesis

> #4256: FILE: platform/linux-generic/odp_schedule_scalable.c:945:

> +if (odp_unlikely(__atomic_load_n(&rwin->turn,

> + __ATOMIC_ACQUIRE) != sn)) {

>

>

> CHECK: Alignment should match open parenthesis

> #4584: FILE: platform/linux-generic/odp_schedule_scalable.c:1273:

> +__atomic_store_n(&thread_state[thr].sg_sem,

> +1,

>

> CHECK: Alignment should match open parenthesis

> #4656: FILE: platform/linux-generic/odp_schedule_scalable.c:1345:

> +shm = odp_shm_reserve(name ? name : "",

> +     (sizeof(sched_group_t) +

>

> CHECK: No space is necessary after a cast

> #4664: FILE: platform/linux-generic/odp_schedule_scalable.c:1353:

> +sg = (sched_group_t *) odp_shm_addr(shm);

>

> CHECK: No space is necessary after a cast

> #4684: FILE: platform/linux-generic/odp_schedule_scalable.c:1373:

> +return (odp_schedule_group_t) (sgi);

>

> CHECK: Alignment should match open parenthesis

> #5054: FILE: platform/linux-generic/odp_schedule_scalable.c:1743:

> +if (odp_schedule_group_join(ODP_SCHED_GROUP_CONTROL,

> +&mask) != 0) {

>

> CHECK: Alignment should match open parenthesis

> #5060: FILE: platform/linux-generic/odp_schedule_scalable.c:1749:

> +if (odp_schedule_group_join(ODP_SCHED_GROUP_WORKER,

> +&mask) != 0) {

>

> CHECK: Alignment should match open parenthesis

> #5096: FILE: platform/linux-generic/odp_schedule_scalable.c:1785:

> +if (odp_schedule_group_leave(ODP_SCHED_GROUP_CONTROL,

> +&mask) != 0)

>

> CHECK: Alignment should match open parenthesis

> #5100: FILE: platform/linux-generic/odp_schedule_scalable.c:1789:

> +if (odp_schedule_group_leave(ODP_SCHED_GROUP_WORKER,

> +&mask) != 0)

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #5185: FILE: platform/linux-generic/odp_schedule_scalable.c:1874:

> +}

> +static int thr_rem(odp_schedule_group_t group, int thr)

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #5192: FILE: platform/linux-generic/odp_schedule_scalable.c:1881:

> +}

> +static int init_queue(uint32_t queue_index,

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #5200: FILE: platform/linux-generic/odp_schedule_scalable.c:1889:

> +}

> +static void destroy_queue(uint32_t queue_index)

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #5205: FILE: platform/linux-generic/odp_schedule_scalable.c:1894:

> +}

> +static int sched_queue(uint32_t queue_index)

>

> CHECK: Please use a blank line after function/struct/union/enum

> declarations

> #5211: FILE: platform/linux-generic/odp_schedule_scalable.c:1900:

> +}

> +static int ord_enq_multi(uint32_t queue_index, void *p_buf_hdr[],

>

>

> CHECK: No space is necessary after a cast

> #5314: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:38:

> +rwin = (reorder_window_t *) odp_shm_addr(*shm);

>

> CHECK: Alignment should match open parenthesis

> #5408: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:132:

> +if (__atomic_compare_exchange(&rwin->hc,

> +&old, /* Updated on failure */

>

> CHECK: Please don't use multiple blank lines

> #5757: FILE: test/common_plat/performance/odp_sched_latency.c:824:

>

> +

>

> total: 0 errors, 54 warnings, 44 checks, 5742 lines checked

>

> NOTE: Ignored message types: BIT_MACRO COMPARISON_TO_NULL

> DEPRECATED_VARIABLE NEW_TYPEDEFS SPLIT_STRING SSCANF_TO_KSTRTO

>

> 0004-A-scalable-software-scheduler.patch has style problems, please

> review.

>

> If any of these errors are false positives, please report

> them to the maintainer, see CHECKPATCH in MAINTAINERS.

>

>

> > <br>

> > Also, this part introduces a number of errors that result in failure<br>

> > to compile using clang.

>

> This is likely true. Is compilation with Clang a blocker?

>

> Yes, it is. We require ODP modules to be compilable with either GCC or

> clang.

>

>

> IMPORTANT NOTICE: The contents of this email and any attachments are

> confidential and may also be privileged. If you are not the intended

> recipient, please notify the sender immediately and do not disclose the

> contents to any other person, use it for any purpose, or store or copy the

> information in any medium. Thank you.

>
Maxim Uvarov March 29, 2017, 7:27 a.m. UTC | #8
isn't queue size connected to number elements in the pool?

Maxim.

On 29 March 2017 at 04:55, Brian Brooks <brian.brooks@arm.com> wrote:

> On 03/28 19:18:37, Bill Fischofer wrote:

> > <html><head><meta http-equiv="Content-Type" content="text/html;

> charset=utf-8">

>

> It is infinitely better to do patch review in plain text rather

> than HTML. I thought this was a plain text mailing list?

>

> > <meta name="Generator" content="Microsoft Exchange Server">

> > <!-- converted from text -->

> > <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt;

> border-left: #800000 2px solid; } --></style></head>

> > <body>

> > <font size="2"><span style="font-size:10pt;"><div class="PlainText">On

> Tue, Mar 28, 2017 at 2:23 PM, Brian Brooks &lt;brian.brooks@arm.com&gt;

> wrote:<br>

> > &gt; Signed-off-by: Brian Brooks &lt;brian.brooks@arm.com&gt;<br>

> > &gt; ---<br>

> > &gt;&nbsp; include/odp/api/spec/queue.h | 5 &#43;&#43;&#43;&#43;&#43;<br>

> > &gt;&nbsp; 1 file changed, 5 insertions(&#43;)<br>

> > &gt;<br>

> > &gt; diff --git a/include/odp/api/spec/queue.h

> b/include/odp/api/spec/queue.h<br>

> > &gt; index 7972feac..1cec4773 100644<br>

> > &gt; --- a/include/odp/api/spec/queue.h<br>

> > &gt; &#43;&#43;&#43; b/include/odp/api/spec/queue.h<br>

> > &gt; @@ -124,6 &#43;124,11 @@ typedef struct odp_queue_param_t {<br>

> > &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the

> queue type. */<br>

> > &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_type_t

> type;<br>

> > &gt;<br>

> > &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Queue size<br>

> > &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>

> > &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Indicates

> the max ring size of the ring buffer. */<br>

> > &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ring_size;<br>

> > <br>

> > ODP queues have historically been of unspecified size. If we're going<br>

> > to introduce the notion of explicitly limited sized queues this has<br>

> > additional implications.<br>

> >

> > First, ring_size is an inappropriate choice of name here since a ring<br>

> > is an implementation model, not a specification. The documentation<br>

> > says &quot;Queue size&quot;, so<br>

> > <br>

> > uint32_t size;<br>

> > <br>

> > is sufficient here.

>

> Agree, will change 'ring_size' to a better name.

>

> > We should document that size = 0 requests a queue<br>

> > of default size (which may be unbounded).<br>

>

> Unbounded size is not practical or possible. Can we agree that 0 means

> that the default aka ODP_CONFIG_QUEUE_SIZE is used? Should we allow for

> greater than ODP_CONFIG_QUEUE_SIZE? E.g. 10,000 queue depth is also not

> practical or possible. Perhaps we need a max which also acts as the

> default.

>

> > <br>

> > Second, if we're going to allow a queue size to be specified then

> this<br>

> > needs to be added as an output to odp_queue_capability()

>

> OK, will look into that.

>

> > so the<br>

> > application knows the max_size supported (again 0 = unbounded).<br>

> > <br>

> > A larger question, however, is why is this being introduced at all<br>

> > since this field is only used in the modified<br>

> > odph_cuckoo_table_create() helper routine and this, in turn, is only<br>

> > used within the cuckootable test module? This seems an extraneous and<br>

> > unnecessary change and has no relationship to the rest of this patch<br>

> > series.<br>

>

> AFAIK, the cuckoo unit test enqueues too many events (millions) to a queue.

> That sounds like it makes no sense, but is an example of how anything is

> possible.

>

> > <br>

> > So Parts 1 and 3 of this series don't seem to have anything to do

> with<br>

> > the scalable scheduler. As a minor point, the order of these needs to<br>

> > be reversed to preserve bisectability since Part 1 can't reference

> the<br>

> > new field before Part 3 defines it.<br>

>

> Agree that there are 2 independent sets of patches, but the order is needed

> in order to get a sane `make check' on ARM-based chips. Without these fixes

> going in first, we have no way of knowing whether the scalable scheduler

> patches

> caused the issue or not. I can break these into 2 separate sets of patches.

>

> > <br>

> > &gt; &#43;<br>

> > &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Enqueue

> mode<br>

> > &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>

> > &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *

> Default value for both queue types is ODP_QUEUE_OP_MT. Application<br>

> > &gt; --<br>

> > &gt; 2.12.1<br>

> > &gt;<br>

> > </div></span></font>

> > </body>

> > </html>

>
Maxim Uvarov March 29, 2017, 7:39 a.m. UTC | #9
1. Prefix has to be "PATCH API-NEXT" not "API-NEXT"
2. Please remove ifdefs. And compile all variants of schedules into the
library. Code needs to be compile each time.

Maxim.

On 29 March 2017 at 06:30, Bill Fischofer <bill.fischofer@linaro.org> wrote:

> On Tue, Mar 28, 2017 at 10:28 PM, Honnappa Nagarahalli <

> Honnappa.Nagarahalli@arm.com> wrote:

>

> > I had run the checkpatch.pl, but I did not see these issues. May be it

> > was to do with the way I generated the patch. I will address the ones

> that

> > make sense.

> >

>

> I did a git am for your patches and then regenerated them for checkpatch

> testing via:

> git format-patch origin/api-next --subject-prefix="API-NEXT PATCH"

>

>

> >

> > Do we have to compile for 32b with gcc?

> >

>

> Yes, we require that ODP code compile and run in both 32-bit and 64-bit

> mode.

>

>

> >

> > From: Bill Fischofer [mailto:bill.fischofer@linaro.org]

> > Sent: Tuesday, March 28, 2017 10:01 PM

> > To: Brian Brooks

> > Cc: lng-odp-forward; Ola Liljedahl; Kevin Wang; Honnappa Nagarahalli

> > Subject: Re: [lng-odp] [API-NEXT 4/4] A scalable software scheduler

> >

> > First off, I'm not sure why you're seeing HTML since Gmail is set to

> plain

> > text mode for me.

> >

> > On Tue, Mar 28, 2017 at 9:18 PM, Brian Brooks <brian.brooks@arm.com>

> > wrote:

> > On 03/28 18:50:32, Bill Fischofer wrote:

> > > <html><head><meta http-equiv="Content-Type" content="text/html;

> > charset=utf-8">

> > > <meta name="Generator" content="Microsoft Exchange Server">

> > > <!-- converted from text -->

> > > <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt;

> > border-left: #800000 2px solid; } --></style></head>

> > > <body>

> > > <font size="2"><span style="font-size:10pt;"><div

> class="PlainText">This

> > part generates numerous checkpatch warnings and errors. Please<br>

> > > run checkpatch and correct for v2.<br>

> >

> > We ran checkpatch.pl and corrected the issues that made sense. We all

> > know that

> > checkpatch.pl is not perfect. Please point out the checkpatch.pl issues

> > that

> > are generated from this patch which are not false positives or not

> > destructive

> > to programmer readability.

> >

> > Checkpatch does issue a number of spurious warnings relating to the use

> of

> > volatile, etc. but the following seem legit:

> >

> > WARNING: Possible unwrapped commit description (prefer a maximum 75 chars

> > per line)

> > #11:

> > respected, and (W)RR scheduling may be used within queues of the same

> > priority.

> >

> > WARNING: 'absense' may be misspelled - perhaps 'absence'?

> > #16:

> > concurrent queues. LL/SC and CAS variants exist in cases where absense of

> >

> > CHECK: No space is necessary after a cast

> > #171: FILE: platform/linux-generic/include/odp/api/plat/schedule_

> > types.h:65:

> > +#define ODP_SCHED_GROUP_INVALID ((odp_schedule_group_t) -1)

> >

> > CHECK: Alignment should match open parenthesis

> > #225: FILE: platform/linux-generic/include/odp_atomic16.h:45:

> > +static inline bool __atomic_compare_exchange_16(register __int128 *var,

> > +__int128 *exp, register __int128 neu,

> >

> > CHECK: Alignment should match open parenthesis

> > #271: FILE: platform/linux-generic/include/odp_atomic16.h:91:

> > +static inline bool __atomic_compare_exchange_16_frail(register __int128

> > *var,

> > +__int128 *exp, register __int128 neu, bool weak,

> >

> > CHECK: Alignment should match open parenthesis

> > #393: FILE: platform/linux-generic/include/odp_atomic16.h:213:

> > +static inline __int128 __atomic_fetch_or_16(__int128 *var,

> > +__int128 mask,

> >

> > CHECK: multiple assignments should be avoided

> > #856: FILE: platform/linux-generic/include/odp_llqueue.h:123:

> > +llq->u.st.head = llq->u.st.tail = node;

> >

> > CHECK: multiple assignments should be avoided

> > #965: FILE: platform/linux-generic/include/odp_llqueue.h:232:

> > +llq->u.st.head = llq->u.st.tail = NULL;

> >

> > CHECK: multiple assignments should be avoided

> > #1064: FILE: platform/linux-generic/include/odp_llqueue.h:331:

> > +llq->u.st.head = llq->u.st.tail = NULL;

> >

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #1189: FILE: platform/linux-generic/include/odp_llsc.h:64:

> > +}

> > +#define ll32(a, b) ll((a), (b))

> >

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #1205: FILE: platform/linux-generic/include/odp_llsc.h:80:

> > +}

> > +#define sc32(a, b, c) sc((a), (b), (c))

> >

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #1220: FILE: platform/linux-generic/include/odp_llsc.h:95:

> > +}

> > +#define ll64(a, b) lld((a), (b))

> >

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #1236: FILE: platform/linux-generic/include/odp_llsc.h:111:

> > +}

> > +#define sc64(a, b, c) scd((a), (b), (c))

> >

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #1336: FILE: platform/linux-generic/include/odp_llsc.h:211:

> > +}

> > +#define ll64(a, b) ll((a), (b))

> >

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #1357: FILE: platform/linux-generic/include/odp_llsc.h:232:

> > +}

> > +#define sc64(a, b, c) sc((a), (b), (c))

> >

> >

> > CHECK: Alignment should match open parenthesis

> > #1981: FILE: platform/linux-generic/include/odp_schedule_ordered_

> > internal.h:131:

> > +void olock_unlock(const reorder_context_t *rctx, reorder_window_t *rwin,

> > + uint32_t lock_index);

> >

> >

> > WARNING: 'noone' may be misspelled - perhaps 'no one'?

> > #2402: FILE: platform/linux-generic/odp_queue_scalable.c:95:

> > +/* All remaining elements claimed, noone else can enqueue */

> >

> > CHECK: spaces preferred around that '<<' (ctx:VxV)

> > #2417: FILE: platform/linux-generic/odp_queue_scalable.c:110:

> > +return 1<<i;

> >          ^

> >

> > CHECK: Alignment should match open parenthesis

> > #2438: FILE: platform/linux-generic/odp_queue_scalable.c:131:

> > +shm = odp_shm_reserve(name,

> > +ring_size * sizeof(odp_buffer_hdr_t *),

> >

> > CHECK: Alignment should match open parenthesis

> > #2698: FILE: platform/linux-generic/odp_queue_scalable.c:391:

> > +while (__atomic_load_n(&q->qschst.numevts, __ATOMIC_RELAXED) != 0 ||

> > +__atomic_load_n(&q->qschst.cur_ticket, __ATOMIC_RELAXED) !=

> >

> >

> > WARNING: macros should not use a trailing semicolon

> > #3366: FILE: platform/linux-generic/odp_schedule_scalable.c:55:

> > +#define __atomic_fetch_max(var, v, mo) do { \

> > +/* Evalulate 'v' once */ \

> > +__typeof__(v) tmp_v = (v); \

> > +__typeof__(*var) old_var = \

> > +__atomic_load_n((var), __ATOMIC_RELAXED); \

> > +while (tmp_v > old_var) { \

> > +/* Attempt to store 'v' in '*var' */ \

> > +if (__atomic_compare_exchange_n((var), &old_var, \

> > +tmp_v, true, (mo), \

> > +(mo))) \

> > +break; \

> > +/* Else failure, try again (with updated value of \

> >

> > WARNING: Avoid unnecessary line continuations

> > #3379: FILE: platform/linux-generic/odp_schedule_scalable.c:68:

> > + */ \

> >

> > CHECK: Alignment should match open parenthesis

> > #3581: FILE: platform/linux-generic/odp_schedule_scalable.c:270:

> > +       LDXR8(&q->qschst.cur_ticket,

> > +      __ATOMIC_ACQUIRE) != ticket)

> >

> > CHECK: Alignment should match open parenthesis

> > #3659: FILE: platform/linux-generic/odp_schedule_scalable.c:348:

> > +static void sched_update_deq(sched_elem_t *q,

> > +uint32_t actual, bool atomic) __attribute__((always_inline));

> >

> > CHECK: Alignment should match open parenthesis

> > #3661: FILE: platform/linux-generic/odp_schedule_scalable.c:350:

> > +static inline void sched_update_deq(sched_elem_t *q,

> > +uint32_t actual, bool atomic)

> >

> > CHECK: Alignment should match open parenthesis

> > #3745: FILE: platform/linux-generic/odp_schedule_scalable.c:434:

> > +       LDXR8(&q->qschst.cur_ticket,

> > +      __ATOMIC_ACQUIRE) != ticket)

> >

> > CHECK: Alignment should match open parenthesis

> > #3791: FILE: platform/linux-generic/odp_schedule_scalable.c:480:

> > +static void sched_update_deq_sc(sched_elem_t *q,

> > +uint32_t actual, bool atomic) __attribute__((always_inline));

> >

> > CHECK: Alignment should match open parenthesis

> > #3793: FILE: platform/linux-generic/odp_schedule_scalable.c:482:

> > +static inline void sched_update_deq_sc(sched_elem_t *q,

> > +uint32_t actual, bool atomic)

> >

> > CHECK: Alignment should match open parenthesis

> > #3977: FILE: platform/linux-generic/odp_schedule_scalable.c:666:

> > +sg_wanted = __atomic_load_n(&ts->sg_wanted[p],

> > +__ATOMIC_ACQUIRE);

> >

> > CHECK: Alignment should match open parenthesis

> > #3989: FILE: platform/linux-generic/odp_schedule_scalable.c:678:

> > +insert_schedq_in_list(ts,

> > +&sg->schedq[p * sg->xfactor +

> >

> > CHECK: Alignment should match open parenthesis

> > #4002: FILE: platform/linux-generic/odp_schedule_scalable.c:691:

> > +remove_schedq_from_list(ts,

> > +    &sg->schedq[p * sg->xfactor + x]);

> >

> > CHECK: multiple assignments should be avoided

> > #4171: FILE: platform/linux-generic/odp_schedule_scalable.c:860:

> > +ts->atomq = atomq = elem;

> >

> > CHECK: Alignment should match open parenthesis

> > #4256: FILE: platform/linux-generic/odp_schedule_scalable.c:945:

> > +if (odp_unlikely(__atomic_load_n(&rwin->turn,

> > + __ATOMIC_ACQUIRE) != sn)) {

> >

> >

> > CHECK: Alignment should match open parenthesis

> > #4584: FILE: platform/linux-generic/odp_schedule_scalable.c:1273:

> > +__atomic_store_n(&thread_state[thr].sg_sem,

> > +1,

> >

> > CHECK: Alignment should match open parenthesis

> > #4656: FILE: platform/linux-generic/odp_schedule_scalable.c:1345:

> > +shm = odp_shm_reserve(name ? name : "",

> > +     (sizeof(sched_group_t) +

> >

> > CHECK: No space is necessary after a cast

> > #4664: FILE: platform/linux-generic/odp_schedule_scalable.c:1353:

> > +sg = (sched_group_t *) odp_shm_addr(shm);

> >

> > CHECK: No space is necessary after a cast

> > #4684: FILE: platform/linux-generic/odp_schedule_scalable.c:1373:

> > +return (odp_schedule_group_t) (sgi);

> >

> > CHECK: Alignment should match open parenthesis

> > #5054: FILE: platform/linux-generic/odp_schedule_scalable.c:1743:

> > +if (odp_schedule_group_join(ODP_SCHED_GROUP_CONTROL,

> > +&mask) != 0) {

> >

> > CHECK: Alignment should match open parenthesis

> > #5060: FILE: platform/linux-generic/odp_schedule_scalable.c:1749:

> > +if (odp_schedule_group_join(ODP_SCHED_GROUP_WORKER,

> > +&mask) != 0) {

> >

> > CHECK: Alignment should match open parenthesis

> > #5096: FILE: platform/linux-generic/odp_schedule_scalable.c:1785:

> > +if (odp_schedule_group_leave(ODP_SCHED_GROUP_CONTROL,

> > +&mask) != 0)

> >

> > CHECK: Alignment should match open parenthesis

> > #5100: FILE: platform/linux-generic/odp_schedule_scalable.c:1789:

> > +if (odp_schedule_group_leave(ODP_SCHED_GROUP_WORKER,

> > +&mask) != 0)

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #5185: FILE: platform/linux-generic/odp_schedule_scalable.c:1874:

> > +}

> > +static int thr_rem(odp_schedule_group_t group, int thr)

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #5192: FILE: platform/linux-generic/odp_schedule_scalable.c:1881:

> > +}

> > +static int init_queue(uint32_t queue_index,

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #5200: FILE: platform/linux-generic/odp_schedule_scalable.c:1889:

> > +}

> > +static void destroy_queue(uint32_t queue_index)

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #5205: FILE: platform/linux-generic/odp_schedule_scalable.c:1894:

> > +}

> > +static int sched_queue(uint32_t queue_index)

> >

> > CHECK: Please use a blank line after function/struct/union/enum

> > declarations

> > #5211: FILE: platform/linux-generic/odp_schedule_scalable.c:1900:

> > +}

> > +static int ord_enq_multi(uint32_t queue_index, void *p_buf_hdr[],

> >

> >

> > CHECK: No space is necessary after a cast

> > #5314: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:38:

> > +rwin = (reorder_window_t *) odp_shm_addr(*shm);

> >

> > CHECK: Alignment should match open parenthesis

> > #5408: FILE: platform/linux-generic/odp_schedule_scalable_ordered.c:132:

> > +if (__atomic_compare_exchange(&rwin->hc,

> > +&old, /* Updated on failure */

> >

> > CHECK: Please don't use multiple blank lines

> > #5757: FILE: test/common_plat/performance/odp_sched_latency.c:824:

> >

> > +

> >

> > total: 0 errors, 54 warnings, 44 checks, 5742 lines checked

> >

> > NOTE: Ignored message types: BIT_MACRO COMPARISON_TO_NULL

> > DEPRECATED_VARIABLE NEW_TYPEDEFS SPLIT_STRING SSCANF_TO_KSTRTO

> >

> > 0004-A-scalable-software-scheduler.patch has style problems, please

> > review.

> >

> > If any of these errors are false positives, please report

> > them to the maintainer, see CHECKPATCH in MAINTAINERS.

> >

> >

> > > <br>

> > > Also, this part introduces a number of errors that result in

> failure<br>

> > > to compile using clang.

> >

> > This is likely true. Is compilation with Clang a blocker?

> >

> > Yes, it is. We require ODP modules to be compilable with either GCC or

> > clang.

> >

> >

> > IMPORTANT NOTICE: The contents of this email and any attachments are

> > confidential and may also be privileged. If you are not the intended

> > recipient, please notify the sender immediately and do not disclose the

> > contents to any other person, use it for any purpose, or store or copy

> the

> > information in any medium. Thank you.

> >

>
Ola Liljedahl March 29, 2017, 8:28 a.m. UTC | #10
On 29 March 2017 at 03:55, Brian Brooks <brian.brooks@arm.com> wrote:
> On 03/28 19:18:37, Bill Fischofer wrote:

>> <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">

>

> It is infinitely better to do patch review in plain text rather

> than HTML. I thought this was a plain text mailing list?

>

>> <meta name="Generator" content="Microsoft Exchange Server">

>> <!-- converted from text -->

>> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style></head>

>> <body>

>> <font size="2"><span style="font-size:10pt;"><div class="PlainText">On Tue, Mar 28, 2017 at 2:23 PM, Brian Brooks &lt;brian.brooks@arm.com&gt; wrote:<br>

>> &gt; Signed-off-by: Brian Brooks &lt;brian.brooks@arm.com&gt;<br>

>> &gt; ---<br>

>> &gt;&nbsp; include/odp/api/spec/queue.h | 5 &#43;&#43;&#43;&#43;&#43;<br>

>> &gt;&nbsp; 1 file changed, 5 insertions(&#43;)<br>

>> &gt;<br>

>> &gt; diff --git a/include/odp/api/spec/queue.h b/include/odp/api/spec/queue.h<br>

>> &gt; index 7972feac..1cec4773 100644<br>

>> &gt; --- a/include/odp/api/spec/queue.h<br>

>> &gt; &#43;&#43;&#43; b/include/odp/api/spec/queue.h<br>

>> &gt; @@ -124,6 &#43;124,11 @@ typedef struct odp_queue_param_t {<br>

>> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the queue type. */<br>

>> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; odp_queue_type_t type;<br>

>> &gt;<br>

>> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Queue size<br>

>> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>

>> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Indicates the max ring size of the ring buffer. */<br>

>> &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t ring_size;<br>

>> <br>

>> ODP queues have historically been of unspecified size. If we're going<br>

>> to introduce the notion of explicitly limited sized queues this has<br>

>> additional implications.<br>

Implementations have likely applied some internal limitation, unknown
to the application.
linux-generic's use of linked lists can't be seen as *the* way to do it.

>>

>> First, ring_size is an inappropriate choice of name here since a ring<br>

>> is an implementation model, not a specification. The documentation<br>

>> says &quot;Queue size&quot;, so<br>

>> <br>

>> uint32_t size;<br>

>> <br>

>> is sufficient here.

>

> Agree, will change 'ring_size' to a better name.

My suggestion is 'min_capacity' (or 'min_size').
The application specifies the minimum capacity requires/desires.

>

>> We should document that size = 0 requests a queue<br>

>> of default size (which may be unbounded).<br>

>

> Unbounded size is not practical or possible. Can we agree that 0 means

> that the default aka ODP_CONFIG_QUEUE_SIZE is used? Should we allow for

> greater than ODP_CONFIG_QUEUE_SIZE? E.g. 10,000 queue depth is also not

> practical or possible. Perhaps we need a max which also acts as the default.

IMO, a 'min_capacity' of 0 should mean use default size (per the ODP
configuration file). Which is likely what implementations already do
when the application cannot specify the size.

>

>> <br>

>> Second, if we're going to allow a queue size to be specified then this<br>

>> needs to be added as an output to odp_queue_capability()

>

> OK, will look into that.

>

>> so the<br>

>> application knows the max_size supported (again 0 = unbounded).<br>

>> <br>

>> A larger question, however, is why is this being introduced at all<br>

>> since this field is only used in the modified<br>

>> odph_cuckoo_table_create() helper routine and this, in turn, is only<br>

>> used within the cuckootable test module? This seems an extraneous and<br>

>> unnecessary change and has no relationship to the rest of this patch<br>

>> series.<br>

>

> AFAIK, the cuckoo unit test enqueues too many events (millions) to a queue.

> That sounds like it makes no sense, but is an example of how anything is

> possible.

The cuckoo hash table uses a queue to store unused "slots". The hash
table could be very large so have a very large number of unused slots
that need to be saved on a queue. I think it is unreasonable of the
cuckoo hash table to expect infinite queue sizes. Better to specify
the required capacity and then fail in odp_queue_create().

>

>> <br>

>> So Parts 1 and 3 of this series don't seem to have anything to do with<br>

>> the scalable scheduler. As a minor point, the order of these needs to<br>

>> be reversed to preserve bisectability since Part 1 can't reference the<br>

>> new field before Part 3 defines it.<br>

>

> Agree that there are 2 independent sets of patches, but the order is needed

> in order to get a sane `make check' on ARM-based chips. Without these fixes

> going in first, we have no way of knowing whether the scalable scheduler patches

> caused the issue or not. I can break these into 2 separate sets of patches.

>

>> <br>

>> &gt; &#43;<br>

>> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /** Enqueue mode<br>

>> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>

>> &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Default value for both queue types is ODP_QUEUE_OP_MT. Application<br>

>> &gt; --<br>

>> &gt; 2.12.1<br>

>> &gt;<br>

>> </div></span></font>

>> </body>

>> </html>
Savolainen, Petri (Nokia - FI/Espoo) March 29, 2017, 9:59 a.m. UTC | #11
> -----Original Message-----

> From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of

> Honnappa Nagarahalli

> Sent: Wednesday, March 29, 2017 6:28 AM

> To: Bill Fischofer <bill.fischofer@linaro.org>; Brian Brooks

> <Brian.Brooks@arm.com>

> Cc: Ola Liljedahl <Ola.Liljedahl@arm.com>; Kevin Wang

> <Kevin.Wang@arm.com>; lng-odp-forward <lng-odp@lists.linaro.org>

> Subject: Re: [lng-odp] [API-NEXT 4/4] A scalable software scheduler

> 

> I had run the checkpatch.pl, but I did not see these issues. May be it was

> to do with the way I generated the patch. I will address the ones that

> make sense.

> 


Checkpatch should pass cleanly for every patch. If you want an exception for some line, then you should give rationale for that e.g. on the cover letter. So, the expectation is that you will correct all and only few, well justified exceptions could be acceptable. An example would be a call to an external library (e.g. openssl) which uses camelCase function names - checkpatch warns but you cannot do anything about it.


-Petri
Savolainen, Petri (Nokia - FI/Espoo) March 29, 2017, 10:16 a.m. UTC | #12
> -----Original Message-----

> From: lng-odp [mailto:lng-odp-bounces@lists.linaro.org] On Behalf Of Maxim

> Uvarov

> Sent: Wednesday, March 29, 2017 10:28 AM

> To: Brian Brooks <brian.brooks@arm.com>

> Cc: lng-odp-forward <lng-odp@lists.linaro.org>

> Subject: Re: [lng-odp] [API-NEXT 3/4] api: queue: Add ring_size

> 

> isn't queue size connected to number elements in the pool?

> 

> Maxim.


In theory, max queue size == sum of all pool sizes. But that's not a practical specification.

I'll send a patch for the queue size capa/param API.

-Petri
Savolainen, Petri (Nokia - FI/Espoo) March 29, 2017, 11:20 a.m. UTC | #13
Couple of high level comments:

1) Too many #ifdefs
   * Code is hard to read and maintain when every 10th line is #ifdef or #else
   * Are all #ifdef combinations tested? Or meant to be supported?
   * It seems that some design trade-offs would be needed for better code maintainability

2) Too many arch dependent #ifdefs
   * ARM_ARCH ifdefs and assembly in main .c / .h files should be replaced with arch specific functions defined under platform/linux-generic/arch/xxx. That's the only directory which should contain inline assembly.

3) Keep and improve modularity
   * #ifdef ODP_SCHEDULE_SCALABLE should not show up common pktio/queue/etc files. Only in makefiles and interface selection.
   * Main build time config options (config_internal.h) should be high level (== max number of XXX), not algorithmic details of one scheduler. Move those into local .c/.h files.
   * Keep definitions local when used only by one file. Check common headers before adding new definitions into common headers. E.g. CHECK_IS_POWER2 is already defined in odp_align_internal.h.
   * Improve e.g. queue interface modularity first with current code base. After that's done, hook the new scheduler to the interface.

4) Split 4/4 into couple of patches
   * First prepare the current code base with couple of patches
     * Proper interfaces / modifications for modularity (see previous bullet)
     * This enables us to see and test how current code base is impacted
     * Also git history is easier to work with when single patch does not touch many files / features
   * Bring in the new scheduler code as the last patch of the series


-Petri
Brian Brooks March 30, 2017, 5:57 a.m. UTC | #14
On 03/29 10:39:35, Maxim Uvarov wrote:
> 1. Prefix has to be "PATCH API-NEXT" not "API-NEXT"


Okay.

> 2. Please remove ifdefs. And compile all variants of schedules into the

> library. Code needs to be compile each time.


There are multiple ways to interpret this. Can you please describe the
change(s) you would like to see in extremely verbose detail so that I can
be sure I understand you?

> Maxim.
Brian Brooks March 30, 2017, 6:44 a.m. UTC | #15
On 03/29 11:20:37, Savolainen, Petri (Nokia - FI/Espoo) wrote:
> Couple of high level comments:

> 

> 1) Too many #ifdefs

>    * Code is hard to read and maintain when every 10th line is #ifdef or #else

>    * Are all #ifdef combinations tested? Or meant to be supported?

>    * It seems that some design trade-offs would be needed for better code maintainability

> 

> 2) Too many arch dependent #ifdefs

>    * ARM_ARCH ifdefs and assembly in main .c / .h files should be replaced with arch specific functions defined under platform/linux-generic/arch/xxx. That's the only directory which should contain inline assembly.


This is the current status quo and there is opportunity to do better.

The first angle is general organization and code duplication. This picture
may help:

  ~/api-next/platform/linux-generic/arch (api-next)$ tree
  .
  ├── arm
  │   ├── odp
  │   │   └── api
  │   │       └── cpu_arch.h
  │   ├── odp_cpu_arch.c
  │   └── odp_sysinfo_parse.c
  ├── default
  │   ├── odp
  │   │   └── api
  │   │       └── cpu_arch.h
  │   ├── odp_cpu_arch.c
  │   └── odp_sysinfo_parse.c
  ├── mips64
  │   ├── odp
  │   │   └── api
  │   │       └── cpu_arch.h
  │   ├── odp_cpu_arch.c
  │   └── odp_sysinfo_parse.c
  ├── powerpc
  │   ├── odp
  │   │   └── api
  │   │       └── cpu_arch.h
  │   ├── odp_cpu_arch.c
  │   └── odp_sysinfo_parse.c
  └── x86
      ├── odp
      │   └── api
      │       └── cpu_arch.h
      ├── odp_cpu_arch.c
      └── odp_sysinfo_parse.c

There is not enough actual code to warrant the current situation,
and I prefer to see a single file containing code for multiple
architectures, e.g.:

  cpu.h

    static inline void odp_cpu_pause(void)
    {
    #if defined(__ARCH_ARM)
      asm volatile("isb" ::: "memory");
    #elif defined(__mips__)
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
      asm volatile("nop");
    #elif defined(__x86_64__) || defined(__i386__)
      asm volatile("pause");
    #else
    #error Please add support for your CPU in cpu.h
    #endif
    }

If architecture specific code must be split into architecture
specific files, an alternative is:

  cpu.h

    #if defined(__ARCH_ARM)
    #include "cpu_arm.h"
    #elif defined(__mips__)
    #include "cpu_mips.h"
    ..

  cpu_arm.h

    static inline void odp_cpu_pause(void)
    {
      asm volatile("isb" ::: "memory");
    }

  ..

Notice how this eliminates the dependency on Autotools to setup
proper include paths and to do architecture detection. The compiler's
system-specific macros are a superior way to conditionally compile
code.

Some of the code isn't even CPU or architecture specific and does not
even belong here, e.g. parsing sysfs.

The second angle is that not all inline assembly applies to all
architectures. So, the current way of doing things will continue to
add more duplication and technical debt. I don't think anyone would
feel good about seeing LL/SC related code in an x86 file even if
it's just a bunch of empty functions. We can do better. I am curious
to know your opinion here.

> 3) Keep and improve modularity

>    * #ifdef ODP_SCHEDULE_SCALABLE should not show up common pktio/queue/etc files. Only in makefiles and interface selection.


Will see what can be done.

>    * Main build time config options (config_internal.h) should be high level (== max number of XXX), not algorithmic details of one scheduler. Move those into local .c/.h files.


This is a pre-existing condition. There are some component-specific
build time config in this file (e.g. burst size, Christophe's work). It is also
easy to locate build time config because it's in one file. I don't know
what the long term approach should be, but I don't think this is a blocker.

>    * Keep definitions local when used only by one file. Check common headers before adding new definitions into common headers. E.g. CHECK_IS_POWER2 is already defined in odp_align_internal.h.


Sure

>    * Improve e.g. queue interface modularity first with current code base. After that's done, hook the new scheduler to the interface.


Will see what can be done, but may take a few iterations.

> 4) Split 4/4 into couple of patches

>    * First prepare the current code base with couple of patches

>      * Proper interfaces / modifications for modularity (see previous bullet)

>      * This enables us to see and test how current code base is impacted

>      * Also git history is easier to work with when single patch does not touch many files / features

>    * Bring in the new scheduler code as the last patch of the series


Will see what can be done, but may take a few iterations.

> 

> 

> -Petri

> 

>
Brian Brooks March 30, 2017, 1:56 p.m. UTC | #16
On 03/28 18:50:32, Bill Fischofer wrote:
> <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">

> <meta name="Generator" content="Microsoft Exchange Server">

> <!-- converted from text -->

> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style></head>

> <body>

> <font size="2"><span style="font-size:10pt;"><div class="PlainText">This part generates numerous checkpatch warnings and errors. Please<br>

> run checkpatch and correct for v2.<br>

> <br>

> Also, this part introduces a number of errors that result in failure<br>

> to compile using clang. Please test with both gcc and clang to ensure<br>

> that it compiles cleanly for both (gcc looks fine)<br>

> <br>

> Specific clang issues:<br>


Does upstream CI build with Clang on ARMv8? I don't think so because
the build is broken when I try it locally. I have the patch and will
send shortly.
Bill Fischofer March 30, 2017, 2:45 p.m. UTC | #17
On Thu, Mar 30, 2017 at 8:56 AM, Brian Brooks <brian.brooks@arm.com> wrote:
> On 03/28 18:50:32, Bill Fischofer wrote:

>> <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">

>> <meta name="Generator" content="Microsoft Exchange Server">

>> <!-- converted from text -->

>> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style></head>

>> <body>

>> <font size="2"><span style="font-size:10pt;"><div class="PlainText">This part generates numerous checkpatch warnings and errors. Please<br>

>> run checkpatch and correct for v2.<br>

>> <br>

>> Also, this part introduces a number of errors that result in failure<br>

>> to compile using clang. Please test with both gcc and clang to ensure<br>

>> that it compiles cleanly for both (gcc looks fine)<br>

>> <br>

>> Specific clang issues:<br>

>

> Does upstream CI build with Clang on ARMv8? I don't think so because

> the build is broken when I try it locally. I have the patch and will

> send shortly.


CI is supposed to be regression testing on ARM using clang as well as
gcc. Maxim may have insight here.
Maxim Uvarov March 30, 2017, 2:56 p.m. UTC | #18
I think for now we do not have build for arm v8 & clang. At least it did
not capture build error.

Maxim.

On 30 March 2017 at 17:45, Bill Fischofer <bill.fischofer@linaro.org> wrote:

> On Thu, Mar 30, 2017 at 8:56 AM, Brian Brooks <brian.brooks@arm.com>

> wrote:

> > On 03/28 18:50:32, Bill Fischofer wrote:

> >> <html><head><meta http-equiv="Content-Type" content="text/html;

> charset=utf-8">

> >> <meta name="Generator" content="Microsoft Exchange Server">

> >> <!-- converted from text -->

> >> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt;

> border-left: #800000 2px solid; } --></style></head>

> >> <body>

> >> <font size="2"><span style="font-size:10pt;"><div

> class="PlainText">This part generates numerous checkpatch warnings and

> errors. Please<br>

> >> run checkpatch and correct for v2.<br>

> >> <br>

> >> Also, this part introduces a number of errors that result in failure<br>

> >> to compile using clang. Please test with both gcc and clang to

> ensure<br>

> >> that it compiles cleanly for both (gcc looks fine)<br>

> >> <br>

> >> Specific clang issues:<br>

> >

> > Does upstream CI build with Clang on ARMv8? I don't think so because

> > the build is broken when I try it locally. I have the patch and will

> > send shortly.

>

> CI is supposed to be regression testing on ARM using clang as well as

> gcc. Maxim may have insight here.

>
Ola Liljedahl March 30, 2017, 2:58 p.m. UTC | #19
No build, no run.

We found several problems (memory ordering related so visible on ARM but not on x86) in the upstream code when running on ARM systems. Aren’t there any ARM systems to run on in the LNG lab?

-- Ola

Ola Liljedahl, Networking System Architect, ARM
Phone: +46 706 866 373  Skype: ola.liljedahl

From: Maxim Uvarov <maxim.uvarov@linaro.org<mailto:maxim.uvarov@linaro.org>>

Date: Thursday, 30 March 2017 at 16:56
To: Bill Fischofer <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>>
Cc: Brian Brooks <Brian.Brooks@arm.com<mailto:Brian.Brooks@arm.com>>, lng-odp-forward <lng-odp@lists.linaro.org<mailto:lng-odp@lists.linaro.org>>, Ola Liljedahl <ola.liljedahl@arm.com<mailto:ola.liljedahl@arm.com>>, Kevin Wang <Kevin.Wang@arm.com<mailto:Kevin.Wang@arm.com>>, Honnappa Nagarahalli <Honnappa.Nagarahalli@arm.com<mailto:Honnappa.Nagarahalli@arm.com>>
Subject: Re: [lng-odp] [API-NEXT 4/4] A scalable software scheduler

I think for now we do not have build for arm v8 & clang. At least it did not capture build error.

Maxim.

On 30 March 2017 at 17:45, Bill Fischofer <bill.fischofer@linaro.org<mailto:bill.fischofer@linaro.org>> wrote:
On Thu, Mar 30, 2017 at 8:56 AM, Brian Brooks <brian.brooks@arm.com<mailto:brian.brooks@arm.com>> wrote:
> On 03/28 18:50:32, Bill Fischofer wrote:

>> <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">

>> <meta name="Generator" content="Microsoft Exchange Server">

>> <!-- converted from text -->

>> <style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style></head>

>> <body>

>> <font size="2"><span style="font-size:10pt;"><div class="PlainText">This part generates numerous checkpatch warnings and errors. Please<br>

>> run checkpatch and correct for v2.<br>

>> <br>

>> Also, this part introduces a number of errors that result in failure<br>

>> to compile using clang. Please test with both gcc and clang to ensure<br>

>> that it compiles cleanly for both (gcc looks fine)<br>

>> <br>

>> Specific clang issues:<br>

>

> Does upstream CI build with Clang on ARMv8? I don't think so because

> the build is broken when I try it locally. I have the patch and will

> send shortly.


CI is supposed to be regression testing on ARM using clang as well as
gcc. Maxim may have insight here.

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
diff mbox series

Patch

diff --git a/helper/cuckootable.c b/helper/cuckootable.c
index 80ff4989..d3d1563c 100644
--- a/helper/cuckootable.c
+++ b/helper/cuckootable.c
@@ -256,6 +256,7 @@  odph_cuckoo_table_create(
 	/* initialize free_slots queue */
 	odp_queue_param_init(&qparam);
 	qparam.type = ODP_QUEUE_TYPE_PLAIN;
+	qparam.ring_size = capacity;
 
 	snprintf(queue_name, sizeof(queue_name), "fs_%s", name);
 	queue = odp_queue_create(queue_name, &qparam);