]> git.droids-corp.org - dpdk.git/commitdiff
eal: factorize lcore main loop
authorDavid Marchand <david.marchand@redhat.com>
Tue, 5 Apr 2022 16:34:47 +0000 (18:34 +0200)
committerDavid Marchand <david.marchand@redhat.com>
Thu, 14 Apr 2022 11:59:50 +0000 (13:59 +0200)
All OS implementations provide the same main loop.
Introduce helpers (shared for Linux and FreeBSD) to handle synchronisation
between main and threads and factorize the rest as common code.
Thread id are now logged as string in a common format across OS.

Note:
- this change also fixes Windows EAL: worker threads cpu affinity was
  incorrectly reported in log.

- libabigail flags this change as breaking ABI in clang builds:
  1 function with some indirect sub-type change:

  [C] 'function int rte_eal_remote_launch(int (void*)*, void*, unsigned
      int)' at eal_common_launch.c:35:1 has some indirect sub-type
      changes:
    parameter 1 of type 'int (void*)*' changed:
      in pointed to type 'function type int (void*)' at rte_launch.h:31:1:
        entity changed from 'function type int (void*)' to 'typedef
          lcore_function_t' at rte_launch.h:31:1
        type size hasn't changed

  This is being investigated on libabigail side.
  For now, we don't have much choice but to waive reports on this symbol.

Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Morten Brørup <mb@smartsharesystems.com>
Acked-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
devtools/libabigail.abignore
lib/eal/common/eal_common_launch.c
lib/eal/common/eal_common_thread.c
lib/eal/common/eal_thread.h
lib/eal/freebsd/eal.c
lib/eal/freebsd/eal_thread.c
lib/eal/linux/eal.c
lib/eal/linux/eal_thread.c
lib/eal/unix/eal_unix_thread.c [new file with mode: 0644]
lib/eal/unix/meson.build
lib/eal/windows/eal_thread.c

index 5be5c28dc3c608091b7b1639b555c0132bb06f25..79ff15dc4eb00850f3bde6ef8c1fabf91a52140a 100644 (file)
@@ -52,3 +52,7 @@
 ; Ignore visibility fix of local functions in experimental gpudev library
 [suppress_file]
         soname_regexp = ^librte_gpudev\.
+
+; Ignore libabigail false-positive in clang builds, after moving code.
+[suppress_function]
+       name = rte_eal_remote_launch
index 9f393b9bdaed74bda7a229ea21b2e5103cb00420..992f8e4631d132375c68cad0bf010816a9b74505 100644 (file)
@@ -5,11 +5,13 @@
 #include <errno.h>
 
 #include <rte_launch.h>
+#include <rte_eal_trace.h>
 #include <rte_atomic.h>
 #include <rte_pause.h>
 #include <rte_lcore.h>
 
 #include "eal_private.h"
