eal: register non-EAL threads as lcores
[dpdk.git] / app / test / test_lcores.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2020 Red Hat, Inc.
3  */
4
5 #include <pthread.h>
6 #include <string.h>
7
8 #include <rte_errno.h>
9 #include <rte_lcore.h>
10
11 #include "test.h"
12
13 struct thread_context {
14         enum { INIT, ERROR, DONE } state;
15         bool lcore_id_any;
16         pthread_t id;
17         unsigned int *registered_count;
18 };
19
20 static void *thread_loop(void *arg)
21 {
22         struct thread_context *t = arg;
23         unsigned int lcore_id;
24
25         lcore_id = rte_lcore_id();
26         if (lcore_id != LCORE_ID_ANY) {
27                 printf("Error: incorrect lcore id for new thread %u\n", lcore_id);
28                 t->state = ERROR;
29         }
30         if (rte_thread_register() < 0)
31                 printf("Warning: could not register new thread (this might be expected during this test), reason %s\n",
32                         rte_strerror(rte_errno));
33         lcore_id = rte_lcore_id();
34         if ((t->lcore_id_any && lcore_id != LCORE_ID_ANY) ||
35                         (!t->lcore_id_any && lcore_id == LCORE_ID_ANY)) {
36                 printf("Error: could not register new thread, got %u while %sexpecting %u\n",
37                         lcore_id, t->lcore_id_any ? "" : "not ", LCORE_ID_ANY);
38                 t->state = ERROR;
39         }
40         /* Report register happened to the control thread. */
41         __atomic_add_fetch(t->registered_count, 1, __ATOMIC_RELEASE);
42
43         /* Wait for release from the control thread. */
44         while (__atomic_load_n(t->registered_count, __ATOMIC_ACQUIRE) != 0)
45                 ;
46         rte_thread_unregister();
47         lcore_id = rte_lcore_id();
48         if (lcore_id != LCORE_ID_ANY) {
49                 printf("Error: could not unregister new thread, %u still assigned\n",
50                         lcore_id);
51                 t->state = ERROR;
52         }
53
54         if (t->state != ERROR)
55                 t->state = DONE;
56
57         return NULL;
58 }
59
60 static int
61 test_non_eal_lcores(unsigned int eal_threads_count)
62 {
63         struct thread_context thread_contexts[RTE_MAX_LCORE];
64         unsigned int non_eal_threads_count;
65         unsigned int registered_count;
66         struct thread_context *t;
67         unsigned int i;
68         int ret;
69
70         non_eal_threads_count = 0;
71         registered_count = 0;
72
73         /* Try to create as many threads as possible. */
74         for (i = 0; i < RTE_MAX_LCORE - eal_threads_count; i++) {
75                 t = &thread_contexts[i];
76                 t->state = INIT;
77                 t->registered_count = &registered_count;
78                 t->lcore_id_any = false;
79                 if (pthread_create(&t->id, NULL, thread_loop, t) != 0)
80                         break;
81                 non_eal_threads_count++;
82         }
83         printf("non-EAL threads count: %u\n", non_eal_threads_count);
84         /* Wait all non-EAL threads to register. */
85         while (__atomic_load_n(&registered_count, __ATOMIC_ACQUIRE) !=
86                         non_eal_threads_count)
87                 ;
88
89         /* We managed to create the max number of threads, let's try to create
90          * one more. This will allow one more check.
91          */
92         if (eal_threads_count + non_eal_threads_count < RTE_MAX_LCORE)
93                 goto skip_lcore_any;
94         t = &thread_contexts[non_eal_threads_count];
95         t->state = INIT;
96         t->registered_count = &registered_count;
97         t->lcore_id_any = true;
98         if (pthread_create(&t->id, NULL, thread_loop, t) == 0) {
99                 non_eal_threads_count++;
100                 printf("non-EAL threads count: %u\n", non_eal_threads_count);
101                 while (__atomic_load_n(&registered_count, __ATOMIC_ACQUIRE) !=
102                                 non_eal_threads_count)
103                         ;
104         }
105
106 skip_lcore_any:
107         /* Release all threads, and check their states. */
108         __atomic_store_n(&registered_count, 0, __ATOMIC_RELEASE);
109         ret = 0;
110         for (i = 0; i < non_eal_threads_count; i++) {
111                 t = &thread_contexts[i];
112                 pthread_join(t->id, NULL);
113                 if (t->state != DONE)
114                         ret = -1;
115         }
116
117         return ret;
118 }
119
120 static int
121 test_lcores(void)
122 {
123         unsigned int eal_threads_count = 0;
124         unsigned int i;
125
126         for (i = 0; i < RTE_MAX_LCORE; i++) {
127                 if (!rte_lcore_has_role(i, ROLE_OFF))
128                         eal_threads_count++;
129         }
130         if (eal_threads_count == 0) {
131                 printf("Error: something is broken, no EAL thread detected.\n");
132                 return TEST_FAILED;
133         }
134         printf("EAL threads count: %u, RTE_MAX_LCORE=%u\n", eal_threads_count,
135                 RTE_MAX_LCORE);
136
137         if (test_non_eal_lcores(eal_threads_count) < 0)
138                 return TEST_FAILED;
139
140         return TEST_SUCCESS;
141 }
142
143 REGISTER_TEST_COMMAND(lcores_autotest, test_lcores);