[RFC,2/5] eal: ensure memory operations are visible to worker

Message ID 20210224212018.17576-3-honnappa.nagarahalli@arm.com
State New
Headers show
Series
  • Use correct memory ordering in eal functions
Related show

Commit Message

Honnappa Nagarahalli Feb. 24, 2021, 9:20 p.m.
Ensure that the memory operations before the call to
rte_eal_remote_launch are visible to the worker thread.

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

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

---
 lib/librte_eal/freebsd/eal_thread.c | 19 +++++++++++++++----
 lib/librte_eal/linux/eal_thread.c   | 19 +++++++++++++++----
 lib/librte_eal/windows/eal_thread.c | 19 +++++++++++++++----
 3 files changed, 45 insertions(+), 12 deletions(-)

-- 
2.17.1

Patch

diff --git a/lib/librte_eal/freebsd/eal_thread.c b/lib/librte_eal/freebsd/eal_thread.c
index bbc3a8e98..17b8f3996 100644
--- a/lib/librte_eal/freebsd/eal_thread.c
+++ b/lib/librte_eal/freebsd/eal_thread.c
@@ -42,8 +42,12 @@  rte_eal_remote_launch(int (*f)(void *), void *arg, unsigned worker_id)
 	if (lcore_config[worker_id].state != WAIT)
 		goto finish;
 
-	lcore_config[worker_id].f = f;
 	lcore_config[worker_id].arg = arg;
+	/* Ensure that all the memory operations are completed
+	 * before the worker thread starts running the function.
+	 * Use worker thread function as the guard variable.
+	 */
+	__atomic_store_n(&lcore_config[worker_id].f, f, __ATOMIC_RELEASE);
 
 	/* send message */
 	n = 0;
@@ -100,6 +104,7 @@  eal_thread_loop(__rte_unused void *arg)
 
 	/* read on our pipe to get commands */
 	while (1) {
+		lcore_function_t *f;
 		void *fct_arg;
 
 		/* wait command */
@@ -119,12 +124,18 @@  eal_thread_loop(__rte_unused void *arg)
 		if (n < 0)
 			rte_panic("cannot write on configuration pipe\n");
 
-		if (lcore_config[lcore_id].f == NULL)
-			rte_panic("NULL function pointer\n");
+		/* Load 'f' with acquire order to ensure that
+		 * the memory operations from the main thread
+		 * are accessed only after update to 'f' is visible.
+		 * Wait till the update to 'f' is visible to the worker.
+		 */
+		while ((f = __atomic_load_n(&lcore_config[lcore_id].f,
+			__ATOMIC_ACQUIRE)) == NULL)
+			rte_pause();
 
 		/* call the function and store the return value */
 		fct_arg = lcore_config[lcore_id].arg;
-		ret = lcore_config[lcore_id].f(fct_arg);
+		ret = f(fct_arg);
 		lcore_config[lcore_id].ret = ret;
 		lcore_config[lcore_id].f = NULL;
 		lcore_config[lcore_id].arg = NULL;
diff --git a/lib/librte_eal/linux/eal_thread.c b/lib/librte_eal/linux/eal_thread.c
index 8f3c0dafd..a0a009104 100644
--- a/lib/librte_eal/linux/eal_thread.c
+++ b/lib/librte_eal/linux/eal_thread.c
@@ -42,8 +42,12 @@  rte_eal_remote_launch(int (*f)(void *), void *arg, unsigned int worker_id)
 	if (lcore_config[worker_id].state != WAIT)
 		goto finish;
 
-	lcore_config[worker_id].f = f;
 	lcore_config[worker_id].arg = arg;
+	/* Ensure that all the memory operations are completed
+	 * before the worker thread starts running the function.
+	 * Use worker thread function as the guard variable.
+	 */
+	__atomic_store_n(&lcore_config[worker_id].f, f, __ATOMIC_RELEASE);
 
 	/* send message */
 	n = 0;
@@ -100,6 +104,7 @@  eal_thread_loop(__rte_unused void *arg)
 
 	/* read on our pipe to get commands */
 	while (1) {
+		lcore_function_t *f;
 		void *fct_arg;
 
 		/* wait command */
@@ -119,12 +124,18 @@  eal_thread_loop(__rte_unused void *arg)
 		if (n < 0)
 			rte_panic("cannot write on configuration pipe\n");
 
-		if (lcore_config[lcore_id].f == NULL)
-			rte_panic("NULL function pointer\n");
+		/* Load 'f' with acquire order to ensure that
+		 * the memory operations from the main thread
+		 * are accessed only after update to 'f' is visible.
+		 * Wait till the update to 'f' is visible to the worker.
+		 */
+		while ((f = __atomic_load_n(&lcore_config[lcore_id].f,
+			__ATOMIC_ACQUIRE)) == NULL)
+			rte_pause();
 
 		/* call the function and store the return value */
 		fct_arg = lcore_config[lcore_id].arg;
-		ret = lcore_config[lcore_id].f(fct_arg);
+		ret = f(fct_arg);
 		lcore_config[lcore_id].ret = ret;
 		lcore_config[lcore_id].f = NULL;
 		lcore_config[lcore_id].arg = NULL;
diff --git a/lib/librte_eal/windows/eal_thread.c b/lib/librte_eal/windows/eal_thread.c
index b69672fe0..7a9277c51 100644
--- a/lib/librte_eal/windows/eal_thread.c
+++ b/lib/librte_eal/windows/eal_thread.c
@@ -32,8 +32,12 @@  rte_eal_remote_launch(lcore_function_t *f, void *arg, unsigned int worker_id)
 	if (lcore_config[worker_id].state != WAIT)
 		return -EBUSY;
 
-	lcore_config[worker_id].f = f;
 	lcore_config[worker_id].arg = arg;
+	/* Ensure that all the memory operations are completed
+	 * before the worker thread starts running the function.
+	 * Use worker thread function as the guard variable.
+	 */
+	__atomic_store_n(&lcore_config[worker_id].f, f, __ATOMIC_RELEASE);
 
 	/* send message */
 	n = 0;
@@ -84,6 +88,7 @@  eal_thread_loop(void *arg __rte_unused)
 
 	/* read on our pipe to get commands */
 	while (1) {
+		lcore_function_t *f;
 		void *fct_arg;
 
 		/* wait command */
@@ -103,12 +108,18 @@  eal_thread_loop(void *arg __rte_unused)
 		if (n < 0)
 			rte_panic("cannot write on configuration pipe\n");
 
-		if (lcore_config[lcore_id].f == NULL)
-			rte_panic("NULL function pointer\n");
+		/* Load 'f' with acquire order to ensure that
+		 * the memory operations from the main thread
+		 * are accessed only after update to 'f' is visible.
+		 * Wait till the update to 'f' is visible to the worker.
+		 */
+		while ((f = __atomic_load_n(&lcore_config[lcore_id].f,
+			__ATOMIC_ACQUIRE)) == NULL)
+			rte_pause();
 
 		/* call the function and store the return value */
 		fct_arg = lcore_config[lcore_id].arg;
-		ret = lcore_config[lcore_id].f(fct_arg);
+		ret = f(fct_arg);
 		lcore_config[lcore_id].ret = ret;
 		lcore_config[lcore_id].f = NULL;
 		lcore_config[lcore_id].arg = NULL;