]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/spdk/test/unit/lib/thread/thread.c/thread_ut.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / test / unit / lib / thread / thread.c / thread_ut.c
index 464e430f2c1aff66cda5c1828065a0b35952e88b..8c593c494aa19063d93d837f56bf811f0ed4d125 100644 (file)
 
 #include "spdk_cunit.h"
 
+#include "spdk_internal/thread.h"
+
 #include "thread/thread.c"
-#include "common/lib/test_env.c"
 #include "common/lib/ut_multithread.c"
 
-static void
-_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx)
+static int g_sched_rc = 0;
+
+static int
+_thread_schedule(struct spdk_thread *thread)
 {
-       fn(ctx);
+       return g_sched_rc;
 }
 
 static void
 thread_alloc(void)
 {
-       CU_ASSERT(TAILQ_EMPTY(&g_threads));
-       allocate_threads(1);
-       CU_ASSERT(!TAILQ_EMPTY(&g_threads));
-       free_threads();
-       CU_ASSERT(TAILQ_EMPTY(&g_threads));
+       struct spdk_thread *thread;
+
+       /* No schedule callback */
+       spdk_thread_lib_init(NULL, 0);
+       thread = spdk_thread_create(NULL, NULL);
+       SPDK_CU_ASSERT_FATAL(thread != NULL);
+       spdk_set_thread(thread);
+       spdk_thread_exit(thread);
+       spdk_thread_destroy(thread);
+       spdk_thread_lib_fini();
+
+       /* Schedule callback exists */
+       spdk_thread_lib_init(_thread_schedule, 0);
+
+       /* Scheduling succeeds */
+       g_sched_rc = 0;
+       thread = spdk_thread_create(NULL, NULL);
+       SPDK_CU_ASSERT_FATAL(thread != NULL);
+       spdk_set_thread(thread);
+       spdk_thread_exit(thread);
+       spdk_thread_destroy(thread);
+
+       /* Scheduling fails */
+       g_sched_rc = -1;
+       thread = spdk_thread_create(NULL, NULL);
+       SPDK_CU_ASSERT_FATAL(thread == NULL);
+
+       spdk_thread_lib_fini();
 }
 
 static void
@@ -116,7 +142,7 @@ thread_poller(void)
        allocate_threads(1);
 
        set_thread(0);
-       reset_time();
+       MOCK_SET(spdk_get_ticks, 0);
        /* Register a poller with no-wait time and test execution */
        poller = spdk_poller_register(poller_run_done, &poller_run, 0);
        CU_ASSERT(poller != NULL);
@@ -135,16 +161,15 @@ thread_poller(void)
        poll_threads();
        CU_ASSERT(poller_run == false);
 
-       increment_time(1000);
+       spdk_delay_us(1000);
        poll_threads();
        CU_ASSERT(poller_run == true);
 
-       reset_time();
        poller_run = false;
        poll_threads();
        CU_ASSERT(poller_run == false);
 
-       increment_time(1000);
+       spdk_delay_us(1000);
        poll_threads();
        CU_ASSERT(poller_run == true);
 
@@ -227,8 +252,8 @@ for_each_channel_remove(void)
        int count = 0;
 
        allocate_threads(3);
-       spdk_io_device_register(&io_target, channel_create, channel_destroy, sizeof(int), NULL);
        set_thread(0);
+       spdk_io_device_register(&io_target, channel_create, channel_destroy, sizeof(int), NULL);
        ch0 = spdk_get_io_channel(&io_target);
        set_thread(1);
        ch1 = spdk_get_io_channel(&io_target);
@@ -246,6 +271,7 @@ for_each_channel_remove(void)
         */
        set_thread(0);
        spdk_put_io_channel(ch0);
+       poll_threads();
        spdk_for_each_channel(&io_target, channel_msg, &count, channel_cpl);
        poll_threads();
 
@@ -301,13 +327,13 @@ for_each_channel_unreg(void)
        int io_target;
 
        allocate_threads(1);
+       set_thread(0);
        CU_ASSERT(TAILQ_EMPTY(&g_io_devices));
        spdk_io_device_register(&io_target, channel_create, channel_destroy, sizeof(int), NULL);
        CU_ASSERT(!TAILQ_EMPTY(&g_io_devices));
        dev = TAILQ_FIRST(&g_io_devices);
        SPDK_CU_ASSERT_FATAL(dev != NULL);
        CU_ASSERT(TAILQ_NEXT(dev, tailq) == NULL);
-       set_thread(0);
        ch0 = spdk_get_io_channel(&io_target);
        spdk_for_each_channel(&io_target, unreg_ch_done, &ctx, unreg_foreach_done);
 
@@ -349,22 +375,30 @@ thread_name(void)
        struct spdk_thread *thread;
        const char *name;
 
+       spdk_thread_lib_init(NULL, 0);
+
        /* Create thread with no name, which automatically generates one */
