From: Narcisa Vasile <navas...@microsoft.com> Add functions for barrier init, destroy, wait.
A portable type is used to represent a barrier identifier. The rte_thread_barrier_wait() function returns the same value on all platforms. --- lib/eal/common/rte_thread.c | 61 ++++++++++++++++++++++++++++++++++++ lib/eal/include/rte_thread.h | 58 ++++++++++++++++++++++++++++++++++ lib/eal/windows/rte_thread.c | 56 +++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) diff --git a/lib/eal/common/rte_thread.c b/lib/eal/common/rte_thread.c index e8e4af0451..7560585784 100644 --- a/lib/eal/common/rte_thread.c +++ b/lib/eal/common/rte_thread.c @@ -273,6 +273,67 @@ rte_thread_mutex_destroy(rte_thread_mutex_t *mutex) return pthread_mutex_destroy(mutex); } +int +rte_thread_barrier_init(rte_thread_barrier_t *barrier, int count) +{ + int ret = 0; + pthread_barrier_t *pthread_barrier = NULL; + + RTE_VERIFY(barrier != NULL); + RTE_VERIFY(count > 0); + + pthread_barrier = calloc(1, sizeof(*pthread_barrier)); + if (pthread_barrier == NULL) { + RTE_LOG(DEBUG, EAL, "Unable to initialize barrier. Insufficient memory!\n"); + ret = ENOMEM; + goto cleanup; + } + ret = pthread_barrier_init(pthread_barrier, NULL, count); + if (ret != 0) { + RTE_LOG(DEBUG, EAL, "Unable to initialize barrier, ret = %d\n", ret); + goto cleanup; + } + + barrier->barrier_id = pthread_barrier; + pthread_barrier = NULL; + +cleanup: + free(pthread_barrier); + return ret; +} + +int rte_thread_barrier_wait(rte_thread_barrier_t *barrier) +{ + int ret = 0; + + RTE_VERIFY(barrier != NULL); + RTE_VERIFY(barrier->barrier_id != NULL); + + ret = pthread_barrier_wait(barrier->barrier_id); + if (ret == PTHREAD_BARRIER_SERIAL_THREAD) { + ret = RTE_THREAD_BARRIER_SERIAL_THREAD; + } + + return ret; +} + +int rte_thread_barrier_destroy(rte_thread_barrier_t *barrier) +{ + int ret = 0; + + RTE_VERIFY(barrier != NULL); + + ret = pthread_barrier_destroy(barrier->barrier_id); + if (ret != 0) { + RTE_LOG(DEBUG, EAL, "Unable to destroy barrier, ret = %d\n", ret); + } + + free(barrier->barrier_id); + barrier->barrier_id = NULL; + + return ret; +} + int rte_thread_cancel(rte_thread_t thread_id) { /* diff --git a/lib/eal/include/rte_thread.h b/lib/eal/include/rte_thread.h index 2fca662616..06b23571a1 100644 --- a/lib/eal/include/rte_thread.h +++ b/lib/eal/include/rte_thread.h @@ -29,6 +29,11 @@ extern "C" { #include <rte_thread_types.h> #endif +/** + * Returned by rte_thread_barrier_wait() when call is successful. + */ +#define RTE_THREAD_BARRIER_SERIAL_THREAD -1 + /** * Thread id descriptor. */ @@ -56,6 +61,13 @@ typedef struct { rte_cpuset_t cpuset; /**< thread affinity */ } rte_thread_attr_t; +/** + * Thread barrier representation. + */ +typedef struct rte_thread_barrier_tag { + void* barrier_id; /**< barrrier identifier */ +} rte_thread_barrier_t; + /** * TLS key type, an opaque pointer. */ @@ -300,6 +312,52 @@ int rte_thread_mutex_unlock(rte_thread_mutex_t *mutex); __rte_experimental int rte_thread_mutex_destroy(rte_thread_mutex_t *mutex); +/** + * Initializes a synchronization barrier. + * + * @param barrier + * A pointer that references the newly created 'barrier' object. + * + * @param count + * The number of threads that must enter the barrier before + * the threads can continue execution. + * + * @return + * On success, return 0. + * On failure, return a positive errno-style error number. + */ +__rte_experimental +int rte_thread_barrier_init(rte_thread_barrier_t *barrier, int count); + +/** + * Causes the calling thread to wait at the synchronization barrier 'barrier'. + * + * @param barrier + * The barrier used for synchronizing the threads. + * + * @return + * Return RTE_THREAD_BARRIER_SERIAL_THREAD for the thread synchronized + * at the barrier. + * Return 0 for all other threads. + * Return a positive errno-style error number, in case of failure. + */ +__rte_experimental +int rte_thread_barrier_wait(rte_thread_barrier_t *barrier); + +/** + * Releases all resources used by a synchronization barrier + * and uninitializes it. + * + * @param barrier + * The barrier to be destroyed. + * + * @return + * On success, return 0. + * On failure, return a positive errno-style error number. + */ +__rte_experimental +int rte_thread_barrier_destroy(rte_thread_barrier_t *barrier); + /** * Terminates a thread. * diff --git a/lib/eal/windows/rte_thread.c b/lib/eal/windows/rte_thread.c index f81876f4f2..e1778b603e 100644 --- a/lib/eal/windows/rte_thread.c +++ b/lib/eal/windows/rte_thread.c @@ -552,6 +552,62 @@ rte_thread_mutex_destroy(rte_thread_mutex_t *mutex) return 0; } +int +rte_thread_barrier_init(rte_thread_barrier_t *barrier, int count) +{ + int ret = 0; + SYNCHRONIZATION_BARRIER *sync_barrier = NULL; + + RTE_VERIFY(barrier != NULL); + RTE_VERIFY(count > 0); + + sync_barrier = calloc(1, sizeof(*sync_barrier)); + if (sync_barrier == NULL) { + RTE_LOG(DEBUG, EAL, "Unable to initialize barrier. Insufficient memory!\n"); + ret = ENOMEM; + goto cleanup; + } + if (!InitializeSynchronizationBarrier(sync_barrier, count, -1)) { + ret = thread_log_last_error("InitializeSynchronizationBarrier()"); + goto cleanup; + } + + barrier->barrier_id = sync_barrier; + sync_barrier = NULL; + +cleanup: + free(sync_barrier); + return ret; +} + +int +rte_thread_barrier_wait(rte_thread_barrier_t *barrier) +{ + RTE_VERIFY(barrier != NULL); + RTE_VERIFY(barrier->barrier_id != NULL); + + if (EnterSynchronizationBarrier(barrier->barrier_id, + SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY)) { + + return RTE_THREAD_BARRIER_SERIAL_THREAD; + } + + return 0; +} + +int +rte_thread_barrier_destroy(rte_thread_barrier_t *barrier) +{ + RTE_VERIFY(barrier != NULL); + + DeleteSynchronizationBarrier(barrier->barrier_id); + + free(barrier->barrier_id); + barrier->barrier_id = NULL; + + return 0; +} + int rte_thread_cancel(rte_thread_t thread_id) { -- 2.31.0.vfs.0.1