[dpdk-dev] [PATCH v3 1/2] eal: simplify the implementation of rte_ctrl_thread_create

Honnappa Nagarahalli honnappa.nagarahalli at arm.com
Mon Aug 30 18:34:12 CEST 2021


Remove the usage of pthread barrier and replace it with
synchronization using atomic variable. This also removes
the use of reference count required to synchronize freeing
the memory.

Signed-off-by: Honnappa Nagarahalli <honnappa.nagarahalli at arm.com>
---
v3:
1) RFC to Patch
2) Changed commit log and API description [Olivier]
3) Used sched_yield while spinning [Stephen]
4) Fixed use after free
5) Added a test case

v2:
1) Used compiler's C++11 atomic built-ins to access the shared variable.

 lib/eal/common/eal_common_thread.c | 83 +++++++++++++++---------------
 lib/eal/include/rte_lcore.h        |  9 ++--
 2 files changed, 46 insertions(+), 46 deletions(-)

diff --git a/lib/eal/common/eal_common_thread.c b/lib/eal/common/eal_common_thread.c
index 1a52f42a2b..b0af965b7b 100644
--- a/lib/eal/common/eal_common_thread.c
+++ b/lib/eal/common/eal_common_thread.c
@@ -166,38 +166,46 @@ __rte_thread_uninit(void)
 	RTE_PER_LCORE(_lcore_id) = LCORE_ID_ANY;
 }
 
+#define _RTE_CTRL_THREAD_LAUNCHING 0
+#define _RTE_CTRL_THREAD_RUNNING 1
+#define _RTE_CTRL_THREAD_ERROR 2
+
 struct rte_thread_ctrl_params {
 	void *(*start_routine)(void *);
 	void *arg;
-	pthread_barrier_t configured;
-	unsigned int refcnt;
+	int ret;
+	/* Control thread status.
+	 *
+	 * _RTE_CTRL_THREAD_LAUNCHING - Yet to call pthread_create function
+	 * _RTE_CTRL_THREAD_RUNNING - Control thread is running successfully
+	 * _RTE_CTRL_THREAD_ERROR - Control thread encountered an error.
+	 *                          'ret' has the error code.
+	 */
+	unsigned int ctrl_thread_status;
 };
 
-static void ctrl_params_free(struct rte_thread_ctrl_params *params)
-{
-	if (__atomic_sub_fetch(&params->refcnt, 1, __ATOMIC_ACQ_REL) == 0) {
-		(void)pthread_barrier_destroy(&params->configured);
-		free(params);
-	}
-}
-
 static void *ctrl_thread_init(void *arg)
 {
 	struct internal_config *internal_conf =
 		eal_get_internal_configuration();
 	rte_cpuset_t *cpuset = &internal_conf->ctrl_cpuset;
 	struct rte_thread_ctrl_params *params = arg;
-	void *(*start_routine)(void *);
+	void *(*start_routine)(void *) = params->start_routine;
 	void *routine_arg = params->arg;
 
 	__rte_thread_init(rte_lcore_id(), cpuset);
-
-	pthread_barrier_wait(&params->configured);
-	start_routine = params->start_routine;
-	ctrl_params_free(params);
-
-	if (start_routine == NULL)
+	params->ret = pthread_setaffinity_np(pthread_self(),
+				sizeof(*cpuset), cpuset);
+	if (params->ret != 0) {
+		__atomic_store_n(&params->ctrl_thread_status,
+					_RTE_CTRL_THREAD_ERROR,
+					__ATOMIC_RELEASE);
 		return NULL;
+	}
+
+	__atomic_store_n(&params->ctrl_thread_status,
+				_RTE_CTRL_THREAD_RUNNING,
+				__ATOMIC_RELEASE);
 
 	return start_routine(routine_arg);
 }
@@ -207,10 +215,8 @@ rte_ctrl_thread_create(pthread_t *thread, const char *name,
 		const pthread_attr_t *attr,
 		void *(*start_routine)(void *), void *arg)
 {
-	struct internal_config *internal_conf =
-		eal_get_internal_configuration();
-	rte_cpuset_t *cpuset = &internal_conf->ctrl_cpuset;
 	struct rte_thread_ctrl_params *params;
+	unsigned int ctrl_thread_status;
 	int ret;
 
 	params = malloc(sizeof(*params));
@@ -219,15 +225,14 @@ rte_ctrl_thread_create(pthread_t *thread, const char *name,
 
 	params->start_routine = start_routine;
 	params->arg = arg;
-	params->refcnt = 2;
-
-	ret = pthread_barrier_init(&params->configured, NULL, 2);
-	if (ret != 0)
-		goto fail_no_barrier;
+	params->ret = 0;
+	params->ctrl_thread_status = _RTE_CTRL_THREAD_LAUNCHING;
 
 	ret = pthread_create(thread, attr, ctrl_thread_init, (void *)params);
-	if (ret != 0)
-		goto fail_with_barrier;
+	if (ret != 0) {
+		free(params);
+		return -ret;
+	}
 
 	if (name != NULL) {
 		ret = rte_thread_setname(*thread, name);
@@ -236,24 +241,18 @@ rte_ctrl_thread_create(pthread_t *thread, const char *name,
 				"Cannot set name for ctrl thread\n");
 	}
 
-	ret = pthread_setaffinity_np(*thread, sizeof(*cpuset), cpuset);
-	if (ret != 0)
-		params->start_routine = NULL;
-
-	pthread_barrier_wait(&params->configured);
-	ctrl_params_free(params);
+	/* Wait for the control thread to initialize successfully */
+	while ((ctrl_thread_status =
+		__atomic_load_n(&params->ctrl_thread_status, __ATOMIC_ACQUIRE))
+		== _RTE_CTRL_THREAD_LAUNCHING)
+		sched_yield();
 
-	if (ret != 0)
-		/* start_routine has been set to NULL above; */
-		/* ctrl thread will exit immediately */
+	/* Check if the control thread encountered an error */
+	if (ctrl_thread_status == _RTE_CTRL_THREAD_ERROR)
+		/* ctrl thread is exiting */
 		pthread_join(*thread, NULL);
 
-	return -ret;
-
-fail_with_barrier:
-	(void)pthread_barrier_destroy(&params->configured);
-
-fail_no_barrier:
+	ret = params->ret;
 	free(params);
 
 	return -ret;
diff --git a/lib/eal/include/rte_lcore.h b/lib/eal/include/rte_lcore.h
index 1550b75da0..b81c8b2685 100644
--- a/lib/eal/include/rte_lcore.h
+++ b/lib/eal/include/rte_lcore.h
@@ -420,10 +420,11 @@ rte_thread_unregister(void);
 /**
  * Create a control thread.
  *
- * Wrapper to pthread_create(), pthread_setname_np() and
- * pthread_setaffinity_np(). The affinity of the new thread is based
- * on the CPU affinity retrieved at the time rte_eal_init() was called,
- * the dataplane and service lcores are then excluded.
+ * Creates a control thread with the given name and attributes. The
+ * affinity of the new thread is based on the CPU affinity retrieved
+ * at the time rte_eal_init() was called, the dataplane and service
+ * lcores are then excluded. If setting the name of the thread fails,
+ * the error is ignored and a debug message is logged.
  *
  * @param thread
  *   Filled with the thread id of the new created thread.
-- 
2.25.1



More information about the dev mailing list