15c307ba2SDavid Marchand /* SPDX-License-Identifier: BSD-3-Clause
25c307ba2SDavid Marchand * Copyright (c) 2020 Red Hat, Inc.
35c307ba2SDavid Marchand */
45c307ba2SDavid Marchand
56bd7a4b2SDavid Marchand #include <sched.h>
65c307ba2SDavid Marchand #include <string.h>
76bd7a4b2SDavid Marchand #include <unistd.h>
85c307ba2SDavid Marchand
961bb5312SDavid Marchand #include <rte_common.h>
105c307ba2SDavid Marchand #include <rte_errno.h>
115c307ba2SDavid Marchand #include <rte_lcore.h>
120e497ee5STyler Retzlaff #include <rte_thread.h>
13*b6a7e685STyler Retzlaff #include <rte_stdatomic.h>
145c307ba2SDavid Marchand
155c307ba2SDavid Marchand #include "test.h"
165c307ba2SDavid Marchand
176bd7a4b2SDavid Marchand #ifndef _POSIX_PRIORITY_SCHEDULING
186bd7a4b2SDavid Marchand /* sched_yield(2):
196bd7a4b2SDavid Marchand * POSIX systems on which sched_yield() is available define
206bd7a4b2SDavid Marchand * _POSIX_PRIORITY_SCHEDULING in <unistd.h>.
216bd7a4b2SDavid Marchand */
226bd7a4b2SDavid Marchand #define sched_yield()
236bd7a4b2SDavid Marchand #endif
246bd7a4b2SDavid Marchand
255c307ba2SDavid Marchand struct thread_context {
26f6846729SJie Zhou enum { Thread_INIT, Thread_ERROR, Thread_DONE } state;
275c307ba2SDavid Marchand bool lcore_id_any;
280e497ee5STyler Retzlaff rte_thread_t id;
29*b6a7e685STyler Retzlaff RTE_ATOMIC(unsigned int) *registered_count;
305c307ba2SDavid Marchand };
315c307ba2SDavid Marchand
thread_loop(void * arg)320e497ee5STyler Retzlaff static uint32_t thread_loop(void *arg)
335c307ba2SDavid Marchand {
345c307ba2SDavid Marchand struct thread_context *t = arg;
355c307ba2SDavid Marchand unsigned int lcore_id;
365c307ba2SDavid Marchand
375c307ba2SDavid Marchand lcore_id = rte_lcore_id();
385c307ba2SDavid Marchand if (lcore_id != LCORE_ID_ANY) {
395c307ba2SDavid Marchand printf("Error: incorrect lcore id for new thread %u\n", lcore_id);
40f6846729SJie Zhou t->state = Thread_ERROR;
415c307ba2SDavid Marchand }
425c307ba2SDavid Marchand if (rte_thread_register() < 0)
435c307ba2SDavid Marchand printf("Warning: could not register new thread (this might be expected during this test), reason %s\n",
445c307ba2SDavid Marchand rte_strerror(rte_errno));
455c307ba2SDavid Marchand lcore_id = rte_lcore_id();
465c307ba2SDavid Marchand if ((t->lcore_id_any && lcore_id != LCORE_ID_ANY) ||
475c307ba2SDavid Marchand (!t->lcore_id_any && lcore_id == LCORE_ID_ANY)) {
485c307ba2SDavid Marchand printf("Error: could not register new thread, got %u while %sexpecting %u\n",
495c307ba2SDavid Marchand lcore_id, t->lcore_id_any ? "" : "not ", LCORE_ID_ANY);
50f6846729SJie Zhou t->state = Thread_ERROR;
515c307ba2SDavid Marchand }
525c307ba2SDavid Marchand /* Report register happened to the control thread. */
53*b6a7e685STyler Retzlaff rte_atomic_fetch_add_explicit(t->registered_count, 1, rte_memory_order_release);
545c307ba2SDavid Marchand
555c307ba2SDavid Marchand /* Wait for release from the control thread. */
56*b6a7e685STyler Retzlaff while (rte_atomic_load_explicit(t->registered_count, rte_memory_order_acquire) != 0)
576bd7a4b2SDavid Marchand sched_yield();
585c307ba2SDavid Marchand rte_thread_unregister();
595c307ba2SDavid Marchand lcore_id = rte_lcore_id();
605c307ba2SDavid Marchand if (lcore_id != LCORE_ID_ANY) {
615c307ba2SDavid Marchand printf("Error: could not unregister new thread, %u still assigned\n",
625c307ba2SDavid Marchand lcore_id);
63f6846729SJie Zhou t->state = Thread_ERROR;
645c307ba2SDavid Marchand }
655c307ba2SDavid Marchand
66f6846729SJie Zhou if (t->state != Thread_ERROR)
67f6846729SJie Zhou t->state = Thread_DONE;
685c307ba2SDavid Marchand
690e497ee5STyler Retzlaff return 0;
705c307ba2SDavid Marchand }
715c307ba2SDavid Marchand
725c307ba2SDavid Marchand static int
test_non_eal_lcores(unsigned int eal_threads_count)735c307ba2SDavid Marchand test_non_eal_lcores(unsigned int eal_threads_count)
745c307ba2SDavid Marchand {
755c307ba2SDavid Marchand struct thread_context thread_contexts[RTE_MAX_LCORE];
765c307ba2SDavid Marchand unsigned int non_eal_threads_count;
77*b6a7e685STyler Retzlaff RTE_ATOMIC(unsigned int) registered_count;
785c307ba2SDavid Marchand struct thread_context *t;
795c307ba2SDavid Marchand unsigned int i;
805c307ba2SDavid Marchand int ret;
815c307ba2SDavid Marchand
825c307ba2SDavid Marchand non_eal_threads_count = 0;
835c307ba2SDavid Marchand registered_count = 0;
845c307ba2SDavid Marchand
855c307ba2SDavid Marchand /* Try to create as many threads as possible. */
865c307ba2SDavid Marchand for (i = 0; i < RTE_MAX_LCORE - eal_threads_count; i++) {
875c307ba2SDavid Marchand t = &thread_contexts[i];
88f6846729SJie Zhou t->state = Thread_INIT;
895c307ba2SDavid Marchand t->registered_count = ®istered_count;
905c307ba2SDavid Marchand t->lcore_id_any = false;
910e497ee5STyler Retzlaff if (rte_thread_create(&t->id, NULL, thread_loop, t) != 0)
925c307ba2SDavid Marchand break;
935c307ba2SDavid Marchand non_eal_threads_count++;
945c307ba2SDavid Marchand }
955c307ba2SDavid Marchand printf("non-EAL threads count: %u\n", non_eal_threads_count);
965c307ba2SDavid Marchand /* Wait all non-EAL threads to register. */
97*b6a7e685STyler Retzlaff while (rte_atomic_load_explicit(®istered_count, rte_memory_order_acquire) !=
985c307ba2SDavid Marchand non_eal_threads_count)
996bd7a4b2SDavid Marchand sched_yield();
1005c307ba2SDavid Marchand
1015c307ba2SDavid Marchand /* We managed to create the max number of threads, let's try to create
1025c307ba2SDavid Marchand * one more. This will allow one more check.
1035c307ba2SDavid Marchand */
1045c307ba2SDavid Marchand if (eal_threads_count + non_eal_threads_count < RTE_MAX_LCORE)
1055c307ba2SDavid Marchand goto skip_lcore_any;
1065c307ba2SDavid Marchand t = &thread_contexts[non_eal_threads_count];
107f6846729SJie Zhou t->state = Thread_INIT;
1085c307ba2SDavid Marchand t->registered_count = ®istered_count;
1095c307ba2SDavid Marchand t->lcore_id_any = true;
1100e497ee5STyler Retzlaff if (rte_thread_create(&t->id, NULL, thread_loop, t) == 0) {
1115c307ba2SDavid Marchand non_eal_threads_count++;
1125c307ba2SDavid Marchand printf("non-EAL threads count: %u\n", non_eal_threads_count);
113*b6a7e685STyler Retzlaff while (rte_atomic_load_explicit(®istered_count, rte_memory_order_acquire) !=
1145c307ba2SDavid Marchand non_eal_threads_count)
1156bd7a4b2SDavid Marchand sched_yield();
1165c307ba2SDavid Marchand }
1175c307ba2SDavid Marchand
1185c307ba2SDavid Marchand skip_lcore_any:
1195c307ba2SDavid Marchand /* Release all threads, and check their states. */
120*b6a7e685STyler Retzlaff rte_atomic_store_explicit(®istered_count, 0, rte_memory_order_release);
1215c307ba2SDavid Marchand ret = 0;
1225c307ba2SDavid Marchand for (i = 0; i < non_eal_threads_count; i++) {
1235c307ba2SDavid Marchand t = &thread_contexts[i];
1240e497ee5STyler Retzlaff rte_thread_join(t->id, NULL);
125f6846729SJie Zhou if (t->state != Thread_DONE)
1265c307ba2SDavid Marchand ret = -1;
1275c307ba2SDavid Marchand }
1285c307ba2SDavid Marchand
1295c307ba2SDavid Marchand return ret;
1305c307ba2SDavid Marchand }
1315c307ba2SDavid Marchand
13261bb5312SDavid Marchand struct limit_lcore_context {
13361bb5312SDavid Marchand unsigned int init;
13461bb5312SDavid Marchand unsigned int max;
13561bb5312SDavid Marchand unsigned int uninit;
13661bb5312SDavid Marchand };
13761bb5312SDavid Marchand
13861bb5312SDavid Marchand static int
limit_lcores_init(unsigned int lcore_id __rte_unused,void * arg)13961bb5312SDavid Marchand limit_lcores_init(unsigned int lcore_id __rte_unused, void *arg)
14061bb5312SDavid Marchand {
14161bb5312SDavid Marchand struct limit_lcore_context *l = arg;
14261bb5312SDavid Marchand
14361bb5312SDavid Marchand l->init++;
14461bb5312SDavid Marchand if (l->init > l->max)
14561bb5312SDavid Marchand return -1;
14661bb5312SDavid Marchand return 0;
14761bb5312SDavid Marchand }
14861bb5312SDavid Marchand
14961bb5312SDavid Marchand static void
limit_lcores_uninit(unsigned int lcore_id __rte_unused,void * arg)15061bb5312SDavid Marchand limit_lcores_uninit(unsigned int lcore_id __rte_unused, void *arg)
15161bb5312SDavid Marchand {
15261bb5312SDavid Marchand struct limit_lcore_context *l = arg;
15361bb5312SDavid Marchand
15461bb5312SDavid Marchand l->uninit++;
15561bb5312SDavid Marchand }
15661bb5312SDavid Marchand
15761bb5312SDavid Marchand static int
test_lcores_callback(unsigned int eal_threads_count)15861bb5312SDavid Marchand test_lcores_callback(unsigned int eal_threads_count)
15961bb5312SDavid Marchand {
16061bb5312SDavid Marchand struct limit_lcore_context l;
16161bb5312SDavid Marchand void *handle;
16261bb5312SDavid Marchand
16361bb5312SDavid Marchand /* Refuse last lcore => callback register error. */
16461bb5312SDavid Marchand memset(&l, 0, sizeof(l));
16561bb5312SDavid Marchand l.max = eal_threads_count - 1;
16661bb5312SDavid Marchand handle = rte_lcore_callback_register("limit", limit_lcores_init,
16761bb5312SDavid Marchand limit_lcores_uninit, &l);
16861bb5312SDavid Marchand if (handle != NULL) {
16961bb5312SDavid Marchand printf("Error: lcore callback register should have failed\n");
17061bb5312SDavid Marchand goto error;
17161bb5312SDavid Marchand }
17261bb5312SDavid Marchand /* Refusal happens at the n th call to the init callback.
17361bb5312SDavid Marchand * Besides, n - 1 were accepted, so we expect as many uninit calls when
17461bb5312SDavid Marchand * the rollback happens.
17561bb5312SDavid Marchand */
17661bb5312SDavid Marchand if (l.init != eal_threads_count) {
17761bb5312SDavid Marchand printf("Error: lcore callback register failed but incorrect init calls, expected %u, got %u\n",
17861bb5312SDavid Marchand eal_threads_count, l.init);
17961bb5312SDavid Marchand goto error;
18061bb5312SDavid Marchand }
18161bb5312SDavid Marchand if (l.uninit != eal_threads_count - 1) {
18261bb5312SDavid Marchand printf("Error: lcore callback register failed but incorrect uninit calls, expected %u, got %u\n",
18361bb5312SDavid Marchand eal_threads_count - 1, l.uninit);
18461bb5312SDavid Marchand goto error;
18561bb5312SDavid Marchand }
18661bb5312SDavid Marchand
18761bb5312SDavid Marchand /* Accept all lcore and unregister. */
18861bb5312SDavid Marchand memset(&l, 0, sizeof(l));
18961bb5312SDavid Marchand l.max = eal_threads_count;
19061bb5312SDavid Marchand handle = rte_lcore_callback_register("limit", limit_lcores_init,
19161bb5312SDavid Marchand limit_lcores_uninit, &l);
19261bb5312SDavid Marchand if (handle == NULL) {
19361bb5312SDavid Marchand printf("Error: lcore callback register failed\n");
19461bb5312SDavid Marchand goto error;
19561bb5312SDavid Marchand }
19661bb5312SDavid Marchand if (l.uninit != 0) {
19761bb5312SDavid Marchand printf("Error: lcore callback register succeeded but incorrect uninit calls, expected 0, got %u\n",
19861bb5312SDavid Marchand l.uninit);
19961bb5312SDavid Marchand goto error;
20061bb5312SDavid Marchand }
20161bb5312SDavid Marchand rte_lcore_callback_unregister(handle);
20261bb5312SDavid Marchand handle = NULL;
20361bb5312SDavid Marchand if (l.init != eal_threads_count) {
20461bb5312SDavid Marchand printf("Error: lcore callback unregister done but incorrect init calls, expected %u, got %u\n",
20561bb5312SDavid Marchand eal_threads_count, l.init);
20661bb5312SDavid Marchand goto error;
20761bb5312SDavid Marchand }
20861bb5312SDavid Marchand if (l.uninit != eal_threads_count) {
20961bb5312SDavid Marchand printf("Error: lcore callback unregister done but incorrect uninit calls, expected %u, got %u\n",
21061bb5312SDavid Marchand eal_threads_count, l.uninit);
21161bb5312SDavid Marchand goto error;
21261bb5312SDavid Marchand }
21361bb5312SDavid Marchand
21461bb5312SDavid Marchand return 0;
21561bb5312SDavid Marchand
21661bb5312SDavid Marchand error:
21761bb5312SDavid Marchand if (handle != NULL)
21861bb5312SDavid Marchand rte_lcore_callback_unregister(handle);
21961bb5312SDavid Marchand
22061bb5312SDavid Marchand return -1;
22161bb5312SDavid Marchand }
22261bb5312SDavid Marchand
22361bb5312SDavid Marchand static int
test_non_eal_lcores_callback(unsigned int eal_threads_count)22461bb5312SDavid Marchand test_non_eal_lcores_callback(unsigned int eal_threads_count)
22561bb5312SDavid Marchand {
22661bb5312SDavid Marchand struct thread_context thread_contexts[2];
22761bb5312SDavid Marchand unsigned int non_eal_threads_count = 0;
22861bb5312SDavid Marchand struct limit_lcore_context l[2] = {};
229*b6a7e685STyler Retzlaff RTE_ATOMIC(unsigned int) registered_count = 0;
23061bb5312SDavid Marchand struct thread_context *t;
23161bb5312SDavid Marchand void *handle[2] = {};
23261bb5312SDavid Marchand unsigned int i;
23361bb5312SDavid Marchand int ret;
23461bb5312SDavid Marchand
23561bb5312SDavid Marchand /* This test requires two empty slots to be sure lcore init refusal is
23661bb5312SDavid Marchand * because of callback execution.
23761bb5312SDavid Marchand */
23861bb5312SDavid Marchand if (eal_threads_count + 2 >= RTE_MAX_LCORE)
23961bb5312SDavid Marchand return 0;
24061bb5312SDavid Marchand
24161bb5312SDavid Marchand /* Register two callbacks:
24261bb5312SDavid Marchand * - first one accepts any lcore,
24361bb5312SDavid Marchand * - second one accepts all EAL lcore + one more for the first non-EAL
24461bb5312SDavid Marchand * thread, then refuses the next lcore.
24561bb5312SDavid Marchand */
24661bb5312SDavid Marchand l[0].max = UINT_MAX;
24761bb5312SDavid Marchand handle[0] = rte_lcore_callback_register("no_limit", limit_lcores_init,
24861bb5312SDavid Marchand limit_lcores_uninit, &l[0]);
24961bb5312SDavid Marchand if (handle[0] == NULL) {
25061bb5312SDavid Marchand printf("Error: lcore callback [0] register failed\n");
25161bb5312SDavid Marchand goto error;
25261bb5312SDavid Marchand }
25361bb5312SDavid Marchand l[1].max = eal_threads_count + 1;
25461bb5312SDavid Marchand handle[1] = rte_lcore_callback_register("limit", limit_lcores_init,
25561bb5312SDavid Marchand limit_lcores_uninit, &l[1]);
25661bb5312SDavid Marchand if (handle[1] == NULL) {
25761bb5312SDavid Marchand printf("Error: lcore callback [1] register failed\n");
25861bb5312SDavid Marchand goto error;
25961bb5312SDavid Marchand }
26061bb5312SDavid Marchand if (l[0].init != eal_threads_count || l[1].init != eal_threads_count) {
26161bb5312SDavid Marchand printf("Error: lcore callbacks register succeeded but incorrect init calls, expected %u, %u, got %u, %u\n",
26261bb5312SDavid Marchand eal_threads_count, eal_threads_count,
26361bb5312SDavid Marchand l[0].init, l[1].init);
26461bb5312SDavid Marchand goto error;
26561bb5312SDavid Marchand }
26661bb5312SDavid Marchand if (l[0].uninit != 0 || l[1].uninit != 0) {
26761bb5312SDavid Marchand printf("Error: lcore callbacks register succeeded but incorrect uninit calls, expected 0, 1, got %u, %u\n",
26861bb5312SDavid Marchand l[0].uninit, l[1].uninit);
26961bb5312SDavid Marchand goto error;
27061bb5312SDavid Marchand }
27161bb5312SDavid Marchand /* First thread that expects a valid lcore id. */
27261bb5312SDavid Marchand t = &thread_contexts[0];
273f6846729SJie Zhou t->state = Thread_INIT;
27461bb5312SDavid Marchand t->registered_count = ®istered_count;
27561bb5312SDavid Marchand t->lcore_id_any = false;
2760e497ee5STyler Retzlaff if (rte_thread_create(&t->id, NULL, thread_loop, t) != 0)
27761bb5312SDavid Marchand goto cleanup_threads;
27861bb5312SDavid Marchand non_eal_threads_count++;
279*b6a7e685STyler Retzlaff while (rte_atomic_load_explicit(®istered_count, rte_memory_order_acquire) !=
28061bb5312SDavid Marchand non_eal_threads_count)
2816bd7a4b2SDavid Marchand sched_yield();
28261bb5312SDavid Marchand if (l[0].init != eal_threads_count + 1 ||
28361bb5312SDavid Marchand l[1].init != eal_threads_count + 1) {
28461bb5312SDavid Marchand printf("Error: incorrect init calls, expected %u, %u, got %u, %u\n",
28561bb5312SDavid Marchand eal_threads_count + 1, eal_threads_count + 1,
28661bb5312SDavid Marchand l[0].init, l[1].init);
28761bb5312SDavid Marchand goto cleanup_threads;
28861bb5312SDavid Marchand }
28961bb5312SDavid Marchand if (l[0].uninit != 0 || l[1].uninit != 0) {
29061bb5312SDavid Marchand printf("Error: incorrect uninit calls, expected 0, 0, got %u, %u\n",
29161bb5312SDavid Marchand l[0].uninit, l[1].uninit);
29261bb5312SDavid Marchand goto cleanup_threads;
29361bb5312SDavid Marchand }
29461bb5312SDavid Marchand /* Second thread, that expects LCORE_ID_ANY because of init refusal. */
29561bb5312SDavid Marchand t = &thread_contexts[1];
296f6846729SJie Zhou t->state = Thread_INIT;
29761bb5312SDavid Marchand t->registered_count = ®istered_count;
29861bb5312SDavid Marchand t->lcore_id_any = true;
2990e497ee5STyler Retzlaff if (rte_thread_create(&t->id, NULL, thread_loop, t) != 0)
30061bb5312SDavid Marchand goto cleanup_threads;
30161bb5312SDavid Marchand non_eal_threads_count++;
302*b6a7e685STyler Retzlaff while (rte_atomic_load_explicit(®istered_count, rte_memory_order_acquire) !=
30361bb5312SDavid Marchand non_eal_threads_count)
3046bd7a4b2SDavid Marchand sched_yield();
30561bb5312SDavid Marchand if (l[0].init != eal_threads_count + 2 ||
30661bb5312SDavid Marchand l[1].init != eal_threads_count + 2) {
30761bb5312SDavid Marchand printf("Error: incorrect init calls, expected %u, %u, got %u, %u\n",
30861bb5312SDavid Marchand eal_threads_count + 2, eal_threads_count + 2,
30961bb5312SDavid Marchand l[0].init, l[1].init);
31061bb5312SDavid Marchand goto cleanup_threads;
31161bb5312SDavid Marchand }
31261bb5312SDavid Marchand if (l[0].uninit != 1 || l[1].uninit != 0) {
31361bb5312SDavid Marchand printf("Error: incorrect uninit calls, expected 1, 0, got %u, %u\n",
31461bb5312SDavid Marchand l[0].uninit, l[1].uninit);
31561bb5312SDavid Marchand goto cleanup_threads;
31661bb5312SDavid Marchand }
317b41befd3SDavid Marchand rte_lcore_dump(stdout);
31861bb5312SDavid Marchand /* Release all threads, and check their states. */
319*b6a7e685STyler Retzlaff rte_atomic_store_explicit(®istered_count, 0, rte_memory_order_release);
32061bb5312SDavid Marchand ret = 0;
32161bb5312SDavid Marchand for (i = 0; i < non_eal_threads_count; i++) {
32261bb5312SDavid Marchand t = &thread_contexts[i];
3230e497ee5STyler Retzlaff rte_thread_join(t->id, NULL);
324f6846729SJie Zhou if (t->state != Thread_DONE)
32561bb5312SDavid Marchand ret = -1;
32661bb5312SDavid Marchand }
32761bb5312SDavid Marchand if (ret < 0)
32861bb5312SDavid Marchand goto error;
329b41befd3SDavid Marchand rte_lcore_dump(stdout);
33061bb5312SDavid Marchand if (l[0].uninit != 2 || l[1].uninit != 1) {
33161bb5312SDavid Marchand printf("Error: threads reported having successfully registered and unregistered, but incorrect uninit calls, expected 2, 1, got %u, %u\n",
33261bb5312SDavid Marchand l[0].uninit, l[1].uninit);
33361bb5312SDavid Marchand goto error;
33461bb5312SDavid Marchand }
33561bb5312SDavid Marchand rte_lcore_callback_unregister(handle[0]);
33661bb5312SDavid Marchand rte_lcore_callback_unregister(handle[1]);
33761bb5312SDavid Marchand return 0;
33861bb5312SDavid Marchand
33961bb5312SDavid Marchand cleanup_threads:
34061bb5312SDavid Marchand /* Release all threads */
341*b6a7e685STyler Retzlaff rte_atomic_store_explicit(®istered_count, 0, rte_memory_order_release);
34261bb5312SDavid Marchand for (i = 0; i < non_eal_threads_count; i++) {
34361bb5312SDavid Marchand t = &thread_contexts[i];
3440e497ee5STyler Retzlaff rte_thread_join(t->id, NULL);
34561bb5312SDavid Marchand }
34661bb5312SDavid Marchand error:
34761bb5312SDavid Marchand if (handle[1] != NULL)
34861bb5312SDavid Marchand rte_lcore_callback_unregister(handle[1]);
34961bb5312SDavid Marchand if (handle[0] != NULL)
35061bb5312SDavid Marchand rte_lcore_callback_unregister(handle[0]);
35161bb5312SDavid Marchand return -1;
35261bb5312SDavid Marchand }
35361bb5312SDavid Marchand
ctrl_thread_loop(void * arg)3548eea1437SThomas Monjalon static uint32_t ctrl_thread_loop(void *arg)
355f217fa71SHonnappa Nagarahalli {
356f217fa71SHonnappa Nagarahalli struct thread_context *t = arg;
357f217fa71SHonnappa Nagarahalli
358f217fa71SHonnappa Nagarahalli printf("Control thread running successfully\n");
359f217fa71SHonnappa Nagarahalli
360f217fa71SHonnappa Nagarahalli /* Set the thread state to DONE */
361f6846729SJie Zhou t->state = Thread_DONE;
362f217fa71SHonnappa Nagarahalli
3638eea1437SThomas Monjalon return 0;
364f217fa71SHonnappa Nagarahalli }
365f217fa71SHonnappa Nagarahalli
366f217fa71SHonnappa Nagarahalli static int
test_ctrl_thread(void)367f217fa71SHonnappa Nagarahalli test_ctrl_thread(void)
368f217fa71SHonnappa Nagarahalli {
369f217fa71SHonnappa Nagarahalli struct thread_context ctrl_thread_context;
370f217fa71SHonnappa Nagarahalli struct thread_context *t;
371f217fa71SHonnappa Nagarahalli
372f217fa71SHonnappa Nagarahalli /* Create one control thread */
373f217fa71SHonnappa Nagarahalli t = &ctrl_thread_context;
374f6846729SJie Zhou t->state = Thread_INIT;
3758eea1437SThomas Monjalon if (rte_thread_create_control(&t->id, "dpdk-test-ctrlt",
3768eea1437SThomas Monjalon ctrl_thread_loop, t) != 0)
377f217fa71SHonnappa Nagarahalli return -1;
378f217fa71SHonnappa Nagarahalli
379f217fa71SHonnappa Nagarahalli /* Wait till the control thread exits.
380f217fa71SHonnappa Nagarahalli * This also acts as the barrier such that the memory operations
381f217fa71SHonnappa Nagarahalli * in control thread are visible to this thread.
382f217fa71SHonnappa Nagarahalli */
3830e497ee5STyler Retzlaff rte_thread_join(t->id, NULL);
384f217fa71SHonnappa Nagarahalli
385f217fa71SHonnappa Nagarahalli /* Check if the control thread set the correct state */
386f6846729SJie Zhou if (t->state != Thread_DONE)
387f217fa71SHonnappa Nagarahalli return -1;
388f217fa71SHonnappa Nagarahalli
389f217fa71SHonnappa Nagarahalli return 0;
390f217fa71SHonnappa Nagarahalli }
391f217fa71SHonnappa Nagarahalli
3925c307ba2SDavid Marchand static int
test_lcores(void)3935c307ba2SDavid Marchand test_lcores(void)
3945c307ba2SDavid Marchand {
3955c307ba2SDavid Marchand unsigned int eal_threads_count = 0;
3965c307ba2SDavid Marchand unsigned int i;
3975c307ba2SDavid Marchand
3985c307ba2SDavid Marchand for (i = 0; i < RTE_MAX_LCORE; i++) {
3995c307ba2SDavid Marchand if (!rte_lcore_has_role(i, ROLE_OFF))
4005c307ba2SDavid Marchand eal_threads_count++;
4015c307ba2SDavid Marchand }
4025c307ba2SDavid Marchand if (eal_threads_count == 0) {
4035c307ba2SDavid Marchand printf("Error: something is broken, no EAL thread detected.\n");
4045c307ba2SDavid Marchand return TEST_FAILED;
4055c307ba2SDavid Marchand }
4065c307ba2SDavid Marchand printf("EAL threads count: %u, RTE_MAX_LCORE=%u\n", eal_threads_count,
4075c307ba2SDavid Marchand RTE_MAX_LCORE);
408b41befd3SDavid Marchand rte_lcore_dump(stdout);
4095c307ba2SDavid Marchand
4105c307ba2SDavid Marchand if (test_non_eal_lcores(eal_threads_count) < 0)
4115c307ba2SDavid Marchand return TEST_FAILED;
4125c307ba2SDavid Marchand
41361bb5312SDavid Marchand if (test_lcores_callback(eal_threads_count) < 0)
41461bb5312SDavid Marchand return TEST_FAILED;
41561bb5312SDavid Marchand
41661bb5312SDavid Marchand if (test_non_eal_lcores_callback(eal_threads_count) < 0)
41761bb5312SDavid Marchand return TEST_FAILED;
41861bb5312SDavid Marchand
419f217fa71SHonnappa Nagarahalli if (test_ctrl_thread() < 0)
420f217fa71SHonnappa Nagarahalli return TEST_FAILED;
421f217fa71SHonnappa Nagarahalli
4225c307ba2SDavid Marchand return TEST_SUCCESS;
4235c307ba2SDavid Marchand }
4245c307ba2SDavid Marchand
425e0a8442cSBruce Richardson REGISTER_FAST_TEST(lcores_autotest, true, true, test_lcores);
426