eal: fix memory ordering around lcore task accesses
[dpdk.git] / lib / eal / freebsd / eal_thread.c
index ce314c1..3b18030 100644 (file)
@@ -39,11 +39,19 @@ rte_eal_remote_launch(int (*f)(void *), void *arg, unsigned worker_id)
        int w2m = lcore_config[worker_id].pipe_worker2main[0];
        int rc = -EBUSY;
 
-       if (lcore_config[worker_id].state != WAIT)
+       /* Check if the worker is in 'WAIT' state. Use acquire order
+        * since 'state' variable is used as the guard variable.
+        */
+       if (__atomic_load_n(&lcore_config[worker_id].state,
+                                       __ATOMIC_ACQUIRE) != 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 +108,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 */
@@ -110,7 +119,11 @@ eal_thread_loop(__rte_unused void *arg)
                if (n <= 0)
                        rte_panic("cannot read on configuration pipe\n");
 
-               lcore_config[lcore_id].state = RUNNING;
+               /* Set the state to 'RUNNING'. Use release order
+                * since 'state' variable is used as the guard variable.
+                */
+               __atomic_store_n(&lcore_config[lcore_id].state, RUNNING,
+                                       __ATOMIC_RELEASE);
 
                /* send ack */
                n = 0;
@@ -119,17 +132,29 @@ 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;
-               rte_wmb();
-               lcore_config[lcore_id].state = WAIT;
+
+               /* Store the state with release order to ensure that
+                * the memory operations from the worker thread
+                * are completed before the state is updated.
+                * Use 'state' as the guard variable.
+                */
+               __atomic_store_n(&lcore_config[lcore_id].state, WAIT,
+                                       __ATOMIC_RELEASE);
        }
 
        /* never reached */