+#include "eal_thread.h"
 
 /*
  * Wait until a lcore finished its job.
@@ -18,12 +20,44 @@ int
 rte_eal_wait_lcore(unsigned worker_id)
 {
        while (__atomic_load_n(&lcore_config[worker_id].state,
-                                       __ATOMIC_ACQUIRE) != WAIT)
+                       __ATOMIC_ACQUIRE) != WAIT)
                rte_pause();
 
        return lcore_config[worker_id].ret;
 }
 
+/*
+ * Send a message to a worker lcore identified by worker_id to call a
+ * function f with argument arg. Once the execution is done, the
+ * remote lcore switches to WAIT state.
+ */
+int
+rte_eal_remote_launch(lcore_function_t *f, void *arg, unsigned int worker_id)
+{
+       int rc = -EBUSY;
+
+       /* 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].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);
+
+       eal_thread_wake_worker(worker_id);
+       rc = 0;
+
+finish:
+       rte_eal_trace_thread_remote_launch(f, arg, worker_id, rc);
+       return rc;
+}
+
 /*
  * Check that every WORKER lcores are in WAIT state, then call
  * rte_eal_remote_launch() for all of them. If call_main is true
index 684bea166c3f293eff3413174a36ce54c390f8eb..962b7e9ac4013fa23895d2c0f079ec7973a7a8da 100644 (file)
@@ -9,6 +9,7 @@
 #include <assert.h>
 #include <string.h>
 
+#include <rte_eal_trace.h>
 #include <rte_errno.h>
 #include <rte_lcore.h>
 #include <rte_log.h>
@@ -163,6 +164,68 @@ __rte_thread_uninit(void)
        RTE_PER_LCORE(_lcore_id) = LCORE_ID_ANY;
 }
 
+/* main loop of threads */
+__rte_noreturn void *
+eal_thread_loop(void *arg)
+{
+       unsigned int lcore_id = (uintptr_t)arg;
+       char cpuset[RTE_CPU_AFFINITY_STR_LEN];
+       int ret;
+
+       __rte_thread_init(lcore_id, &lcore_config[lcore_id].cpuset);
+
+       ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
+       RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%zx;cpuset=[%s%s])\n",
+               lcore_id, (uintptr_t)pthread_self(), cpuset,
+               ret == 0 ? "" : "...");
+
+       rte_eal_trace_thread_lcore_ready(lcore_id, cpuset);
+
+       /* read on our pipe to get commands */
+       while (1) {
+               lcore_function_t *f;
+               void *fct_arg;
+
+               eal_thread_wait_command();
+
+               /* 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);
+
+               eal_thread_ack_command();
+
+               /* 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 = f(fct_arg);
+               lcore_config[lcore_id].ret = ret;
+               lcore_config[lcore_id].f = NULL;
+               lcore_config[lcore_id].arg = NULL;
+
+               /* 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 */
+       /* pthread_exit(NULL); */
+       /* return NULL; */
+}
+
 enum __rte_ctrl_thread_status {
        CTRL_THREAD_LAUNCHING, /* Yet to call pthread_create function */
        CTRL_THREAD_RUNNING, /* Control thread is running successfully */
index 3c84efd553745aee60d3a83d6eb241098addf5c3..ca3378d4639142d45d0563d801529fd96ac69021 100644 (file)
@@ -58,4 +58,31 @@ eal_thread_dump_affinity(rte_cpuset_t *cpuset, char *str, unsigned int size);
 int
 eal_thread_dump_current_affinity(char *str, unsigned int size);
 
+/**
+ * Called by the main thread to wake up a worker in 'WAIT' state.
+ * This function blocks until the worker acknowledge it started processing a
+ * new command.
+ * This function is private to EAL.
+ *
+ * @param worker_id
+ *   The lcore_id of a worker thread.
+ */
+void
+eal_thread_wake_worker(unsigned int worker_id);
+
+/**
+ * Called by a worker thread to sleep after entering 'WAIT' state.
+ * This function is private to EAL.
+ */
+void
+eal_thread_wait_command(void);
+
+/**
+ * Called by a worker thread to acknowledge new command after leaving 'WAIT'
+ * state.
+ * This function is private to EAL.
+ */
+void
+eal_thread_ack_command(void);
+
 #endif /* EAL_THREAD_H */
index e233e57184c58710ee43e935bc468fa7a4b6e5ec..a6b20960f2d5f5c790eaf8daddc89fc801c47b4e 100644 (file)
@@ -579,7 +579,6 @@ int
 rte_eal_init(int argc, char **argv)
 {
        int i, fctret, ret;
-       pthread_t thread_id;
        static uint32_t run_once;
        uint32_t has_run = 0;
        char cpuset[RTE_CPU_AFFINITY_STR_LEN];
@@ -604,8 +603,6 @@ rte_eal_init(int argc, char **argv)
                return -1;
        }
 
-       thread_id = pthread_self();
-
        eal_reset_internal_config(internal_conf);
 
        /* clone argv to report out later in telemetry */
@@ -794,8 +791,8 @@ rte_eal_init(int argc, char **argv)
 
        ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
 
-       RTE_LOG(DEBUG, EAL, "Main lcore %u is ready (tid=%p;cpuset=[%s%s])\n",
-               config->main_lcore, thread_id, cpuset,
+       RTE_LOG(DEBUG, EAL, "Main lcore %u is ready (tid=%zx;cpuset=[%s%s])\n",
+               config->main_lcore, (uintptr_t)pthread_self(), cpuset,
                ret == 0 ? "" : "...");
 
        RTE_LCORE_FOREACH_WORKER(i) {
index 9044d70ef77ea219f881c1c7c8d2807580ed98e4..ab81b527bcd6a1bc7ef1e0c89ab8031dea1b777f 100644 (file)
 #include <rte_per_lcore.h>
 #include <rte_eal.h>
 #include <rte_lcore.h>
-#include <rte_eal_trace.h>
 
 #include "eal_private.h"
 #include "eal_thread.h"
 
-/*
- * Send a message to a worker lcore identified by worker_id to call a
- * function f with argument arg. Once the execution is done, the
- * remote lcore switches to WAIT state.
- */
-int
-rte_eal_remote_launch(int (*f)(void *), void *arg, unsigned worker_id)
-{
-       int n;
-       char c = 0;
-       int m2w = lcore_config[worker_id].pipe_main2worker[1];
-       int w2m = lcore_config[worker_id].pipe_worker2main[0];
-       int rc = -EBUSY;
-
-       /* 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].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;
-       while (n == 0 || (n < 0 && errno == EINTR))
-               n = write(m2w, &c, 1);
-       if (n < 0)
-               rte_panic("cannot write on configuration pipe\n");
-
-       /* wait ack */
-       do {
-               n = read(w2m, &c, 1);
-       } while (n < 0 && errno == EINTR);
-
-       if (n <= 0)
-               rte_panic("cannot read on configuration pipe\n");
-
-       rc = 0;
-finish:
-       rte_eal_trace_thread_remote_launch(f, arg, worker_id, rc);
-       return rc;
-}
-
-/* main loop of threads */
-__rte_noreturn void *
-eal_thread_loop(void *arg)
-{
-       unsigned int lcore_id = (uintptr_t)arg;
-       char c;
-       int n, ret;
-       unsigned lcore_id;
-       int m2w, w2m;
-       char cpuset[RTE_CPU_AFFINITY_STR_LEN];
-
-       m2w = lcore_config[lcore_id].pipe_main2worker[0];
-       w2m = lcore_config[lcore_id].pipe_worker2main[1];
-
-       __rte_thread_init(lcore_id, &lcore_config[lcore_id].cpuset);
-
-       ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
-       RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%p;cpuset=[%s%s])\n",
-               lcore_id, pthread_self(), cpuset, ret == 0 ? "" : "...");
-
-       rte_eal_trace_thread_lcore_ready(lcore_id, cpuset);
-
-       /* read on our pipe to get commands */
-       while (1) {
-               lcore_function_t *f;
-               void *fct_arg;
-
-               /* wait command */
-               do {
-                       n = read(m2w, &c, 1);
-               } while (n < 0 && errno == EINTR);
-
-               if (n <= 0)
-                       rte_panic("cannot read on configuration pipe\n");
-
-               /* 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;
-               while (n == 0 || (n < 0 && errno == EINTR))
-                       n = write(w2m, &c, 1);
-               if (n < 0)
-                       rte_panic("cannot write on configuration pipe\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 = f(fct_arg);
-               lcore_config[lcore_id].ret = ret;
-               lcore_config[lcore_id].f = NULL;
-               lcore_config[lcore_id].arg = NULL;
-
-               /* 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 */
-       /* pthread_exit(NULL); */
-       /* return NULL; */
-}
-
 /* require calling thread tid by gettid() */
 int rte_sys_gettid(void)
 {
index 98c6838026827e81182016ddf1aa29f820044480..1ef263434abec8a8e64c86f79099cdcddf38b667 100644 (file)
@@ -862,7 +862,6 @@ int
 rte_eal_init(int argc, char **argv)
 {
        int i, fctret, ret;
-       pthread_t thread_id;
        static uint32_t run_once;
        uint32_t has_run = 0;
        const char *p;
@@ -890,7 +889,6 @@ rte_eal_init(int argc, char **argv)
 
        p = strrchr(argv[0], '/');
        strlcpy(logid, p ? p + 1 : argv[0], sizeof(logid));
-       thread_id = pthread_self();
 
        eal_reset_internal_config(internal_conf);
 
@@ -1129,7 +1127,7 @@ rte_eal_init(int argc, char **argv)
 
        ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
        RTE_LOG(DEBUG, EAL, "Main lcore %u is ready (tid=%zx;cpuset=[%s%s])\n",
-               config->main_lcore, (uintptr_t)thread_id, cpuset,
+               config->main_lcore, (uintptr_t)pthread_self(), cpuset,
                ret == 0 ? "" : "...");
 
        RTE_LCORE_FOREACH_WORKER(i) {
index 26b0a7d48aa5d22b65c11f06c7c0297cbcaa7596..820cc905e08c84771ae775e9d9159717b3743fc8 100644 (file)
 #include <rte_log.h>
 #include <rte_eal.h>
 #include <rte_lcore.h>
-#include <rte_eal_trace.h>
+#include <rte_string_fns.h>
 
 #include "eal_private.h"
 #include "eal_thread.h"
 
-/*
- * Send a message to a worker lcore identified by worker_id to call a
- * function f with argument arg. Once the execution is done, the
- * remote lcore switches to WAIT state.
- */
-int
-rte_eal_remote_launch(int (*f)(void *), void *arg, unsigned int worker_id)
-{
-       int n;
-       char c = 0;
-       int m2w = lcore_config[worker_id].pipe_main2worker[1];
-       int w2m = lcore_config[worker_id].pipe_worker2main[0];
-       int rc = -EBUSY;
-
-       /* 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].arg = arg;
-       /* Ensure that all the memory operations are completed
-        * before the worker thread starts running the function.
-        * Use worker thread function pointer as the guard variable.
-        */
-       __atomic_store_n(&lcore_config[worker_id].f, f, __ATOMIC_RELEASE);
-
-       /* send message */
-       n = 0;
-       while (n == 0 || (n < 0 && errno == EINTR))
-               n = write(m2w, &c, 1);
-       if (n < 0)
-               rte_panic("cannot write on configuration pipe\n");
-
-       /* wait ack */
-       do {
-               n = read(w2m, &c, 1);
-       } while (n < 0 && errno == EINTR);
-
-       if (n <= 0)
-               rte_panic("cannot read on configuration pipe\n");
-
-       rc = 0;
-finish:
-       rte_eal_trace_thread_remote_launch(f, arg, worker_id, rc);
-       return rc;
-}
-
-/* main loop of threads */
-__rte_noreturn void *
-eal_thread_loop(void *arg)
-{
-       unsigned int lcore_id = (uintptr_t)arg;
-       char c;
-       int n, ret;
-       int m2w, w2m;
-       char cpuset[RTE_CPU_AFFINITY_STR_LEN];
-
-
-       m2w = lcore_config[lcore_id].pipe_main2worker[0];
-       w2m = lcore_config[lcore_id].pipe_worker2main[1];
-
-       __rte_thread_init(lcore_id, &lcore_config[lcore_id].cpuset);
-
-       ret = eal_thread_dump_current_affinity(cpuset, sizeof(cpuset));
-       RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%zx;cpuset=[%s%s])\n",
-               lcore_id, (uintptr_t)pthread_self(), cpuset,
-               ret == 0 ? "" : "...");
-
-       rte_eal_trace_thread_lcore_ready(lcore_id, cpuset);
-
-       /* read on our pipe to get commands */
-       while (1) {
-               lcore_function_t *f;
-               void *fct_arg;
-
-               /* wait command */
-               do {
-                       n = read(m2w, &c, 1);
-               } while (n < 0 && errno == EINTR);
-
-               if (n <= 0)
-                       rte_panic("cannot read on configuration pipe\n");
-
-               /* 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;
-               while (n == 0 || (n < 0 && errno == EINTR))
-                       n = write(w2m, &c, 1);
-               if (n < 0)
-                       rte_panic("cannot write on configuration pipe\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 = f(fct_arg);
-               lcore_config[lcore_id].ret = ret;
-               lcore_config[lcore_id].f = NULL;
-               lcore_config[lcore_id].arg = NULL;
-
-               /* 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 */
-       /* pthread_exit(NULL); */
-       /* return NULL; */
-}
-
 /* require calling thread tid by gettid() */
 int rte_sys_gettid(void)
 {
diff --git a/lib/eal/unix/eal_unix_thread.c b/lib/eal/unix/eal_unix_thread.c
new file mode 100644 (file)
index 0000000..70b5ba6
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Red Hat, Inc.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <rte_debug.h>
+
+#include "eal_private.h"
+
+void
+eal_thread_wake_worker(unsigned int worker_id)
+{
+       int m2w = lcore_config[worker_id].pipe_main2worker[1];
+       int w2m = lcore_config[worker_id].pipe_worker2main[0];
+       char c = 0;
+       int n;
+
+       do {
+               n = write(m2w, &c, 1);
+       } while (n == 0 || (n < 0 && errno == EINTR));
+       if (n < 0)
+               rte_panic("cannot write on configuration pipe\n");
+
+       do {
+               n = read(w2m, &c, 1);
+       } while (n < 0 && errno == EINTR);
+       if (n <= 0)
+               rte_panic("cannot read on configuration pipe\n");
+}
+
+void
+eal_thread_wait_command(void)
+{
+       unsigned int lcore_id = rte_lcore_id();
+       int m2w;
+       char c;
+       int n;
+
+       m2w = lcore_config[lcore_id].pipe_main2worker[0];
+       do {
+               n = read(m2w, &c, 1);
+       } while (n < 0 && errno == EINTR);
+       if (n <= 0)
+               rte_panic("cannot read on configuration pipe\n");
+}
+
+void
+eal_thread_ack_command(void)
+{
+       unsigned int lcore_id = rte_lcore_id();
+       char c = 0;
+       int w2m;
+       int n;
+
+       w2m = lcore_config[lcore_id].pipe_worker2main[1];
+       do {
+               n = write(w2m, &c, 1);
+       } while (n == 0 || (n < 0 && errno == EINTR));
+       if (n < 0)
+               rte_panic("cannot write on configuration pipe\n");
+}
index a22ea7cabc46fff114af3a1790d95a24ac1460e9..781505ca90612093383a83ebadf6ffb1e9beb85c 100644 (file)
@@ -3,9 +3,10 @@
 
 sources += files(
         'eal_file.c',
+        'eal_filesystem.c',
+        'eal_firmware.c',
         'eal_unix_memory.c',
+        'eal_unix_thread.c',
         'eal_unix_timer.c',
-        'eal_firmware.c',
-        'eal_filesystem.c',
         'rte_thread.c',
 )
index 95e96548dea81d13089d781729a4dc2e98188672..f3c61b44566ebc0241aaa704b82097b33c49f2cb 100644 (file)
 #include <rte_per_lcore.h>
 #include <rte_common.h>
 #include <rte_memory.h>
-#include <eal_thread.h>
 
 #include "eal_private.h"
+#include "eal_thread.h"
 #include "eal_windows.h"
 
-/*
- * Send a message to a worker lcore identified by worker_id to call a
- * function f with argument arg. Once the execution is done, the
- * remote lcore switches to WAIT state.
- */
-int
-rte_eal_remote_launch(lcore_function_t *f, void *arg, unsigned int worker_id)
+void
+eal_thread_wake_worker(unsigned int worker_id)
 {
-       int n;
-       char c = 0;
        int m2w = lcore_config[worker_id].pipe_main2worker[1];
        int w2m = lcore_config[worker_id].pipe_worker2main[0];
+       char c = 0;
+       int n;
 
-       /* 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)
-               return -EBUSY;
-
-       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;
-       while (n == 0 || (n < 0 && errno == EINTR))
+       do {
                n = _write(m2w, &c, 1);
+       } while (n == 0 || (n < 0 && errno == EINTR));
        if (n < 0)
                rte_panic("cannot write on configuration pipe\n");
 
-       /* wait ack */
        do {
                n = _read(w2m, &c, 1);
        } while (n < 0 && errno == EINTR);
-
        if (n <= 0)
                rte_panic("cannot read on configuration pipe\n");
-
-       return 0;
 }
 
-/* main loop of threads */
-void *
-eal_thread_loop(void *arg)
+void
+eal_thread_wait_command(void)
 {
-       unsigned int lcore_id = (uintptr_t)arg;
+       unsigned int lcore_id = rte_lcore_id();
+       int m2w;
        char c;
-       int n, ret;
-       int m2w, w2m;
-       char cpuset[RTE_CPU_AFFINITY_STR_LEN];
+       int n;
 
        m2w = lcore_config[lcore_id].pipe_main2worker[0];
-       w2m = lcore_config[lcore_id].pipe_worker2main[1];
+       do {
+               n = _read(m2w, &c, 1);
+       } while (n < 0 && errno == EINTR);
+       if (n <= 0)
+               rte_panic("cannot read on configuration pipe\n");
+}
 
-       __rte_thread_init(lcore_id, &lcore_config[lcore_id].cpuset);
-
-       RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%zx;cpuset=[%s])\n",
-               lcore_id, (uintptr_t)pthread_self(), cpuset);
-
-       /* read on our pipe to get commands */
-       while (1) {
-               lcore_function_t *f;
-               void *fct_arg;
-
-               /* wait command */
-               do {
-                       n = _read(m2w, &c, 1);
-               } while (n < 0 && errno == EINTR);
-
-               if (n <= 0)
-                       rte_panic("cannot read on configuration pipe\n");
-
-               /* 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;
-               while (n == 0 || (n < 0 && errno == EINTR))
-                       n = _write(w2m, &c, 1);
-               if (n < 0)
-                       rte_panic("cannot write on configuration pipe\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 = f(fct_arg);
-               lcore_config[lcore_id].ret = ret;
-               lcore_config[lcore_id].f = NULL;
-               lcore_config[lcore_id].arg = NULL;
-
-               /* 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);
-       }
+void
+eal_thread_ack_command(void)
+{
+       unsigned int lcore_id = rte_lcore_id();
+       char c = 0;
+       int w2m;
+       int n;
+
+       w2m = lcore_config[lcore_id].pipe_worker2main[1];
+       do {
+               n = _write(w2m, &c, 1);
+       } while (n == 0 || (n < 0 && errno == EINTR));
+       if (n < 0)
+               rte_panic("cannot write on configuration pipe\n");
 }
 
 /* function to create threads */