]>
git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/unit/lib/thread/thread.c/thread_ut.c
4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "spdk/stdinc.h"
36 #include "spdk_cunit.h"
38 #include "spdk_internal/thread.h"
40 #include "thread/thread.c"
41 #include "common/lib/ut_multithread.c"
43 static int g_sched_rc
= 0;
46 _thread_schedule(struct spdk_thread
*thread
)
54 struct spdk_thread
*thread
;
56 /* No schedule callback */
57 spdk_thread_lib_init(NULL
, 0);
58 thread
= spdk_thread_create(NULL
, NULL
);
59 SPDK_CU_ASSERT_FATAL(thread
!= NULL
);
60 spdk_set_thread(thread
);
61 spdk_thread_exit(thread
);
62 spdk_thread_destroy(thread
);
63 spdk_thread_lib_fini();
65 /* Schedule callback exists */
66 spdk_thread_lib_init(_thread_schedule
, 0);
68 /* Scheduling succeeds */
70 thread
= spdk_thread_create(NULL
, NULL
);
71 SPDK_CU_ASSERT_FATAL(thread
!= NULL
);
72 spdk_set_thread(thread
);
73 spdk_thread_exit(thread
);
74 spdk_thread_destroy(thread
);
76 /* Scheduling fails */
78 thread
= spdk_thread_create(NULL
, NULL
);
79 SPDK_CU_ASSERT_FATAL(thread
== NULL
);
81 spdk_thread_lib_fini();
85 send_msg_cb(void *ctx
)
95 struct spdk_thread
*thread0
;
100 thread0
= spdk_get_thread();
103 /* Simulate thread 1 sending a message to thread 0. */
104 spdk_thread_send_msg(thread0
, send_msg_cb
, &done
);
106 /* We have not polled thread 0 yet, so done should be false. */
110 * Poll thread 1. The message was sent to thread 0, so this should be
111 * a nop and done should still be false.
117 * Poll thread 0. This should execute the message and done should then
127 poller_run_done(void *ctx
)
129 bool *poller_run
= ctx
;
139 struct spdk_poller
*poller
= NULL
;
140 bool poller_run
= false;
145 MOCK_SET(spdk_get_ticks
, 0);
146 /* Register a poller with no-wait time and test execution */
147 poller
= spdk_poller_register(poller_run_done
, &poller_run
, 0);
148 CU_ASSERT(poller
!= NULL
);
151 CU_ASSERT(poller_run
== true);
153 spdk_poller_unregister(&poller
);
154 CU_ASSERT(poller
== NULL
);
156 /* Register a poller with 1000us wait time and test single execution */
158 poller
= spdk_poller_register(poller_run_done
, &poller_run
, 1000);
159 CU_ASSERT(poller
!= NULL
);
162 CU_ASSERT(poller_run
== false);
166 CU_ASSERT(poller_run
== true);
170 CU_ASSERT(poller_run
== false);
174 CU_ASSERT(poller_run
== true);
176 spdk_poller_unregister(&poller
);
177 CU_ASSERT(poller
== NULL
);
183 for_each_cb(void *ctx
)
191 thread_for_each(void)
199 spdk_for_each_thread(for_each_cb
, &count
, for_each_cb
);
201 /* We have not polled thread 0 yet, so count should be 0 */
202 CU_ASSERT(count
== 0);
204 /* Poll each thread to verify the message is passed to each */
205 for (i
= 0; i
< 3; i
++) {
207 CU_ASSERT(count
== (i
+ 1));
211 * After each thread is called, the completion calls it
215 CU_ASSERT(count
== 4);
221 channel_create(void *io_device
, void *ctx_buf
)
227 channel_destroy(void *io_device
, void *ctx_buf
)
232 channel_msg(struct spdk_io_channel_iter
*i
)
234 struct spdk_io_channel
*ch
= spdk_io_channel_iter_get_channel(i
);
235 int *count
= spdk_io_channel_get_ctx(ch
);
239 spdk_for_each_channel_continue(i
, 0);
243 channel_cpl(struct spdk_io_channel_iter
*i
, int status
)
248 for_each_channel_remove(void)
250 struct spdk_io_channel
*ch0
, *ch1
, *ch2
;
256 spdk_io_device_register(&io_target
, channel_create
, channel_destroy
, sizeof(int), NULL
);
257 ch0
= spdk_get_io_channel(&io_target
);
259 ch1
= spdk_get_io_channel(&io_target
);
261 ch2
= spdk_get_io_channel(&io_target
);
264 * Test that io_channel handles the case where we start to iterate through
265 * the channels, and during the iteration, one of the channels is deleted.
266 * This is done in some different and sometimes non-intuitive orders, because
267 * some operations are deferred and won't execute until their threads are
270 * Case #1: Put the I/O channel before spdk_for_each_channel.
273 spdk_put_io_channel(ch0
);
275 spdk_for_each_channel(&io_target
, channel_msg
, &count
, channel_cpl
);
279 * Case #2: Put the I/O channel after spdk_for_each_channel, but before
280 * thread 0 is polled.
282 ch0
= spdk_get_io_channel(&io_target
);
283 spdk_for_each_channel(&io_target
, channel_msg
, &count
, channel_cpl
);
284 spdk_put_io_channel(ch0
);
288 spdk_put_io_channel(ch1
);
290 spdk_put_io_channel(ch2
);
291 spdk_io_device_unregister(&io_target
, NULL
);
303 unreg_ch_done(struct spdk_io_channel_iter
*i
)
305 struct unreg_ctx
*ctx
= spdk_io_channel_iter_get_ctx(i
);
309 SPDK_CU_ASSERT_FATAL(i
->cur_thread
!= NULL
);
310 spdk_for_each_channel_continue(i
, 0);
314 unreg_foreach_done(struct spdk_io_channel_iter
*i
, int status
)
316 struct unreg_ctx
*ctx
= spdk_io_channel_iter_get_ctx(i
);
318 ctx
->foreach_done
= true;
322 for_each_channel_unreg(void)
324 struct spdk_io_channel
*ch0
;
325 struct io_device
*dev
;
326 struct unreg_ctx ctx
= {};
331 CU_ASSERT(TAILQ_EMPTY(&g_io_devices
));
332 spdk_io_device_register(&io_target
, channel_create
, channel_destroy
, sizeof(int), NULL
);
333 CU_ASSERT(!TAILQ_EMPTY(&g_io_devices
));
334 dev
= TAILQ_FIRST(&g_io_devices
);
335 SPDK_CU_ASSERT_FATAL(dev
!= NULL
);
336 CU_ASSERT(TAILQ_NEXT(dev
, tailq
) == NULL
);
337 ch0
= spdk_get_io_channel(&io_target
);
338 spdk_for_each_channel(&io_target
, unreg_ch_done
, &ctx
, unreg_foreach_done
);
340 spdk_io_device_unregister(&io_target
, NULL
);
342 * There is an outstanding foreach call on the io_device, so the unregister should not
343 * have removed the device.
345 CU_ASSERT(dev
== TAILQ_FIRST(&g_io_devices
));
346 spdk_io_device_register(&io_target
, channel_create
, channel_destroy
, sizeof(int), NULL
);
348 * There is already a device registered at &io_target, so a new io_device should not
349 * have been added to g_io_devices.
351 CU_ASSERT(dev
== TAILQ_FIRST(&g_io_devices
));
352 CU_ASSERT(TAILQ_NEXT(dev
, tailq
) == NULL
);
355 CU_ASSERT(ctx
.ch_done
== true);
356 CU_ASSERT(ctx
.foreach_done
== true);
358 * There are no more foreach operations outstanding, so we can unregister the device,
359 * even though a channel still exists for the device.
361 spdk_io_device_unregister(&io_target
, NULL
);
362 CU_ASSERT(TAILQ_EMPTY(&g_io_devices
));
365 spdk_put_io_channel(ch0
);
375 struct spdk_thread
*thread
;
378 spdk_thread_lib_init(NULL
, 0);
380 /* Create thread with no name, which automatically generates one */
381 thread
= spdk_thread_create(NULL
, NULL
);
382 spdk_set_thread(thread
);
383 thread
= spdk_get_thread();
384 SPDK_CU_ASSERT_FATAL(thread
!= NULL
);
385 name
= spdk_thread_get_name(thread
);
386 CU_ASSERT(name
!= NULL
);
387 spdk_thread_exit(thread
);
388 spdk_thread_destroy(thread
);
390 /* Create thread named "test_thread" */
391 thread
= spdk_thread_create("test_thread", NULL
);
392 spdk_set_thread(thread
);
393 thread
= spdk_get_thread();
394 SPDK_CU_ASSERT_FATAL(thread
!= NULL
);
395 name
= spdk_thread_get_name(thread
);
396 SPDK_CU_ASSERT_FATAL(name
!= NULL
);
397 CU_ASSERT(strcmp(name
, "test_thread") == 0);
398 spdk_thread_exit(thread
);
399 spdk_thread_destroy(thread
);
401 spdk_thread_lib_fini();
404 static uint64_t device1
;
405 static uint64_t device2
;
406 static uint64_t device3
;
408 static uint64_t ctx1
= 0x1111;
409 static uint64_t ctx2
= 0x2222;
411 static int g_create_cb_calls
= 0;
412 static int g_destroy_cb_calls
= 0;
415 create_cb_1(void *io_device
, void *ctx_buf
)
417 CU_ASSERT(io_device
== &device1
);
418 *(uint64_t *)ctx_buf
= ctx1
;
424 destroy_cb_1(void *io_device
, void *ctx_buf
)
426 CU_ASSERT(io_device
== &device1
);
427 CU_ASSERT(*(uint64_t *)ctx_buf
== ctx1
);
428 g_destroy_cb_calls
++;
432 create_cb_2(void *io_device
, void *ctx_buf
)
434 CU_ASSERT(io_device
== &device2
);
435 *(uint64_t *)ctx_buf
= ctx2
;
441 destroy_cb_2(void *io_device
, void *ctx_buf
)
443 CU_ASSERT(io_device
== &device2
);
444 CU_ASSERT(*(uint64_t *)ctx_buf
== ctx2
);
445 g_destroy_cb_calls
++;
451 struct spdk_io_channel
*ch1
, *ch2
;
457 spdk_io_device_register(&device1
, create_cb_1
, destroy_cb_1
, sizeof(ctx1
), NULL
);
458 spdk_io_device_register(&device2
, create_cb_2
, destroy_cb_2
, sizeof(ctx2
), NULL
);
460 g_create_cb_calls
= 0;
461 ch1
= spdk_get_io_channel(&device1
);
462 CU_ASSERT(g_create_cb_calls
== 1);
463 SPDK_CU_ASSERT_FATAL(ch1
!= NULL
);
465 g_create_cb_calls
= 0;
466 ch2
= spdk_get_io_channel(&device1
);
467 CU_ASSERT(g_create_cb_calls
== 0);
468 CU_ASSERT(ch1
== ch2
);
469 SPDK_CU_ASSERT_FATAL(ch2
!= NULL
);
471 g_destroy_cb_calls
= 0;
472 spdk_put_io_channel(ch2
);
474 CU_ASSERT(g_destroy_cb_calls
== 0);
476 g_create_cb_calls
= 0;
477 ch2
= spdk_get_io_channel(&device2
);
478 CU_ASSERT(g_create_cb_calls
== 1);
479 CU_ASSERT(ch1
!= ch2
);
480 SPDK_CU_ASSERT_FATAL(ch2
!= NULL
);
482 ctx
= spdk_io_channel_get_ctx(ch2
);
483 CU_ASSERT(*(uint64_t *)ctx
== ctx2
);
485 g_destroy_cb_calls
= 0;
486 spdk_put_io_channel(ch1
);
488 CU_ASSERT(g_destroy_cb_calls
== 1);
490 g_destroy_cb_calls
= 0;
491 spdk_put_io_channel(ch2
);
493 CU_ASSERT(g_destroy_cb_calls
== 1);
495 ch1
= spdk_get_io_channel(&device3
);
496 CU_ASSERT(ch1
== NULL
);
498 spdk_io_device_unregister(&device1
, NULL
);
500 spdk_io_device_unregister(&device2
, NULL
);
502 CU_ASSERT(TAILQ_EMPTY(&g_io_devices
));
504 CU_ASSERT(TAILQ_EMPTY(&g_threads
));
508 create_cb(void *io_device
, void *ctx_buf
)
510 uint64_t *refcnt
= (uint64_t *)ctx_buf
;
512 CU_ASSERT(*refcnt
== 0);
519 destroy_cb(void *io_device
, void *ctx_buf
)
521 uint64_t *refcnt
= (uint64_t *)ctx_buf
;
523 CU_ASSERT(*refcnt
== 1);
528 * This test is checking that a sequence of get, put, get, put without allowing
529 * the deferred put operation to complete doesn't result in releasing the memory
530 * for the channel twice.
533 channel_destroy_races(void)
536 struct spdk_io_channel
*ch
;
541 spdk_io_device_register(&device
, create_cb
, destroy_cb
, sizeof(uint64_t), NULL
);
543 ch
= spdk_get_io_channel(&device
);
544 SPDK_CU_ASSERT_FATAL(ch
!= NULL
);
546 spdk_put_io_channel(ch
);
548 ch
= spdk_get_io_channel(&device
);
549 SPDK_CU_ASSERT_FATAL(ch
!= NULL
);
551 spdk_put_io_channel(ch
);
554 spdk_io_device_unregister(&device
, NULL
);
557 CU_ASSERT(TAILQ_EMPTY(&g_io_devices
));
559 CU_ASSERT(TAILQ_EMPTY(&g_threads
));
563 main(int argc
, char **argv
)
565 CU_pSuite suite
= NULL
;
566 unsigned int num_failures
;
568 if (CU_initialize_registry() != CUE_SUCCESS
) {
569 return CU_get_error();
572 suite
= CU_add_suite("io_channel", NULL
, NULL
);
574 CU_cleanup_registry();
575 return CU_get_error();
579 CU_add_test(suite
, "thread_alloc", thread_alloc
) == NULL
||
580 CU_add_test(suite
, "thread_send_msg", thread_send_msg
) == NULL
||
581 CU_add_test(suite
, "thread_poller", thread_poller
) == NULL
||
582 CU_add_test(suite
, "thread_for_each", thread_for_each
) == NULL
||
583 CU_add_test(suite
, "for_each_channel_remove", for_each_channel_remove
) == NULL
||
584 CU_add_test(suite
, "for_each_channel_unreg", for_each_channel_unreg
) == NULL
||
585 CU_add_test(suite
, "thread_name", thread_name
) == NULL
||
586 CU_add_test(suite
, "channel", channel
) == NULL
||
587 CU_add_test(suite
, "channel_destroy_races", channel_destroy_races
) == NULL
589 CU_cleanup_registry();
590 return CU_get_error();
593 CU_basic_set_mode(CU_BRM_VERBOSE
);
594 CU_basic_run_tests();
595 num_failures
= CU_get_number_of_failures();
596 CU_cleanup_registry();