Jelajahi Sumber

Merge pull request #5136 from cndabai/thread_tc

guo 3 tahun lalu
induk
melakukan
0f8c465352

+ 1 - 0
.github/workflows/action_utest.yml

@@ -15,6 +15,7 @@ jobs:
          - {UTEST: "kernel/ipc",       RTT_BSP: "bsp/qemu-vexpress-a9",    QEMU_ARCH: "arm",      QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "kernel/ipc.conf",     SD_FILE: "sd.bin"}
          - {UTEST: "kernel/irq",       RTT_BSP: "bsp/qemu-vexpress-a9",    QEMU_ARCH: "arm",      QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "kernel/irq.conf",     SD_FILE: "sd.bin"}
          - {UTEST: "kernel/timer",     RTT_BSP: "bsp/qemu-vexpress-a9",    QEMU_ARCH: "arm",      QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "kernel/timer.conf",   SD_FILE: "sd.bin"}
+         - {UTEST: "kernel/thread",    RTT_BSP: "bsp/qemu-vexpress-a9",    QEMU_ARCH: "arm",      QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "kernel/thread.conf",  SD_FILE: "sd.bin"}
          - {UTEST: "components/utest", RTT_BSP: "bsp/qemu-vexpress-a9",    QEMU_ARCH: "arm",      QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "utest_self/self.conf", SD_FILE: "sd.bin"}
          - {UTEST: "kernel/mem/riscv64", RTT_BSP: "bsp/qemu-riscv-virt64", QEMU_ARCH: "riscv64",  QEMU_MACHINE: "virt",  CONFIG_FILE: "kernel/mem.conf",   SD_FILE: "None"}
     env:

+ 4 - 0
examples/utest/configs/kernel/thread.conf

@@ -0,0 +1,4 @@
+CONFIG_UTEST_THREAD_TC=y
+# dependencies
+CONFIG_RT_USING_TIMER_SOFT=y
+CONFIG_RT_USING_THREAD=y

+ 6 - 0
examples/utest/testcases/kernel/Kconfig

@@ -39,4 +39,10 @@ config UTEST_MAILBOX_TC
     bool "mailbox test"
     default n
 
+config UTEST_THREAD_TC
+    bool "thread test"
+    default n
+    select RT_USING_TIMER_SOFT
+    select RT_USING_THREAD
+
 endmenu

+ 3 - 0
examples/utest/testcases/kernel/SConscript

@@ -32,6 +32,9 @@ if GetDepend(['UTEST_MUTEX_TC']):
 if GetDepend(['UTEST_MAILBOX_TC']):
     src += ['mailbox_tc.c']
 
+if GetDepend(['UTEST_THREAD_TC']):
+    src += ['thread_tc.c']
+
 CPPPATH = [cwd]
 
 group = DefineGroup('utestcases', src, depend = [], CPPPATH = CPPPATH)

+ 642 - 0
examples/utest/testcases/kernel/thread_tc.c

