1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2020 Red Hat, Inc.
8 #include <rte_common.h>
10 #include <rte_lcore.h>
14 struct thread_context {
15 enum { INIT, ERROR, DONE } state;
18 unsigned int *registered_count;
21 static void *thread_loop(void *arg)
23 struct thread_context *t = arg;
24 unsigned int lcore_id;
26 lcore_id = rte_lcore_id();
27 if (lcore_id != LCORE_ID_ANY) {
28 printf("Error: incorrect lcore id for new thread %u\n", lcore_id);
31 if (rte_thread_register() < 0)
32 printf("Warning: could not register new thread (this might be expected during this test), reason %s\n",
33 rte_strerror(rte_errno));
34 lcore_id = rte_lcore_id();
35 if ((t->lcore_id_any && lcore_id != LCORE_ID_ANY) ||
36 (!t->lcore_id_any && lcore_id == LCORE_ID_ANY)) {
37 printf("Error: could not register new thread, got %u while %sexpecting %u\n",
38 lcore_id, t->lcore_id_any ? "" : "not ", LCORE_ID_ANY);
41 /* Report register happened to the control thread. */
42 __atomic_add_fetch(t->registered_count, 1, __ATOMIC_RELEASE);
44 /* Wait for release from the control thread. */
45 while (__atomic_load_n(t->registered_count, __ATOMIC_ACQUIRE) != 0)
47 rte_thread_unregister();
48 lcore_id = rte_lcore_id();
49 if (lcore_id != LCORE_ID_ANY) {
50 printf("Error: could not unregister new thread, %u still assigned\n",
55 if (t->state != ERROR)
62 test_non_eal_lcores(unsigned int eal_threads_count)
64 struct thread_context thread_contexts[RTE_MAX_LCORE];
65 unsigned int non_eal_threads_count;
66 unsigned int registered_count;
67 struct thread_context *t;
71 non_eal_threads_count = 0;
74 /* Try to create as many threads as possible. */
75 for (i = 0; i < RTE_MAX_LCORE - eal_threads_count; i++) {
76 t = &thread_contexts[i];
78 t->registered_count = ®istered_count;
79 t->lcore_id_any = false;
80 if (pthread_create(&t->id, NULL, thread_loop, t) != 0)
82 non_eal_threads_count++;
84 printf("non-EAL threads count: %u\n", non_eal_threads_count);
85 /* Wait all non-EAL threads to register. */
86 while (__atomic_load_n(®istered_count, __ATOMIC_ACQUIRE) !=
87 non_eal_threads_count)
90 /* We managed to create the max number of threads, let's try to create
91 * one more. This will allow one more check.
93 if (eal_threads_count + non_eal_threads_count < RTE_MAX_LCORE)
95 t = &thread_contexts[non_eal_threads_count];
97 t->registered_count = ®istered_count;
98 t->lcore_id_any = true;
99 if (pthread_create(&t->id, NULL, thread_loop, t) == 0) {
100 non_eal_threads_count++;
101 printf("non-EAL threads count: %u\n", non_eal_threads_count);
102 while (__atomic_load_n(®istered_count, __ATOMIC_ACQUIRE) !=
103 non_eal_threads_count)
108 /* Release all threads, and check their states. */
109 __atomic_store_n(®istered_count, 0, __ATOMIC_RELEASE);
111 for (i = 0; i < non_eal_threads_count; i++) {
112 t = &thread_contexts[i];
113 pthread_join(t->id, NULL);
114 if (t->state != DONE)
121 struct limit_lcore_context {
128 limit_lcores_init(unsigned int lcore_id __rte_unused, void *arg)
130 struct limit_lcore_context *l = arg;
133 if (l->init > l->max)
139 limit_lcores_uninit(unsigned int lcore_id __rte_unused, void *arg)
141 struct limit_lcore_context *l = arg;
147 test_lcores_callback(unsigned int eal_threads_count)
149 struct limit_lcore_context l;
152 /* Refuse last lcore => callback register error. */
153 memset(&l, 0, sizeof(l));
154 l.max = eal_threads_count - 1;
155 handle = rte_lcore_callback_register("limit", limit_lcores_init,
156 limit_lcores_uninit, &l);
157 if (handle != NULL) {
158 printf("Error: lcore callback register should have failed\n");
161 /* Refusal happens at the n th call to the init callback.
162 * Besides, n - 1 were accepted, so we expect as many uninit calls when
163 * the rollback happens.
165 if (l.init != eal_threads_count) {
166 printf("Error: lcore callback register failed but incorrect init calls, expected %u, got %u\n",
167 eal_threads_count, l.init);
170 if (l.uninit != eal_threads_count - 1) {
171 printf("Error: lcore callback register failed but incorrect uninit calls, expected %u, got %u\n",
172 eal_threads_count - 1, l.uninit);
176 /* Accept all lcore and unregister. */
177 memset(&l, 0, sizeof(l));
178 l.max = eal_threads_count;
179 handle = rte_lcore_callback_register("limit", limit_lcores_init,
180 limit_lcores_uninit, &l);
181 if (handle == NULL) {
182 printf("Error: lcore callback register failed\n");
186 printf("Error: lcore callback register succeeded but incorrect uninit calls, expected 0, got %u\n",
190 rte_lcore_callback_unregister(handle);
192 if (l.init != eal_threads_count) {
193 printf("Error: lcore callback unregister done but incorrect init calls, expected %u, got %u\n",
194 eal_threads_count, l.init);
197 if (l.uninit != eal_threads_count) {
198 printf("Error: lcore callback unregister done but incorrect uninit calls, expected %u, got %u\n",
199 eal_threads_count, l.uninit);
207 rte_lcore_callback_unregister(handle);
213 test_non_eal_lcores_callback(unsigned int eal_threads_count)
215 struct thread_context thread_contexts[2];
216 unsigned int non_eal_threads_count = 0;
217 struct limit_lcore_context l[2] = {};
218 unsigned int registered_count = 0;
219 struct thread_context *t;
220 void *handle[2] = {};
224 /* This test requires two empty slots to be sure lcore init refusal is
225 * because of callback execution.
227 if (eal_threads_count + 2 >= RTE_MAX_LCORE)
230 /* Register two callbacks:
231 * - first one accepts any lcore,
232 * - second one accepts all EAL lcore + one more for the first non-EAL
233 * thread, then refuses the next lcore.
236 handle[0] = rte_lcore_callback_register("no_limit", limit_lcores_init,
237 limit_lcores_uninit, &l[0]);
238 if (handle[0] == NULL) {
239 printf("Error: lcore callback [0] register failed\n");
242 l[1].max = eal_threads_count + 1;
243 handle[1] = rte_lcore_callback_register("limit", limit_lcores_init,
244 limit_lcores_uninit, &l[1]);
245 if (handle[1] == NULL) {
246 printf("Error: lcore callback [1] register failed\n");
249 if (l[0].init != eal_threads_count || l[1].init != eal_threads_count) {
250 printf("Error: lcore callbacks register succeeded but incorrect init calls, expected %u, %u, got %u, %u\n",
251 eal_threads_count, eal_threads_count,
252 l[0].init, l[1].init);
255 if (l[0].uninit != 0 || l[1].uninit != 0) {
256 printf("Error: lcore callbacks register succeeded but incorrect uninit calls, expected 0, 1, got %u, %u\n",
257 l[0].uninit, l[1].uninit);
260 /* First thread that expects a valid lcore id. */
261 t = &thread_contexts[0];
263 t->registered_count = ®istered_count;
264 t->lcore_id_any = false;
265 if (pthread_create(&t->id, NULL, thread_loop, t) != 0)
266 goto cleanup_threads;
267 non_eal_threads_count++;
268 while (__atomic_load_n(®istered_count, __ATOMIC_ACQUIRE) !=
269 non_eal_threads_count)
271 if (l[0].init != eal_threads_count + 1 ||
272 l[1].init != eal_threads_count + 1) {
273 printf("Error: incorrect init calls, expected %u, %u, got %u, %u\n",
274 eal_threads_count + 1, eal_threads_count + 1,
275 l[0].init, l[1].init);
276 goto cleanup_threads;
278 if (l[0].uninit != 0 || l[1].uninit != 0) {
279 printf("Error: incorrect uninit calls, expected 0, 0, got %u, %u\n",
280 l[0].uninit, l[1].uninit);
281 goto cleanup_threads;
283 /* Second thread, that expects LCORE_ID_ANY because of init refusal. */
284 t = &thread_contexts[1];
286 t->registered_count = ®istered_count;
287 t->lcore_id_any = true;
288 if (pthread_create(&t->id, NULL, thread_loop, t) != 0)
289 goto cleanup_threads;
290 non_eal_threads_count++;
291 while (__atomic_load_n(®istered_count, __ATOMIC_ACQUIRE) !=
292 non_eal_threads_count)
294 if (l[0].init != eal_threads_count + 2 ||
295 l[1].init != eal_threads_count + 2) {
296 printf("Error: incorrect init calls, expected %u, %u, got %u, %u\n",
297 eal_threads_count + 2, eal_threads_count + 2,
298 l[0].init, l[1].init);
299 goto cleanup_threads;
301 if (l[0].uninit != 1 || l[1].uninit != 0) {
302 printf("Error: incorrect uninit calls, expected 1, 0, got %u, %u\n",
303 l[0].uninit, l[1].uninit);
304 goto cleanup_threads;
306 rte_lcore_dump(stdout);
307 /* Release all threads, and check their states. */
308 __atomic_store_n(®istered_count, 0, __ATOMIC_RELEASE);
310 for (i = 0; i < non_eal_threads_count; i++) {
311 t = &thread_contexts[i];
312 pthread_join(t->id, NULL);
313 if (t->state != DONE)
318 rte_lcore_dump(stdout);
319 if (l[0].uninit != 2 || l[1].uninit != 1) {
320 printf("Error: threads reported having successfully registered and unregistered, but incorrect uninit calls, expected 2, 1, got %u, %u\n",
321 l[0].uninit, l[1].uninit);
324 rte_lcore_callback_unregister(handle[0]);
325 rte_lcore_callback_unregister(handle[1]);
329 /* Release all threads */
330 __atomic_store_n(®istered_count, 0, __ATOMIC_RELEASE);
331 for (i = 0; i < non_eal_threads_count; i++) {
332 t = &thread_contexts[i];
333 pthread_join(t->id, NULL);
336 if (handle[1] != NULL)
337 rte_lcore_callback_unregister(handle[1]);
338 if (handle[0] != NULL)
339 rte_lcore_callback_unregister(handle[0]);
346 unsigned int eal_threads_count = 0;
349 for (i = 0; i < RTE_MAX_LCORE; i++) {
350 if (!rte_lcore_has_role(i, ROLE_OFF))
353 if (eal_threads_count == 0) {
354 printf("Error: something is broken, no EAL thread detected.\n");
357 printf("EAL threads count: %u, RTE_MAX_LCORE=%u\n", eal_threads_count,
359 rte_lcore_dump(stdout);
361 if (test_non_eal_lcores(eal_threads_count) < 0)
364 if (test_lcores_callback(eal_threads_count) < 0)
367 if (test_non_eal_lcores_callback(eal_threads_count) < 0)
373 REGISTER_TEST_COMMAND(lcores_autotest, test_lcores);