From patchwork Mon Aug 2 17:32:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Narcisa Ana Maria Vasile X-Patchwork-Id: 96557 Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 4FE21A0C41; Mon, 2 Aug 2021 19:33:07 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 841AB4119B; Mon, 2 Aug 2021 19:32:39 +0200 (CEST) Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by mails.dpdk.org (Postfix) with ESMTP id 8DA564117D for ; Mon, 2 Aug 2021 19:32:32 +0200 (CEST) Received: by linux.microsoft.com (Postfix, from userid 1059) id 516FA20B26FD; Mon, 2 Aug 2021 10:32:31 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 516FA20B26FD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1627925551; bh=cZ6mEmqcnWA8b7Ww2j7URe44ln6Kp4O7AdxBtaRoxIM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jL1T2ZSF3pewOJlRCaULM+Vq1QhT8QeL7ISsSiFpNp1RdH1J13kBQW919bGJMKghb UKGIw7sUxVFpBrUK2Zo8rr+cjsibVBIrE79f2xsfIPxFfGoWhjUO0dKjFON1lVecpn YP2oIg4N4a4xtF+cgZ9WZmIz8u10JbCiuHIauI3E= From: Narcisa Ana Maria Vasile To: dev@dpdk.org, thomas@monjalon.net, dmitry.kozliuk@gmail.com, khot@microsoft.com, navasile@microsoft.com, dmitrym@microsoft.com, roretzla@microsoft.com, talshn@nvidia.com, ocardona@microsoft.com Cc: bruce.richardson@intel.com, david.marchand@redhat.com, pallavi.kadam@intel.com Date: Mon, 2 Aug 2021 10:32:24 -0700 Message-Id: <1627925546-29982-9-git-send-email-navasile@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1627925546-29982-1-git-send-email-navasile@linux.microsoft.com> References: <1627684312-28630-1-git-send-email-navasile@linux.microsoft.com> <1627925546-29982-1-git-send-email-navasile@linux.microsoft.com> Subject: [dpdk-dev] [PATCH v12 08/10] eal: implement functions for thread barrier management X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Narcisa Vasile 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. Signed-off-by: Narcisa Vasile --- lib/eal/common/rte_thread.c | 61 ++++++++++++++++++++++++++++++++++++ lib/eal/include/rte_thread.h | 58 ++++++++++++++++++++++++++++++++++ lib/eal/version.map | 3 ++ lib/eal/windows/rte_thread.c | 56 +++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+) diff --git a/lib/eal/common/rte_thread.c b/lib/eal/common/rte_thread.c index ebae4a8af1..3fdb267337 100644 --- a/lib/eal/common/rte_thread.c +++ b/lib/eal/common/rte_thread.c @@ -312,6 +312,67 @@ rte_thread_mutex_destroy(rte_thread_mutex *mutex) return ret; } +int +rte_thread_barrier_init(rte_thread_barrier *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, "Failed to init 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 *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 *barrier) +{ + int ret = 0; + + RTE_VERIFY(barrier != NULL); + + ret = pthread_barrier_destroy(barrier->barrier_id); + if (ret != 0) + RTE_LOG(DEBUG, EAL, "Failed to destroy barrier: %d\n", ret); + + free(barrier->barrier_id); + barrier->barrier_id = NULL; + + return ret; +} + int rte_thread_key_create(rte_thread_key *key, void (*destructor)(void *)) { diff --git a/lib/eal/include/rte_thread.h b/lib/eal/include/rte_thread.h index 7e813b573d..40da83467b 100644 --- a/lib/eal/include/rte_thread.h +++ b/lib/eal/include/rte_thread.h @@ -76,6 +76,18 @@ typedef struct rte_thread_mutex_tag { void *mutex_id; /**< mutex identifier */ } rte_thread_mutex; +/** + * Returned by rte_thread_barrier_wait() when call is successful. + */ +#define RTE_THREAD_BARRIER_SERIAL_THREAD -1 + +/** + * Thread barrier representation. + */ +typedef struct rte_thread_barrier_tag { + void *barrier_id; /**< barrrier identifier */ +} rte_thread_barrier; + /** * TLS key type, an opaque pointer. */ @@ -381,6 +393,52 @@ int rte_thread_mutex_unlock(rte_thread_mutex *mutex); __rte_experimental int rte_thread_mutex_destroy(rte_thread_mutex *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 *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 *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 *barrier); + /** * Create a TLS data key visible to all threads in the process. * the created key is later used to get/set a value. diff --git a/lib/eal/version.map b/lib/eal/version.map index a1c7a8e87d..c081fdd96c 100644 --- a/lib/eal/version.map +++ b/lib/eal/version.map @@ -443,6 +443,9 @@ EXPERIMENTAL { rte_thread_mutex_lock; rte_thread_mutex_unlock; rte_thread_mutex_destroy; + rte_thread_barrier_init; + rte_thread_barrier_wait; + rte_thread_barrier_destroy; }; INTERNAL { diff --git a/lib/eal/windows/rte_thread.c b/lib/eal/windows/rte_thread.c index 23f00cfba2..b2ff16f51f 100644 --- a/lib/eal/windows/rte_thread.c +++ b/lib/eal/windows/rte_thread.c @@ -500,6 +500,62 @@ rte_thread_mutex_destroy(rte_thread_mutex *mutex) return 0; } +int +rte_thread_barrier_init(rte_thread_barrier *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 *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 *barrier) +{ + RTE_VERIFY(barrier != NULL); + + DeleteSynchronizationBarrier(barrier->barrier_id); + + free(barrier->barrier_id); + barrier->barrier_id = NULL; + + return 0; +} + int rte_thread_key_create(rte_thread_key *key, __rte_unused void (*destructor)(void *))