> From: Tyler Retzlaff [mailto:roret...@linux.microsoft.com] > Sent: Friday, 11 August 2023 19.32 > > Adapt the EAL public headers to use rte optional atomics API instead of > directly using and exposing toolchain specific atomic builtin intrinsics. > > Signed-off-by: Tyler Retzlaff <roret...@linux.microsoft.com> > ---
[...] > --- a/app/test/test_mcslock.c > +++ b/app/test/test_mcslock.c > @@ -36,9 +36,9 @@ > * lock multiple times. > */ > > -rte_mcslock_t *p_ml; > -rte_mcslock_t *p_ml_try; > -rte_mcslock_t *p_ml_perf; > +rte_mcslock_t * __rte_atomic p_ml; > +rte_mcslock_t * __rte_atomic p_ml_try; > +rte_mcslock_t * __rte_atomic p_ml_perf; Although this looks weird, it is pointers themselves, not the structures, that are used atomically. So it is correct. > diff --git a/lib/eal/include/generic/rte_pause.h > b/lib/eal/include/generic/rte_pause.h > index bebfa95..c816e7d 100644 > --- a/lib/eal/include/generic/rte_pause.h > +++ b/lib/eal/include/generic/rte_pause.h > @@ -36,13 +36,13 @@ > * A 16-bit expected value to be in the memory location. > * @param memorder > * Two different memory orders that can be specified: > - * __ATOMIC_ACQUIRE and __ATOMIC_RELAXED. These map to > + * rte_memory_order_acquire and rte_memory_order_relaxed. These map to > * C++11 memory orders with the same names, see the C++11 standard or > * the GCC wiki on atomic synchronization for detailed definition. Delete the last part of the description, starting at "These map to...". > */ > static __rte_always_inline void > rte_wait_until_equal_16(volatile uint16_t *addr, uint16_t expected, > - int memorder); > + rte_memory_order memorder); > > /** > * Wait for *addr to be updated with a 32-bit expected value, with a relaxed > @@ -54,13 +54,13 @@ > * A 32-bit expected value to be in the memory location. > * @param memorder > * Two different memory orders that can be specified: > - * __ATOMIC_ACQUIRE and __ATOMIC_RELAXED. These map to > + * rte_memory_order_acquire and rte_memory_order_relaxed. These map to > * C++11 memory orders with the same names, see the C++11 standard or > * the GCC wiki on atomic synchronization for detailed definition. Delete the last part of the description, starting at "These map to...". > */ > static __rte_always_inline void > rte_wait_until_equal_32(volatile uint32_t *addr, uint32_t expected, > - int memorder); > + rte_memory_order memorder); > > /** > * Wait for *addr to be updated with a 64-bit expected value, with a relaxed > @@ -72,42 +72,42 @@ > * A 64-bit expected value to be in the memory location. > * @param memorder > * Two different memory orders that can be specified: > - * __ATOMIC_ACQUIRE and __ATOMIC_RELAXED. These map to > + * rte_memory_order_acquire and rte_memory_order_relaxed. These map to > * C++11 memory orders with the same names, see the C++11 standard or > * the GCC wiki on atomic synchronization for detailed definition. Delete the last part of the description, starting at "These map to...". > */ > static __rte_always_inline void > rte_wait_until_equal_64(volatile uint64_t *addr, uint64_t expected, > - int memorder); > + rte_memory_order memorder); [...] > @@ -125,16 +125,16 @@ > * An expected value to be in the memory location. > * @param memorder > * Two different memory orders that can be specified: > - * __ATOMIC_ACQUIRE and __ATOMIC_RELAXED. These map to > + * rte_memory_order_acquire and rte_memory_order_relaxed. These map to > * C++11 memory orders with the same names, see the C++11 standard or > * the GCC wiki on atomic synchronization for detailed definition. Delete the last part of the description, starting at "These map to...". There might be more similar comments that need removal; I haven't tried searching. > */ > #define RTE_WAIT_UNTIL_MASKED(addr, mask, cond, expected, memorder) do { \ [...] > --- a/lib/eal/include/generic/rte_spinlock.h > +++ b/lib/eal/include/generic/rte_spinlock.h > @@ -29,7 +29,7 @@ > * The rte_spinlock_t type. > */ > typedef struct __rte_lockable { > - volatile int locked; /**< lock status 0 = unlocked, 1 = locked */ > + volatile int __rte_atomic locked; /**< lock status 0 = unlocked, 1 = > locked */ I think __rte_atomic should be before the type: volatile __rte_atomic int locked; /**< lock status [...] Alternatively (just mentioning it, I know we don't use this form): volatile __rte_atomic(int) locked; /**< lock status [...] Thinking of where you would put "const" might help. Maybe your order is also correct, so it is a matter of preference. The DPDK coding style guidelines doesn't mention where to place "const", but looking at the code, it seems to use "const unsigned int" and "const char *". > } rte_spinlock_t; > > /** [...] > --- a/lib/eal/include/rte_mcslock.h > +++ b/lib/eal/include/rte_mcslock.h > @@ -33,8 +33,8 @@ > * The rte_mcslock_t type. > */ > typedef struct rte_mcslock { > - struct rte_mcslock *next; > - int locked; /* 1 if the queue locked, 0 otherwise */ > + struct rte_mcslock * __rte_atomic next; Correct, the pointer is atomic, not the struct. > + int __rte_atomic locked; /* 1 if the queue locked, 0 otherwise */ Again, I think __rte_atomic should be before the type: __rte_atomic int locked; /* 1 if the queue locked, 0 otherwise */ > } rte_mcslock_t; > [...] > @@ -101,34 +101,34 @@ > * A pointer to the node of MCS lock passed in rte_mcslock_lock. > */ > static inline void > -rte_mcslock_unlock(rte_mcslock_t **msl, rte_mcslock_t *me) > +rte_mcslock_unlock(rte_mcslock_t * __rte_atomic *msl, rte_mcslock_t * > __rte_atomic me) > { > /* Check if there are more nodes in the queue. */ > - if (likely(__atomic_load_n(&me->next, __ATOMIC_RELAXED) == NULL)) { > + if (likely(rte_atomic_load_explicit(&me->next, rte_memory_order_relaxed) > == NULL)) { > /* No, last member in the queue. */ > - rte_mcslock_t *save_me = __atomic_load_n(&me, __ATOMIC_RELAXED); > + rte_mcslock_t *save_me = rte_atomic_load_explicit(&me, > rte_memory_order_relaxed); > > /* Release the lock by setting it to NULL */ > - if (likely(__atomic_compare_exchange_n(msl, &save_me, NULL, 0, > - __ATOMIC_RELEASE, __ATOMIC_RELAXED))) > + if (likely(rte_atomic_compare_exchange_strong_explicit(msl, > &save_me, NULL, > + rte_memory_order_release, > rte_memory_order_relaxed))) > return; > > /* Speculative execution would be allowed to read in the > * while-loop first. This has the potential to cause a > * deadlock. Need a load barrier. > */ > - __atomic_thread_fence(__ATOMIC_ACQUIRE); > + __rte_atomic_thread_fence(rte_memory_order_acquire); > /* More nodes added to the queue by other CPUs. > * Wait until the next pointer is set. > */ > - uintptr_t *next; > - next = (uintptr_t *)&me->next; > + uintptr_t __rte_atomic *next; > + next = (uintptr_t __rte_atomic *)&me->next; This way around, I think: __rte_atomic uintptr_t *next; next = (__rte_atomic uintptr_t *)&me->next; [...] > --- a/lib/eal/include/rte_pflock.h > +++ b/lib/eal/include/rte_pflock.h > @@ -41,8 +41,8 @@ > */ > struct rte_pflock { > struct { > - uint16_t in; > - uint16_t out; > + uint16_t __rte_atomic in; > + uint16_t __rte_atomic out; Again, I think __rte_atomic should be before the type: __rte_atomic uint16_t in; __rte_atomic uint16_t out; > } rd, wr; > }; [...] > --- a/lib/eal/include/rte_seqcount.h > +++ b/lib/eal/include/rte_seqcount.h > @@ -32,7 +32,7 @@ > * The RTE seqcount type. > */ > typedef struct { > - uint32_t sn; /**< A sequence number for the protected data. */ > + uint32_t __rte_atomic sn; /**< A sequence number for the protected data. > */ Again, I think __rte_atomic should be before the type: __rte_atomic uint32_t sn; /**< A sequence [...] > } rte_seqcount_t; [...] > --- a/lib/eal/include/rte_ticketlock.h > +++ b/lib/eal/include/rte_ticketlock.h > @@ -30,10 +30,10 @@ > * The rte_ticketlock_t type. > */ > typedef union { > - uint32_t tickets; > + uint32_t __rte_atomic tickets; > struct { > - uint16_t current; > - uint16_t next; > + uint16_t __rte_atomic current; > + uint16_t __rte_atomic next; Again, I think __rte_atomic should be before the type: __rte_atomic uint16_t current; __rte_atomic uint16_t next; > } s; > } rte_ticketlock_t; > @@ -127,7 +129,7 @@ > > typedef struct { > rte_ticketlock_t tl; /**< the actual ticketlock */ > - int user; /**< core id using lock, TICKET_LOCK_INVALID_ID for unused */ > + int __rte_atomic user; /**< core id using lock, TICKET_LOCK_INVALID_ID > for unused */ Again, I think __rte_atomic should be before the type: __rte_atomic int user; /**< core id [...] > unsigned int count; /**< count of time this lock has been called */ > } rte_ticketlock_recursive_t; [...] > --- a/lib/eal/include/rte_trace_point.h > +++ b/lib/eal/include/rte_trace_point.h > @@ -33,7 +33,7 @@ > #include <rte_stdatomic.h> > > /** The tracepoint object. */ > -typedef uint64_t rte_trace_point_t; > +typedef uint64_t __rte_atomic rte_trace_point_t; Again, I think __rte_atomic should be before the type: typedef __rte_atomic uint64_t rte_trace_point_t; [...] At the risk of having gone "speed blind" by all the search-replaces along the way... Reviewed-by: Morten Brørup <m...@smartsharesystems.com>