-       spdk_allocate_thread(_send_msg, NULL, NULL, NULL, NULL);
+       thread = spdk_thread_create(NULL, NULL);
+       spdk_set_thread(thread);
        thread = spdk_get_thread();
        SPDK_CU_ASSERT_FATAL(thread != NULL);
        name = spdk_thread_get_name(thread);
        CU_ASSERT(name != NULL);
-       spdk_free_thread();
+       spdk_thread_exit(thread);
+       spdk_thread_destroy(thread);
 
        /* Create thread named "test_thread" */
-       spdk_allocate_thread(_send_msg, NULL, NULL, NULL, "test_thread");
+       thread = spdk_thread_create("test_thread", NULL);
+       spdk_set_thread(thread);
        thread = spdk_get_thread();
        SPDK_CU_ASSERT_FATAL(thread != NULL);
        name = spdk_thread_get_name(thread);
        SPDK_CU_ASSERT_FATAL(name != NULL);
        CU_ASSERT(strcmp(name, "test_thread") == 0);
-       spdk_free_thread();
+       spdk_thread_exit(thread);
+       spdk_thread_destroy(thread);
+
+       spdk_thread_lib_fini();
 }
 
 static uint64_t device1;
@@ -417,7 +451,9 @@ channel(void)
        struct spdk_io_channel *ch1, *ch2;
        void *ctx;
 
-       spdk_allocate_thread(_send_msg, NULL, NULL, NULL, "thread0");
+       allocate_threads(1);
+       set_thread(0);
+
        spdk_io_device_register(&device1, create_cb_1, destroy_cb_1, sizeof(ctx1), NULL);
        spdk_io_device_register(&device2, create_cb_2, destroy_cb_2, sizeof(ctx2), NULL);
 
@@ -434,6 +470,7 @@ channel(void)
 
        g_destroy_cb_calls = 0;
        spdk_put_io_channel(ch2);
+       poll_threads();
        CU_ASSERT(g_destroy_cb_calls == 0);
 
        g_create_cb_calls = 0;
@@ -447,19 +484,78 @@ channel(void)
 
        g_destroy_cb_calls = 0;
        spdk_put_io_channel(ch1);
+       poll_threads();
        CU_ASSERT(g_destroy_cb_calls == 1);
 
        g_destroy_cb_calls = 0;
        spdk_put_io_channel(ch2);
+       poll_threads();
        CU_ASSERT(g_destroy_cb_calls == 1);
 
        ch1 = spdk_get_io_channel(&device3);
        CU_ASSERT(ch1 == NULL);
 
        spdk_io_device_unregister(&device1, NULL);
+       poll_threads();
        spdk_io_device_unregister(&device2, NULL);
+       poll_threads();
+       CU_ASSERT(TAILQ_EMPTY(&g_io_devices));
+       free_threads();
+       CU_ASSERT(TAILQ_EMPTY(&g_threads));
+}
+
+static int
+create_cb(void *io_device, void *ctx_buf)
+{
+       uint64_t *refcnt = (uint64_t *)ctx_buf;
+
+       CU_ASSERT(*refcnt == 0);
+       *refcnt = 1;
+
+       return 0;
+}
+
+static void
+destroy_cb(void *io_device, void *ctx_buf)
+{
+       uint64_t *refcnt = (uint64_t *)ctx_buf;
+
+       CU_ASSERT(*refcnt == 1);
+       *refcnt = 0;
+}
+
+/**
+ * This test is checking that a sequence of get, put, get, put without allowing
+ * the deferred put operation to complete doesn't result in releasing the memory
+ * for the channel twice.
+ */
+static void
+channel_destroy_races(void)
+{
+       uint64_t device;
+       struct spdk_io_channel *ch;
+
+       allocate_threads(1);
+       set_thread(0);
+
+       spdk_io_device_register(&device, create_cb, destroy_cb, sizeof(uint64_t), NULL);
+
+       ch = spdk_get_io_channel(&device);
+       SPDK_CU_ASSERT_FATAL(ch != NULL);
+
+       spdk_put_io_channel(ch);
+
+       ch = spdk_get_io_channel(&device);
+       SPDK_CU_ASSERT_FATAL(ch != NULL);
+
+       spdk_put_io_channel(ch);
+       poll_threads();
+
+       spdk_io_device_unregister(&device, NULL);
+       poll_threads();
+
        CU_ASSERT(TAILQ_EMPTY(&g_io_devices));
-       spdk_free_thread();
+       free_threads();
        CU_ASSERT(TAILQ_EMPTY(&g_threads));
 }
 
@@ -487,7 +583,8 @@ main(int argc, char **argv)
                CU_add_test(suite, "for_each_channel_remove", for_each_channel_remove) == NULL ||
                CU_add_test(suite, "for_each_channel_unreg", for_each_channel_unreg) == NULL ||
                CU_add_test(suite, "thread_name", thread_name) == NULL ||
-               CU_add_test(suite, "channel", channel) == NULL
+               CU_add_test(suite, "channel", channel) == NULL ||
+               CU_add_test(suite, "channel_destroy_races", channel_destroy_races) == NULL
        ) {
                CU_cleanup_registry();
                return CU_get_error();