@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-09.01     yangjie      the firet version
+ * 2021-10.11     mazhiyuan    add idle, yield, suspend, control, priority, delay_until
+ */
+
+#include <rtthread.h>
+#include <stdlib.h>
+#include "utest.h"
+
+#define THREAD_STACK_SIZE  512
+#define THREAD_TIMESLICE   10
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+#ifdef RT_USING_HEAP
+    static rt_thread_t tid1 = RT_NULL;
+    static rt_thread_t tid3 = RT_NULL;
+    static rt_thread_t tid4 = RT_NULL;
+    static rt_thread_t tid5 = RT_NULL;
+    static rt_thread_t tid6 = RT_NULL;
+    static rt_thread_t tid7 = RT_NULL;
+#endif /* RT_USING_HEAP */
+
+static rt_uint32_t tid3_delay_pass_flag = 0;
+static rt_uint32_t tid3_finish_flag = 0;
+static rt_uint32_t tid4_finish_flag = 0;
+static rt_uint32_t tid6_finish_flag = 0;
+static rt_uint32_t thread5_source = 0;
+
+#ifndef RT_USING_SMP
+    static rt_uint32_t thread_yield_flag = 0;
+#endif
+static rt_uint32_t entry_idle_hook_times = 0;
+static rt_thread_t __current_thread;
+static rt_uint8_t change_priority;
+static rt_uint32_t count = 0;
+
+void thread1_entry(void *param)
+{
+    while (1);
+}
+
+static void test_dynamic_thread(void)
+{
+    rt_err_t ret_startup = -RT_ERROR;
+    rt_err_t ret_delete = -RT_ERROR;
+
+    tid1 = rt_thread_create("thread1",
+                            thread1_entry,
+                            (void *)1,
+                            THREAD_STACK_SIZE,
+                            __current_thread->current_priority + 1,
+                            THREAD_TIMESLICE - 5);
+    if (tid1 == RT_NULL)
+    {
+        uassert_false(tid1 == RT_NULL);
+        goto __exit;
+    }
+
+    ret_startup = rt_thread_startup(tid1);
+    if (ret_startup != RT_EOK)
+    {
+        uassert_false(ret_startup != RT_EOK);
+        goto __exit;
+    }
+
+    ret_delete = rt_thread_delete(tid1);
+    if (ret_delete != RT_EOK)
+    {
+        uassert_false(ret_delete != RT_EOK);
+        goto __exit;
+    }
+
+    uassert_true(tid1 != RT_NULL && ret_startup == RT_EOK && ret_delete == RT_EOK);
+
+__exit:
+    if (tid1 != RT_NULL && ret_delete != RT_EOK)
+    {
+        rt_thread_delete(tid1);
+    }
+    return;
+}
+
+void thread2_entry(void *param)
+{
+    while (1);
+}
+
+static void test_static_thread(void)
+{
+    rt_err_t ret_init = -RT_ERROR;
+    rt_err_t ret_startup = -RT_ERROR;
+    rt_err_t ret_detach = - RT_ERROR;
+
+    ret_init = rt_thread_init(&thread2,
+                              "thread2",
+                              thread2_entry,
+                              (void *)2,
+                              &thread2_stack[0],
+                              sizeof(thread2_stack),
+                              __current_thread->current_priority + 1,
+                              THREAD_TIMESLICE);
+    if (ret_init != RT_EOK)
+    {
+        uassert_false(ret_init != RT_EOK);
+        goto __exit;
+    }
+
+    ret_startup = rt_thread_startup(&thread2);
+    if (ret_startup != RT_EOK)
+    {
+        uassert_false(ret_startup != RT_EOK);
+        goto __exit;
+    }
+
+    ret_detach = rt_thread_detach(&thread2);
+    if (ret_detach != RT_EOK)
+    {
+        uassert_false(ret_detach != RT_EOK);
+        goto __exit;
+    }
+
+    uassert_true(ret_init == RT_EOK && ret_startup == RT_EOK && ret_detach == RT_EOK);
+
+__exit:
+    if (ret_init == RT_EOK && ret_detach != RT_EOK)
+    {
+        rt_thread_detach(&thread2);
+    }
+    return;
+}
+
+static void thread3_entry(void *parameter)
+{
+    rt_tick_t tick;
+    tick = rt_tick_get();
+    rt_thread_delay(15);
+    if (rt_tick_get() - tick > 16)
+    {
+        tid3_finish_flag = 1;
+        tid3_delay_pass_flag = 0;
+        return;
+    }
+    tid3_delay_pass_flag = 1;
+    tid3_finish_flag = 1;
+}
+
+static void test_thread_delay(void)
+{
+    rt_err_t ret_startup = -RT_ERROR;
+
+    tid3 = rt_thread_create("thread3",
+                            thread3_entry,
+                            RT_NULL,
+                            THREAD_STACK_SIZE,
+                            __current_thread->current_priority - 1,
+                            THREAD_TIMESLICE);
+    if (tid3 == RT_NULL)
+    {
+        LOG_E("rt_thread_create failed!");
+        uassert_false(tid3 == RT_NULL);
+        goto __exit;
+    }
+
+    ret_startup = rt_thread_startup(tid3);
+    if (ret_startup != RT_EOK)
+    {
+        LOG_E("rt_thread_startup failed!");
+        uassert_false(1);
+        goto __exit;
+    }
+
+    while (tid3_finish_flag != 1);
+    uassert_true(tid3_delay_pass_flag == 1);
+
+__exit:
+    return;
+}
+
+static void idle_hook(void)
+{
+    entry_idle_hook_times ++;
+}
+
+static void thread4_entry(void *parameter)
+{
+    rt_uint32_t delay_times = 5;
+    while (delay_times --)
+    {
+        rt_thread_mdelay(300);
+    }
+    rt_thread_idle_delhook(idle_hook);
+    tid4_finish_flag = 1;
+}
+
+static void test_idle_hook(void)
+{
+    rt_err_t ret_startup = -RT_ERROR;
+
+    rt_thread_idle_sethook(idle_hook);
+
+    tid4 = rt_thread_create("thread4",
+                            thread4_entry,
+                            RT_NULL,
+                            THREAD_STACK_SIZE,
+                            __current_thread->current_priority - 1,
+                            THREAD_TIMESLICE);
+    if (tid4 == RT_NULL)
+    {
+        LOG_E("rt_thread_create failed!");
+        uassert_false(tid4 == RT_NULL);
+        goto __exit;
+    }
+
+    ret_startup = rt_thread_startup(tid4);
+    if (ret_startup != RT_EOK)
+    {
+        LOG_E("rt_thread_startup failed!");
+        uassert_false(1);
+        goto __exit;
+    }
+
+    while (tid4_finish_flag != 1)
+    {
+        rt_thread_mdelay(200);
+    }
+    uassert_true(entry_idle_hook_times > 0);
+
+__exit:
+    return;
+}
+
+static void thread5_entry(void *parameter)
+{
+    while (1)
+    {
+        thread5_source ++;
+        rt_thread_delay(5);
+        if (thread5_source == 5)
+        {
+            rt_thread_yield();
+        }
+    }
+}
+
+static void thread6_entry(void *parameter)
+{
+    while (++ thread5_source <= 9);
+    tid6_finish_flag = 1;
+}
+
+static void test_thread_yield(void)
+{
+    rt_err_t ret_startup = -RT_ERROR;
+    tid5 = rt_thread_create("thread5",
+                            thread5_entry,
+                            RT_NULL,
+                            THREAD_STACK_SIZE,
+                            __current_thread->current_priority - 1,
+                            THREAD_TIMESLICE);
+    if (tid5 == RT_NULL)
+    {
+        LOG_E("rt_thread_create failed!");
+        uassert_false(tid5 == RT_NULL);
+        goto __exit;
+    }
+    ret_startup = rt_thread_startup(tid5);
+    if (ret_startup != RT_EOK)
+    {
+        LOG_E("rt_thread_startup failed!");
+        uassert_false(1);
+        goto __exit;
+    }
+    tid6 = rt_thread_create("thread6",
+                            thread6_entry,
+                            RT_NULL,
+                            THREAD_STACK_SIZE,
+                            __current_thread->current_priority - 1,
+                            THREAD_TIMESLICE);
+    if (tid6 == RT_NULL)
+    {
+        LOG_E("rt_thread_create failed!");
+        uassert_false(tid6 == RT_NULL);
+        goto __exit;
+    }
+    ret_startup = rt_thread_startup(tid6);
+    if (ret_startup != RT_EOK)
+    {
+        LOG_E("rt_thread_startup failed!");
+        uassert_false(1);
+        goto __exit;
+    }
+
+    while (tid6_finish_flag != 1);
+    uassert_true(thread5_source == 10);
+
+__exit:
+    if (tid5 != RT_NULL)
+    {
+        rt_thread_delete(tid5);
+    }
+    return;
+}
+
+static void thread7_entry(void *parameter)
+{
+    while (1);
+}
+
+static void test_thread_control(void)
+{
+    rt_err_t ret_control = -RT_ERROR;
+    rt_err_t rst_delete = -RT_ERROR;
+
+    tid7 = rt_thread_create("thread7",
+                            thread7_entry,
+                            RT_NULL,
+                            THREAD_STACK_SIZE,
+                            __current_thread->current_priority + 1,
+                            THREAD_TIMESLICE);
+    if (tid7 == RT_NULL)
+    {
+        LOG_E("rt_thread_create failed!");
+        uassert_false(tid7 == RT_NULL);
+        goto __exit;
+    }
+
+    ret_control = rt_thread_control(tid7, RT_THREAD_CTRL_STARTUP, RT_NULL);
+    if (ret_control != RT_EOK)
+    {
+        LOG_E("rt_thread_control failed!");
+        uassert_false(1);
+        goto __exit;
+    }
+    rt_thread_mdelay(200);
+    rt_thread_control(tid7, RT_THREAD_CTRL_CHANGE_PRIORITY, &change_priority);
+    if (tid7->current_priority != change_priority)
+    {
+        LOG_E("rt_thread_control failed!");
+        uassert_false(1);
+        goto __exit;
+    }
+    rst_delete = rt_thread_control(tid7, RT_THREAD_CTRL_CLOSE, RT_NULL);
+    if (rst_delete != RT_EOK)
+    {
+        LOG_E("rt_thread_control failed!");
+        uassert_false(rst_delete != RT_EOK);
+        goto __exit;
+    }
+
+    uassert_true(1);
+
+__exit:
+    if (tid7 != RT_NULL && rst_delete != RT_EOK)
+    {
+        rt_thread_delete(tid7);
+    }
+    return;
+}
+
+static void thread8_entry(void *parameter)
+{
+    for (; count < 10; count ++);
+}
+
+static void test_thread_priority(void)
+{
+    rt_err_t ret_startup = -RT_ERROR;
+    rt_thread_t tid8 = RT_NULL;
+
+    tid8 = rt_thread_create("thread8",
+                            thread8_entry,
+                            RT_NULL,
+                            THREAD_STACK_SIZE,
+                            __current_thread->current_priority - 1,
+                            THREAD_TIMESLICE);
+    if (tid8 == RT_NULL)
+    {
+        LOG_E("rt_thread_create failed!");
+        uassert_false(tid8 == RT_NULL);
+        return;
+    }
+    count = 0;
+    ret_startup = rt_thread_startup(tid8);
+    if (ret_startup != RT_EOK)
+    {
+        uassert_false(ret_startup != RT_EOK);
+        return ;
+    }
+    uassert_true(count == 10);
+
+    return;
+}
+
+static void test_delay_until(void)
+{
+    rt_tick_t tick;
+    rt_tick_t check_tick = 0;
+    rt_tick_t delta = 0;
+
+    tick = rt_tick_get();
+
+    check_tick = tick;
+    rt_thread_delay_until(&tick, 100);
+    delta = rt_tick_get() - check_tick;
+    rt_kprintf("delta[100] -> %d\n", delta);
+    uassert_int_equal(delta, 100);
+
+    check_tick = tick;
+    rt_thread_delay(2);
+    rt_thread_delay_until(&tick, 200);
+    delta = rt_tick_get() - check_tick;
+    rt_kprintf("delta[200] -> %d\n", delta);
+    uassert_int_equal(delta, 200);
+
+    check_tick = tick;
+    rt_thread_delay(2);
+    rt_thread_delay_until(&tick, 300);
+    delta = rt_tick_get() - check_tick;
+    rt_kprintf("delta[300] -> %d\n", delta);
+    uassert_int_equal(delta, 300);
+
+    check_tick = tick;
+    rt_thread_delay(2);
+    rt_thread_delay_until(&tick, 100);
+    delta = rt_tick_get() - check_tick;
+    uassert_int_equal(delta, 100);
+
+    check_tick = tick;
+    rt_thread_delay(2);
+    rt_thread_delay_until(&tick, 50);
+    delta = rt_tick_get() - check_tick;
+    rt_kprintf("delta[50] -> %d\n", delta);
+    uassert_int_equal(delta, 50);
+
+    check_tick = tick;
+    rt_thread_delay(2);
+    rt_thread_delay_until(&tick, 20);
+    delta = rt_tick_get() - check_tick;
+    rt_kprintf("delta[20] -> %d\n", delta);
+    uassert_int_equal(delta, 20);
+
+    check_tick = tick;
+    rt_thread_delay(2);
+    rt_thread_delay_until(&tick, 10);
+    delta = rt_tick_get() - check_tick;
+    rt_kprintf("delta[10] -> %d\n", delta);
+    uassert_int_equal(delta, 10);
+}
+
+#ifndef RT_USING_SMP
+static volatile rt_uint32_t yield_count;
+
+static void test_thread_yield_inc_entry(void *parameter)
+{
+    rt_uint32_t loop = 0;
+
+    while (1)
+    {
+        if (loop++ > 10001)
+            break;
+        yield_count++;
+        rt_thread_yield();
+    }
+}
+
+static void test_thread_yield_entry(void *parameter)
+{
+    rt_err_t ret_startup = -RT_ERROR;
+
+    rt_thread_t tid;
+    rt_uint32_t loop = 0;
+    rt_uint32_t count_before;
+
+    tid = rt_thread_create("inc", test_thread_yield_inc_entry, RT_NULL,
+                           2048, 1, 10);
+    if (!tid)
+    {
+        LOG_E("rt_thread_create failed!");
+        return;
+    }
+
+    ret_startup = rt_thread_startup(tid);
+    if (ret_startup != RT_EOK)
+    {
+        LOG_E("rt_thread_startup failed!");
+        uassert_false(1);
+        return ;
+    }
+
+    while (1)
+    {
+        if (loop++ > 10000)
+            break;
+
+        count_before = yield_count;
+        rt_thread_yield();
+        if (yield_count == count_before)
+        {
+            LOG_E("yield error!");
+            return;
+        }
+    }
+    thread_yield_flag = 1;
+}
+
+void test_thread_yield_nosmp(void)
+{
+    rt_err_t ret_startup = -RT_ERROR;
+
+    rt_thread_t tid;
+
+    yield_count = 0;
+
+    tid = rt_thread_create("chkcnt", test_thread_yield_entry, RT_NULL,
+                           2048, 1, 10);
+    if (!tid)
+    {
+        LOG_E("rt_thread_create failed!");
+        return;
+    }
+
+    ret_startup = rt_thread_startup(tid);
+    if (ret_startup != RT_EOK)
+    {
+        LOG_E("rt_thread_startup failed!");
+        uassert_false(1);
+        return ;
+    }
+
+    uassert_true(thread_yield_flag == 1);
+}
+
+static rt_uint32_t thread9_count = 0;
+static void thread9_entry(void *parameter)
+{
+    while (1)
+    {
+        thread9_count ++;
+    }
+
+}
+static void test_thread_suspend(void)
+{
+    static rt_thread_t tid;
+    rt_err_t ret_startup = -RT_ERROR;
+    uint32_t count_before_suspend, count_before_resume, count_after_resume;
+    tid = rt_thread_create("thread9",
+                           thread9_entry,
+                           RT_NULL,
+                           THREAD_STACK_SIZE,
+                           __current_thread->current_priority + 1,
+                           THREAD_TIMESLICE);
+    if (tid == RT_NULL)
+    {
+        LOG_E("rt_thread_create failed!");
+        uassert_false(tid4 == RT_NULL);
+        goto __exit;
+    }
+
+    ret_startup = rt_thread_startup(tid);
+    if (ret_startup != RT_EOK)
+    {
+        LOG_E("rt_thread_startup failed!");
+        uassert_false(1);
+        goto __exit;
+    }
+    rt_thread_delay(5);
+    rt_thread_suspend(tid);
+    count_before_suspend = thread9_count;
+    uassert_true(count_before_suspend != 0);
+    rt_thread_delay(5);
+    count_before_resume = thread9_count;
+    uassert_true(count_before_suspend == count_before_resume);
+    rt_thread_resume(tid);
+    rt_thread_delay(5);
+    count_after_resume = thread9_count;
+    uassert_true(count_after_resume != count_before_resume);
+
+__exit:
+    if (tid != RT_NULL)
+    {
+        rt_thread_delete(tid);
+    }
+    return;
+}
+#endif
+
+static rt_err_t utest_tc_init(void)
+{
+    __current_thread = rt_thread_self();
+    change_priority = __current_thread->current_priority + 5;
+    tid3_delay_pass_flag = 0;
+    tid3_finish_flag = 0;
+    tid4_finish_flag = 0;
+    tid6_finish_flag = 0;
+    entry_idle_hook_times = 0;
+    count = 0;
+    return RT_EOK;
+}
+
+static rt_err_t utest_tc_cleanup(void)
+{
+    return RT_EOK;
+}
+
+static void testcase(void)
+{
+    /* init, detach */
+    UTEST_UNIT_RUN(test_static_thread);
+    /* create, delete */
+    UTEST_UNIT_RUN(test_dynamic_thread);
+    /* delay */
+    UTEST_UNIT_RUN(test_thread_delay);
+    /* idle_sethook, idle_delhook */
+    UTEST_UNIT_RUN(test_idle_hook);
+    /* yield */
+    UTEST_UNIT_RUN(test_thread_yield);
+#ifndef RT_USING_SMP
+    /* yield_nosmp */
+    UTEST_UNIT_RUN(test_thread_yield_nosmp);
+    /* suspend, resume */
+    UTEST_UNIT_RUN(test_thread_suspend);
+#endif
+    /* control */
+    UTEST_UNIT_RUN(test_thread_control);
+    UTEST_UNIT_RUN(test_thread_priority);
+    /* delay_until */
+    UTEST_UNIT_RUN(test_delay_until);
+}
+
+
+UTEST_TC_EXPORT(testcase, "testcases.kernel.thread_tc", utest_tc_init, utest_tc_cleanup, 1000);
+
+/********************* end of file ************************/