原始版本
This commit is contained in:
73
RT_Thread/examples/utest/README.md
Normal file
73
RT_Thread/examples/utest/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
# RT-Thread 测试用例集合
|
||||
|
||||
## 简介
|
||||
|
||||
为了保证某一部分代码的质量,通常可以通过编写测试用例的方式,验证此代码的功能。为了保证 RT-Thread 相关仓库的代码质量,我们基于 utest 框架搭建了一套简易的自动化测试环境。有兴趣,有精力的小伙伴可以利用这套机制完善自己的代码检查。如果有意愿让社区上更多的小伙伴受益,也可以在提交代码的时候,把对应的测试用例也提交上来。
|
||||
|
||||
## 目录结构
|
||||
|
||||
| 目录 | 用途 |
|
||||
| --------- | ------------------------------------------------------------ |
|
||||
| configs | 配置文件集合(每一个目录代表一种功能集合,如:kernel,net等) |
|
||||
| testcases | 测试用例源代码 |
|
||||
|
||||
## 如何贡献
|
||||
|
||||
### 1. 编写测试用例
|
||||
|
||||
参考已有的测试用例在 [examples\utest\testcases](./testcases) 目录下添加自己的测试用例。测试用例的编写方法参考文档中心[《utest 测试框架》章节](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/utest/utest)。
|
||||
|
||||
### 2. 本地测试
|
||||
|
||||
1. 在 `bsp\qemu-vexpress-a9` 目录下打开 `menuconfig`,使能对应的测试用例,如下:
|
||||
|
||||
```
|
||||
RT-Thread Utestcases --->
|
||||
[*] RT-Thread Utestcases
|
||||
Utest Self Testcase --->
|
||||
[*] Pass test
|
||||
```
|
||||
|
||||
2. 保存并退出,输入 scons 编译当前 bsp。
|
||||
|
||||
3. 输入 .\qemu.bat 运行当前 bsp,在 msh 环境下执行 utest_run 命令,验证代码运行是否正常。
|
||||
|
||||
```
|
||||
msh />utest_run
|
||||
[I/utest] [==========] [ utest ] loop 1/1
|
||||
[I/utest] [==========] [ utest ] started
|
||||
[I/utest] [----------] [ testcase ] (testcases.utest.pass_tc) started
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:16) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:17) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:19) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:20) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:22) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:23) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:25) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:26) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:28) is passed
|
||||
[D/utest] [ OK ] [ unit ] (test_assert_pass:29) is passed
|
||||
[I/utest] [ PASSED ] [ result ] testcase (testcases.utest.pass_tc)
|
||||
[I/utest] [----------] [ testcase ] (testcases.utest.pass_tc) finished
|
||||
[I/utest] [==========] [ utest ] finished
|
||||
```
|
||||
|
||||
### 3. 提交
|
||||
|
||||
1. 如果是对已有测试集合的完善,需要把添加的测试用例的配置项,以及对应的依赖项添加到对应测试集合的配置文件里,如:[examples\utest\configs\kernel\mem.conf](./configs/kernel/mem.conf)。
|
||||
|
||||
```
|
||||
CONFIG_UTEST_MEMHEAP_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_MEMHEAP=y
|
||||
```
|
||||
|
||||
2. 如果要添加新的测试集合,需要参考已有的测试集合,在 [examples\utest\configs](./configs) 目录下添加新的测试集合配置项。并更新 [.github\workflows\action_utest.yml](../../.github/workflows/action_utest.yml) 内的测试集合。
|
||||
|
||||
```
|
||||
- {UTEST: "kernel/mem", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "arm", QEMU_MACHINE: "vexpress-a9", CONFIG_FILE: "kernel/mem.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"}
|
||||
```
|
||||
|
||||
3. 向 RT-Thread 主仓库提交合并请求。
|
||||
4
RT_Thread/examples/utest/configs/cpp11/cpp11.conf
Normal file
4
RT_Thread/examples/utest/configs/cpp11/cpp11.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_CPP11_THREAD_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_CPLUSPLUS=y
|
||||
CONFIG_RT_USING_CPLUSPLUS11=y
|
||||
4
RT_Thread/examples/utest/configs/kernel/atomic.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/atomic.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_ATOMIC_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
CONFIG_RT_USING_THREAD=y
|
||||
5
RT_Thread/examples/utest/configs/kernel/atomic_c11.conf
Normal file
5
RT_Thread/examples/utest/configs/kernel/atomic_c11.conf
Normal file
@ -0,0 +1,5 @@
|
||||
CONFIG_UTEST_ATOMIC_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
CONFIG_RT_USING_THREAD=y
|
||||
CONFIG_RT_USING_STDC_ATOMIC=y
|
||||
4
RT_Thread/examples/utest/configs/kernel/device.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/device.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_DEVICE_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
CONFIG_RT_USING_THREAD=y
|
||||
14
RT_Thread/examples/utest/configs/kernel/ipc.conf
Normal file
14
RT_Thread/examples/utest/configs/kernel/ipc.conf
Normal file
@ -0,0 +1,14 @@
|
||||
CONFIG_UTEST_SEMAPHORE_TC=y
|
||||
CONFIG_UTEST_EVENT_TC=y
|
||||
CONFIG_UTEST_MESSAGEQUEUE_TC=y
|
||||
CONFIG_UTEST_SIGNAL_TC=y
|
||||
CONFIG_UTEST_MUTEX_TC=y
|
||||
CONFIG_UTEST_MAILBOX_TC=y
|
||||
CONFIG_UTEST_WORKQUEUE_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_SEMAPHORE=y
|
||||
CONFIG_RT_USING_EVENT=y
|
||||
CONFIG_RT_USING_MESSAGEQUEUE=y
|
||||
CONFIG_RT_USING_SIGNALS=y
|
||||
CONFIG_RT_USING_MUTEX=y
|
||||
CONFIG_RT_USING_MAILBOX=y
|
||||
3
RT_Thread/examples/utest/configs/kernel/irq.conf
Normal file
3
RT_Thread/examples/utest/configs/kernel/irq.conf
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_UTEST_IRQ_TC=y
|
||||
CONFIG_RT_HOOK_USING_FUNC_PTR=y
|
||||
# dependencies
|
||||
4
RT_Thread/examples/utest/configs/kernel/mem.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/mem.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_MEMHEAP_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_MEMHEAP=y
|
||||
4
RT_Thread/examples/utest/configs/kernel/thread.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/thread.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_THREAD_TC=y
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
CONFIG_RT_USING_THREAD=y
|
||||
4
RT_Thread/examples/utest/configs/kernel/timer.conf
Normal file
4
RT_Thread/examples/utest/configs/kernel/timer.conf
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_UTEST_TIMER_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_TIMER_SOFT=y
|
||||
6
RT_Thread/examples/utest/configs/rtsmart/base.conf
Normal file
6
RT_Thread/examples/utest/configs/rtsmart/base.conf
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_UTEST_MEMHEAP_TC=y
|
||||
|
||||
# dependencies
|
||||
CONFIG_RT_USING_SMART=y
|
||||
CONFIG_RT_USING_MEMHEAP=y
|
||||
CONFIG_RT_USING_DFS_V2=y
|
||||
1
RT_Thread/examples/utest/configs/utest_self/self.conf
Normal file
1
RT_Thread/examples/utest/configs/utest_self/self.conf
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_UTEST_SELF_PASS_TC=y
|
||||
22
RT_Thread/examples/utest/testcases/Kconfig
Normal file
22
RT_Thread/examples/utest/testcases/Kconfig
Normal file
@ -0,0 +1,22 @@
|
||||
menu "RT-Thread Utestcases"
|
||||
|
||||
config RT_USING_UTESTCASES
|
||||
bool "RT-Thread Utestcases"
|
||||
default n
|
||||
select RT_USING_UTEST
|
||||
|
||||
if RT_USING_UTESTCASES
|
||||
|
||||
rsource "utest/Kconfig"
|
||||
rsource "kernel/Kconfig"
|
||||
rsource "cpp11/Kconfig"
|
||||
rsource "drivers/serial_v2/Kconfig"
|
||||
rsource "drivers/serial_bypass/Kconfig"
|
||||
rsource "drivers/ipc/Kconfig"
|
||||
rsource "posix/Kconfig"
|
||||
rsource "mm/Kconfig"
|
||||
rsource "tmpfs/Kconfig"
|
||||
rsource "smp_call/Kconfig"
|
||||
endif
|
||||
|
||||
endmenu
|
||||
15
RT_Thread/examples/utest/testcases/SConscript
Normal file
15
RT_Thread/examples/utest/testcases/SConscript
Normal file
@ -0,0 +1,15 @@
|
||||
# RT-Thread building script for bridge
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
objs = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
Return('objs')
|
||||
9
RT_Thread/examples/utest/testcases/cpp11/Kconfig
Normal file
9
RT_Thread/examples/utest/testcases/cpp11/Kconfig
Normal file
@ -0,0 +1,9 @@
|
||||
menu "CPP11 Testcase"
|
||||
|
||||
config UTEST_CPP11_THREAD_TC
|
||||
bool "Cpp11 thread test"
|
||||
select RT_USING_CPLUSPLUS
|
||||
select RT_USING_CPLUSPLUS11
|
||||
default n
|
||||
|
||||
endmenu
|
||||
13
RT_Thread/examples/utest/testcases/cpp11/SConscript
Normal file
13
RT_Thread/examples/utest/testcases/cpp11/SConscript
Normal file
@ -0,0 +1,13 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split('''
|
||||
thread_tc.cpp
|
||||
''')
|
||||
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['UTEST_CPP11_THREAD_TC'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
59
RT_Thread/examples/utest/testcases/cpp11/thread_tc.cpp
Normal file
59
RT_Thread/examples/utest/testcases/cpp11/thread_tc.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-03 liukang the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <thread>
|
||||
|
||||
static void test_thread(void)
|
||||
{
|
||||
int count = 0;
|
||||
auto func = [&]() mutable
|
||||
{
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
};
|
||||
|
||||
std::thread t1(func);
|
||||
t1.join();
|
||||
|
||||
if (count != 100)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
std::thread t2(func);
|
||||
t2.join();
|
||||
|
||||
if (count != 200)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_thread);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.cpp11.thread_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
15
RT_Thread/examples/utest/testcases/drivers/SConscript
Normal file
15
RT_Thread/examples/utest/testcases/drivers/SConscript
Normal file
@ -0,0 +1,15 @@
|
||||
# RT-Thread building script for bridge
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
objs = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
Return('objs')
|
||||
11
RT_Thread/examples/utest/testcases/drivers/ipc/Kconfig
Normal file
11
RT_Thread/examples/utest/testcases/drivers/ipc/Kconfig
Normal file
@ -0,0 +1,11 @@
|
||||
menu "Utest IPC Testcase"
|
||||
|
||||
config UTEST_COMPLETION_TC
|
||||
bool "rt_completion testcase"
|
||||
default n
|
||||
|
||||
config UTEST_WORKQUEUE_TC
|
||||
bool "rt_workqueue testcase"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
16
RT_Thread/examples/utest/testcases/drivers/ipc/SConscript
Normal file
16
RT_Thread/examples/utest/testcases/drivers/ipc/SConscript
Normal file
@ -0,0 +1,16 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend(['UTEST_COMPLETION_TC']):
|
||||
src += ['completion_tc.c', 'completion_timeout_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_WORKQUEUE_TC']):
|
||||
src += ['workqueue_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
199
RT_Thread/examples/utest/testcases/drivers/ipc/completion_tc.c
Normal file
199
RT_Thread/examples/utest/testcases/drivers/ipc/completion_tc.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-04-30 Shell init ver.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Case for rt_completion API
|
||||
*
|
||||
* The test simulates a producer-consumer interaction where a producer thread
|
||||
* generates data, and a consumer thread consumes the data after waiting for its
|
||||
* availability using rt_completion synchronization primitives.
|
||||
*
|
||||
* Test Criteria:
|
||||
* - The producer should correctly increment the test data and signal
|
||||
* completion.
|
||||
* - The consumer should correctly wait for data update, consume it, and signal
|
||||
* completion.
|
||||
* - Data integrity should be maintained between producer and consumer.
|
||||
* - Synchronization is properly done so both can see consistent data.
|
||||
* - Random latency is introduced to simulate racing scenarios.
|
||||
*/
|
||||
|
||||
#define TEST_LATENCY_TICK (1)
|
||||
#define TEST_LOOP_TIMES (60 * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_ON (RT_TICK_PER_SECOND)
|
||||
|
||||
#include "utest.h"
|
||||
|
||||
#include <ipc/completion.h>
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static struct rt_completion _prod_completion;
|
||||
static struct rt_completion _cons_completion;
|
||||
static int _test_data = 0;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
|
||||
static void done_safely(struct rt_completion *completion)
|
||||
{
|
||||
rt_err_t error;
|
||||
|
||||
/* Signal completion */
|
||||
error = rt_completion_wakeup(completion);
|
||||
|
||||
/* try again if failed to produce */
|
||||
if (error == -RT_EEMPTY)
|
||||
{
|
||||
rt_thread_yield();
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
uassert_false(0);
|
||||
rt_thread_delete(rt_thread_self());
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_safely(struct rt_completion *completion)
|
||||
{
|
||||
rt_err_t error;
|
||||
do
|
||||
{
|
||||
error = rt_completion_wait_flags(completion, RT_WAITING_FOREVER,
|
||||
RT_INTERRUPTIBLE);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(error == -RT_EINTR);
|
||||
rt_thread_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static void producer_thread_entry(void *parameter)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* Produce data */
|
||||
_test_data++;
|
||||
|
||||
/* notify consumer */
|
||||
done_safely(&_prod_completion);
|
||||
|
||||
/* Delay before producing next data */
|
||||
rt_thread_delay(TEST_LATENCY_TICK);
|
||||
|
||||
/* sync with consumer */
|
||||
wait_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void _wait_until_edge(void)
|
||||
{
|
||||
rt_tick_t entry_level, current;
|
||||
rt_base_t random_latency;
|
||||
|
||||
entry_level = rt_tick_get();
|
||||
do
|
||||
{
|
||||
current = rt_tick_get();
|
||||
} while (current == entry_level);
|
||||
|
||||
/* give a random latency for test */
|
||||
random_latency = rand();
|
||||
entry_level = current;
|
||||
for (size_t i = 0; i < random_latency; i++)
|
||||
{
|
||||
current = rt_tick_get();
|
||||
if (current != entry_level) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void consumer_thread_entry(void *parameter)
|
||||
{
|
||||
int local_test_data = 0;
|
||||
|
||||
rt_thread_startup(parameter);
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* add more random case for test */
|
||||
_wait_until_edge();
|
||||
|
||||
/* Wait for data update */
|
||||
wait_safely(&_prod_completion);
|
||||
|
||||
/* Consume data */
|
||||
if (local_test_data + 1 != _test_data)
|
||||
{
|
||||
LOG_I("local test data is %d, shared test data is %d",
|
||||
local_test_data, _test_data);
|
||||
uassert_true(0);
|
||||
}
|
||||
else if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
{
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
local_test_data = _test_data;
|
||||
done_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
/* Initialize completion object */
|
||||
rt_completion_init(&_prod_completion);
|
||||
rt_completion_init(&_cons_completion);
|
||||
|
||||
/* Create producer and consumer threads */
|
||||
rt_thread_t producer_thread =
|
||||
rt_thread_create("producer", producer_thread_entry, RT_NULL,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
rt_thread_t consumer_thread =
|
||||
rt_thread_create("consumer", consumer_thread_entry, producer_thread,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
uassert_true(producer_thread != RT_NULL);
|
||||
uassert_true(consumer_thread != RT_NULL);
|
||||
|
||||
LOG_I("Summary:\n"
|
||||
"\tTest times: %ds(%d)",
|
||||
TEST_LOOP_TIMES / RT_TICK_PER_SECOND, TEST_LOOP_TIMES);
|
||||
|
||||
rt_thread_startup(consumer_thread);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_test_data = 0;
|
||||
_progress_counter = 0;
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.ipc.rt_completion.basic",
|
||||
utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-04-30 Shell init ver.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test Case for rt_completion API
|
||||
*
|
||||
* The test simulates a producer-consumer interaction where a producer thread
|
||||
* generates data, and a consumer thread consumes the data after waiting for its
|
||||
* availability using rt_completion synchronization primitives.
|
||||
*
|
||||
* Test Criteria:
|
||||
* - The producer produces data correctly and notifies the consumer thread.
|
||||
* - The consumer receives data correctly and acknowledges receipt to the
|
||||
* producer.
|
||||
* - The producer and consumer threads synchronize their operations effectively.
|
||||
* - Verify the correctness of data production and consumption between producer
|
||||
* and consumer threads.
|
||||
* - The asynchronous woken of consumer thread was handled properly so the
|
||||
* consumer don't lose woken from producer.
|
||||
*
|
||||
* Test APIs:
|
||||
* - rt_completion_init()
|
||||
* - rt_completion_wakeup()
|
||||
* - rt_completion_wait_flags()
|
||||
*/
|
||||
|
||||
#define TEST_LATENCY_TICK (1)
|
||||
#define TEST_LOOP_TIMES (60 * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_ON (RT_TICK_PER_SECOND)
|
||||
|
||||
#include "utest.h"
|
||||
|
||||
#include <ipc/completion.h>
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static struct rt_completion _prod_completion;
|
||||
static struct rt_completion _cons_completion;
|
||||
static int _test_data;
|
||||
static int _async_intr_count;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
|
||||
static void _test_thread_exit_failure(char *string)
|
||||
{
|
||||
LOG_E("\t[TEST failed] %s", string);
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
rt_thread_delete(rt_thread_self());
|
||||
}
|
||||
|
||||
static void done_safely(struct rt_completion *completion)
|
||||
{
|
||||
rt_err_t error;
|
||||
|
||||
/* Signal completion */
|
||||
error = rt_completion_wakeup(completion);
|
||||
|
||||
/* try again if failed to produce */
|
||||
if (error == -RT_EEMPTY)
|
||||
{
|
||||
rt_thread_yield();
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
uassert_true(error == RT_EOK);
|
||||
_test_thread_exit_failure("unexpected error");
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_safely(struct rt_completion *completion)
|
||||
{
|
||||
int try_times = 3;
|
||||
rt_err_t error;
|
||||
do
|
||||
{
|
||||
/* wait for one tick, to add more random */
|
||||
error = rt_completion_wait_flags(completion, 1, RT_INTERRUPTIBLE);
|
||||
if (error)
|
||||
{
|
||||
if (error == -RT_ETIMEOUT || error == -RT_EINTR)
|
||||
{
|
||||
_async_intr_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("Async event %d\n", error);
|
||||
uassert_true(0);
|
||||
}
|
||||
rt_thread_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (try_times--);
|
||||
|
||||
if (error != RT_EOK)
|
||||
{
|
||||
uassert_true(error == RT_EOK);
|
||||
_test_thread_exit_failure("wait failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void producer_thread_entry(void *parameter)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* Produce data */
|
||||
_test_data++;
|
||||
|
||||
/* Delay before producing next data */
|
||||
rt_thread_delay(TEST_LATENCY_TICK);
|
||||
|
||||
/* notify consumer */
|
||||
done_safely(&_prod_completion);
|
||||
|
||||
/* sync with consumer */
|
||||
wait_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void consumer_thread_entry(void *parameter)
|
||||
{
|
||||
int local_test_data = 0;
|
||||
|
||||
rt_thread_startup(parameter);
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
/* Wait for data update */
|
||||
wait_safely(&_prod_completion);
|
||||
|
||||
/* Consume data */
|
||||
if (local_test_data + 1 != _test_data)
|
||||
{
|
||||
LOG_I("local test data is %d, shared test data is %d",
|
||||
local_test_data, _test_data);
|
||||
uassert_true(0);
|
||||
}
|
||||
else if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
{
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
local_test_data = _test_data;
|
||||
done_safely(&_cons_completion);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
rt_thread_t _watching_thread1;
|
||||
rt_thread_t _watching_thread2;
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
/* Initialize completion object */
|
||||
rt_completion_init(&_prod_completion);
|
||||
rt_completion_init(&_cons_completion);
|
||||
|
||||
/* Create producer and consumer threads */
|
||||
rt_thread_t producer_thread =
|
||||
rt_thread_create("producer", producer_thread_entry, RT_NULL,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
rt_thread_t consumer_thread =
|
||||
rt_thread_create("consumer", consumer_thread_entry, producer_thread,
|
||||
UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY, 100);
|
||||
uassert_true(producer_thread != RT_NULL);
|
||||
uassert_true(consumer_thread != RT_NULL);
|
||||
_watching_thread1 = consumer_thread;
|
||||
_watching_thread2 = producer_thread;
|
||||
|
||||
rt_thread_startup(consumer_thread);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
LOG_I("Summary:\n"
|
||||
"\tTest times: %ds(%d times)\n"
|
||||
"\tAsync interruption count: %d\n",
|
||||
TEST_LOOP_TIMES / RT_TICK_PER_SECOND, TEST_LOOP_TIMES,
|
||||
_async_intr_count);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_test_data = 0;
|
||||
_progress_counter = 0;
|
||||
_async_intr_count = 0;
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.ipc.rt_completion.timeout",
|
||||
utest_tc_init, utest_tc_cleanup, 1000);
|
||||
603
RT_Thread/examples/utest/testcases/drivers/ipc/workqueue_tc.c
Normal file
603
RT_Thread/examples/utest/testcases/drivers/ipc/workqueue_tc.c
Normal file
@ -0,0 +1,603 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-02-06 tyx first commit
|
||||
* 2024-12-31 rbb666 Adding Test Cases
|
||||
*/
|
||||
|
||||
#include "rtthread.h"
|
||||
#include "rtdevice.h"
|
||||
#include "utest.h"
|
||||
|
||||
#ifdef RT_USING_DEVICE_IPC
|
||||
|
||||
static rt_uint8_t get_test_thread_priority(rt_int8_t pos)
|
||||
{
|
||||
rt_int16_t priority;
|
||||
|
||||
priority = RT_SCHED_PRIV(rt_thread_self()).init_priority;
|
||||
if (pos == 0)
|
||||
{
|
||||
return priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority += pos;
|
||||
}
|
||||
if (priority < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (priority >= RT_THREAD_PRIORITY_MAX)
|
||||
{
|
||||
return RT_THREAD_PRIORITY_MAX - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (rt_uint8_t)priority;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_work_test_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void do_work_test(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 higher priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, do_work_test_fun, (void *)&work_flag);
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Delay 5 ticks to ensure that the task has been executed */
|
||||
rt_thread_delay(5);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void do_delay_work_test_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((rt_tick_t *)work_data) = rt_tick_get();
|
||||
}
|
||||
|
||||
static void do_delay_work_test(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile rt_tick_t work_start = 0;
|
||||
volatile rt_tick_t work_end = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 higher priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, do_delay_work_test_fun, (void *)&work_end);
|
||||
work_start = rt_tick_get();
|
||||
/* Normal delayed work submission test */
|
||||
err = rt_workqueue_submit_work(queue, &work, 10);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Ensure that the delayed work has been executed */
|
||||
rt_thread_delay(15);
|
||||
/* Check if the delayed task is executed after 10 ticks */
|
||||
if (work_end < work_start || work_end - work_start < 10)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void cancle_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, cancle_work_test01_fun, (void *)&work_flag);
|
||||
/* Cancel the work before it is executed */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Cancel Now */
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test02_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
}
|
||||
|
||||
static void cancle_work_test02(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 higher priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, cancle_work_test02_fun, RT_NULL);
|
||||
/* Cancel the work while it is in progress */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, -RT_EBUSY);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test03_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
|
||||
static void cancle_work_test03(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, cancle_work_test03_fun, RT_NULL);
|
||||
/* Canceling a work after it has been executed */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(10);
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_work_test04_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void cancle_work_test04(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, cancle_work_test04_fun, (void *)&work_flag);
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
/* Synchronized cancellation work */
|
||||
err = rt_workqueue_cancel_work_sync(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancle_delay_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) = 1;
|
||||
}
|
||||
|
||||
static void cancle_delay_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, cancle_delay_work_test01_fun, (void *)&work_flag);
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(10);
|
||||
/* Cancel work */
|
||||
err = rt_workqueue_cancel_work(queue, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(15);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void repeat_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test01", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, repeat_work_test01_fun, (void *)&work_flag);
|
||||
/* Multiple submissions of the same work */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* The same work, before it is executed, can be submitted repeatedly and executed only once */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
LOG_E("L:%d err. %d", __LINE__, err);
|
||||
}
|
||||
rt_thread_delay(10);
|
||||
/* Check if it was executed only once */
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void repeat_work_test02_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_work_test02(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 priority higher than current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue = rt_workqueue_create("test02", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, repeat_work_test02_fun, (void *)&work_flag);
|
||||
/* Submit work with high queue priority that will be executed immediately */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(5);
|
||||
/* Re-submission of work in progress */
|
||||
err = rt_workqueue_submit_work(queue, &work, 0);
|
||||
if (err != RT_EOK)
|
||||
{
|
||||
LOG_E("L:%d err. %d", __LINE__, err);
|
||||
}
|
||||
rt_thread_delay(10);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(10);
|
||||
uassert_int_equal(work_flag, 2);
|
||||
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static struct rt_workqueue *queue_3;
|
||||
|
||||
static void repeat_work_test03_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
int *work_flag = (int *)work_data;
|
||||
(*work_flag) += 1;
|
||||
rt_kprintf("work_flag:%d\n", *work_flag);
|
||||
if (*work_flag < 20)
|
||||
{
|
||||
rt_workqueue_submit_work(queue_3, work, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void repeat_work_test03(void)
|
||||
{
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 priority higher than current test thread */
|
||||
curr_priority = get_test_thread_priority(-1);
|
||||
queue_3 = rt_workqueue_create("test03", 2048, curr_priority);
|
||||
if (queue_3 == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
rt_work_init(&work, repeat_work_test03_fun, (void *)&work_flag);
|
||||
/* Submit work with high queue priority that will be executed immediately */
|
||||
err = rt_workqueue_submit_work(queue_3, &work, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Wait for the work to be executed 20 times with a timeout */
|
||||
err = rt_workqueue_cancel_work_sync(queue_3, &work);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Check if the work was executed 20 times */
|
||||
uassert_int_equal(work_flag, 20);
|
||||
|
||||
rt_workqueue_destroy(queue_3);
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test01_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test01(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, repeat_delay_work_test01_fun, (void *)&work_flag);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* At this point the delayed work has not been executed */
|
||||
rt_thread_delay(10);
|
||||
/* Re-submission of time-delayed work */
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(15);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
/* Waiting for delayed task execution */
|
||||
rt_thread_delay(15);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test02_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
rt_thread_delay(10);
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void repeat_delay_work_test02(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
/* 1 lower priority than the current test thread */
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work, repeat_delay_work_test02_fun, (void *)&work_flag);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Waiting for delayed work execution */
|
||||
rt_thread_delay(25);
|
||||
err = rt_workqueue_submit_work(queue, &work, 20);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Check if the delayed work has been run only once */
|
||||
rt_thread_delay(10);
|
||||
uassert_int_equal(work_flag, 1);
|
||||
|
||||
rt_thread_delay(25);
|
||||
/* Check if the delayed work is executed twice */
|
||||
uassert_int_equal(work_flag, 2);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static void cancel_all_work_test_fun(struct rt_work *work, void *work_data)
|
||||
{
|
||||
*((int *)work_data) += 1;
|
||||
}
|
||||
|
||||
static void cancel_all_work_test(void)
|
||||
{
|
||||
struct rt_workqueue *queue;
|
||||
rt_uint8_t curr_priority;
|
||||
struct rt_work work1;
|
||||
struct rt_work work2;
|
||||
struct rt_work work3;
|
||||
struct rt_work work4;
|
||||
volatile int work_flag = 0;
|
||||
rt_err_t err;
|
||||
|
||||
curr_priority = get_test_thread_priority(1);
|
||||
queue = rt_workqueue_create("test", 2048, curr_priority);
|
||||
if (queue == RT_NULL)
|
||||
{
|
||||
LOG_E("queue create failed, L:%d", __LINE__);
|
||||
return;
|
||||
}
|
||||
work_flag = 0;
|
||||
rt_work_init(&work1, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
rt_work_init(&work2, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
rt_work_init(&work3, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
rt_work_init(&work4, cancel_all_work_test_fun, (void *)&work_flag);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work1, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work2, 0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work3, 10);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_submit_work(queue, &work4, 10);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_workqueue_cancel_all_work(queue);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_thread_delay(20);
|
||||
uassert_int_equal(work_flag, 0);
|
||||
|
||||
rt_thread_delay(100);
|
||||
rt_workqueue_destroy(queue);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
/* General work queue test */
|
||||
UTEST_UNIT_RUN(do_work_test);
|
||||
/* Delayed work queue test */
|
||||
UTEST_UNIT_RUN(do_delay_work_test);
|
||||
/* Cancellation of work prior to implementation */
|
||||
UTEST_UNIT_RUN(cancle_work_test01);
|
||||
/* Cancellation of work during execution */
|
||||
UTEST_UNIT_RUN(cancle_work_test02);
|
||||
/* Cancellation of work after implementation */
|
||||
UTEST_UNIT_RUN(cancle_work_test03);
|
||||
/* Synchronized cancellation of work during execution */
|
||||
UTEST_UNIT_RUN(cancle_work_test04);
|
||||
/* Cancel delayed work before execution */
|
||||
UTEST_UNIT_RUN(cancle_delay_work_test01);
|
||||
/* Multiple submissions of the same work prior to implementation */
|
||||
UTEST_UNIT_RUN(repeat_work_test01);
|
||||
/* Multiple submissions of the same work during execution */
|
||||
UTEST_UNIT_RUN(repeat_work_test02);
|
||||
/* Submitting the same task multiple times in a mission */
|
||||
UTEST_UNIT_RUN(repeat_work_test03);
|
||||
/* Multiple submissions of the same delayed task before execution */
|
||||
UTEST_UNIT_RUN(repeat_delay_work_test01);
|
||||
/* Multiple submissions of the same delayed task during execution */
|
||||
UTEST_UNIT_RUN(repeat_delay_work_test02);
|
||||
/* Cancel all works */
|
||||
UTEST_UNIT_RUN(cancel_all_work_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "components.drivers.ipc.workqueue_tc", utest_tc_init, utest_tc_cleanup, 300);
|
||||
#endif
|
||||
@ -0,0 +1,7 @@
|
||||
menu "Serial-Bypass Testcase"
|
||||
|
||||
config UTEST_SERIAL_BYPASS
|
||||
bool "Serial testcase"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
@ -0,0 +1,11 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('bypass*.c')
|
||||
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_BYPASS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static struct rt_spinlock lock;
|
||||
static int cnt = 0;
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
|
||||
#define UART_FR(base) __REG32(base + 0x18)
|
||||
#define UART_DR(base) __REG32(base + 0x00)
|
||||
#define UARTFR_TXFF 0x20
|
||||
|
||||
static rt_err_t utest_get_c(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
rt_atomic_add(&cnt, 1);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc(struct rt_serial_device* serial)
|
||||
{
|
||||
static int num = 0;
|
||||
|
||||
rt_spin_lock(&lock);
|
||||
if (rt_atomic_load(&num) == 10)
|
||||
{
|
||||
rt_atomic_flag_clear(&num);
|
||||
rt_spin_unlock(&lock);
|
||||
return -1;
|
||||
}
|
||||
rt_atomic_add(&num, 1);
|
||||
rt_spin_unlock(&lock);
|
||||
return 'a';
|
||||
}
|
||||
|
||||
struct hw_uart_device
|
||||
{
|
||||
rt_size_t hw_base;
|
||||
rt_size_t irqno;
|
||||
};
|
||||
|
||||
static int uart_putc(struct rt_serial_device* serial, char c)
|
||||
{
|
||||
struct hw_uart_device* uart;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
uart = (struct hw_uart_device*)serial->parent.user_data;
|
||||
|
||||
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
|
||||
UART_DR(uart->hw_base) = c;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc,
|
||||
};
|
||||
|
||||
|
||||
static void thread_rx1(void* parameter)
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_rx2(void* parameter)
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
rt_workqueue_dowork(_serial0->bypass->lower_workq, &_serial0->bypass->work);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_high_priority(void* parameter)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_get_c, RT_NULL);
|
||||
rt_bypass_upper_unregister(_serial0, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_low_priority(void* parameter)
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
}
|
||||
}
|
||||
|
||||
static void bypass_rx_stress_003(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
|
||||
rt_thread_t high = rt_thread_create("high_prio", thread_high_priority, RT_NULL, 2048, 15, 10);
|
||||
rt_thread_t low = rt_thread_create("low_prio", thread_low_priority, RT_NULL, 2048, 20, 10);
|
||||
|
||||
rt_atomic_flag_clear(&cnt);
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_upper_register(_serial0, "test", 0, utest_get_c, RT_NULL);
|
||||
|
||||
rt_thread_startup(high);
|
||||
rt_thread_startup(low);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, 0);
|
||||
uassert_true(rt_atomic_load(&cnt) == 200);
|
||||
}
|
||||
|
||||
static void bypass_rx_stress_002(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
rt_thread_t rx2 = rt_thread_create("rx2", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_thread_t rx3 = rt_thread_create("rx3", thread_rx2, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
|
||||
rt_atomic_flag_clear(&cnt);
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_lower_register(_serial0, "utest", 0, utest_get_c, RT_NULL);
|
||||
|
||||
rt_thread_startup(rx2);
|
||||
rt_thread_startup(rx3);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
uassert_true(rt_atomic_load(&cnt) == 100);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_lower_unregister(_serial0, 0);
|
||||
}
|
||||
|
||||
static void bypass_rx_stress_001(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
rt_thread_t rx1 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_thread_t rx2 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
|
||||
cnt = 0;
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_upper_register(_serial0, "utest", 0, utest_get_c, RT_NULL);
|
||||
|
||||
rt_thread_startup(rx1);
|
||||
rt_thread_startup(rx2);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
uassert_true(rt_atomic_load(&cnt) == 200);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, 0);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_rx_stress_001);
|
||||
UTEST_UNIT_RUN(bypass_rx_stress_002);
|
||||
UTEST_UNIT_RUN(bypass_rx_stress_003);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.conflict.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static int cnt = 0;
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
|
||||
#define UART_FR(base) __REG32(base + 0x18)
|
||||
#define UART_DR(base) __REG32(base + 0x00)
|
||||
#define UARTFR_TXFF 0x20
|
||||
|
||||
struct hw_uart_device
|
||||
{
|
||||
rt_size_t hw_base;
|
||||
rt_size_t irqno;
|
||||
};
|
||||
|
||||
static int uart_putc(struct rt_serial_device* serial, char c)
|
||||
{
|
||||
struct hw_uart_device* uart;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
uart = (struct hw_uart_device*)serial->parent.user_data;
|
||||
|
||||
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
|
||||
UART_DR(uart->hw_base) = c;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
num++;
|
||||
uassert_true(ch == ('a' + num));
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc_2(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 20)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a' + num;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops2 =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc_2,
|
||||
};
|
||||
|
||||
static rt_err_t utest_lower_run(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
uassert_true(ch == 'a');
|
||||
cnt++;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
static int utest_getc(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 10)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a';
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc,
|
||||
};
|
||||
static void bypass_lower_001(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run, RT_NULL);
|
||||
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
|
||||
}
|
||||
|
||||
static void bypass_lower_002(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops2;
|
||||
rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL);
|
||||
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_lower_001);
|
||||
UTEST_UNIT_RUN(bypass_lower_002);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.lower.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static struct rt_spinlock lock;
|
||||
|
||||
static rt_err_t utest_001_run(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thread_serial_register1(void* parameter)
|
||||
{
|
||||
for (int i = 2; i < 10; i += 2)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_serial_register_upper(void* parameter)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_serial_register_lower(void* parameter)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
rt_bypass_lower_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void bypass_register_001(void)
|
||||
{
|
||||
rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL);
|
||||
rt_thread_startup(t1);
|
||||
for (int i = 1; i < 10; i += 2)
|
||||
{
|
||||
rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL);
|
||||
}
|
||||
rt_thread_mdelay(1000);
|
||||
rt_list_t* node = _serial0->bypass->upper_h->head.next;
|
||||
for (int i = 0; i < 10;i++)
|
||||
{
|
||||
rt_list_t* next = node->next;
|
||||
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
|
||||
uassert_true(temp->level == i);
|
||||
rt_bypass_upper_unregister(_serial0, temp->level);
|
||||
node = next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void bypass_register_002(void)
|
||||
{
|
||||
rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register_upper, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_thread_t t2 = rt_thread_create("serial_register", thread_serial_register_lower, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL);
|
||||
|
||||
rt_thread_startup(t1);
|
||||
rt_thread_startup(t2);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
rt_list_t* node = _serial0->bypass->upper_h->head.next;
|
||||
for (int i = 0; i < 10;i++)
|
||||
{
|
||||
rt_list_t* next = node->next;
|
||||
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
|
||||
uassert_true(temp->level == i);
|
||||
rt_bypass_upper_unregister(_serial0, temp->level);
|
||||
node = next;
|
||||
}
|
||||
node = _serial0->bypass->lower_h->head.next;
|
||||
for (int i = 1; i < 10;i++)
|
||||
{
|
||||
rt_list_t* next = node->next;
|
||||
struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node);
|
||||
uassert_true(temp->level == i);
|
||||
rt_bypass_lower_unregister(_serial0, temp->level);
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_register_001);
|
||||
UTEST_UNIT_RUN(bypass_register_002);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.register.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-11-20 zhujiale the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_serial_device* _serial0;
|
||||
static int cnt;
|
||||
|
||||
#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x)))
|
||||
#define UART_FR(base) __REG32(base + 0x18)
|
||||
#define UART_DR(base) __REG32(base + 0x00)
|
||||
#define UARTFR_TXFF 0x20
|
||||
static rt_err_t utest_upper_run(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
uassert_true(ch == 'a');
|
||||
cnt++;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 10)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a';
|
||||
}
|
||||
|
||||
struct hw_uart_device
|
||||
{
|
||||
rt_size_t hw_base;
|
||||
rt_size_t irqno;
|
||||
};
|
||||
|
||||
static int uart_putc(struct rt_serial_device* serial, char c)
|
||||
{
|
||||
struct hw_uart_device* uart;
|
||||
|
||||
RT_ASSERT(serial != RT_NULL);
|
||||
uart = (struct hw_uart_device*)serial->parent.user_data;
|
||||
|
||||
while (UART_FR(uart->hw_base) & UARTFR_TXFF);
|
||||
UART_DR(uart->hw_base) = c;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc,
|
||||
};
|
||||
|
||||
static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
num++;
|
||||
uassert_true(ch == ('a' + num));
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int utest_getc_2(struct rt_serial_device* serial)
|
||||
{
|
||||
static rt_uint8_t num = 0;
|
||||
if (num == 20)
|
||||
return -1;
|
||||
num++;
|
||||
return 'a' + num;
|
||||
}
|
||||
|
||||
static const struct rt_uart_ops _utest_ops2 =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
uart_putc,
|
||||
utest_getc_2,
|
||||
};
|
||||
static void bypass_upper_001(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops;
|
||||
rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_LEVEL_1, utest_upper_run, RT_NULL);
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, RT_BYPASS_LEVEL_1);
|
||||
}
|
||||
|
||||
static void bypass_upper_002(void)
|
||||
{
|
||||
const struct rt_uart_ops* tmp = _serial0->ops;
|
||||
_serial0->ops = &_utest_ops2;
|
||||
rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL);
|
||||
|
||||
rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(cnt == 10);
|
||||
_serial0->ops = tmp;
|
||||
rt_bypass_upper_unregister(_serial0, RT_BYPASS_MAX_LEVEL);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_serial0 = (struct rt_serial_device*)rt_console_get_device();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(bypass_upper_001);
|
||||
UTEST_UNIT_RUN(bypass_upper_002);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(_testcase, "testcase.bypass.upper.001", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,7 @@
|
||||
menu "Utest Serial Testcase"
|
||||
|
||||
config UTEST_SERIAL_TC
|
||||
bool "Serial testcase"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
158
RT_Thread/examples/utest/testcases/drivers/serial_v2/README.md
Normal file
158
RT_Thread/examples/utest/testcases/drivers/serial_v2/README.md
Normal file
@ -0,0 +1,158 @@
|
||||
## 1、介绍
|
||||
|
||||
该目录下 c 文件是新版本串口的测试用例,在 `examples/utest/testcases/drivers/serial_v2` 目录结构里,该测试用例用来测试串口的各个操作模式是否正常工作。
|
||||
|
||||
## 2、 文件说明
|
||||
|
||||
| 文件 | 描述 |
|
||||
| ---------------- | ----------------------------------------- |
|
||||
| uart_rxb_txb.c | 串口接收阻塞和发送阻塞模式 的测试用例 |
|
||||
| uart_rxb_txnb.c | 串口接收阻塞和发送非阻塞模式 的测试用例 |
|
||||
| uart_rxnb_txb.c | 串口接收非阻塞和发送阻塞模式 的测试用例 |
|
||||
| uart_rxnb_txnb.c | 串口接收非阻塞和发送非阻塞模式 的测试用例 |
|
||||
| uart_blocking_tx.c| 串口阻塞发送模式 的测试 |
|
||||
| uart_blocking_rx.c| 串口阻塞接收模式 的测试 |
|
||||
| uart_nonblocking_tx.c| 串口非阻塞发送模式 的测试 |
|
||||
| uart_nonblocking_rx.c | 串口非阻塞接收模式 的测试 |
|
||||
|
||||
## 3、软硬件环境
|
||||
|
||||
硬件上需要支持 RT-Thread 的完整版操作系统,版本为4.0.4及以上,且硬件有串口硬件外设,软件上需要支持 内核接口、IPC 、Device 框架。
|
||||
|
||||
## 4、测试项
|
||||
|
||||
### 4.1 测试说明
|
||||
|
||||
上文所提及的模式是指串口使用时的操作模式,不涉及硬件的工作模式的配置情况(硬件工作模式一般有轮询POLL、中断INT、DMA),因此使用时需要结合具体的硬件工作模式去配置使用。例如 发送阻塞和接收非阻塞模式 ,这个测试有很多种硬件配置,配置情况例如:DMA发送阻塞和DMA接收非阻塞,INT发送阻塞和DMA接收非阻塞,POLL发送阻塞和DMA接收非阻塞等等。因此通过排列组合后的测试场景有4*9=36种,有意义的组合方式为20种。如下表:
|
||||
|
||||
|
||||
| 接收非阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 |
|
||||
| ---------- | -------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | ✔ |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | ✔ |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
| 接收非阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 |
|
||||
| ---------- | ---------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
| 接收阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 |
|
||||
| -------- | -------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | ✔ |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | ✔ |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
| 接收阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 |
|
||||
| -------- | ---------- | ----------------- | ---------------- |
|
||||
| POLL | POLL | RX_POLL + TX_POLL | |
|
||||
| | INT | RX_POLL + TX_INT | |
|
||||
| | DMA | RX_POLL + TX_DMA | |
|
||||
| INT | POLL | RX_INT + TX_POLL | |
|
||||
| | INT | RX_INT + TX_INT | ✔ |
|
||||
| | DMA | RX_INT + TX_DMA | ✔ |
|
||||
| DMA | POLL | RX_DMA + TX_POLL | |
|
||||
| | INT | RX_DMA + TX_INT | ✔ |
|
||||
| | DMA | RX_DMA + TX_DMA | ✔ |
|
||||
|
||||
需要解释的是,为什么会存在无意义的组合模式,举个例子,非阻塞模式下,肯定是不会出现POLL(轮询)方式的,因为POLL方式已经表明是阻塞方式了。
|
||||
该测试用例在测试多种组合时,需要通过更改`rtconfig.h`文件对硬件模式进行静态配置。
|
||||
|
||||
### 4.2 测试思路
|
||||
|
||||
前四个测试用例的测试思路:
|
||||
|
||||
>硬件上:**短接串口的发送TX引脚和接收RX引脚,完成自发自收的回路**。
|
||||
>
|
||||
>软件上:创建两个线程A和B,A为接收线程,B为发送线程,设置A线程优先级比B线程优先级高。发送线程发送随机长度(长度范围是 0 到 1000)的数据,接收线程接收到数据进行校验,数据正确则测试通过,默认测试100次。
|
||||
|
||||
后四个测试用例的测试思路:
|
||||
|
||||
>硬件上: **不需要将TX,RX引脚进行短接**,每次只针对发送或接收中的一种进行测试,更为简单与直接
|
||||
>
|
||||
>软件上: 四个样例每次仅测试TX/RX中的一种引脚与一种对应的阻塞/非阻塞模式
|
||||
>四种测试模式具体分为:
|
||||
>>阻塞接收模式----(硬件工作模式可选: 轮询, 中断, DMA)
|
||||
>>阻塞发送模式----(硬件工作模式可选: 轮询, 中断, DMA)
|
||||
>>非阻塞接收模式--(硬件工作模式可选: 中断, DMA)
|
||||
>>非阻塞发送模式--(硬件工作模式可选: 中断, DMA)
|
||||
>
|
||||
>其中阻塞或非阻塞背后的具体硬件工作模式选择(如 轮询, 中断, DMA)需要对`rtconfig.h`文件做出配置,具体配置流程可见文章中关于
|
||||
[seril_v2硬件工作模式的选择](https://club.rt-thread.org/ask/article/b4c536303c8e2335.html "serial_v2源码分析")一节.
|
||||
>
|
||||
>发送测试流程 :
|
||||
>>1. 先关闭串口,再以需要测试的模式打开.
|
||||
>>2. 然后依次发送 UART_SEND_TIMES(默认为400) * 1024, 8, 32, 128, 512, 1024个数据.
|
||||
>>3. 发送的同时记录每次发送所耗费的时钟周期与成功发送的数据数量.
|
||||
>>3. 打印记录的数据,通过时钟周期来反应发送效率, 通过成功发送的数据量来反应是否产生丢包问题.
|
||||
>
|
||||
>接收测试流程 :
|
||||
>>1. 先关闭串口,再以需要测试的模式打开.
|
||||
>>2. 然后以此接收 256, 256, 256, 128, 128, 共计1024个数据
|
||||
>>3. 接收的同时记录成功接收的数据数量
|
||||
>>4. 打印记录的数据, 通过现实成功接收的数据量与串口发送的数据量做对比,来验证是否出现丢包问题
|
||||
|
||||
## 5、配置
|
||||
|
||||
使用该测试用例需要在 `env` 工具的 `menuconfig` 中做相关配置,配置如下所示(使用 RT-Thread-Studio 的配置路径一致 ):
|
||||
|
||||
```
|
||||
RT-Thread Utestcases --->
|
||||
[*] RT-Thread Utestcases --->
|
||||
Utest Serial Testcase --->
|
||||
[*] Serial testcase
|
||||
```
|
||||
|
||||
## 6、使用
|
||||
|
||||
\- 编译下载。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_rxb_txb` 运行串口接收阻塞和发送阻塞测试用例。
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_blocking_tx` 运行串口阻塞发送测试
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_blocking_rx` 运行串口阻塞接收测试
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_nonblocking_tx` 运行串口非阻塞发送测试
|
||||
|
||||
\- 在 MSH 中输入 `utest_run testcases.drivers.uart_nonblocking_rx` 运行串口非阻塞接收测试
|
||||
|
||||
如果仅仅配置了 `Serial testcase` 相关的测试用例,则直接输入 `utest_run` 运行即可将上述测试用例按序测试。
|
||||
|
||||
## 7、注意事项
|
||||
|
||||
\- 需配置正确的测试用例。
|
||||
|
||||
\- 如有需要,可开启 ULOG 查看测试用例日志信息。
|
||||
|
||||
\- 需在 MSH 中输入正确的命令行。
|
||||
|
||||
\- 测试用例默认的测试数据长度范围最大为1000字节,如果接收端的缓冲区大小配置为小于1000字节时,那么在测试接收阻塞模式时,将会由于获取不了1000字节长度导致线程持续阻塞(因为测试用例是按 `recv_len` 长度去接收的,而不是按照单字节去接收的),因此建议接收端的缓冲区大小 (对应宏例如为 `BSP_UART2_RX_BUFSIZE`)设置为1024即可;当然也可按需减小测试的最大数据长度。
|
||||
|
||||
\- 该测试用例需要结合硬件具体的工作模式(POLL 、INT、DMA)进行测试,而硬件工作模式只能选择一种,因此需要在 `rtconfig.h` 中对串口相应的宏进行配置,来选择不同的工作模式去进行测试。
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split('''
|
||||
uart_rxb_txnb.c
|
||||
uart_rxb_txb.c
|
||||
uart_rxnb_txb.c
|
||||
uart_rxnb_txnb.c
|
||||
uart_blocking_rx.c
|
||||
uart_blocking_tx.c
|
||||
uart_nonblocking_rx.c
|
||||
uart_nonblocking_tx.c
|
||||
''')
|
||||
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_TC'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@ -0,0 +1,93 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t block_read(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t total_length, recv_length;
|
||||
rt_uint8_t uart_read_buffer[1024], log_buffer[64];
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_RX_BLOCKING);
|
||||
|
||||
rt_sprintf(log_buffer, "\nBLOCKING READ BEGIN, PLEASE SEND SOME DATAS\n");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
total_length = 0;
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read, total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
|
||||
rt_sprintf(log_buffer, "\nblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "BLOCKING READ END");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_blocking_rx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (block_read(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_blocking_rx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_blocking_rx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,118 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
#define UART_SEND_TIMES 400
|
||||
#define UART_TEST_NUMBER 6
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t block_write(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t i, wr_sz, index, write_num_array[UART_TEST_NUMBER], total_write_num[UART_TEST_NUMBER];
|
||||
rt_tick_t tick1, tick2, tick_array[UART_TEST_NUMBER];
|
||||
rt_uint8_t uart_write_buffer[1024];
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
uart_write_buffer[i] = '0' + (i % 49);
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
|
||||
LOG_D("\nBLOCKING WRITE BEGIN\n");
|
||||
rt_thread_mdelay(2000);
|
||||
|
||||
index = 0;
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
for(i = 0; i < UART_SEND_TIMES; i++)
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 1024);
|
||||
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = UART_SEND_TIMES * 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 8);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 8;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 32);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 32;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 128);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 128;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 512);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 512;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
wr_sz += rt_device_write(uart_dev, 0, uart_write_buffer, 1024);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
LOG_D("\nBLOCKING_TX END\n");
|
||||
for(i = 0; i < index; i++)
|
||||
{
|
||||
LOG_D("\nBLOCKING_MODE : write %d / %d bytes in %d ticks\n", write_num_array[i], total_write_num[i], tick_array[i]);
|
||||
rt_thread_mdelay(1000);
|
||||
}
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_blocking_tx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (block_write(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_blocking_tx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_blocking_tx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,107 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t nonblock_read(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t total_length, recv_length;
|
||||
rt_uint8_t uart_read_buffer[1024], log_buffer[64];
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_RX_NON_BLOCKING);
|
||||
|
||||
rt_sprintf(log_buffer, "\nNONBLOCKING READ BEGIN, PLEASE SEND SOME DATAS\n");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
total_length = 0;
|
||||
rt_device_write(uart_dev, 0, "5\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "\nnonblock : %d bytes read, total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "4\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer,"\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev,0,log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "3\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 256);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 256);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "\nnonblock : %d bytes read, total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev,0,log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "2\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer,"\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_device_write(uart_dev, 0, "1\n", 2);
|
||||
recv_length = 0;
|
||||
recv_length = rt_device_read(uart_dev, -1, uart_read_buffer, 128);
|
||||
rt_device_write(uart_dev, 0, uart_read_buffer, 128);
|
||||
total_length += recv_length;
|
||||
rt_thread_mdelay(1000);
|
||||
|
||||
rt_sprintf(log_buffer, "\nnonblock : %d bytes read , total: %d \n", recv_length, total_length);
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
rt_sprintf(log_buffer, "BLOCKING READ END");
|
||||
rt_device_write(uart_dev, 0, log_buffer, rt_strlen(log_buffer));
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_nonblocking_rx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (nonblock_read(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_nonblocking_rx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_nonblocking_rx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,128 @@
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define SERIAL_UART_NAME "uart2"
|
||||
#define UART_SEND_TIMES 400
|
||||
#define UART_TEST_NUMBER 6
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
static rt_bool_t nonblock_write(rt_device_t uart_dev)
|
||||
{
|
||||
rt_size_t wr_sz = 0, tmp = 0, i, write_num_array[UART_TEST_NUMBER], total_write_num[UART_TEST_NUMBER], index;
|
||||
rt_tick_t tick1, tick2, tick_array[UART_TEST_NUMBER];
|
||||
rt_uint8_t uart_write_buffer[1024];
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
uart_write_buffer[i] = '0' + (i % 50);
|
||||
|
||||
/* make sure device is closed and reopen it */
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_NON_BLOCKING | RT_DEVICE_FLAG_RX_NON_BLOCKING);
|
||||
|
||||
LOG_D("\nNONBLOCKING WRITE BEGIN\n");
|
||||
rt_thread_mdelay(2000);
|
||||
|
||||
index = 0;
|
||||
tmp = 0;
|
||||
tick1 = rt_tick_get();
|
||||
for (i = 0; i < UART_SEND_TIMES; i++)
|
||||
{
|
||||
wr_sz = 0;
|
||||
while(wr_sz < 1024)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 1024-wr_sz);
|
||||
tmp += wr_sz;
|
||||
}
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = UART_SEND_TIMES * 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = tmp;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 8)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 8-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 8;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 32)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 32-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 32;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 128)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 128-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 128;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 512)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 512-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 512;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
wr_sz = 0;
|
||||
tick1 = rt_tick_get();
|
||||
while(wr_sz < 1024)
|
||||
wr_sz += rt_device_write(uart_dev, 0, &uart_write_buffer[wr_sz], 1024-wr_sz);
|
||||
tick2 = rt_tick_get();
|
||||
total_write_num[index] = 1024;
|
||||
tick_array[index] = tick2 - tick1;
|
||||
write_num_array[index++] = wr_sz;
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
LOG_D("\nNONBLOCKING_TX END\n");
|
||||
for(i = 0; i < index; i++)
|
||||
{
|
||||
LOG_D("\nNONBLOCKING_MODE : write %d / %d bytes in %d ticks\n", write_num_array[i], total_write_num[i], tick_array[i]);
|
||||
rt_thread_mdelay(1000);
|
||||
}
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static void uart_test_nonblocking_tx(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
uassert_not_null(uart_dev);
|
||||
|
||||
uassert_true (nonblock_write(uart_dev));
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_device_t uart_dev;
|
||||
uart_dev = rt_device_find(SERIAL_UART_NAME);
|
||||
while(rt_device_close(uart_dev) != -RT_ERROR);
|
||||
rt_device_open(uart_dev, RT_DEVICE_FLAG_TX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(uart_test_nonblocking_tx);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "uart_nonblocking_tx", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-06-16 KyleChan the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <rtdevice.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TC_UART_DEVICE_NAME "uart2"
|
||||
#define TC_UART_SEND_TIMES 100
|
||||
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
#define TEST_UART_NAME TC_UART_DEVICE_NAME
|
||||
|
||||
static struct rt_serial_device *serial;
|
||||
static rt_uint8_t uart_over_flag;
|
||||
static rt_bool_t uart_result = RT_TRUE;
|
||||
|
||||
static rt_err_t uart_find(void)
|
||||
{
|
||||
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
|
||||
|
||||
if (serial == RT_NULL)
|
||||
{
|
||||
LOG_E("find %s device failed!\n", TEST_UART_NAME);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void uart_send_entry(void *parameter)
|
||||
{
|
||||
rt_uint8_t *uart_write_buffer;
|
||||
rt_uint16_t send_len;
|
||||
|
||||
rt_uint32_t i = 0;
|
||||
send_len = *(rt_uint16_t *)parameter;
|
||||
/* assign send buffer */
|
||||
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
|
||||
if (uart_write_buffer == RT_NULL)
|
||||
{
|
||||
LOG_E("Without spare memory for uart dma!");
|
||||
uart_result = RT_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
rt_memset(uart_write_buffer, 0, send_len);
|
||||
|
||||
for (i = 0; i < send_len; i++)
|
||||
{
|
||||
uart_write_buffer[i] = (rt_uint8_t)i;
|
||||
}
|
||||
/* send buffer */
|
||||
if (rt_device_write(&serial->parent, 0, uart_write_buffer, send_len) != send_len)
|
||||
{
|
||||
LOG_E("device write failed\r\n");
|
||||
}
|
||||
rt_free(uart_write_buffer);
|
||||
|
||||
}
|
||||
|
||||
static void uart_rec_entry(void *parameter)
|
||||
{
|
||||
rt_uint16_t rev_len;
|
||||
|
||||
rev_len = *(rt_uint16_t *)parameter;
|
||||
rt_uint8_t *ch;
|
||||
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
|
||||
rt_int32_t cnt, i;
|
||||
rt_uint8_t last_old_data;
|
||||
rt_bool_t fisrt_flag = RT_TRUE;
|
||||
rt_uint32_t all_receive_length = 0;
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
|
||||
if (cnt == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fisrt_flag != RT_TRUE)
|
||||
{
|
||||
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
|
||||
{
|
||||
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fisrt_flag = RT_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt - 1; i++)
|
||||
{
|
||||
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
|
||||
{
|
||||
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
|
||||
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
all_receive_length += cnt;
|
||||
if (all_receive_length >= rev_len)
|
||||
break;
|
||||
else
|
||||
last_old_data = ch[cnt - 1];
|
||||
}
|
||||
rt_free(ch);
|
||||
uart_over_flag = RT_TRUE;
|
||||
}
|
||||
|
||||
static rt_err_t uart_api(rt_uint16_t length)
|
||||
{
|
||||
rt_thread_t thread_send = RT_NULL;
|
||||
rt_thread_t thread_recv = RT_NULL;
|
||||
rt_err_t result = RT_EOK;
|
||||
uart_over_flag = RT_FALSE;
|
||||
|
||||
result = uart_find();
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* Reinitialize */
|
||||
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
||||
config.baud_rate = BAUD_RATE_115200;
|
||||
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
|
||||
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
|
||||
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
|
||||
|
||||
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("Open uart device failed.");
|
||||
uart_result = RT_FALSE;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
thread_send = rt_thread_create("uart_send", uart_send_entry, &length, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
|
||||
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &length, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
if ((thread_send != RT_NULL) && (thread_recv != RT_NULL))
|
||||
{
|
||||
rt_thread_startup(thread_send);
|
||||
rt_thread_startup(thread_recv);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (uart_result != RT_TRUE)
|
||||
{
|
||||
LOG_E("The test for uart dma is failure.");
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
if (uart_over_flag == RT_TRUE)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
/* waiting for test over */
|
||||
rt_thread_mdelay(5);
|
||||
}
|
||||
__exit:
|
||||
rt_device_close(&serial->parent);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void tc_uart_api(void)
|
||||
{
|
||||
rt_uint32_t times = 0;
|
||||
rt_uint16_t num = 0;
|
||||
while (TC_UART_SEND_TIMES - times)
|
||||
{
|
||||
num = (rand() % 1000) + 1;
|
||||
if(uart_api(num) == RT_EOK)
|
||||
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
|
||||
else
|
||||
{
|
||||
LOG_E("uart test error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
uassert_true(uart_over_flag == RT_TRUE);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
uart_result = RT_TRUE;
|
||||
uart_over_flag = RT_FALSE;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(tc_uart_api);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxb_txb", utest_tc_init, utest_tc_cleanup, 30);
|
||||
|
||||
#endif /* TC_UART_USING_TC */
|
||||
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-06-16 KyleChan the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <rtdevice.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TC_UART_DEVICE_NAME "uart2"
|
||||
#define TC_UART_SEND_TIMES 100
|
||||
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
#define TEST_UART_NAME TC_UART_DEVICE_NAME
|
||||
|
||||
static struct rt_serial_device *serial;
|
||||
static rt_sem_t tx_sem;
|
||||
static rt_uint8_t uart_over_flag;
|
||||
static rt_bool_t uart_result = RT_TRUE;
|
||||
|
||||
static rt_err_t uart_find(void)
|
||||
{
|
||||
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
|
||||
|
||||
if (serial == RT_NULL)
|
||||
{
|
||||
LOG_E("find %s device failed!\n", TEST_UART_NAME);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t uart_tx_completion(rt_device_t device, void *buffer)
|
||||
{
|
||||
rt_sem_release(tx_sem);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void uart_send_entry(void *parameter)
|
||||
{
|
||||
rt_uint8_t *uart_write_buffer;
|
||||
rt_uint16_t send_len, len = 0;
|
||||
rt_err_t result;
|
||||
|
||||
rt_uint32_t i = 0;
|
||||
send_len = *(rt_uint16_t *)parameter;
|
||||
/* assign send buffer */
|
||||
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
|
||||
if (uart_write_buffer == RT_NULL)
|
||||
{
|
||||
LOG_E("Without spare memory for uart dma!");
|
||||
uart_result = RT_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
rt_memset(uart_write_buffer, 0, send_len);
|
||||
|
||||
for (i = 0; i < send_len; i++)
|
||||
{
|
||||
uart_write_buffer[i] = (rt_uint8_t)i;
|
||||
}
|
||||
/* send buffer */
|
||||
while (send_len - len)
|
||||
{
|
||||
len += rt_device_write(&serial->parent, 0, uart_write_buffer + len, send_len - len);
|
||||
result = rt_sem_take(tx_sem, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("take sem err in send.");
|
||||
}
|
||||
}
|
||||
rt_free(uart_write_buffer);
|
||||
|
||||
}
|
||||
|
||||
static void uart_rec_entry(void *parameter)
|
||||
{
|
||||
rt_uint16_t rev_len;
|
||||
|
||||
rev_len = *(rt_uint16_t *)parameter;
|
||||
rt_uint8_t *ch;
|
||||
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
|
||||
rt_int32_t cnt, i;
|
||||
rt_uint8_t last_old_data;
|
||||
rt_bool_t fisrt_flag = RT_TRUE;
|
||||
rt_uint32_t all_receive_length = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
|
||||
if (cnt != rev_len)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fisrt_flag != RT_TRUE)
|
||||
{
|
||||
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
|
||||
{
|
||||
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fisrt_flag = RT_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt - 1; i++)
|
||||
{
|
||||
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
|
||||
{
|
||||
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
|
||||
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
all_receive_length += cnt;
|
||||
if (all_receive_length >= rev_len)
|
||||
break;
|
||||
else
|
||||
last_old_data = ch[cnt - 1];
|
||||
}
|
||||
rt_free(ch);
|
||||
uart_over_flag = RT_TRUE;
|
||||
}
|
||||
|
||||
static rt_err_t uart_api(rt_uint16_t test_buf)
|
||||
{
|
||||
rt_thread_t thread_send = RT_NULL;
|
||||
rt_thread_t thread_recv = RT_NULL;
|
||||
rt_err_t result = RT_EOK;
|
||||
uart_over_flag = RT_FALSE;
|
||||
|
||||
result = uart_find();
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
tx_sem = rt_sem_create("tx_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (tx_sem == RT_NULL)
|
||||
{
|
||||
LOG_E("Init sem failed.");
|
||||
uart_result = RT_FALSE;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* Reinitialize */
|
||||
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
||||
config.baud_rate = BAUD_RATE_115200;
|
||||
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
|
||||
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
|
||||
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
|
||||
|
||||
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING);
|
||||
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("Open uart device failed.");
|
||||
uart_result = RT_FALSE;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* set receive callback function */
|
||||
result = rt_device_set_tx_complete(&serial->parent, uart_tx_completion);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
|
||||
|
||||
if (thread_send != RT_NULL && thread_recv != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(thread_recv);
|
||||
rt_thread_startup(thread_send);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (uart_result != RT_TRUE)
|
||||
{
|
||||
LOG_E("The test for uart dma is failure.");
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
if (uart_over_flag == RT_TRUE)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
/* waiting for test over */
|
||||
rt_thread_mdelay(5);
|
||||
}
|
||||
__exit:
|
||||
if (tx_sem)
|
||||
rt_sem_delete(tx_sem);
|
||||
|
||||
rt_device_close(&serial->parent);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void tc_uart_api(void)
|
||||
{
|
||||
rt_uint32_t times = 0;
|
||||
rt_uint16_t num = 0;
|
||||
while (TC_UART_SEND_TIMES - times)
|
||||
{
|
||||
num = (rand() % 1000) + 1;
|
||||
if(uart_api(num) == RT_EOK)
|
||||
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
|
||||
else
|
||||
{
|
||||
LOG_E("uart test error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
uassert_true(uart_over_flag == RT_TRUE);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
tx_sem = RT_NULL;
|
||||
uart_result = RT_TRUE;
|
||||
uart_over_flag = RT_FALSE;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(tc_uart_api);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxb_txnb", utest_tc_init, utest_tc_cleanup, 30);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-06-16 KyleChan the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <rtdevice.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TC_UART_DEVICE_NAME "uart2"
|
||||
#define TC_UART_SEND_TIMES 100
|
||||
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
#define TEST_UART_NAME TC_UART_DEVICE_NAME
|
||||
|
||||
static struct rt_serial_device *serial;
|
||||
static rt_sem_t rx_sem;
|
||||
static rt_uint8_t uart_over_flag;
|
||||
static rt_bool_t uart_result = RT_TRUE;
|
||||
|
||||
static rt_err_t uart_find(void)
|
||||
{
|
||||
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
|
||||
|
||||
if (serial == RT_NULL)
|
||||
{
|
||||
LOG_E("find %s device failed!\n", TEST_UART_NAME);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t uart_rx_indicate(rt_device_t device, rt_size_t size)
|
||||
{
|
||||
rt_sem_release(rx_sem);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void uart_send_entry(void *parameter)
|
||||
{
|
||||
rt_uint8_t *uart_write_buffer;
|
||||
rt_uint16_t send_len;
|
||||
|
||||
rt_uint32_t i = 0;
|
||||
send_len = *(rt_uint16_t *)parameter;
|
||||
|
||||
/* assign send buffer */
|
||||
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
|
||||
if (uart_write_buffer == RT_NULL)
|
||||
{
|
||||
LOG_E("Without spare memory for uart dma!");
|
||||
uart_result = RT_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
rt_memset(uart_write_buffer, 0, send_len);
|
||||
|
||||
for (i = 0; i < send_len; i++)
|
||||
{
|
||||
uart_write_buffer[i] = (rt_uint8_t)i;
|
||||
}
|
||||
|
||||
/* send buffer */
|
||||
if (rt_device_write(&serial->parent, 0, uart_write_buffer, send_len) != send_len)
|
||||
{
|
||||
LOG_E("device write failed\r\n");
|
||||
}
|
||||
rt_free(uart_write_buffer);
|
||||
}
|
||||
|
||||
static void uart_rec_entry(void *parameter)
|
||||
{
|
||||
rt_uint16_t rev_len;
|
||||
|
||||
rev_len = *(rt_uint16_t *)parameter;
|
||||
rt_uint8_t *ch;
|
||||
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
|
||||
rt_int32_t cnt, i;
|
||||
rt_uint8_t last_old_data;
|
||||
rt_bool_t fisrt_flag = RT_TRUE;
|
||||
rt_uint32_t all_receive_length = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_sem_take(rx_sem, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("take sem err in recv.");
|
||||
}
|
||||
|
||||
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
|
||||
if (cnt == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fisrt_flag != RT_TRUE)
|
||||
{
|
||||
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
|
||||
{
|
||||
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fisrt_flag = RT_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt - 1; i++)
|
||||
{
|
||||
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
|
||||
{
|
||||
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
|
||||
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
all_receive_length += cnt;
|
||||
if (all_receive_length >= rev_len)
|
||||
break;
|
||||
else
|
||||
last_old_data = ch[cnt - 1];
|
||||
}
|
||||
rt_free(ch);
|
||||
uart_over_flag = RT_TRUE;
|
||||
}
|
||||
|
||||
static rt_err_t uart_api(rt_uint16_t test_buf)
|
||||
{
|
||||
rt_thread_t thread_send = RT_NULL;
|
||||
rt_thread_t thread_recv = RT_NULL;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = uart_find();
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rx_sem = rt_sem_create("rx_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (rx_sem == RT_NULL)
|
||||
{
|
||||
LOG_E("Init sem failed.");
|
||||
uart_result = RT_FALSE;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* reinitialize */
|
||||
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
||||
config.baud_rate = BAUD_RATE_115200;
|
||||
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
|
||||
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
|
||||
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
|
||||
|
||||
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
|
||||
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("Open uart device failed.");
|
||||
uart_result = RT_FALSE;
|
||||
rt_sem_delete(rx_sem);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* set receive callback function */
|
||||
result = rt_device_set_rx_indicate(&serial->parent, uart_rx_indicate);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
|
||||
|
||||
if (thread_send != RT_NULL && thread_recv != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(thread_recv);
|
||||
rt_thread_startup(thread_send);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (uart_result != RT_TRUE)
|
||||
{
|
||||
LOG_E("The test for uart dma is failure.");
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
if (uart_over_flag == RT_TRUE)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
/* waiting for test over */
|
||||
rt_thread_mdelay(5);
|
||||
}
|
||||
__exit:
|
||||
if (rx_sem)
|
||||
rt_sem_delete(rx_sem);
|
||||
rt_device_close(&serial->parent);
|
||||
uart_over_flag = RT_FALSE;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void tc_uart_api(void)
|
||||
{
|
||||
rt_uint32_t times = 0;
|
||||
rt_uint16_t num = 0;
|
||||
while (TC_UART_SEND_TIMES - times)
|
||||
{
|
||||
num = (rand() % 1000) + 1;
|
||||
if(uart_api(num) == RT_EOK)
|
||||
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
|
||||
else
|
||||
{
|
||||
LOG_E("uart test error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
uassert_true(uart_result == RT_TRUE);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rx_sem = RT_NULL;
|
||||
uart_result = RT_TRUE;
|
||||
uart_over_flag = RT_FALSE;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(tc_uart_api);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxnb_txb", utest_tc_init, utest_tc_cleanup, 30);
|
||||
|
||||
#endif /* TC_UART_USING_TC */
|
||||
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-06-16 KyleChan the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <rtdevice.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TC_UART_DEVICE_NAME "uart2"
|
||||
#define TC_UART_SEND_TIMES 100
|
||||
|
||||
|
||||
#ifdef UTEST_SERIAL_TC
|
||||
|
||||
#define TEST_UART_NAME TC_UART_DEVICE_NAME
|
||||
|
||||
static struct rt_serial_device *serial;
|
||||
static rt_sem_t tx_sem;
|
||||
static rt_sem_t rx_sem;
|
||||
static rt_uint8_t uart_over_flag;
|
||||
static rt_bool_t uart_result = RT_TRUE;
|
||||
|
||||
static rt_err_t uart_find(void)
|
||||
{
|
||||
serial = (struct rt_serial_device *)rt_device_find(TEST_UART_NAME);
|
||||
|
||||
if (serial == RT_NULL)
|
||||
{
|
||||
LOG_E("find %s device failed!\n", TEST_UART_NAME);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t uart_tx_completion(rt_device_t device, void *buffer)
|
||||
{
|
||||
rt_sem_release(tx_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t uart_rx_indicate(rt_device_t device, rt_size_t size)
|
||||
{
|
||||
rt_sem_release(rx_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void uart_send_entry(void *parameter)
|
||||
{
|
||||
rt_uint8_t *uart_write_buffer;
|
||||
rt_uint16_t send_len, len = 0;
|
||||
rt_err_t result;
|
||||
|
||||
rt_uint32_t i = 0;
|
||||
send_len = *(rt_uint16_t *)parameter;
|
||||
/* assign send buffer */
|
||||
uart_write_buffer = (rt_uint8_t *)rt_malloc(send_len);
|
||||
if (uart_write_buffer == RT_NULL)
|
||||
{
|
||||
LOG_E("Without spare memory for uart dma!");
|
||||
uart_result = RT_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
rt_memset(uart_write_buffer, 0, send_len);
|
||||
|
||||
for (i = 0; i < send_len; i++)
|
||||
{
|
||||
uart_write_buffer[i] = (rt_uint8_t)i;
|
||||
}
|
||||
/* send buffer */
|
||||
while (send_len - len)
|
||||
{
|
||||
len += rt_device_write(&serial->parent, 0, uart_write_buffer + len, send_len - len);
|
||||
result = rt_sem_take(tx_sem, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("take sem err in send.");
|
||||
}
|
||||
}
|
||||
rt_free(uart_write_buffer);
|
||||
|
||||
}
|
||||
|
||||
static void uart_rec_entry(void *parameter)
|
||||
{
|
||||
rt_uint16_t rev_len;
|
||||
|
||||
rev_len = *(rt_uint16_t *)parameter;
|
||||
rt_uint8_t *ch;
|
||||
ch = (rt_uint8_t *)rt_calloc(1, sizeof(rt_uint8_t) * (rev_len + 1));
|
||||
rt_int32_t cnt, i;
|
||||
rt_uint8_t last_old_data;
|
||||
rt_bool_t fisrt_flag = RT_TRUE;
|
||||
rt_uint32_t all_receive_length = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_sem_take(rx_sem, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("take sem err in recv.");
|
||||
}
|
||||
|
||||
cnt = rt_device_read(&serial->parent, 0, (void *)ch, rev_len);
|
||||
if (cnt == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fisrt_flag != RT_TRUE)
|
||||
{
|
||||
if ((rt_uint8_t)(last_old_data + 1) != ch[0])
|
||||
{
|
||||
LOG_E("_Read Different data -> former data: %x, current data: %x.", last_old_data, ch[0]);
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fisrt_flag = RT_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt - 1; i++)
|
||||
{
|
||||
if ((rt_uint8_t)(ch[i] + 1) != ch[i + 1])
|
||||
{
|
||||
LOG_E("Read Different data -> former data: %x, current data: %x.", ch[i], ch[i + 1]);
|
||||
|
||||
uart_result = RT_FALSE;
|
||||
rt_free(ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
all_receive_length += cnt;
|
||||
if (all_receive_length >= rev_len)
|
||||
break;
|
||||
else
|
||||
last_old_data = ch[cnt - 1];
|
||||
}
|
||||
rt_free(ch);
|
||||
uart_over_flag = RT_TRUE;
|
||||
}
|
||||
|
||||
static rt_err_t uart_api(rt_uint16_t test_buf)
|
||||
{
|
||||
rt_thread_t thread_send = RT_NULL;
|
||||
rt_thread_t thread_recv = RT_NULL;
|
||||
rt_err_t result = RT_EOK;
|
||||
uart_over_flag = RT_FALSE;
|
||||
|
||||
result = uart_find();
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rx_sem = rt_sem_create("rx_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (rx_sem == RT_NULL)
|
||||
{
|
||||
LOG_E("Init rx_sem failed.");
|
||||
uart_result = RT_FALSE;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
tx_sem = rt_sem_create("tx_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (tx_sem == RT_NULL)
|
||||
{
|
||||
LOG_E("Init tx_sem failed.");
|
||||
uart_result = RT_FALSE;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* reinitialize */
|
||||
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
||||
config.baud_rate = BAUD_RATE_115200;
|
||||
config.rx_bufsz = BSP_UART2_RX_BUFSIZE;
|
||||
config.tx_bufsz = BSP_UART2_TX_BUFSIZE;
|
||||
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONFIG, &config);
|
||||
|
||||
result = rt_device_open(&serial->parent, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_NON_BLOCKING);
|
||||
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("Open uart device failed.");
|
||||
uart_result = RT_FALSE;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
/* set receive callback function */
|
||||
result = rt_device_set_tx_complete(&serial->parent, uart_tx_completion);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
result = rt_device_set_rx_indicate(&serial->parent, uart_rx_indicate);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
thread_recv = rt_thread_create("uart_recv", uart_rec_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 5, 10);
|
||||
thread_send = rt_thread_create("uart_send", uart_send_entry, &test_buf, 1024, RT_THREAD_PRIORITY_MAX - 4, 10);
|
||||
|
||||
if (thread_send != RT_NULL && thread_recv != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(thread_recv);
|
||||
rt_thread_startup(thread_send);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (uart_result != RT_TRUE)
|
||||
{
|
||||
LOG_E("The test for uart dma is failure.");
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
if (uart_over_flag == RT_TRUE)
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
/* waiting for test over */
|
||||
rt_thread_mdelay(5);
|
||||
}
|
||||
__exit:
|
||||
if (tx_sem)
|
||||
rt_sem_delete(tx_sem);
|
||||
|
||||
if (rx_sem)
|
||||
rt_sem_delete(rx_sem);
|
||||
|
||||
rt_device_close(&serial->parent);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void tc_uart_api(void)
|
||||
{
|
||||
rt_uint32_t times = 0;
|
||||
rt_uint16_t num = 0;
|
||||
while (TC_UART_SEND_TIMES - times)
|
||||
{
|
||||
num = (rand() % 1000) + 1;
|
||||
if(uart_api(num) == RT_EOK)
|
||||
LOG_I("data_lens [%3d], it is correct to read and write data. [%d] times testing.", num, ++times);
|
||||
else
|
||||
{
|
||||
LOG_E("uart test error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
uassert_true(uart_over_flag == RT_TRUE);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
LOG_I("UART TEST: Please connect Tx and Rx directly for self testing.");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
tx_sem = RT_NULL;
|
||||
uart_result = RT_TRUE;
|
||||
uart_over_flag = RT_FALSE;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(tc_uart_api);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.drivers.uart_rxnb_txnb", utest_tc_init, utest_tc_cleanup, 30);
|
||||
|
||||
#endif
|
||||
84
RT_Thread/examples/utest/testcases/kernel/Kconfig
Normal file
84
RT_Thread/examples/utest/testcases/kernel/Kconfig
Normal file
@ -0,0 +1,84 @@
|
||||
menu "Kernel Testcase"
|
||||
|
||||
config UTEST_MEMHEAP_TC
|
||||
bool "memheap stability test"
|
||||
default y
|
||||
depends on RT_USING_MEMHEAP
|
||||
|
||||
config UTEST_SMALL_MEM_TC
|
||||
bool "mem test"
|
||||
default y
|
||||
depends on RT_USING_SMALL_MEM
|
||||
|
||||
config UTEST_SLAB_TC
|
||||
bool "slab test"
|
||||
default n
|
||||
depends on RT_USING_SLAB
|
||||
|
||||
config UTEST_IRQ_TC
|
||||
bool "IRQ test"
|
||||
default n
|
||||
|
||||
config UTEST_SEMAPHORE_TC
|
||||
bool "semaphore test"
|
||||
default n
|
||||
depends on RT_USING_SEMAPHORE
|
||||
|
||||
config UTEST_EVENT_TC
|
||||
bool "event test"
|
||||
default n
|
||||
depends on RT_USING_EVENT
|
||||
|
||||
config UTEST_TIMER_TC
|
||||
bool "timer test"
|
||||
default n
|
||||
|
||||
config UTEST_MESSAGEQUEUE_TC
|
||||
bool "message queue test"
|
||||
default n
|
||||
|
||||
config UTEST_SIGNAL_TC
|
||||
bool "signal test"
|
||||
select RT_USING_SIGNALS
|
||||
default n
|
||||
|
||||
config UTEST_MUTEX_TC
|
||||
bool "mutex test"
|
||||
default n
|
||||
|
||||
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
|
||||
|
||||
config UTEST_DEVICE_TC
|
||||
bool "device test"
|
||||
default n
|
||||
|
||||
config UTEST_ATOMIC_TC
|
||||
bool "atomic test"
|
||||
default n
|
||||
|
||||
config UTEST_HOOKLIST_TC
|
||||
bool "hook list test"
|
||||
select RT_USING_HOOKLIST
|
||||
default n
|
||||
|
||||
config UTEST_MTSAFE_KPRINT_TC
|
||||
bool "mtsafe kprint test"
|
||||
default n
|
||||
|
||||
config UTEST_SCHEDULER_TC
|
||||
bool "scheduler test"
|
||||
default n
|
||||
|
||||
if RT_USING_SMP
|
||||
rsource "smp/Kconfig"
|
||||
endif
|
||||
|
||||
endmenu
|
||||
70
RT_Thread/examples/utest/testcases/kernel/SConscript
Normal file
70
RT_Thread/examples/utest/testcases/kernel/SConscript
Normal file
@ -0,0 +1,70 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend(['UTEST_MEMHEAP_TC']):
|
||||
src += ['memheap_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SMALL_MEM_TC']):
|
||||
src += ['mem_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SLAB_TC']):
|
||||
src += ['slab_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_IRQ_TC']):
|
||||
src += ['irq_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SEMAPHORE_TC']):
|
||||
src += ['semaphore_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_EVENT_TC']):
|
||||
src += ['event_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_TIMER_TC']):
|
||||
src += ['timer_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MESSAGEQUEUE_TC']):
|
||||
src += ['messagequeue_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SIGNAL_TC']):
|
||||
src += ['signal_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MUTEX_TC']):
|
||||
src += ['mutex_tc.c', 'mutex_pi_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MAILBOX_TC']):
|
||||
src += ['mailbox_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_THREAD_TC']):
|
||||
src += ['thread_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_DEVICE_TC']):
|
||||
src += ['device_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_ATOMIC_TC']):
|
||||
src += ['atomic_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_HOOKLIST_TC']):
|
||||
src += ['hooklist_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MTSAFE_KPRINT_TC']):
|
||||
src += ['mtsafe_kprint_tc.c']
|
||||
|
||||
# Stressful testcase for scheduler (MP/UP)
|
||||
if GetDepend(['UTEST_SCHEDULER_TC']):
|
||||
src += ['sched_timed_sem_tc.c']
|
||||
src += ['sched_timed_mtx_tc.c']
|
||||
src += ['sched_mtx_tc.c']
|
||||
src += ['sched_sem_tc.c', 'sched_thread_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
list = os.listdir(cwd)
|
||||
for item in list:
|
||||
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
|
||||
group = group + SConscript(os.path.join(item, 'SConscript'))
|
||||
|
||||
Return('group')
|
||||
173
RT_Thread/examples/utest/testcases/kernel/atomic_tc.c
Normal file
173
RT_Thread/examples/utest/testcases/kernel/atomic_tc.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-07-27 flybreak the first version
|
||||
* 2023-03-21 WangShun add atomic test
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include "rtatomic.h"
|
||||
#include <rthw.h>
|
||||
|
||||
#define THREAD_PRIORITY 25
|
||||
#define THREAD_TIMESLICE 1
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
|
||||
/* convenience macro - return either 64-bit or 32-bit value */
|
||||
#define ATOMIC_WORD(val_if_64, val_if_32) \
|
||||
((rt_atomic_t)((sizeof(void *) == sizeof(uint64_t)) ? (val_if_64) : (val_if_32)))
|
||||
|
||||
static rt_atomic_t count = 0;
|
||||
static rt_sem_t sem_t;
|
||||
|
||||
static void test_atomic_api(void)
|
||||
{
|
||||
rt_atomic_t base;
|
||||
rt_atomic_t oldval;
|
||||
rt_atomic_t result;
|
||||
|
||||
/* rt_atomic_t */
|
||||
uassert_true(sizeof(rt_atomic_t) == ATOMIC_WORD(sizeof(uint64_t), sizeof(uint32_t)));
|
||||
|
||||
/* rt_atomic_add */
|
||||
base = 0;
|
||||
result = rt_atomic_add(&base, 10);
|
||||
uassert_true(base == 10);
|
||||
uassert_true(result == 0);
|
||||
/* rt_atomic_add negative */
|
||||
base = 2;
|
||||
result = rt_atomic_add(&base, -4);
|
||||
uassert_true(base == -2);
|
||||
uassert_true(result == 2);
|
||||
|
||||
/* rt_atomic_sub */
|
||||
base = 11;
|
||||
result = rt_atomic_sub(&base, 10);
|
||||
uassert_true(base == 1);
|
||||
uassert_true(result == 11);
|
||||
/* rt_atomic_sub negative */
|
||||
base = 2;
|
||||
result = rt_atomic_sub(&base, -5);
|
||||
uassert_true(base == 7);
|
||||
uassert_true(result == 2);
|
||||
|
||||
/* rt_atomic_or */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_or(&base, 0x0F0F);
|
||||
uassert_true(base == 0xFF0F);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_xor */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_xor(&base, 0x0F0F);
|
||||
uassert_true(base == 0xF00F);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_and */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_and(&base, 0x0F0F);
|
||||
uassert_true(base == 0x0F00);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_exchange */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_exchange(&base, 0x0F0F);
|
||||
uassert_true(base == 0x0F0F);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_flag_test_and_set (Flag 0) */
|
||||
base = 0x0;
|
||||
result = rt_atomic_flag_test_and_set(&base);
|
||||
uassert_true(base == 0x1);
|
||||
uassert_true(result == 0x0);
|
||||
/* rt_atomic_flag_test_and_set (Flag 1) */
|
||||
base = 0x1;
|
||||
result = rt_atomic_flag_test_and_set(&base);
|
||||
uassert_true(base == 0x1);
|
||||
uassert_true(result == 0x1);
|
||||
|
||||
/* rt_atomic_flag_clear */
|
||||
base = 0x1;
|
||||
rt_atomic_flag_clear(&base);
|
||||
uassert_true(base == 0x0);
|
||||
|
||||
/* rt_atomic_load */
|
||||
base = 0xFF00;
|
||||
result = rt_atomic_load(&base);
|
||||
uassert_true(base == 0xFF00);
|
||||
uassert_true(result == 0xFF00);
|
||||
|
||||
/* rt_atomic_store */
|
||||
base = 0xFF00;
|
||||
rt_atomic_store(&base, 0x0F0F);
|
||||
uassert_true(base == 0x0F0F);
|
||||
|
||||
/* rt_atomic_compare_exchange_strong (equal) */
|
||||
base = 10;
|
||||
oldval = 10;
|
||||
result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
|
||||
uassert_true(base == 11);
|
||||
uassert_true(result == 0x1);
|
||||
/* rt_atomic_compare_exchange_strong (not equal) */
|
||||
base = 10;
|
||||
oldval = 5;
|
||||
result = rt_atomic_compare_exchange_strong(&base, &oldval, 11);
|
||||
uassert_true(base == 10);
|
||||
uassert_true(result == 0x0);
|
||||
}
|
||||
|
||||
static void ture_entry(void *parameter)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 1000000; i++)
|
||||
{
|
||||
rt_atomic_add(&count, 1);
|
||||
}
|
||||
rt_sem_release(sem_t);
|
||||
}
|
||||
|
||||
static void test_atomic_add(void)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
size_t i;
|
||||
sem_t = rt_sem_create("atomic_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
|
||||
rt_atomic_store(&count, 0);
|
||||
|
||||
thread = rt_thread_create("t1", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(thread);
|
||||
thread = rt_thread_create("t2", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(thread);
|
||||
thread = rt_thread_create("t3", ture_entry, RT_NULL, THREAD_STACKSIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(thread);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
rt_sem_take(sem_t, RT_WAITING_FOREVER);
|
||||
}
|
||||
i = rt_atomic_load(&count);
|
||||
uassert_true(i == 3000000);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_atomic_api);
|
||||
UTEST_UNIT_RUN(test_atomic_add);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.atomic_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
59
RT_Thread/examples/utest/testcases/kernel/device_tc.c
Normal file
59
RT_Thread/examples/utest/testcases/kernel/device_tc.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-05-20 Shell the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
static void test_rt_device_find(void)
|
||||
{
|
||||
char _device_name[RT_NAME_MAX + 1] = {0};
|
||||
rt_device_t console;
|
||||
rt_device_t device1, device2, device3;
|
||||
|
||||
console = rt_console_get_device();
|
||||
uassert_not_null(console);
|
||||
rt_memcpy(_device_name, console->parent.name, RT_NAME_MAX);
|
||||
|
||||
/* Test finding a device */
|
||||
device1 = rt_device_find(_device_name);
|
||||
uassert_true(device1 == console);
|
||||
|
||||
/* Test finding another device */
|
||||
device2 = rt_device_find(RT_CONSOLE_DEVICE_NAME);
|
||||
if (rt_strcmp(RT_CONSOLE_DEVICE_NAME, _device_name) == 0)
|
||||
{
|
||||
uassert_true(device2 == device1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_not_null(device2);
|
||||
uassert_true(device2 != device1);
|
||||
}
|
||||
|
||||
/* Test finding a device 3 */
|
||||
device3 = rt_device_find(console->parent.name);
|
||||
uassert_true(device1 == device3);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_rt_device_find);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.device.find", utest_tc_init, utest_tc_cleanup, 5);
|
||||
346
RT_Thread/examples/utest/testcases/kernel/event_tc.c
Normal file
346
RT_Thread/examples/utest/testcases/kernel/event_tc.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-15 liukang the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
#define EVENT_FLAG3 (1 << 3)
|
||||
#define EVENT_FLAG5 (1 << 5)
|
||||
|
||||
static struct rt_event static_event = {0};
|
||||
#ifdef RT_USING_HEAP
|
||||
static rt_event_t dynamic_event = RT_NULL;
|
||||
static rt_uint32_t dynamic_event_recv_thread_finish = 0, dynamic_event_send_thread_finish = 0;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread3_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread3;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread4_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread4;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
static rt_uint32_t recv_event_times1 = 0, recv_event_times2 = 0;
|
||||
static rt_uint32_t static_event_recv_thread_finish = 0, static_event_send_thread_finish = 0;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread1_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread1;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread2_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread2;
|
||||
|
||||
#define THREAD_PRIORITY 9
|
||||
#define THREAD_TIMESLICE 5
|
||||
|
||||
static void test_event_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_event_detach(&static_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_event_detach(&static_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_event_detach(void)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_detach(&static_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread1_recv_static_event(void *param)
|
||||
{
|
||||
rt_uint32_t e;
|
||||
|
||||
if (rt_event_recv(&static_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recv_event_times1 = e;
|
||||
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
if (rt_event_recv(&static_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
recv_event_times2 = e;
|
||||
|
||||
static_event_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread2_send_static_event(void *param)
|
||||
{
|
||||
rt_event_send(&static_event, EVENT_FLAG3);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(&static_event, EVENT_FLAG5);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(&static_event, EVENT_FLAG3);
|
||||
|
||||
static_event_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
|
||||
static void test_static_event_send_recv(void)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_event_init(&static_event, "event", RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
rt_thread_init(&thread1,
|
||||
"thread1",
|
||||
thread1_recv_static_event,
|
||||
RT_NULL,
|
||||
&thread1_stack[0],
|
||||
sizeof(thread1_stack),
|
||||
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread1);
|
||||
|
||||
rt_thread_init(&thread2,
|
||||
"thread2",
|
||||
thread2_send_static_event,
|
||||
RT_NULL,
|
||||
&thread2_stack[0],
|
||||
sizeof(thread2_stack),
|
||||
THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread2);
|
||||
|
||||
while (static_event_recv_thread_finish != 1 || static_event_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (recv_event_times1 == EVENT_FLAG3 && recv_event_times2 == (EVENT_FLAG3 | EVENT_FLAG5))
|
||||
{
|
||||
if (rt_event_detach(&static_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_true(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rt_event_detach(&static_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
static void test_event_create(void)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_FIFO);
|
||||
if (dynamic_event == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_delete(dynamic_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_event_delete(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_FIFO);
|
||||
if (dynamic_event == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_event_delete(dynamic_event);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread3_recv_dynamic_event(void *param)
|
||||
{
|
||||
rt_uint32_t e;
|
||||
|
||||
if (rt_event_recv(dynamic_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recv_event_times1 = e;
|
||||
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
if (rt_event_recv(dynamic_event, (EVENT_FLAG3 | EVENT_FLAG5),
|
||||
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER, &e) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
recv_event_times2 = e;
|
||||
|
||||
dynamic_event_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread4_send_dynamic_event(void *param)
|
||||
{
|
||||
rt_event_send(dynamic_event, EVENT_FLAG3);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(dynamic_event, EVENT_FLAG5);
|
||||
rt_thread_mdelay(10);
|
||||
|
||||
rt_event_send(dynamic_event, EVENT_FLAG3);
|
||||
|
||||
dynamic_event_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void test_dynamic_event_send_recv(void)
|
||||
{
|
||||
dynamic_event = rt_event_create("dynamic_event", RT_IPC_FLAG_PRIO);
|
||||
if (dynamic_event == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
rt_thread_init(&thread3,
|
||||
"thread3",
|
||||
thread3_recv_dynamic_event,
|
||||
RT_NULL,
|
||||
&thread3_stack[0],
|
||||
sizeof(thread3_stack),
|
||||
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread3);
|
||||
|
||||
rt_thread_init(&thread4,
|
||||
"thread4",
|
||||
thread4_send_dynamic_event,
|
||||
RT_NULL,
|
||||
&thread4_stack[0],
|
||||
sizeof(thread4_stack),
|
||||
THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread4);
|
||||
|
||||
while (dynamic_event_recv_thread_finish != 1 || dynamic_event_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (recv_event_times1 == EVENT_FLAG3 && recv_event_times2 == (EVENT_FLAG3 | EVENT_FLAG5))
|
||||
{
|
||||
if (rt_event_delete(dynamic_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_true(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rt_event_delete(dynamic_event) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
static_event_recv_thread_finish = 0;
|
||||
static_event_send_thread_finish = 0;
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_event_recv_thread_finish = 0;
|
||||
dynamic_event_send_thread_finish = 0;
|
||||
#endif
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_event_init);
|
||||
UTEST_UNIT_RUN(test_event_detach);
|
||||
UTEST_UNIT_RUN(test_static_event_send_recv);
|
||||
#ifdef RT_USING_HEAP
|
||||
UTEST_UNIT_RUN(test_event_create);
|
||||
UTEST_UNIT_RUN(test_event_delete);
|
||||
UTEST_UNIT_RUN(test_dynamic_event_send_recv);
|
||||
#endif
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "src.ipc.event_tc", utest_tc_init, utest_tc_cleanup, 60);
|
||||
98
RT_Thread/examples/utest/testcases/kernel/hooklist_tc.c
Normal file
98
RT_Thread/examples/utest/testcases/kernel/hooklist_tc.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-12-22 Shell Support hook list
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "rtconfig.h"
|
||||
#include "utest.h"
|
||||
#include "utest_assert.h"
|
||||
|
||||
static int hooker1_ent_count;
|
||||
static int hooker2_ent_count;
|
||||
static struct rt_thread thr_tobe_inited;
|
||||
|
||||
static void thread_inited_hooker1(rt_thread_t thread)
|
||||
{
|
||||
LOG_D("%s: count %d", __func__, hooker1_ent_count);
|
||||
hooker1_ent_count += 1;
|
||||
}
|
||||
RT_OBJECT_HOOKLIST_DEFINE_NODE(rt_thread_inited, hooker1_node, thread_inited_hooker1);
|
||||
|
||||
static void thread_inited_hooker2(rt_thread_t thread)
|
||||
{
|
||||
LOG_D("%s: count %d", __func__, hooker2_ent_count);
|
||||
hooker2_ent_count += 1;
|
||||
}
|
||||
RT_OBJECT_HOOKLIST_DEFINE_NODE(rt_thread_inited, hooker2_node, thread_inited_hooker2);
|
||||
|
||||
static char _thr_stack[UTEST_THR_STACK_SIZE];
|
||||
static void thr_tobe_inited_entry(void *param)
|
||||
{
|
||||
rt_kprintf("Hello!\n");
|
||||
}
|
||||
|
||||
static void hooklist_test(void)
|
||||
{
|
||||
hooker1_ent_count = 0;
|
||||
hooker2_ent_count = 0;
|
||||
rt_thread_inited_sethook(&hooker1_node);
|
||||
rt_thread_inited_sethook(&hooker2_node);
|
||||
|
||||
/* run 1 */
|
||||
rt_thread_init(&thr_tobe_inited,
|
||||
"thr_tobe_inited",
|
||||
thr_tobe_inited_entry,
|
||||
NULL,
|
||||
_thr_stack,
|
||||
sizeof(_thr_stack),
|
||||
25,
|
||||
100);
|
||||
|
||||
uassert_int_equal(hooker1_ent_count, 1);
|
||||
uassert_int_equal(hooker2_ent_count, 1);
|
||||
|
||||
rt_thread_detach(&thr_tobe_inited);
|
||||
rt_thread_mdelay(1); /* wait recycling done */
|
||||
|
||||
/* run 2 */
|
||||
rt_thread_inited_rmhook(&hooker2_node);
|
||||
|
||||
rt_thread_init(&thr_tobe_inited,
|
||||
"thr_tobe_inited",
|
||||
thr_tobe_inited_entry,
|
||||
NULL,
|
||||
_thr_stack,
|
||||
sizeof(_thr_stack),
|
||||
25,
|
||||
100);
|
||||
|
||||
uassert_int_equal(hooker1_ent_count, 2);
|
||||
uassert_int_equal(hooker2_ent_count, 1);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
hooker1_ent_count = 0;
|
||||
hooker2_ent_count = 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_thread_detach(&thr_tobe_inited);
|
||||
rt_thread_inited_rmhook(&hooker1_node);
|
||||
rt_thread_inited_rmhook(&hooker2_node);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(hooklist_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.hooklist_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
78
RT_Thread/examples/utest/testcases/kernel/irq_tc.c
Normal file
78
RT_Thread/examples/utest/testcases/kernel/irq_tc.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-15 supperthomas add irq_test
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include "rthw.h"
|
||||
|
||||
#define UTEST_NAME "irq_tc"
|
||||
static volatile uint32_t irq_count = 0;
|
||||
static volatile uint32_t max_get_nest_count = 0;
|
||||
|
||||
static void irq_callback()
|
||||
{
|
||||
if(rt_interrupt_get_nest() > max_get_nest_count)
|
||||
{
|
||||
max_get_nest_count = rt_interrupt_get_nest();
|
||||
}
|
||||
irq_count ++;
|
||||
}
|
||||
|
||||
static void irq_test(void)
|
||||
{
|
||||
irq_count = 0;
|
||||
rt_interrupt_enter_sethook(irq_callback);
|
||||
rt_interrupt_leave_sethook(irq_callback);
|
||||
rt_thread_mdelay(2);
|
||||
LOG_D("%s test irq_test! irq_count %d max_get_nest_count %d\n", UTEST_NAME, irq_count, max_get_nest_count);
|
||||
uassert_int_not_equal(0, irq_count);
|
||||
uassert_int_not_equal(0, max_get_nest_count);
|
||||
rt_interrupt_enter_sethook(RT_NULL);
|
||||
rt_interrupt_leave_sethook(RT_NULL);
|
||||
LOG_D("irq_test OK!\n");
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
irq_count = 0;
|
||||
max_get_nest_count = 0;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void interrupt_test(void)
|
||||
{
|
||||
rt_base_t level;
|
||||
uint32_t i = 1000;
|
||||
|
||||
rt_interrupt_enter_sethook(irq_callback);
|
||||
rt_interrupt_leave_sethook(irq_callback);
|
||||
irq_count = 0;
|
||||
level = rt_hw_interrupt_disable();
|
||||
while(i)
|
||||
{
|
||||
i --;
|
||||
}
|
||||
uassert_int_equal(0, irq_count);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_interrupt_enter_sethook(RT_NULL);
|
||||
rt_interrupt_leave_sethook(RT_NULL);
|
||||
|
||||
}
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(irq_test);
|
||||
UTEST_UNIT_RUN(interrupt_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.irq_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
374
RT_Thread/examples/utest/testcases/kernel/mailbox_tc.c
Normal file
374
RT_Thread/examples/utest/testcases/kernel/mailbox_tc.c
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09-08 liukang the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
|
||||
static struct rt_mailbox test_static_mb;
|
||||
static char mb_pool[128];
|
||||
|
||||
static rt_mailbox_t test_dynamic_mb;
|
||||
|
||||
static uint8_t static_mb_recv_thread_finish, static_mb_send_thread_finish;
|
||||
static uint8_t dynamic_mb_recv_thread_finish, dynamic_mb_send_thread_finish;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread1_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread1;
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread2_stack[UTEST_THR_STACK_SIZE];
|
||||
static struct rt_thread thread2;
|
||||
|
||||
#define THREAD_PRIORITY 9
|
||||
#define THREAD_TIMESLICE 5
|
||||
|
||||
static rt_thread_t mb_send = RT_NULL;
|
||||
static rt_thread_t mb_recv = RT_NULL;
|
||||
|
||||
static rt_uint8_t mb_send_str1[] = "this is first mail!";
|
||||
static rt_uint8_t mb_send_str2[] = "this is second mail!";
|
||||
static rt_uint8_t mb_send_str3[] = "this is thirdy mail!";
|
||||
|
||||
static rt_uint8_t *mb_recv_str1;
|
||||
static rt_uint8_t *mb_recv_str2;
|
||||
static rt_uint8_t *mb_recv_str3;
|
||||
|
||||
static void test_mailbox_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_mailbox_deatch(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_detach(&test_static_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_mailbox_create(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void test_mailbox_delete(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
test_dynamic_mb = rt_mb_create("test_dynamic_mb", sizeof(mb_pool) / 4, RT_IPC_FLAG_PRIO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
result = rt_mb_delete(test_dynamic_mb);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread2_send_static_mb(void *arg)
|
||||
{
|
||||
rt_err_t res = RT_EOK;
|
||||
|
||||
res = rt_mb_send(&test_static_mb, (rt_ubase_t)&mb_send_str1);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_send_wait(&test_static_mb, (rt_ubase_t)&mb_send_str2, 10);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_urgent(&test_static_mb, (rt_ubase_t)&mb_send_str3);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
static_mb_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread1_recv_static_mb(void *arg)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str1, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str1, (const char *)mb_send_str1) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str2, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str2, (const char *)mb_send_str2) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(&test_static_mb, (rt_ubase_t *)&mb_recv_str3, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str3, (const char *)mb_send_str3) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
static_mb_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void test_static_mailbox_send_recv(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_mb_init(&test_static_mb, "mbt", &mb_pool[0], sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
rt_thread_init(&thread1,
|
||||
"thread1",
|
||||
thread1_recv_static_mb,
|
||||
RT_NULL,
|
||||
&thread1_stack[0],
|
||||
sizeof(thread1_stack),
|
||||
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread1);
|
||||
|
||||
rt_thread_init(&thread2,
|
||||
"thread2",
|
||||
thread2_send_static_mb,
|
||||
RT_NULL,
|
||||
&thread2_stack[0],
|
||||
sizeof(thread2_stack),
|
||||
THREAD_PRIORITY, THREAD_TIMESLICE);
|
||||
rt_thread_startup(&thread2);
|
||||
|
||||
while (static_mb_recv_thread_finish != 1 || static_mb_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (rt_mb_detach(&test_static_mb) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static void thread4_send_dynamic_mb(void *arg)
|
||||
{
|
||||
rt_err_t res = RT_EOK;
|
||||
|
||||
res = rt_mb_send(test_dynamic_mb, (rt_ubase_t)&mb_send_str1);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_send_wait(test_dynamic_mb, (rt_ubase_t)&mb_send_str2, 10);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
res = rt_mb_urgent(test_dynamic_mb, (rt_ubase_t)&mb_send_str3);
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
dynamic_mb_send_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void thread3_recv_dynamic_mb(void *arg)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str1, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str1, (const char *)mb_send_str1) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str2, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str2, (const char *)mb_send_str2) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
result = rt_mb_recv(test_dynamic_mb, (rt_ubase_t *)&mb_recv_str3, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK || rt_strcmp((const char *)mb_recv_str3, (const char *)mb_send_str3) != 0)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
dynamic_mb_recv_thread_finish = 1;
|
||||
}
|
||||
|
||||
static void test_dynamic_mailbox_send_recv(void)
|
||||
{
|
||||
test_dynamic_mb = rt_mb_create("mbt", sizeof(mb_pool) / 4, RT_IPC_FLAG_FIFO);
|
||||
if (test_dynamic_mb == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
mb_recv = rt_thread_create("mb_recv_thread",
|
||||
thread3_recv_dynamic_mb,
|
||||
RT_NULL,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
THREAD_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (mb_recv == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_startup(mb_recv);
|
||||
|
||||
mb_send = rt_thread_create("mb_send_thread",
|
||||
thread4_send_dynamic_mb,
|
||||
RT_NULL,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
THREAD_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (mb_send == RT_NULL)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
rt_thread_startup(mb_send);
|
||||
|
||||
while (dynamic_mb_recv_thread_finish != 1 || dynamic_mb_send_thread_finish != 1)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
if (rt_mb_delete(test_dynamic_mb) != RT_EOK)
|
||||
{
|
||||
uassert_false(1);
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_mailbox_init);
|
||||
UTEST_UNIT_RUN(test_mailbox_deatch);
|
||||
UTEST_UNIT_RUN(test_mailbox_create);
|
||||
UTEST_UNIT_RUN(test_mailbox_delete);
|
||||
UTEST_UNIT_RUN(test_static_mailbox_send_recv);
|
||||
UTEST_UNIT_RUN(test_dynamic_mailbox_send_recv);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "src.ipc.mailbox_tc", utest_tc_init, utest_tc_cleanup, 60);
|
||||
585
RT_Thread/examples/utest/testcases/kernel/mem_tc.c
Normal file
585
RT_Thread/examples/utest/testcases/kernel/mem_tc.c
Normal file
@ -0,0 +1,585 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-14 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
struct rt_small_mem_item
|
||||
{
|
||||
rt_ubase_t pool_ptr; /**< small memory object addr */
|
||||
rt_size_t next; /**< next free item */
|
||||
rt_size_t prev; /**< prev free item */
|
||||
#ifdef RT_USING_MEMTRACE
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
rt_uint8_t thread[8]; /**< thread name */
|
||||
#else
|
||||
rt_uint8_t thread[4]; /**< thread name */
|
||||
#endif /* ARCH_CPU_64BIT */
|
||||
#endif /* RT_USING_MEMTRACE */
|
||||
};
|
||||
|
||||
struct rt_small_mem
|
||||
{
|
||||
struct rt_memory parent; /**< inherit from rt_memory */
|
||||
rt_uint8_t *heap_ptr; /**< pointer to the heap */
|
||||
struct rt_small_mem_item *heap_end;
|
||||
struct rt_small_mem_item *lfree;
|
||||
rt_size_t mem_size_aligned; /**< aligned memory size */
|
||||
};
|
||||
|
||||
#define MEM_SIZE(_heap, _mem) \
|
||||
(((struct rt_small_mem_item *)(_mem))->next - ((rt_ubase_t)(_mem) - \
|
||||
(rt_ubase_t)((_heap)->heap_ptr)) - RT_ALIGN(sizeof(struct rt_small_mem_item), RT_ALIGN_SIZE))
|
||||
|
||||
#define TEST_MEM_SIZE 1024
|
||||
|
||||
static rt_size_t max_block(struct rt_small_mem *heap)
|
||||
{
|
||||
struct rt_small_mem_item *mem;
|
||||
rt_size_t max = 0, size;
|
||||
|
||||
for (mem = (struct rt_small_mem_item *)heap->heap_ptr;
|
||||
mem != heap->heap_end;
|
||||
mem = (struct rt_small_mem_item *)&heap->heap_ptr[mem->next])
|
||||
{
|
||||
if (((rt_ubase_t)mem->pool_ptr & 0x1) == 0)
|
||||
{
|
||||
size = MEM_SIZE(heap, mem);
|
||||
if (size > max)
|
||||
{
|
||||
max = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
{
|
||||
if (*(rt_uint8_t *)ptr != v)
|
||||
return *(rt_uint8_t *)ptr - v;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mem_test_context
|
||||
{
|
||||
void *ptr;
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
static void mem_functional_test(void)
|
||||
{
|
||||
rt_size_t total_size;
|
||||
rt_uint8_t *buf;
|
||||
struct rt_small_mem *heap;
|
||||
rt_uint8_t magic = __LINE__;
|
||||
|
||||
/* Prepare test memory */
|
||||
buf = rt_malloc(TEST_MEM_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
|
||||
/* small heap init */
|
||||
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
|
||||
/* get total size */
|
||||
total_size = max_block(heap);
|
||||
uassert_int_not_equal(total_size, 0);
|
||||
/*
|
||||
* Allocate all memory at a time and test whether
|
||||
* the memory allocation release function is effective
|
||||
*/
|
||||
{
|
||||
struct mem_test_context ctx;
|
||||
ctx.magic = magic++;
|
||||
ctx.size = max_block(heap);
|
||||
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
|
||||
uassert_not_null(ctx.ptr);
|
||||
rt_memset(ctx.ptr, ctx.magic, ctx.size);
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
rt_smem_free(ctx.ptr);
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/*
|
||||
* Apply for memory release sequentially and
|
||||
* test whether memory block merging is effective
|
||||
*/
|
||||
{
|
||||
rt_size_t i, max_free = 0;
|
||||
struct mem_test_context ctx[3];
|
||||
/* alloc mem */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
ctx[i].magic = magic++;
|
||||
ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
|
||||
ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
|
||||
uassert_not_null(ctx[i].ptr);
|
||||
rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
|
||||
}
|
||||
/* All memory has been applied. The remaining memory should be 0 */
|
||||
uassert_int_equal(max_block(heap), 0);
|
||||
/* Verify that the memory data is correct */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
}
|
||||
/* Sequential memory release */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
rt_smem_free(ctx[i].ptr);
|
||||
max_free += ctx[i].size;
|
||||
uassert_true(max_block(heap) >= max_free);
|
||||
}
|
||||
/* Check whether the memory is fully merged */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/*
|
||||
* Apply for memory release at an interval to
|
||||
* test whether memory block merging is effective
|
||||
*/
|
||||
{
|
||||
rt_size_t i, max_free = 0;
|
||||
struct mem_test_context ctx[3];
|
||||
/* alloc mem */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
ctx[i].magic = magic++;
|
||||
ctx[i].size = max_block(heap) / (sizeof(ctx) / sizeof(ctx[0]) - i);
|
||||
ctx[i].ptr = rt_smem_alloc(&heap->parent, ctx[i].size);
|
||||
uassert_not_null(ctx[i].ptr);
|
||||
rt_memset(ctx[i].ptr, ctx[i].magic, ctx[i].size);
|
||||
}
|
||||
/* All memory has been applied. The remaining memory should be 0 */
|
||||
uassert_int_equal(max_block(heap), 0);
|
||||
/* Verify that the memory data is correct */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
}
|
||||
/* Release even address */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
rt_smem_free(ctx[i].ptr);
|
||||
uassert_true(max_block(heap) >= ctx[0].size);
|
||||
}
|
||||
}
|
||||
/* Release odd addresses and merge memory blocks */
|
||||
for (i = 0; i < sizeof(ctx) / sizeof(ctx[0]); i++)
|
||||
{
|
||||
if (i % 2 != 0)
|
||||
{
|
||||
uassert_int_equal(_mem_cmp(ctx[i].ptr, ctx[i].magic, ctx[i].size), 0);
|
||||
rt_smem_free(ctx[i].ptr);
|
||||
max_free += ctx[i - 1].size + ctx[i + 1].size;
|
||||
uassert_true(max_block(heap) >= max_free);
|
||||
}
|
||||
}
|
||||
/* Check whether the memory is fully merged */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* mem realloc test,Small - > Large */
|
||||
{
|
||||
/* Request a piece of memory for subsequent reallocation operations */
|
||||
struct mem_test_context ctx[3];
|
||||
ctx[0].magic = magic++;
|
||||
ctx[0].size = max_block(heap) / 3;
|
||||
ctx[0].ptr = rt_smem_alloc(&heap->parent, ctx[0].size);
|
||||
uassert_not_null(ctx[0].ptr);
|
||||
rt_memset(ctx[0].ptr, ctx[0].magic, ctx[0].size);
|
||||
/* Apply for a small piece of memory and split the continuous memory */
|
||||
ctx[1].magic = magic++;
|
||||
ctx[1].size = RT_ALIGN_SIZE;
|
||||
ctx[1].ptr = rt_smem_alloc(&heap->parent, ctx[1].size);
|
||||
uassert_not_null(ctx[1].ptr);
|
||||
rt_memset(ctx[1].ptr, ctx[1].magic, ctx[1].size);
|
||||
/* Check whether the maximum memory block is larger than the first piece of memory */
|
||||
uassert_true(max_block(heap) > ctx[0].size);
|
||||
/* Reallocate the first piece of memory */
|
||||
ctx[2].magic = magic++;
|
||||
ctx[2].size = max_block(heap);
|
||||
ctx[2].ptr = rt_smem_realloc(&heap->parent, ctx[0].ptr, ctx[2].size);
|
||||
uassert_not_null(ctx[2].ptr);
|
||||
uassert_int_not_equal(ctx[0].ptr, ctx[2].ptr);
|
||||
uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[0].magic, ctx[0].size), 0);
|
||||
rt_memset(ctx[2].ptr, ctx[2].magic, ctx[2].size);
|
||||
/* Free the second piece of memory */
|
||||
uassert_int_equal(_mem_cmp(ctx[1].ptr, ctx[1].magic, ctx[1].size), 0);
|
||||
rt_smem_free(ctx[1].ptr);
|
||||
/* Free reallocated memory */
|
||||
uassert_int_equal(_mem_cmp(ctx[2].ptr, ctx[2].magic, ctx[2].size), 0);
|
||||
rt_smem_free(ctx[2].ptr);
|
||||
/* Check memory integrity */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* mem realloc test,Large - > Small */
|
||||
{
|
||||
rt_size_t max_free;
|
||||
struct mem_test_context ctx;
|
||||
/* alloc a piece of memory */
|
||||
ctx.magic = magic++;
|
||||
ctx.size = max_block(heap) / 2;
|
||||
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
|
||||
uassert_not_null(ctx.ptr);
|
||||
rt_memset(ctx.ptr, ctx.magic, ctx.size);
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
/* Get remaining memory */
|
||||
max_free = max_block(heap);
|
||||
/* Change memory size */
|
||||
ctx.size = ctx.size / 2;
|
||||
uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
|
||||
/* Get remaining size */
|
||||
uassert_true(max_block(heap) > max_free);
|
||||
/* Free memory */
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
rt_smem_free(ctx.ptr);
|
||||
/* Check memory integrity */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* mem realloc test,equal */
|
||||
{
|
||||
rt_size_t max_free;
|
||||
struct mem_test_context ctx;
|
||||
/* alloc a piece of memory */
|
||||
ctx.magic = magic++;
|
||||
ctx.size = max_block(heap) / 2;
|
||||
ctx.ptr = rt_smem_alloc(&heap->parent, ctx.size);
|
||||
uassert_not_null(ctx.ptr);
|
||||
rt_memset(ctx.ptr, ctx.magic, ctx.size);
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
/* Get remaining memory */
|
||||
max_free = max_block(heap);
|
||||
/* Do not change memory size */
|
||||
uassert_int_equal((rt_ubase_t)rt_smem_realloc(&heap->parent, ctx.ptr, ctx.size), (rt_ubase_t)ctx.ptr);
|
||||
/* Get remaining size */
|
||||
uassert_true(max_block(heap) == max_free);
|
||||
/* Free memory */
|
||||
uassert_int_equal(_mem_cmp(ctx.ptr, ctx.magic, ctx.size), 0);
|
||||
rt_smem_free(ctx.ptr);
|
||||
/* Check memory integrity */
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
}
|
||||
/* small heap deinit */
|
||||
rt_smem_detach(&heap->parent);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
struct mem_alloc_context
|
||||
{
|
||||
rt_list_t node;
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
struct mem_alloc_head
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_size_t count;
|
||||
rt_tick_t start;
|
||||
rt_tick_t end;
|
||||
rt_tick_t interval;
|
||||
};
|
||||
|
||||
#define MEM_RANG_ALLOC_BLK_MIN 2
|
||||
#define MEM_RANG_ALLOC_BLK_MAX 5
|
||||
#define MEM_RANG_ALLOC_TEST_TIME 5
|
||||
|
||||
static void mem_alloc_test(void)
|
||||
{
|
||||
struct mem_alloc_head head;
|
||||
rt_uint8_t *buf;
|
||||
struct rt_small_mem *heap;
|
||||
rt_size_t total_size, size;
|
||||
struct mem_alloc_context *ctx;
|
||||
|
||||
/* init */
|
||||
rt_list_init(&head.list);
|
||||
head.count = 0;
|
||||
head.start = rt_tick_get();
|
||||
head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
|
||||
head.interval = (head.end - head.start) / 20;
|
||||
buf = rt_malloc(TEST_MEM_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
|
||||
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
|
||||
total_size = max_block(heap);
|
||||
uassert_int_not_equal(total_size, 0);
|
||||
/* test run */
|
||||
while (head.end - head.start < RT_TICK_MAX / 2)
|
||||
{
|
||||
if (rt_tick_get() - head.start >= head.interval)
|
||||
{
|
||||
head.start = rt_tick_get();
|
||||
rt_kprintf("#");
|
||||
}
|
||||
/* %60 probability to perform alloc operation */
|
||||
if (rand() % 10 >= 4)
|
||||
{
|
||||
size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
|
||||
size *= sizeof(struct mem_alloc_context);
|
||||
ctx = rt_smem_alloc(&heap->parent, size);
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
if (head.count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
size = head.count / 2;
|
||||
while (size != head.count)
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_free(ctx);
|
||||
head.count --;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx)
|
||||
{
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx);
|
||||
}
|
||||
rt_memset(ctx, 0, size);
|
||||
rt_list_init(&ctx->node);
|
||||
ctx->size = size;
|
||||
ctx->magic = rand() & 0xff;
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
rt_list_insert_after(&head.list, &ctx->node);
|
||||
head.count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rt_list_isempty(&head.list))
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_free(ctx);
|
||||
head.count --;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!rt_list_isempty(&head.list))
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct mem_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_free(ctx);
|
||||
head.count --;
|
||||
}
|
||||
uassert_int_equal(head.count, 0);
|
||||
uassert_int_equal(max_block(heap), total_size);
|
||||
/* small heap deinit */
|
||||
rt_smem_detach(&heap->parent);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
#define MEM_RANG_REALLOC_BLK_MIN 0
|
||||
#define MEM_RANG_REALLOC_BLK_MAX 5
|
||||
#define MEM_RANG_REALLOC_TEST_TIME 5
|
||||
|
||||
struct mem_realloc_context
|
||||
{
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
struct mem_realloc_head
|
||||
{
|
||||
struct mem_realloc_context **ctx_tab;
|
||||
rt_size_t count;
|
||||
rt_tick_t start;
|
||||
rt_tick_t end;
|
||||
rt_tick_t interval;
|
||||
};
|
||||
|
||||
static void mem_realloc_test(void)
|
||||
{
|
||||
struct mem_realloc_head head;
|
||||
rt_uint8_t *buf;
|
||||
struct rt_small_mem *heap;
|
||||
rt_size_t total_size, size, idx;
|
||||
struct mem_realloc_context *ctx;
|
||||
int res;
|
||||
|
||||
size = RT_ALIGN(sizeof(struct mem_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE;
|
||||
size = TEST_MEM_SIZE / size;
|
||||
/* init */
|
||||
head.ctx_tab = RT_NULL;
|
||||
head.count = size;
|
||||
head.start = rt_tick_get();
|
||||
head.end = rt_tick_get() + rt_tick_from_millisecond(MEM_RANG_ALLOC_TEST_TIME * 1000);
|
||||
head.interval = (head.end - head.start) / 20;
|
||||
buf = rt_malloc(TEST_MEM_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_MEM_SIZE);
|
||||
heap = (struct rt_small_mem *)rt_smem_init("mem_tc", buf, TEST_MEM_SIZE);
|
||||
total_size = max_block(heap);
|
||||
uassert_int_not_equal(total_size, 0);
|
||||
/* init ctx tab */
|
||||
size = head.count * sizeof(struct mem_realloc_context *);
|
||||
head.ctx_tab = rt_smem_alloc(&heap->parent, size);
|
||||
uassert_not_null(head.ctx_tab);
|
||||
rt_memset(head.ctx_tab, 0, size);
|
||||
/* test run */
|
||||
while (head.end - head.start < RT_TICK_MAX / 2)
|
||||
{
|
||||
if (rt_tick_get() - head.start >= head.interval)
|
||||
{
|
||||
head.start = rt_tick_get();
|
||||
rt_kprintf("#");
|
||||
}
|
||||
size = rand() % MEM_RANG_ALLOC_BLK_MAX + MEM_RANG_ALLOC_BLK_MIN;
|
||||
size *= sizeof(struct mem_realloc_context);
|
||||
idx = rand() % head.count;
|
||||
ctx = rt_smem_realloc(&heap->parent, head.ctx_tab[idx], size);
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
if (head.ctx_tab[idx])
|
||||
{
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (idx = 0; idx < head.count; idx++)
|
||||
{
|
||||
ctx = head.ctx_tab[idx];
|
||||
if (rand() % 2 && ctx)
|
||||
{
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_realloc(&heap->parent, ctx, 0);
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* check mem */
|
||||
if (head.ctx_tab[idx] != RT_NULL)
|
||||
{
|
||||
res = 0;
|
||||
if (ctx->size < size)
|
||||
{
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
/* init mem */
|
||||
ctx->magic = rand() & 0xff;
|
||||
ctx->size = size;
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
head.ctx_tab[idx] = ctx;
|
||||
}
|
||||
/* free all mem */
|
||||
for (idx = 0; idx < head.count; idx++)
|
||||
{
|
||||
ctx = head.ctx_tab[idx];
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_smem_realloc(&heap->parent, ctx, 0);
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
uassert_int_not_equal(max_block(heap), total_size);
|
||||
/* small heap deinit */
|
||||
rt_smem_detach(&heap->parent);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(mem_functional_test);
|
||||
UTEST_UNIT_RUN(mem_alloc_test);
|
||||
UTEST_UNIT_RUN(mem_realloc_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.mem_tc", utest_tc_init, utest_tc_cleanup, 20);
|
||||
97
RT_Thread/examples/utest/testcases/kernel/memheap_tc.c
Normal file
97
RT_Thread/examples/utest/testcases/kernel/memheap_tc.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-01-16 flybreak the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define HEAP_SIZE (64 * 1024)
|
||||
#define HEAP_ALIGN (4)
|
||||
#define SLICE_NUM (40)
|
||||
#define TEST_TIMES (100000)
|
||||
#define HEAP_NAME "heap1"
|
||||
#define SLICE_SIZE_MAX (HEAP_SIZE/SLICE_NUM)
|
||||
|
||||
static void memheap_test(void)
|
||||
{
|
||||
struct rt_memheap heap1;
|
||||
void * ptr_start;
|
||||
void *ptr[SLICE_NUM];
|
||||
int i, cnt = 0;
|
||||
|
||||
/* init heap */
|
||||
ptr_start = rt_malloc_align(HEAP_SIZE, HEAP_ALIGN);
|
||||
if (ptr_start == RT_NULL)
|
||||
{
|
||||
rt_kprintf("totle size too big,can not malloc memory!");
|
||||
return;
|
||||
}
|
||||
|
||||
rt_memheap_init(&heap1, HEAP_NAME, ptr_start, HEAP_SIZE);
|
||||
|
||||
/* test start */
|
||||
for (i = 0; i < SLICE_NUM; i++)
|
||||
{
|
||||
ptr[i] = 0;
|
||||
}
|
||||
/* test alloc */
|
||||
for (i = 0; i < SLICE_NUM; i++)
|
||||
{
|
||||
rt_uint32_t slice_size = rand() % SLICE_SIZE_MAX;
|
||||
ptr[i] = rt_memheap_alloc(&heap1, slice_size);
|
||||
}
|
||||
/* test realloc */
|
||||
while (cnt < TEST_TIMES)
|
||||
{
|
||||
rt_uint32_t slice_size = rand() % SLICE_SIZE_MAX;
|
||||
rt_uint32_t ptr_index = rand() % SLICE_NUM;
|
||||
rt_uint32_t operation = rand() % 2;
|
||||
|
||||
if (ptr[ptr_index])
|
||||
{
|
||||
if (operation == 0) /* free and malloc */
|
||||
{
|
||||
rt_memheap_free(ptr[ptr_index]);
|
||||
ptr[ptr_index] = rt_memheap_alloc(&heap1, slice_size);
|
||||
}
|
||||
else /* realloc */
|
||||
{
|
||||
ptr[ptr_index] = rt_memheap_realloc(&heap1, ptr[ptr_index], slice_size);
|
||||
}
|
||||
}
|
||||
cnt ++;
|
||||
if (cnt % (TEST_TIMES / 10) == 0)
|
||||
{
|
||||
rt_kprintf(">");
|
||||
}
|
||||
}
|
||||
|
||||
rt_kprintf("test OK!\n");
|
||||
|
||||
/* test end */
|
||||
rt_memheap_detach(&heap1);
|
||||
rt_free_align((void *)ptr_start);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(memheap_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.memheap_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
234
RT_Thread/examples/utest/testcases/kernel/messagequeue_tc.c
Normal file
234
RT_Thread/examples/utest/testcases/kernel/messagequeue_tc.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-28 Sherman the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
* fix in smp
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define THREAD_STACKSIZE UTEST_THR_STACK_SIZE
|
||||
|
||||
#define MSG_SIZE 4
|
||||
#define MAX_MSGS 5
|
||||
|
||||
static struct rt_messagequeue static_mq;
|
||||
static rt_uint8_t mq_buf[RT_MQ_BUF_SIZE(MSG_SIZE, MAX_MSGS)];
|
||||
|
||||
static struct rt_thread mq_send_thread;
|
||||
static struct rt_thread mq_recv_thread;
|
||||
static rt_uint8_t mq_send_stack[UTEST_THR_STACK_SIZE];
|
||||
static rt_uint8_t mq_recv_stack[UTEST_THR_STACK_SIZE];
|
||||
|
||||
static struct rt_event finish_e;
|
||||
#define MQSEND_FINISH 0x01
|
||||
#define MQRECV_FINIHS 0x02
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
static rt_mq_t dynamic_mq;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
static void test_mq_init(void)
|
||||
{
|
||||
rt_err_t ret;
|
||||
ret = rt_mq_init(&static_mq,"testmq1", mq_buf, MSG_SIZE, sizeof(mq_buf), RT_IPC_FLAG_FIFO);
|
||||
uassert_true(ret == RT_EOK);
|
||||
}
|
||||
|
||||
static void test_mq_create(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_mq = rt_mq_create("testmq2", MSG_SIZE, MAX_MSGS, RT_IPC_FLAG_FIFO);
|
||||
uassert_true(dynamic_mq != RT_NULL);
|
||||
#endif /* RT_USING_HEAP */
|
||||
}
|
||||
|
||||
static void mq_send_case(rt_mq_t testmq)
|
||||
{
|
||||
rt_uint32_t send_buf[MAX_MSGS+1] = {0};
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
for (int var = 0; var < MAX_MSGS; ++var)
|
||||
{
|
||||
send_buf[var] = var + 1;
|
||||
ret = rt_mq_send_wait(testmq, &send_buf[var], sizeof(send_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
}
|
||||
send_buf[MAX_MSGS] = MAX_MSGS + 1;
|
||||
ret = rt_mq_send(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]));
|
||||
uassert_true(ret == -RT_EFULL);
|
||||
|
||||
ret = rt_mq_send_wait(testmq, &send_buf[MAX_MSGS], sizeof(send_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
while (testmq->entry != 0)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
|
||||
ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
ret = rt_mq_send(testmq, &send_buf[2], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
ret = rt_mq_urgent(testmq, &send_buf[0], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
while (testmq->entry != 0)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_MESSAGEQUEUE_PRIORITY
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[3], sizeof(send_buf[0]), 3, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[0], sizeof(send_buf[0]), 0, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[2], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[4], sizeof(send_buf[0]), 4, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_send_wait_prio(testmq, &send_buf[1], sizeof(send_buf[0]), 1, 0, RT_UNINTERRUPTIBLE);
|
||||
uassert_true(ret == RT_EOK);
|
||||
|
||||
while (testmq->entry != 0)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = rt_mq_send(testmq, &send_buf[1], sizeof(send_buf[0]));
|
||||
uassert_true(ret == RT_EOK);
|
||||
ret = rt_mq_control(testmq, RT_IPC_CMD_RESET, RT_NULL);
|
||||
uassert_true(ret == RT_EOK);
|
||||
uassert_true(testmq->entry == 0);
|
||||
}
|
||||
|
||||
static void mq_send_entry(void *param)
|
||||
{
|
||||
mq_send_case(&static_mq);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
if(dynamic_mq != RT_NULL)
|
||||
{
|
||||
mq_send_case(dynamic_mq);
|
||||
}
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
rt_event_send(&finish_e, MQSEND_FINISH);
|
||||
}
|
||||
|
||||
static void mq_recv_case(rt_mq_t testmq)
|
||||
{
|
||||
rt_uint32_t recv_buf[MAX_MSGS+1] = {0};
|
||||
rt_ssize_t ret = RT_EOK;
|
||||
|
||||
for (int var = 0; var < MAX_MSGS + 1; ++var)
|
||||
{
|
||||
ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret >= 0);
|
||||
uassert_true(recv_buf[var] == (var + 1));
|
||||
}
|
||||
|
||||
for (int var = 0; var < 3; ++var)
|
||||
{
|
||||
ret = rt_mq_recv(testmq, &recv_buf[var], sizeof(recv_buf[0]), RT_WAITING_FOREVER);
|
||||
uassert_true(ret >= 0);
|
||||
uassert_true(recv_buf[var] == (var + 1));
|
||||
}
|
||||
#ifdef RT_USING_MESSAGEQUEUE_PRIORITY
|
||||
rt_int32_t msg_prio;
|
||||
while (testmq->entry == MAX_MSGS)
|
||||
{
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
for (int var = 0; var < MAX_MSGS; ++var)
|
||||
{
|
||||
ret = rt_mq_recv_prio(testmq, &recv_buf[var], sizeof(recv_buf[0]), &msg_prio, RT_WAITING_FOREVER, RT_UNINTERRUPTIBLE);
|
||||
rt_kprintf("msg_prio = %d\r\n", msg_prio);
|
||||
uassert_true(ret >= 0);
|
||||
uassert_true(recv_buf[var] == (MAX_MSGS - var));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mq_recv_entry(void *param)
|
||||
{
|
||||
mq_recv_case(&static_mq);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
if(dynamic_mq != RT_NULL)
|
||||
{
|
||||
mq_recv_case(dynamic_mq);
|
||||
}
|
||||
#endif /* RT_USING_HEAP */
|
||||
rt_event_send(&finish_e, MQRECV_FINIHS);
|
||||
}
|
||||
|
||||
static void test_mq_testcase(void)
|
||||
{
|
||||
rt_thread_startup(&mq_send_thread);
|
||||
rt_thread_startup(&mq_recv_thread);
|
||||
|
||||
rt_event_recv(&finish_e, MQSEND_FINISH | MQRECV_FINIHS, RT_EVENT_FLAG_AND, RT_WAITING_FOREVER, RT_NULL);
|
||||
}
|
||||
|
||||
static void test_mq_detach(void)
|
||||
{
|
||||
rt_err_t ret = rt_mq_detach(&static_mq);
|
||||
uassert_true(ret == RT_EOK);
|
||||
}
|
||||
|
||||
static void test_mq_delete(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_err_t ret = rt_mq_delete(dynamic_mq);
|
||||
uassert_true(ret == RT_EOK);
|
||||
#endif /* RT_USING_HEAP */
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_err_t ret ;
|
||||
ret = rt_thread_init(&mq_send_thread, "mq_send", mq_send_entry, RT_NULL, mq_send_stack, sizeof(mq_send_stack), 22, 20);
|
||||
if(ret != RT_EOK)
|
||||
return -RT_ERROR;
|
||||
|
||||
ret = rt_thread_init(&mq_recv_thread, "mq_recv", mq_recv_entry, RT_NULL, mq_recv_stack, sizeof(mq_recv_stack), 23, 20);
|
||||
if(ret != RT_EOK)
|
||||
return -RT_ERROR;
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
rt_thread_control(&mq_send_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
|
||||
rt_thread_control(&mq_recv_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
|
||||
#endif
|
||||
|
||||
ret = rt_event_init(&finish_e, "finish", RT_IPC_FLAG_FIFO);
|
||||
if(ret != RT_EOK)
|
||||
return -RT_ERROR;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_mq_init);
|
||||
UTEST_UNIT_RUN(test_mq_create);
|
||||
UTEST_UNIT_RUN(test_mq_testcase);
|
||||
UTEST_UNIT_RUN(test_mq_detach);
|
||||
UTEST_UNIT_RUN(test_mq_delete);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.messagequeue_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
68
RT_Thread/examples/utest/testcases/kernel/mtsafe_kprint_tc.c
Normal file
68
RT_Thread/examples/utest/testcases/kernel/mtsafe_kprint_tc.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-12-25 Shell the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_LOOP_TIMES 20
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
|
||||
static void _thread_entry(void *param)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
rt_kprintf("This is thread %p\n", rt_thread_self());
|
||||
rt_thread_mdelay(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
#define TEST_THREAD_COUNT 16
|
||||
|
||||
static void mtsafe_kprint_tc(void)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_thread_t new_thread =
|
||||
rt_thread_create(
|
||||
"test",
|
||||
_thread_entry,
|
||||
NULL,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY,
|
||||
100);
|
||||
rt_thread_startup(new_thread);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(mtsafe_kprint_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.mtsafe_kprint", utest_tc_init, utest_tc_cleanup, 10);
|
||||
353
RT_Thread/examples/utest/testcases/kernel/mutex_pi_tc.c
Normal file
353
RT_Thread/examples/utest/testcases/kernel/mutex_pi_tc.c
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
#define THREAD_STACKSIZE 8192
|
||||
#else
|
||||
#define THREAD_STACKSIZE 4096
|
||||
#endif
|
||||
|
||||
#define MUTEX_NUM 3
|
||||
#define THREAD_NUM 5
|
||||
|
||||
static struct rt_mutex _mutex[MUTEX_NUM];
|
||||
static volatile int _sync_flag;
|
||||
|
||||
static void test_thread_entry(void *para)
|
||||
{
|
||||
while (!_sync_flag)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
rt_ubase_t thread_id = (rt_ubase_t)para;
|
||||
rt_err_t ret;
|
||||
rt_thread_mdelay(50 + thread_id * 100);
|
||||
ret = rt_mutex_take(&_mutex[thread_id % MUTEX_NUM], RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == RT_SCHED_PRIV(rt_thread_self()).init_priority);
|
||||
|
||||
if (thread_id == 1)
|
||||
{
|
||||
rt_thread_mdelay(100); // wait for main thread re-get _mutex[1]
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
|
||||
}
|
||||
|
||||
ret = rt_mutex_release(&_mutex[thread_id % MUTEX_NUM]);
|
||||
uassert_true(ret == RT_EOK);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == RT_SCHED_PRIV(rt_thread_self()).init_priority);
|
||||
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void test_main_thread_entry(void *para)
|
||||
{
|
||||
while (!_sync_flag)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
}
|
||||
|
||||
rt_err_t ret;
|
||||
|
||||
ret = rt_mutex_take(&_mutex[0], RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
|
||||
rt_thread_mdelay(100); // wait for t0 take mutex0
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
|
||||
|
||||
ret = rt_mutex_take(&_mutex[1], RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
|
||||
rt_thread_mdelay(100); // wait for t1 take mutex1
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 9);
|
||||
|
||||
ret = rt_mutex_take(&_mutex[2], RT_WAITING_FOREVER);
|
||||
uassert_true(ret == RT_EOK);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 9);
|
||||
rt_thread_mdelay(100); // wait for t2 take mutex2
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
|
||||
|
||||
rt_thread_mdelay(100); // wait for t3 take mutex0
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 7);
|
||||
|
||||
rt_thread_mdelay(100); // wait for t4 take mutex1
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 7);
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
rt_mutex_release(&_mutex[0]); // give _mutex0 to t3
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
rt_mutex_release(&_mutex[1]); // give _mutex1 to t1
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
|
||||
|
||||
rt_thread_mdelay(50);
|
||||
rt_mutex_take(&_mutex[1], RT_WAITING_FOREVER); // re-get _mutex1, which is hold by t1
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
|
||||
rt_mutex_release(&_mutex[1]); // give _mutex1 to thread t1
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 8);
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
rt_mutex_release(&_mutex[2]);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
|
||||
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void test_mutex_pi(void)
|
||||
{
|
||||
rt_thread_t t_main;
|
||||
rt_thread_t t[THREAD_NUM];
|
||||
rt_uint8_t prio[THREAD_NUM] = {13, 9, 8, 7, 11}; // prio of threads
|
||||
|
||||
for (int i = 0; i < MUTEX_NUM; i++)
|
||||
{
|
||||
rt_mutex_init(&_mutex[i], "test1", 0);
|
||||
}
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
t_main = rt_thread_create("t_main", test_main_thread_entry, RT_NULL, THREAD_STACKSIZE, 12, 10000);
|
||||
uassert_true(t_main != RT_NULL);
|
||||
rt_thread_startup(t_main);
|
||||
|
||||
for (rt_ubase_t i = 0; i < THREAD_NUM; i++)
|
||||
{
|
||||
t[i] = rt_thread_create("t", test_thread_entry, (void *)i, THREAD_STACKSIZE, prio[i], 10000);
|
||||
uassert_true(t[i] != RT_NULL);
|
||||
rt_thread_startup(t[i]);
|
||||
}
|
||||
|
||||
_sync_flag = 1;
|
||||
|
||||
while (_sync_flag != THREAD_NUM + 1 + 1)
|
||||
{
|
||||
rt_thread_mdelay(100);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MUTEX_NUM; i++)
|
||||
{
|
||||
rt_mutex_detach(&_mutex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static struct rt_mutex _timeout_mutex;
|
||||
|
||||
static void test_main_timeout_entry(void *para)
|
||||
{
|
||||
rt_err_t ret;
|
||||
|
||||
ret = rt_mutex_take(&_timeout_mutex, RT_WAITING_FOREVER);
|
||||
uassert_true(ret == -RT_EOK);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 10);
|
||||
rt_thread_mdelay(100);
|
||||
uassert_true(RT_SCHED_PRIV(rt_thread_self()).current_priority == 12);
|
||||
rt_mutex_release(&_timeout_mutex);
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void test_timeout_entry(void *para)
|
||||
{
|
||||
rt_err_t ret;
|
||||
|
||||
rt_thread_mdelay(50);
|
||||
ret = rt_mutex_take(&_timeout_mutex, rt_tick_from_millisecond(100));
|
||||
uassert_true(ret == -RT_ETIMEOUT);
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void test_mutex_pi_timeout(void)
|
||||
{
|
||||
_sync_flag = 0;
|
||||
|
||||
rt_mutex_init(&_timeout_mutex, "_timeout_mutex", 0);
|
||||
|
||||
rt_thread_t t1 = rt_thread_create("t1", test_main_timeout_entry, RT_NULL, THREAD_STACKSIZE, 12, 10000);
|
||||
uassert_true(t1 != RT_NULL);
|
||||
rt_thread_startup(t1);
|
||||
|
||||
rt_thread_t t2 = rt_thread_create("t2", test_timeout_entry, (void *)t1, THREAD_STACKSIZE, 10, 10000);
|
||||
uassert_true(t2 != RT_NULL);
|
||||
rt_thread_startup(t2);
|
||||
|
||||
while (_sync_flag != 2)
|
||||
{
|
||||
rt_thread_mdelay(100);
|
||||
}
|
||||
|
||||
rt_mutex_detach(&_timeout_mutex);
|
||||
}
|
||||
|
||||
#define TC_THREAD_NUM 4
|
||||
#define TC_MUTEX_NUM TC_THREAD_NUM
|
||||
static rt_thread_t t[TC_THREAD_NUM], t_hi_prio;
|
||||
static struct rt_mutex m[TC_MUTEX_NUM];
|
||||
|
||||
static void test_recursive_mutex_depend_entry(void *para)
|
||||
{
|
||||
rt_ubase_t id = (rt_ubase_t)para;
|
||||
|
||||
rt_mutex_take(&m[id], RT_WAITING_FOREVER);
|
||||
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
if (id != 0)
|
||||
{
|
||||
rt_mutex_take(&m[id - 1], RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
{
|
||||
rt_thread_mdelay(250);
|
||||
rt_mutex_release(&m[id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_mutex_release(&m[id - 1]);
|
||||
rt_mutex_release(&m[id]);
|
||||
}
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void test_recursive_mutex_depend_hi_pri_entry(void *para)
|
||||
{
|
||||
rt_thread_mdelay(100);
|
||||
rt_err_t err = rt_mutex_take(&m[TC_MUTEX_NUM - 1], rt_tick_from_millisecond(100));
|
||||
uassert_true(err == -RT_ETIMEOUT);
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void test_mutex_pi_recursive_prio_update(void)
|
||||
{
|
||||
_sync_flag = 0;
|
||||
|
||||
for (int i = 0; i < TC_MUTEX_NUM; i++)
|
||||
{
|
||||
rt_mutex_init(&m[i], "test", 0);
|
||||
}
|
||||
|
||||
for (rt_ubase_t i = 0; i < TC_THREAD_NUM; i++)
|
||||
{
|
||||
t[i] = rt_thread_create("t", test_recursive_mutex_depend_entry, (void *)i, THREAD_STACKSIZE, 10, 10000);
|
||||
rt_thread_startup(t[i]);
|
||||
}
|
||||
t_hi_prio = rt_thread_create("t", test_recursive_mutex_depend_hi_pri_entry, (void *)RT_NULL, THREAD_STACKSIZE, 3, 10000);
|
||||
rt_thread_startup(t_hi_prio);
|
||||
|
||||
rt_thread_mdelay(150);
|
||||
|
||||
for (int i = 0; i < TC_THREAD_NUM; i++)
|
||||
{
|
||||
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 3);
|
||||
}
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
for (int i = 0; i < TC_THREAD_NUM; i++)
|
||||
{
|
||||
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 10);
|
||||
}
|
||||
|
||||
while (_sync_flag != TC_THREAD_NUM + 1)
|
||||
{
|
||||
rt_thread_mdelay(100);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TC_MUTEX_NUM; i++)
|
||||
{
|
||||
rt_mutex_detach(&m[i]);
|
||||
}
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void test_mutex_waiter_to_wakeup_entry(void *para)
|
||||
{
|
||||
rt_thread_mdelay(100);
|
||||
rt_err_t err = rt_mutex_take(&m[TC_MUTEX_NUM - 1], RT_WAITING_FOREVER);
|
||||
uassert_true(err == -RT_EINTR);
|
||||
_sync_flag ++;
|
||||
}
|
||||
|
||||
static void wakeup_func(void *para)
|
||||
{
|
||||
rt_thread_resume(t_hi_prio);
|
||||
}
|
||||
static void test_mutex_pi_wakeup_mutex_waiter(void)
|
||||
{
|
||||
struct rt_timer wakeup_timer;
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
for (int i = 0; i < TC_MUTEX_NUM; i++)
|
||||
{
|
||||
rt_mutex_init(&m[i], "test", 0);
|
||||
}
|
||||
|
||||
for (rt_ubase_t i = 0; i < TC_THREAD_NUM; i++)
|
||||
{
|
||||
t[i] = rt_thread_create("t", test_recursive_mutex_depend_entry, (void *)i, THREAD_STACKSIZE, 10, 10000);
|
||||
rt_thread_startup(t[i]);
|
||||
}
|
||||
t_hi_prio = rt_thread_create("t", test_mutex_waiter_to_wakeup_entry, (void *)RT_NULL, THREAD_STACKSIZE, 3, 10000);
|
||||
rt_thread_startup(t_hi_prio);
|
||||
|
||||
rt_timer_init(&wakeup_timer, "wakeup_timer", wakeup_func, RT_NULL, rt_tick_from_millisecond(200), RT_TIMER_FLAG_ONE_SHOT);
|
||||
rt_timer_start(&wakeup_timer);
|
||||
rt_thread_mdelay(150);
|
||||
|
||||
for (int i = 0; i < TC_THREAD_NUM; i++)
|
||||
{
|
||||
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 3);
|
||||
}
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
for (int i = 0; i < TC_THREAD_NUM; i++)
|
||||
{
|
||||
uassert_true(RT_SCHED_PRIV(t[i]).current_priority == 10);
|
||||
}
|
||||
|
||||
while (_sync_flag != TC_THREAD_NUM + 1)
|
||||
{
|
||||
rt_thread_mdelay(100);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TC_MUTEX_NUM; i++)
|
||||
{
|
||||
rt_mutex_detach(&m[i]);
|
||||
}
|
||||
rt_timer_detach(&wakeup_timer);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_mutex_pi);
|
||||
UTEST_UNIT_RUN(test_mutex_pi_recursive_prio_update);
|
||||
UTEST_UNIT_RUN(test_mutex_pi_timeout);
|
||||
UTEST_UNIT_RUN(test_mutex_pi_wakeup_mutex_waiter);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.mutex_pi_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
|
||||
/********************* end of file ************************/
|
||||
798
RT_Thread/examples/utest/testcases/kernel/mutex_tc.c
Normal file
798
RT_Thread/examples/utest/testcases/kernel/mutex_tc.c
Normal file
@ -0,0 +1,798 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-09.01 luckyzjq the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
#define THREAD_STACKSIZE 8192
|
||||
#else
|
||||
#define THREAD_STACKSIZE 4096
|
||||
#endif
|
||||
|
||||
static struct rt_mutex static_mutex;
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
static rt_mutex_t dynamic_mutex;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
static volatile int _sync_flag;
|
||||
|
||||
/* init test */
|
||||
static void test_static_mutex_init(void)
|
||||
{
|
||||
rt_err_t result = -RT_ERROR;
|
||||
|
||||
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
result = rt_mutex_detach(&static_mutex);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
result = rt_mutex_detach(&static_mutex);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* static take test */
|
||||
static void static_mutex_take_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex;
|
||||
|
||||
int rand_num = rand() % 0x1000;
|
||||
mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_take(mutex, rand_num);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
|
||||
static void test_static_mutex_take(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* take mutex and not release */
|
||||
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
rt_thread_t tid = rt_thread_create("mutex_th",
|
||||
static_mutex_take_entry,
|
||||
&static_mutex,
|
||||
THREAD_STACKSIZE,
|
||||
10,
|
||||
10);
|
||||
if (RT_NULL == tid)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* startup thread take second */
|
||||
rt_thread_startup(tid);
|
||||
|
||||
while (_sync_flag != 1)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_detach(&static_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* static release test */
|
||||
static void static_mutex_release_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex;
|
||||
|
||||
int rand_num = rand() % 0x1000;
|
||||
mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_take(mutex, rand_num);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
static void test_static_mutex_release(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
result = rt_mutex_release(&static_mutex);
|
||||
uassert_true(result < 0);
|
||||
|
||||
/* take mutex */
|
||||
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
/* release mutex */
|
||||
result = rt_mutex_release(&static_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
rt_thread_t tid = rt_thread_create("mutex_th",
|
||||
static_mutex_release_entry,
|
||||
&static_mutex,
|
||||
THREAD_STACKSIZE,
|
||||
10,
|
||||
10);
|
||||
if (RT_NULL == tid)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* startup thread and take mutex second */
|
||||
rt_thread_startup(tid);
|
||||
|
||||
while (_sync_flag != 1)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_detach(&static_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* static trytake test */
|
||||
static void static_mutex_trytake_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex;
|
||||
|
||||
mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_trytake(mutex);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
static void test_static_mutex_trytake(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* take mutex and not release */
|
||||
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
rt_thread_t tid = rt_thread_create("mutex_th",
|
||||
static_mutex_trytake_entry,
|
||||
&static_mutex,
|
||||
THREAD_STACKSIZE,
|
||||
10,
|
||||
10);
|
||||
if (RT_NULL == tid)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* startup thread and trytake mutex second */
|
||||
rt_thread_startup(tid);
|
||||
|
||||
while (_sync_flag != 1)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_detach(&static_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static rt_thread_t tid1 = RT_NULL;
|
||||
static rt_thread_t tid2 = RT_NULL;
|
||||
static rt_thread_t tid3 = RT_NULL;
|
||||
|
||||
/* static mutex priority reverse test */
|
||||
static void static_thread1_entry(void *param)
|
||||
{
|
||||
/* let system schedule */
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
/* thread3 hode mutex thread2 take mutex */
|
||||
/* check thread2 and thread3 priority */
|
||||
if (RT_SCHED_PRIV(tid2).current_priority != RT_SCHED_PRIV(tid3).current_priority)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
|
||||
static void static_thread2_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex = (rt_mutex_t)param;
|
||||
|
||||
/* let system schedule */
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
rt_mutex_release(mutex);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
static void static_thread3_entry(void *param)
|
||||
{
|
||||
rt_tick_t tick;
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
tick = rt_tick_get();
|
||||
while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2));
|
||||
|
||||
rt_mutex_release(mutex);
|
||||
_sync_flag++;
|
||||
}
|
||||
|
||||
static void test_static_pri_reverse(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
tid1 = RT_NULL;
|
||||
tid2 = RT_NULL;
|
||||
tid3 = RT_NULL;
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* thread1 */
|
||||
tid1 = rt_thread_create("thread1",
|
||||
static_thread1_entry,
|
||||
&static_mutex,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
10 - 1,
|
||||
10);
|
||||
if (tid1 != RT_NULL)
|
||||
rt_thread_startup(tid1);
|
||||
|
||||
/* thread2 */
|
||||
tid2 = rt_thread_create("thread2",
|
||||
static_thread2_entry,
|
||||
&static_mutex,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
10,
|
||||
10);
|
||||
if (tid2 != RT_NULL)
|
||||
rt_thread_startup(tid2);
|
||||
|
||||
/* thread3 */
|
||||
tid3 = rt_thread_create("thread3",
|
||||
static_thread3_entry,
|
||||
&static_mutex,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
10 + 1,
|
||||
10);
|
||||
if (tid3 != RT_NULL)
|
||||
rt_thread_startup(tid3);
|
||||
|
||||
while (_sync_flag != 3)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_detach(&static_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* create test */
|
||||
static void test_dynamic_mutex_create(void)
|
||||
{
|
||||
rt_err_t result = -RT_ERROR;
|
||||
|
||||
/* PRIO mode */
|
||||
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_mutex)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
result = rt_mutex_delete(dynamic_mutex);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
/* FIFO mode */
|
||||
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_mutex)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
result = rt_mutex_delete(dynamic_mutex);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* dynamic take test */
|
||||
static void dynamic_mutex_take_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex;
|
||||
|
||||
int rand_num = rand() % 0x1000;
|
||||
mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_take(mutex, rand_num);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
|
||||
static void test_dynamic_mutex_take(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_mutex)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* take mutex and not release */
|
||||
result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
rt_thread_t tid = rt_thread_create("mutex_th",
|
||||
dynamic_mutex_take_entry,
|
||||
dynamic_mutex,
|
||||
THREAD_STACKSIZE,
|
||||
10,
|
||||
10);
|
||||
if (RT_NULL == tid)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* startup thread take second */
|
||||
rt_thread_startup(tid);
|
||||
|
||||
while (_sync_flag != 1)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_delete(dynamic_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* dynamic release test */
|
||||
static void dynamic_mutex_release_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex;
|
||||
|
||||
int rand_num = rand() % 0x1000;
|
||||
mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_take(mutex, rand_num);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
static void test_dynamic_mutex_release(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
_sync_flag = 0;
|
||||
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_mutex)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
result = rt_mutex_release(dynamic_mutex);
|
||||
uassert_true(result < 0);
|
||||
|
||||
/* take mutex */
|
||||
result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
/* release mutex */
|
||||
result = rt_mutex_release(dynamic_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
rt_thread_t tid = rt_thread_create("mutex_th",
|
||||
dynamic_mutex_release_entry,
|
||||
dynamic_mutex,
|
||||
THREAD_STACKSIZE,
|
||||
10,
|
||||
10);
|
||||
if (RT_NULL == tid)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* startup thread and take mutex second */
|
||||
rt_thread_startup(tid);
|
||||
|
||||
while (_sync_flag != 1)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_delete(dynamic_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* dynamic trytake test */
|
||||
static void dynamic_mutex_trytake_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex;
|
||||
|
||||
mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_trytake(mutex);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
static void test_dynamic_mutex_trytake(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
_sync_flag = 0;
|
||||
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_mutex)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* take mutex and not release */
|
||||
result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
rt_thread_t tid = rt_thread_create("mutex_th",
|
||||
dynamic_mutex_trytake_entry,
|
||||
dynamic_mutex,
|
||||
THREAD_STACKSIZE,
|
||||
10,
|
||||
10);
|
||||
if (RT_NULL == tid)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* startup thread and trytake mutex second */
|
||||
rt_thread_startup(tid);
|
||||
|
||||
while (_sync_flag != 1)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_delete(dynamic_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
/* dynamic mutex priority reverse test */
|
||||
static void dynamic_thread1_entry(void *param)
|
||||
{
|
||||
/* let system schedule */
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
/* thread3 hode mutex thread2 take mutex */
|
||||
/* check thread2 and thread3 priority */
|
||||
if (RT_SCHED_PRIV(tid2).current_priority != RT_SCHED_PRIV(tid3).current_priority)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
|
||||
static void dynamic_thread2_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex = (rt_mutex_t)param;
|
||||
|
||||
/* let system schedule */
|
||||
rt_thread_mdelay(50);
|
||||
|
||||
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
if (result == RT_EOK)
|
||||
{
|
||||
rt_mutex_release(mutex);
|
||||
}
|
||||
_sync_flag++;
|
||||
}
|
||||
static void dynamic_thread3_entry(void *param)
|
||||
{
|
||||
rt_tick_t tick;
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
tick = rt_tick_get();
|
||||
while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2));
|
||||
|
||||
rt_mutex_release(mutex);
|
||||
_sync_flag++;
|
||||
}
|
||||
|
||||
static void test_dynamic_pri_reverse(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
tid1 = RT_NULL;
|
||||
tid2 = RT_NULL;
|
||||
tid3 = RT_NULL;
|
||||
|
||||
_sync_flag = 0;
|
||||
dynamic_mutex = rt_mutex_create("dynamic_mutex", RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_mutex)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* thread1 */
|
||||
tid1 = rt_thread_create("thread1",
|
||||
dynamic_thread1_entry,
|
||||
dynamic_mutex,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
10 - 1,
|
||||
10);
|
||||
if (tid1 != RT_NULL)
|
||||
rt_thread_startup(tid1);
|
||||
|
||||
/* thread2 */
|
||||
tid2 = rt_thread_create("thread2",
|
||||
dynamic_thread2_entry,
|
||||
dynamic_mutex,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
10,
|
||||
10);
|
||||
if (tid2 != RT_NULL)
|
||||
rt_thread_startup(tid2);
|
||||
|
||||
/* thread3 */
|
||||
tid3 = rt_thread_create("thread3",
|
||||
dynamic_thread3_entry,
|
||||
dynamic_mutex,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
10 + 1,
|
||||
10);
|
||||
if (tid3 != RT_NULL)
|
||||
rt_thread_startup(tid3);
|
||||
|
||||
while (_sync_flag != 3)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_delete(dynamic_mutex);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static void recursive_lock_test_entry(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_mutex_t mutex = (rt_mutex_t)param;
|
||||
|
||||
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
uassert_true(result == RT_EOK);
|
||||
uassert_true(_sync_flag == 0);
|
||||
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
uassert_true(result == RT_EOK);
|
||||
_sync_flag++;
|
||||
}
|
||||
|
||||
static void test_recurse_lock(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
_sync_flag = 0;
|
||||
result = rt_mutex_init(&static_mutex, "static_mutex", RT_IPC_FLAG_PRIO);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* take mutex and not release */
|
||||
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* take mutex twice */
|
||||
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
rt_thread_t tid = rt_thread_create("mutex_th",
|
||||
recursive_lock_test_entry,
|
||||
&static_mutex,
|
||||
THREAD_STACKSIZE,
|
||||
10,
|
||||
10);
|
||||
_sync_flag = -1;
|
||||
|
||||
if (tid != RT_NULL)
|
||||
rt_thread_startup(tid);
|
||||
|
||||
result = rt_mutex_release(&static_mutex);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
_sync_flag = 0;
|
||||
|
||||
result = rt_mutex_release(&static_mutex);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
while (_sync_flag != 1)
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
result = rt_mutex_detach(&static_mutex);
|
||||
uassert_true(result == RT_EOK);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_mutex = RT_NULL;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_mutex = RT_NULL;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_static_mutex_init);
|
||||
UTEST_UNIT_RUN(test_static_mutex_take);
|
||||
UTEST_UNIT_RUN(test_static_mutex_release);
|
||||
UTEST_UNIT_RUN(test_static_mutex_trytake);
|
||||
UTEST_UNIT_RUN(test_static_pri_reverse);
|
||||
#ifdef RT_USING_HEAP
|
||||
UTEST_UNIT_RUN(test_dynamic_mutex_create);
|
||||
UTEST_UNIT_RUN(test_dynamic_mutex_take);
|
||||
UTEST_UNIT_RUN(test_dynamic_mutex_release);
|
||||
UTEST_UNIT_RUN(test_dynamic_mutex_trytake);
|
||||
UTEST_UNIT_RUN(test_dynamic_pri_reverse);
|
||||
#endif
|
||||
UTEST_UNIT_RUN(test_recurse_lock);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.mutex_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
|
||||
/********************* end of file ************************/
|
||||
107
RT_Thread/examples/utest/testcases/kernel/sched_mtx_tc.c
Normal file
107
RT_Thread/examples/utest/testcases/kernel/sched_mtx_tc.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-17 Shell the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
/**
|
||||
* Stressful Test for Mutex
|
||||
*/
|
||||
|
||||
#define TEST_SECONDS 30
|
||||
#define TEST_LOOP_TICKS (TEST_SECONDS * RT_TICK_PER_SECOND)
|
||||
#define TEST_THREAD_COUNTS (RT_CPUS_NR)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TICKS/TEST_PROGRESS_COUNTS)
|
||||
#define TEST_PRIORITY_HIGHEST (UTEST_THR_PRIORITY+1)
|
||||
#define TEST_RANDOM_LATENCY_MAX (1000 * 1000)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static rt_atomic_t _exit_flag;
|
||||
static struct rt_mutex _racing_lock;
|
||||
|
||||
static void test_thread_entry(void *param)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
rt_mutex_take(&_racing_lock, RT_WAITING_FOREVER);
|
||||
rt_mutex_release(&_racing_lock);
|
||||
|
||||
if (rt_atomic_load(&_exit_flag))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void mutex_stress_tc(void)
|
||||
{
|
||||
rt_err_t error;
|
||||
rt_thread_t tester;
|
||||
const rt_base_t priority_base = TEST_PRIORITY_HIGHEST;
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNTS; i++)
|
||||
{
|
||||
tester = rt_thread_create(
|
||||
"tester",
|
||||
test_thread_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
priority_base + (i % (RT_THREAD_PRIORITY_MAX - TEST_PRIORITY_HIGHEST)),
|
||||
1);
|
||||
|
||||
rt_thread_startup(tester);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
/* trigger exit request for all sub-threads */
|
||||
rt_atomic_store(&_exit_flag, 1);
|
||||
|
||||
/* waiting for sub-threads to exit */
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNTS; i++)
|
||||
{
|
||||
error = rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
uassert_int_equal(error, RT_EOK);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
int *pseed = rt_malloc(sizeof(int));
|
||||
srand(*(int *)pseed);
|
||||
rt_free(pseed);
|
||||
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
rt_mutex_init(&_racing_lock, "ipc", RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
rt_mutex_detach(&_racing_lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(mutex_stress_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.mutex", utest_tc_init, utest_tc_cleanup, TEST_SECONDS);
|
||||
198
RT_Thread/examples/utest/testcases/kernel/sched_sem_tc.c
Normal file
198
RT_Thread/examples/utest/testcases/kernel/sched_sem_tc.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-17 Shell the first version
|
||||
*/
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "rthw.h"
|
||||
#include "utest.h"
|
||||
|
||||
#define KERN_TEST_CONFIG_LOOP_TIMES 160
|
||||
#define KERN_TEST_CONCURRENT_THREADS (RT_CPUS_NR * 2)
|
||||
#define KERN_TEST_CONFIG_HIGHEST_PRIO 3
|
||||
#define KERN_TEST_CONFIG_LOWEST_PRIO (RT_THREAD_PRIORITY_MAX - 2)
|
||||
|
||||
#define TEST_LEVEL_COUNTS (KERN_TEST_CONFIG_LOWEST_PRIO - KERN_TEST_CONFIG_HIGHEST_PRIO + 1)
|
||||
#if TEST_LEVEL_COUNTS <= RT_CPUS_NR
|
||||
#warning for the best of this test, TEST_LEVEL_COUNTS should greater than RT_CPUS_NR
|
||||
#endif
|
||||
#if KERN_TEST_CONCURRENT_THREADS < RT_CPUS_NR
|
||||
#warning for the best of this test, KERN_TEST_CONCURRENT_THREADS should greater than RT_CPUS_NR
|
||||
#endif
|
||||
#if KERN_TEST_CONFIG_LOWEST_PRIO >= RT_THREAD_PRIORITY_MAX - 1
|
||||
#error the thread priority should at least be greater than idle
|
||||
#endif
|
||||
|
||||
static rt_atomic_t _star_counter;
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static struct rt_semaphore _level_waiting[TEST_LEVEL_COUNTS];
|
||||
static rt_thread_t _thread_matrix[TEST_LEVEL_COUNTS][KERN_TEST_CONCURRENT_THREADS];
|
||||
static rt_atomic_t _load_average[RT_CPUS_NR];
|
||||
|
||||
static void _print_char(rt_thread_t thr_self, int character)
|
||||
{
|
||||
rt_base_t current_counter;
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
rt_kprintf("%c%d", character, RT_SCHED_CTX(thr_self).oncpu);
|
||||
#else
|
||||
rt_kprintf("%c0", character);
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
current_counter = rt_atomic_add(&_star_counter, 1);
|
||||
if (current_counter % 30 == 0)
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void _stats_load_avg_inc(void)
|
||||
{
|
||||
int cpuid;
|
||||
|
||||
cpuid = rt_hw_cpu_id();
|
||||
rt_atomic_add(&_load_average[cpuid], 1);
|
||||
}
|
||||
|
||||
static void _stats_load_avg_print(void)
|
||||
{
|
||||
rt_base_t counts = 0;
|
||||
const rt_base_t total_test_counts = KERN_TEST_CONFIG_LOOP_TIMES * TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS;
|
||||
|
||||
for (size_t i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
rt_kprintf("%ld ", _load_average[i]);
|
||||
counts += _load_average[i];
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
uassert_int_equal(counts, total_test_counts);
|
||||
}
|
||||
|
||||
static void _thread_entry(void *param)
|
||||
{
|
||||
int level = (rt_ubase_t)param;
|
||||
rt_thread_t thr_self = rt_thread_self();
|
||||
|
||||
if (level == 0)
|
||||
{
|
||||
/* always the first to execute among other working threads */
|
||||
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
|
||||
{
|
||||
/* notify our consumer */
|
||||
rt_sem_release(&_level_waiting[level + 1]);
|
||||
|
||||
_stats_load_avg_inc();
|
||||
|
||||
/* waiting for resource of ours */
|
||||
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
else if (level == TEST_LEVEL_COUNTS - 1)
|
||||
{
|
||||
|
||||
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
|
||||
{
|
||||
/* waiting for our resource first */
|
||||
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
|
||||
|
||||
_stats_load_avg_inc();
|
||||
|
||||
_print_char(thr_self, '*');
|
||||
|
||||
rt_thread_delay(1);
|
||||
|
||||
/* produce for level 0 worker */
|
||||
rt_sem_release(&_level_waiting[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
|
||||
{
|
||||
/* waiting for resource of ours */
|
||||
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
|
||||
|
||||
_stats_load_avg_inc();
|
||||
|
||||
/* notify our consumer */
|
||||
rt_sem_release(&_level_waiting[level + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void scheduler_tc(void)
|
||||
{
|
||||
LOG_I("Test starts...");
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
|
||||
{
|
||||
for (size_t j = 0; j < KERN_TEST_CONCURRENT_THREADS; j++)
|
||||
{
|
||||
rt_thread_startup(_thread_matrix[i][j]);
|
||||
}
|
||||
}
|
||||
LOG_I("%d threads startup...", TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS);
|
||||
|
||||
/* waiting for sub-threads to exit */
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
/* print load average */
|
||||
_stats_load_avg_print();
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
LOG_I("Setup environment...");
|
||||
_star_counter = 1;
|
||||
rt_memset(_load_average, 0, sizeof(_load_average));
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
|
||||
{
|
||||
rt_sem_init(&_level_waiting[i], "test", 0, RT_IPC_FLAG_PRIO);
|
||||
|
||||
for (size_t j = 0; j < KERN_TEST_CONCURRENT_THREADS; j++)
|
||||
{
|
||||
_thread_matrix[i][j] =
|
||||
rt_thread_create("test",
|
||||
_thread_entry,
|
||||
(void *)i,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
KERN_TEST_CONFIG_HIGHEST_PRIO+i,
|
||||
5);
|
||||
if (!_thread_matrix[i][j])
|
||||
uassert_not_null(_thread_matrix[i][j]);
|
||||
}
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
|
||||
{
|
||||
rt_sem_detach(&_level_waiting[i]);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(scheduler_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.sem", utest_tc_init, utest_tc_cleanup, 10);
|
||||
121
RT_Thread/examples/utest/testcases/kernel/sched_thread_tc.c
Normal file
121
RT_Thread/examples/utest/testcases/kernel/sched_thread_tc.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-25 Shell init ver.
|
||||
*/
|
||||
#define __RT_KERNEL_SOURCE__
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_LOOP_TIMES (100 * 1000)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_THREAD_COUNT (RT_CPUS_NR * 1)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TIMES*TEST_THREAD_COUNT/TEST_PROGRESS_COUNTS)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static rt_atomic_t _progress_counter;
|
||||
|
||||
static volatile rt_thread_t threads_group[TEST_THREAD_COUNT][2];
|
||||
|
||||
static void _thread_entry1(void *param)
|
||||
{
|
||||
rt_base_t critical_level;
|
||||
size_t idx = (size_t)param;
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
critical_level = rt_enter_critical();
|
||||
|
||||
rt_thread_suspend(rt_thread_self());
|
||||
rt_thread_resume(threads_group[idx][1]);
|
||||
|
||||
rt_exit_critical_safe(critical_level);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _thread_entry2(void *param)
|
||||
{
|
||||
rt_base_t critical_level;
|
||||
size_t idx = (size_t)param;
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
critical_level = rt_enter_critical();
|
||||
|
||||
rt_thread_suspend(rt_thread_self());
|
||||
rt_thread_resume(threads_group[idx][0]);
|
||||
|
||||
rt_exit_critical_safe(critical_level);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void scheduler_tc(void)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_thread_t t1 =
|
||||
rt_thread_create(
|
||||
"t1",
|
||||
_thread_entry1,
|
||||
(void *)i,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
rt_thread_t t2 =
|
||||
rt_thread_create(
|
||||
"t2",
|
||||
_thread_entry2,
|
||||
(void *)i,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
|
||||
threads_group[i][0] = t1;
|
||||
threads_group[i][1] = t2;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_thread_startup(threads_group[i][0]);
|
||||
rt_thread_startup(threads_group[i][1]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(scheduler_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.thread", utest_tc_init, utest_tc_cleanup, 10);
|
||||
232
RT_Thread/examples/utest/testcases/kernel/sched_timed_mtx_tc.c
Normal file
232
RT_Thread/examples/utest/testcases/kernel/sched_timed_mtx_tc.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-25 Shell init ver.
|
||||
*/
|
||||
#define __RT_KERNEL_SOURCE__
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_SECONDS 10
|
||||
#define TEST_LOOP_TICKS (TEST_SECONDS * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TICKS*2/TEST_PROGRESS_COUNTS)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static struct rt_mutex _ipc_primitive;
|
||||
static struct rt_semaphore _cons_can_take_mtx;
|
||||
static struct rt_semaphore _prod_can_take_mtx;
|
||||
static rt_atomic_t _progress_counter;
|
||||
#define CONSUMER_MAGIC 0x11223344
|
||||
#define PRODUCER_MAGIC 0x44332211
|
||||
static rt_atomic_t _last_holder_flag = CONSUMER_MAGIC;
|
||||
static rt_base_t _timedout_failed_times = 0;
|
||||
|
||||
/**
|
||||
* Test on timedout IPC with racing condition where timedout routine and producer
|
||||
* thread may race to wakeup sleeper.
|
||||
*
|
||||
* This test will fork 2 thread, one producer and one consumer. The producer will
|
||||
* looping and trigger the IPC on the edge of new tick arrives. The consumer will
|
||||
* wait on IPC with a timedout of 1 tick.
|
||||
*/
|
||||
|
||||
static void _wait_until_edge(void)
|
||||
{
|
||||
rt_tick_t entry_level, current;
|
||||
rt_base_t random_latency;
|
||||
|
||||
entry_level = rt_tick_get();
|
||||
do
|
||||
{
|
||||
current = rt_tick_get();
|
||||
}
|
||||
while (current == entry_level);
|
||||
|
||||
/* give a random latency for test */
|
||||
random_latency = rand() % 1000 * 1000;
|
||||
entry_level = current;
|
||||
for (size_t i = 0; i < random_latency; i++)
|
||||
{
|
||||
current = rt_tick_get();
|
||||
if (current != entry_level)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _producer_entry(void *param)
|
||||
{
|
||||
rt_err_t error;
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
/**
|
||||
* only try to take mutex after consumer have taken it after last
|
||||
* release from us.
|
||||
*/
|
||||
error = rt_sem_take(&_prod_can_take_mtx, RT_WAITING_FOREVER);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
error = rt_mutex_take(&_ipc_primitive, RT_WAITING_FOREVER);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ensure that mutex should be held in round-robin method */
|
||||
if (rt_atomic_load(&_last_holder_flag) != CONSUMER_MAGIC)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_atomic_store(&_last_holder_flag, PRODUCER_MAGIC);
|
||||
rt_sem_release(&_cons_can_take_mtx);
|
||||
}
|
||||
|
||||
_wait_until_edge();
|
||||
|
||||
rt_mutex_release(&_ipc_primitive);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _consumer_entry(void *param)
|
||||
{
|
||||
rt_err_t error;
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
/**
|
||||
* only try to take mutex after producer have taken it after last
|
||||
* release from us.
|
||||
*/
|
||||
error = rt_sem_take(&_cons_can_take_mtx, RT_WAITING_FOREVER);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
error = rt_mutex_take_interruptible(&_ipc_primitive, 1);
|
||||
if (error == -RT_ETIMEOUT)
|
||||
{
|
||||
_timedout_failed_times++;
|
||||
if (rt_mutex_get_owner(&_ipc_primitive) == rt_thread_self())
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error != RT_EOK)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ensure that mutex should be held in round-robin method */
|
||||
if (rt_atomic_load(&_last_holder_flag) != PRODUCER_MAGIC)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_atomic_store(&_last_holder_flag, CONSUMER_MAGIC);
|
||||
rt_sem_release(&_prod_can_take_mtx);
|
||||
}
|
||||
|
||||
rt_mutex_release(&_ipc_primitive);
|
||||
if (rt_mutex_get_owner(&_ipc_primitive) == rt_thread_self())
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void timed_mtx_tc(void)
|
||||
{
|
||||
rt_thread_t prod = rt_thread_create(
|
||||
"prod",
|
||||
_producer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
4);
|
||||
|
||||
rt_thread_t cons = rt_thread_create(
|
||||
"cons",
|
||||
_consumer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
|
||||
rt_thread_startup(prod);
|
||||
rt_thread_startup(cons);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
uassert_int_equal(
|
||||
rt_sem_take(&_thr_exit_sem, 4 * TEST_LOOP_TICKS),
|
||||
RT_EOK);
|
||||
}
|
||||
|
||||
/* Summary */
|
||||
LOG_I("Total failed times: %ld(in %d)\n", _timedout_failed_times, TEST_LOOP_TICKS);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_timedout_failed_times = 0;
|
||||
|
||||
rt_mutex_init(&_ipc_primitive, "ipc", RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_cons_can_take_mtx, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_prod_can_take_mtx, "test", 1, RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_mutex_detach(&_ipc_primitive);
|
||||
rt_sem_detach(&_cons_can_take_mtx);
|
||||
rt_sem_detach(&_prod_can_take_mtx);
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(timed_mtx_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.timed_mtx", utest_tc_init, utest_tc_cleanup, TEST_SECONDS * 2);
|
||||
149
RT_Thread/examples/utest/testcases/kernel/sched_timed_sem_tc.c
Normal file
149
RT_Thread/examples/utest/testcases/kernel/sched_timed_sem_tc.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-25 Shell init ver.
|
||||
*/
|
||||
#define __RT_KERNEL_SOURCE__
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_SECONDS 10
|
||||
#define TEST_LOOP_TICKS (TEST_SECONDS * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TICKS*2/TEST_PROGRESS_COUNTS)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static struct rt_semaphore _ipc_sem;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static rt_base_t _timedout_failed_times = 0;
|
||||
|
||||
/**
|
||||
* Test on timedout IPC with racing condition where timedout routine and producer
|
||||
* thread may race to wakeup sleeper.
|
||||
*
|
||||
* This test will fork 2 thread, one producer and one consumer. The producer will
|
||||
* looping and trigger the IPC on the edge of new tick arrives. The consumer will
|
||||
* wait on IPC with a timedout of 1 tick.
|
||||
*/
|
||||
|
||||
static void _wait_until_edge(void)
|
||||
{
|
||||
rt_tick_t entry_level, current;
|
||||
rt_base_t random_latency;
|
||||
|
||||
entry_level = rt_tick_get();
|
||||
do
|
||||
{
|
||||
current = rt_tick_get();
|
||||
}
|
||||
while (current == entry_level);
|
||||
|
||||
/* give a random latency for test */
|
||||
random_latency = rand();
|
||||
entry_level = current;
|
||||
for (size_t i = 0; i < random_latency; i++)
|
||||
{
|
||||
current = rt_tick_get();
|
||||
if (current != entry_level)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _producer_entry(void *param)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
_wait_until_edge();
|
||||
|
||||
rt_sem_release(&_ipc_sem);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _consumer_entry(void *param)
|
||||
{
|
||||
int error;
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
error = rt_sem_take_interruptible(&_ipc_sem, 1);
|
||||
if (error == -RT_ETIMEOUT)
|
||||
{
|
||||
_timedout_failed_times++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error != RT_EOK)
|
||||
uassert_true(0);
|
||||
}
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void timed_sem_tc(void)
|
||||
{
|
||||
rt_thread_t prod = rt_thread_create(
|
||||
"prod",
|
||||
_producer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
4);
|
||||
|
||||
rt_thread_t cons = rt_thread_create(
|
||||
"cons",
|
||||
_consumer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
|
||||
rt_thread_startup(prod);
|
||||
rt_thread_startup(cons);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
/* Summary */
|
||||
LOG_I("Total failed times: %ld(in %d)\n", _timedout_failed_times, TEST_LOOP_TICKS);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
int *pseed = rt_malloc(sizeof(int));
|
||||
srand(*(int *)pseed);
|
||||
rt_free(pseed);
|
||||
|
||||
rt_sem_init(&_ipc_sem, "ipc", 0, RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_ipc_sem);
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(timed_sem_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.timed_sem", utest_tc_init, utest_tc_cleanup, TEST_SECONDS * 2);
|
||||
558
RT_Thread/examples/utest/testcases/kernel/semaphore_tc.c
Normal file
558
RT_Thread/examples/utest/testcases/kernel/semaphore_tc.c
Normal file
@ -0,0 +1,558 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-12 luckyzjq the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
static struct rt_semaphore static_semaphore;
|
||||
#ifdef RT_USING_HEAP
|
||||
static rt_sem_t dynamic_semaphore;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
static void test_static_semaphore_init(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
int rand_num = rand() % 0x10000;
|
||||
|
||||
for (int i = 0; i < rand_num; i++)
|
||||
{
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
rt_sem_detach(&static_semaphore);
|
||||
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_FIFO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
rt_sem_detach(&static_semaphore);
|
||||
}
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_static_semaphore_detach(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
int rand_num = rand() % 0x10000;
|
||||
|
||||
for (int i = 0; i < rand_num; i++)
|
||||
{
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result = rt_sem_detach(&static_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_FIFO);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result = rt_sem_detach(&static_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_static_semaphore_take(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
/* first take */
|
||||
result = rt_sem_take(&static_semaphore, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
/* second take */
|
||||
result = rt_sem_take(&static_semaphore, 100);
|
||||
if (-RT_ETIMEOUT != result)
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_detach(&static_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_static_semaphore_trytake(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
/* first take */
|
||||
result = rt_sem_trytake(&static_semaphore);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
/* second take */
|
||||
result = rt_sem_trytake(&static_semaphore);
|
||||
if (-RT_ETIMEOUT != result)
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_detach(&static_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_static_semaphore_release(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
/* first take */
|
||||
result = rt_sem_take(&static_semaphore, 100);
|
||||
if (-RT_ETIMEOUT != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
/* release */
|
||||
result = rt_sem_release(&static_semaphore);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
/* second take */
|
||||
result = rt_sem_take(&static_semaphore, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_detach(&static_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_static_semaphore_control(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
int value = 0;
|
||||
|
||||
value = rand() % 100;
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
result = rt_sem_control(&static_semaphore, RT_IPC_CMD_RESET, &value);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < value; i++)
|
||||
{
|
||||
result = rt_sem_take(&static_semaphore, 10);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
rt_sem_detach(&static_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static void static_release_isr_hardware_callback(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_sem_release(&static_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void static_release_isr_software_callback(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_sem_release(&static_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_static_semaphore_release_isr(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_timer_t hardware_timer;
|
||||
rt_timer_t software_timer;
|
||||
|
||||
/* create timer */
|
||||
hardware_timer = rt_timer_create("release_isr",
|
||||
static_release_isr_hardware_callback,
|
||||
RT_NULL,
|
||||
100,
|
||||
RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_ONE_SHOT);
|
||||
software_timer = rt_timer_create("release_isr",
|
||||
static_release_isr_software_callback,
|
||||
RT_NULL,
|
||||
100,
|
||||
RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
|
||||
/* start tiemr */
|
||||
if (hardware_timer)
|
||||
rt_timer_start(hardware_timer);
|
||||
if (software_timer)
|
||||
rt_timer_start(software_timer);
|
||||
|
||||
result = rt_sem_init(&static_semaphore, "static_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (RT_EOK == result)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
result = rt_sem_take(&static_semaphore, 1000);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_detach(&static_semaphore);
|
||||
rt_timer_delete(hardware_timer);
|
||||
rt_timer_delete(software_timer);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
static void test_dynamic_semaphore_create(void)
|
||||
{
|
||||
int rand_num = rand() % 0x10000;
|
||||
|
||||
for (int i = 0; i < rand_num; i++)
|
||||
{
|
||||
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_semaphore)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
rt_sem_delete(dynamic_semaphore);
|
||||
|
||||
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_FIFO);
|
||||
if (RT_NULL == dynamic_semaphore)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
rt_sem_delete(dynamic_semaphore);
|
||||
}
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_dynamic_semaphore_delete(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
int rand_num = rand() % 0x10000;
|
||||
|
||||
for (int i = 0; i < rand_num; i++)
|
||||
{
|
||||
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL == dynamic_semaphore)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result = rt_sem_delete(dynamic_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_FIFO);
|
||||
if (RT_NULL == dynamic_semaphore)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result = rt_sem_delete(dynamic_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_dynamic_semaphore_take(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL != dynamic_semaphore)
|
||||
{
|
||||
/* first take */
|
||||
result = rt_sem_take(dynamic_semaphore, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
/* second take */
|
||||
result = rt_sem_take(dynamic_semaphore, 100);
|
||||
if (-RT_ETIMEOUT != result)
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_delete(dynamic_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_dynamic_semaphore_trytake(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL != dynamic_semaphore)
|
||||
{
|
||||
/* first take */
|
||||
result = rt_sem_trytake(dynamic_semaphore);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
/* second take */
|
||||
result = rt_sem_trytake(dynamic_semaphore);
|
||||
if (-RT_ETIMEOUT != result)
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_delete(dynamic_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_dynamic_semaphore_release(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
dynamic_semaphore = rt_sem_create("static_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL != dynamic_semaphore)
|
||||
{
|
||||
/* first take */
|
||||
result = rt_sem_take(dynamic_semaphore, 100);
|
||||
if (-RT_ETIMEOUT != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
/* release */
|
||||
result = rt_sem_release(dynamic_semaphore);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
|
||||
/* second take */
|
||||
result = rt_sem_take(dynamic_semaphore, RT_WAITING_FOREVER);
|
||||
if (RT_EOK != result)
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_delete(dynamic_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_dynamic_semaphore_control(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
int value = 0;
|
||||
|
||||
value = rand() % 100;
|
||||
dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL != dynamic_semaphore)
|
||||
{
|
||||
result = rt_sem_control(dynamic_semaphore, RT_IPC_CMD_RESET, &value);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < value; i++)
|
||||
{
|
||||
result = rt_sem_take(dynamic_semaphore, 10);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
rt_sem_delete(dynamic_semaphore);
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
static void dynamic_release_isr_hardware_callback(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_sem_release(dynamic_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void dynamic_release_isr_software_callback(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
result = rt_sem_release(dynamic_semaphore);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_dynamic_semaphore_release_isr(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
rt_timer_t hardware_timer;
|
||||
rt_timer_t software_timer;
|
||||
|
||||
/* create timer */
|
||||
hardware_timer = rt_timer_create("release_isr",
|
||||
dynamic_release_isr_hardware_callback,
|
||||
RT_NULL,
|
||||
100,
|
||||
RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_ONE_SHOT);
|
||||
software_timer = rt_timer_create("release_isr",
|
||||
dynamic_release_isr_software_callback,
|
||||
RT_NULL,
|
||||
100,
|
||||
RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT);
|
||||
/* start tiemr */
|
||||
if (hardware_timer)
|
||||
rt_timer_start(hardware_timer);
|
||||
if (software_timer)
|
||||
rt_timer_start(software_timer);
|
||||
|
||||
dynamic_semaphore = rt_sem_create("static_sem", 0, RT_IPC_FLAG_PRIO);
|
||||
if (RT_NULL != dynamic_semaphore)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
result = rt_sem_take(dynamic_semaphore, 1000);
|
||||
if (RT_EOK != result)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rt_sem_delete(dynamic_semaphore);
|
||||
rt_timer_delete(hardware_timer);
|
||||
rt_timer_delete(software_timer);
|
||||
|
||||
uassert_true(RT_TRUE);
|
||||
}
|
||||
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_semaphore = RT_NULL;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
dynamic_semaphore = RT_NULL;
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_static_semaphore_init);
|
||||
UTEST_UNIT_RUN(test_static_semaphore_take);
|
||||
UTEST_UNIT_RUN(test_static_semaphore_release);
|
||||
UTEST_UNIT_RUN(test_static_semaphore_detach);
|
||||
UTEST_UNIT_RUN(test_static_semaphore_trytake);
|
||||
UTEST_UNIT_RUN(test_static_semaphore_control);
|
||||
UTEST_UNIT_RUN(test_static_semaphore_release_isr);
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
UTEST_UNIT_RUN(test_dynamic_semaphore_create);
|
||||
UTEST_UNIT_RUN(test_dynamic_semaphore_take);
|
||||
UTEST_UNIT_RUN(test_dynamic_semaphore_release);
|
||||
UTEST_UNIT_RUN(test_dynamic_semaphore_delete);
|
||||
UTEST_UNIT_RUN(test_dynamic_semaphore_trytake);
|
||||
UTEST_UNIT_RUN(test_dynamic_semaphore_control);
|
||||
UTEST_UNIT_RUN(test_dynamic_semaphore_release_isr);
|
||||
#endif /* RT_USING_HEAP */
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.semaphore_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
207
RT_Thread/examples/utest/testcases/kernel/signal_tc.c
Normal file
207
RT_Thread/examples/utest/testcases/kernel/signal_tc.c
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-12 flybreak the first version
|
||||
*
|
||||
* case 1:rt_signal_install, install all available signal
|
||||
* case 2:rt_signal_install, install illegal signal
|
||||
* case 3:rt_signal_mask/unmask, one thread self, install and unmask, then kill, should received.
|
||||
* case 4:rt_signal_mask/unmask, one thread self, install and unmask and mask, then kill, should can't received.
|
||||
* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received.
|
||||
* case 6:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: sleep 2s then kill, should can't received.
|
||||
* case 7:rt_signal_kill, kill legal thread, return 0;
|
||||
* case 8:rt_signal_kill, kill illegal thread, return failed (unused);
|
||||
* case 9:rt_signal_kill, kill illegal signo, return -RT_EINVAL;
|
||||
*
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
static volatile int recive_sig = 0;
|
||||
static struct rt_semaphore _received_signal;
|
||||
|
||||
void sig_handle_default(int signo)
|
||||
{
|
||||
recive_sig = signo;
|
||||
}
|
||||
|
||||
static void rt_signal_install_test(void)
|
||||
{
|
||||
int signo;
|
||||
rt_sighandler_t result;
|
||||
|
||||
/* case 1:rt_signal_install, install all available signal. */
|
||||
for (signo = 0; signo < RT_SIG_MAX; signo++)
|
||||
{
|
||||
result = rt_signal_install(signo, sig_handle_default);
|
||||
uassert_true(result != SIG_ERR);
|
||||
}
|
||||
/* case 2:rt_signal_install, install illegal signal. */
|
||||
result = rt_signal_install(signo, sig_handle_default);
|
||||
uassert_true(result == SIG_ERR);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void rt_signal_mask_test(void)
|
||||
{
|
||||
int signo;
|
||||
rt_sighandler_t result;
|
||||
|
||||
/* case 3:rt_signal_mask/unmask, one thread self, install and unmask, then kill, should received. */
|
||||
for (signo = 0; signo < RT_SIG_MAX; signo++)
|
||||
{
|
||||
recive_sig = -1;
|
||||
result = rt_signal_install(signo, sig_handle_default);
|
||||
uassert_true(result != SIG_ERR);
|
||||
rt_signal_unmask(signo);
|
||||
uassert_int_equal(rt_thread_kill(rt_thread_self(), signo), RT_EOK);
|
||||
rt_thread_mdelay(1);
|
||||
uassert_int_equal(recive_sig, signo);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void rt_signal_unmask_test(void)
|
||||
{
|
||||
int signo;
|
||||
rt_sighandler_t result;
|
||||
|
||||
/* case 4:rt_signal_mask/unmask, one thread self, install and unmask and mask, then kill, should can't received. */
|
||||
for (signo = 0; signo < RT_SIG_MAX; signo++)
|
||||
{
|
||||
recive_sig = -1;
|
||||
result = rt_signal_install(signo, sig_handle_default);
|
||||
uassert_true(result != SIG_ERR);
|
||||
rt_signal_unmask(signo);
|
||||
rt_signal_mask(signo);
|
||||
uassert_int_equal(rt_thread_kill(rt_thread_self(), signo), RT_EOK);
|
||||
rt_thread_mdelay(1);
|
||||
uassert_int_not_equal(recive_sig, signo);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void rt_signal_kill_test(void)
|
||||
{
|
||||
int signo;
|
||||
rt_sighandler_t result;
|
||||
|
||||
/* case 7:rt_signal_kill, kill legal thread, return 0; */
|
||||
for (signo = 0; signo < RT_SIG_MAX; signo++)
|
||||
{
|
||||
recive_sig = -1;
|
||||
result = rt_signal_install(signo, sig_handle_default);
|
||||
uassert_true(result != SIG_ERR);
|
||||
rt_signal_unmask(signo);
|
||||
uassert_int_equal(rt_thread_kill(rt_thread_self(), signo), RT_EOK);
|
||||
rt_thread_mdelay(1);
|
||||
uassert_int_equal(recive_sig, signo);
|
||||
}
|
||||
/* case 8:rt_signal_kill, kill illegal thread, return failed; */
|
||||
// uassert_true(rt_thread_kill((rt_thread_t)-1, signo) == -RT_ERROR);
|
||||
|
||||
/* case 9:rt_signal_kill, kill illegal signo, return -RT_EINVAL; */
|
||||
uassert_true(rt_thread_kill(rt_thread_self(), -1) == -RT_EINVAL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void rt_signal_wait_thread(void *parm)
|
||||
{
|
||||
sigset_t selectset;
|
||||
siginfo_t recive_si;
|
||||
|
||||
rt_signal_install(SIGUSR1, sig_handle_default);
|
||||
rt_signal_unmask(SIGUSR1);
|
||||
|
||||
(void)sigemptyset(&selectset);
|
||||
(void)sigaddset(&selectset, SIGUSR1);
|
||||
|
||||
/* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received. */
|
||||
if (rt_signal_wait((void *)&selectset, &recive_si, RT_TICK_PER_SECOND) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recive_sig = recive_si.si_signo;
|
||||
|
||||
LOG_I("received signal %d", recive_sig);
|
||||
rt_sem_release(&_received_signal);
|
||||
}
|
||||
|
||||
static void rt_signal_wait_test(void)
|
||||
{
|
||||
rt_thread_t t1;
|
||||
|
||||
recive_sig = -1;
|
||||
t1 = rt_thread_create("sig_t1", rt_signal_wait_thread, 0, 4096, 14, 10);
|
||||
if (t1)
|
||||
{
|
||||
rt_thread_startup(t1);
|
||||
}
|
||||
|
||||
rt_thread_mdelay(1);
|
||||
/* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received. */
|
||||
uassert_int_equal(rt_thread_kill(t1, SIGUSR1), RT_EOK);
|
||||
rt_sem_take(&_received_signal, RT_WAITING_FOREVER);
|
||||
uassert_int_equal(recive_sig, SIGUSR1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void rt_signal_wait_test2(void)
|
||||
{
|
||||
rt_thread_t t1;
|
||||
|
||||
recive_sig = -1;
|
||||
t1 = rt_thread_create("sig_t1", rt_signal_wait_thread, 0, 4096, 14, 10);
|
||||
if (t1)
|
||||
{
|
||||
rt_thread_startup(t1);
|
||||
}
|
||||
|
||||
/* case 6:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: sleep 2s then kill, should can't received. */
|
||||
rt_thread_mdelay(2000);
|
||||
uassert_int_equal(rt_thread_kill(t1, SIGUSR1), RT_EOK);
|
||||
uassert_int_not_equal(
|
||||
rt_sem_take(&_received_signal, 1),
|
||||
RT_EOK);
|
||||
uassert_int_not_equal(recive_sig, SIGUSR1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_sem_init(&_received_signal, "utest", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_received_signal);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
#ifdef RT_USING_HEAP
|
||||
UTEST_UNIT_RUN(rt_signal_install_test);
|
||||
UTEST_UNIT_RUN(rt_signal_mask_test);
|
||||
UTEST_UNIT_RUN(rt_signal_unmask_test);
|
||||
UTEST_UNIT_RUN(rt_signal_kill_test);
|
||||
UTEST_UNIT_RUN(rt_signal_wait_test);
|
||||
UTEST_UNIT_RUN(rt_signal_wait_test2);
|
||||
#endif /* RT_USING_HEAP */
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.signal_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
|
||||
/*********************** end of file ****************************/
|
||||
323
RT_Thread/examples/utest/testcases/kernel/slab_tc.c
Normal file
323
RT_Thread/examples/utest/testcases/kernel/slab_tc.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-10-14 tyx the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_SLAB_SIZE 1024 * 1024
|
||||
|
||||
static int _mem_cmp(void *ptr, rt_uint8_t v, rt_size_t size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
{
|
||||
if (*(rt_uint8_t *)ptr != v)
|
||||
return *(rt_uint8_t *)ptr - v;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct slab_alloc_context
|
||||
{
|
||||
rt_list_t node;
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
struct slab_alloc_head
|
||||
{
|
||||
rt_list_t list;
|
||||
rt_size_t count;
|
||||
rt_tick_t start;
|
||||
rt_tick_t end;
|
||||
rt_tick_t interval;
|
||||
};
|
||||
|
||||
#define SLAB_RANG_ALLOC_BLK_MIN 2
|
||||
#define SLAB_RANG_ALLOC_BLK_MAX 5
|
||||
#define SLAB_RANG_ALLOC_TEST_TIME 5
|
||||
|
||||
static void slab_alloc_test(void)
|
||||
{
|
||||
struct slab_alloc_head head;
|
||||
rt_uint8_t *buf;
|
||||
rt_slab_t heap;
|
||||
rt_size_t size;
|
||||
struct slab_alloc_context *ctx;
|
||||
|
||||
/* init */
|
||||
rt_list_init(&head.list);
|
||||
head.count = 0;
|
||||
head.start = rt_tick_get();
|
||||
head.end = rt_tick_get() + rt_tick_from_millisecond(SLAB_RANG_ALLOC_TEST_TIME * 1000);
|
||||
head.interval = (head.end - head.start) / 20;
|
||||
buf = rt_malloc(TEST_SLAB_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_SLAB_SIZE);
|
||||
heap = rt_slab_init("slab_tc", buf, TEST_SLAB_SIZE);
|
||||
// test run
|
||||
while (head.end - head.start < RT_TICK_MAX / 2)
|
||||
{
|
||||
if (rt_tick_get() - head.start >= head.interval)
|
||||
{
|
||||
head.start = rt_tick_get();
|
||||
rt_kprintf("#");
|
||||
}
|
||||
// %60 probability to perform alloc operation
|
||||
if (rand() % 10 >= 4)
|
||||
{
|
||||
size = rand() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN;
|
||||
size *= sizeof(struct slab_alloc_context);
|
||||
ctx = rt_slab_alloc(heap, size);
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
if (head.count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
size = head.count / 2;
|
||||
while (size != head.count)
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_slab_free(heap, ctx);
|
||||
head.count --;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
//if (RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE) != (rt_ubase_t)ctx)
|
||||
//{
|
||||
// uassert_int_equal(RT_ALIGN((rt_ubase_t)ctx, RT_ALIGN_SIZE), (rt_ubase_t)ctx);
|
||||
//}
|
||||
rt_memset(ctx, 0, size);
|
||||
rt_list_init(&ctx->node);
|
||||
ctx->size = size;
|
||||
ctx->magic = rand() & 0xff;
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
rt_list_insert_after(&head.list, &ctx->node);
|
||||
head.count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rt_list_isempty(&head.list))
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_slab_free(heap, ctx);
|
||||
head.count --;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!rt_list_isempty(&head.list))
|
||||
{
|
||||
ctx = rt_list_first_entry(&head.list, struct slab_alloc_context, node);
|
||||
rt_list_remove(&ctx->node);
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
if (_mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx)) != 0)
|
||||
{
|
||||
uassert_true(0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_slab_free(heap, ctx);
|
||||
head.count --;
|
||||
}
|
||||
uassert_int_equal(head.count, 0);
|
||||
// slab heap deinit
|
||||
rt_slab_detach(heap);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
#define SLAB_RANG_REALLOC_BLK_MIN 0
|
||||
#define SLAB_RANG_REALLOC_BLK_MAX 5
|
||||
#define SLAB_RANG_REALLOC_TEST_TIME 5
|
||||
|
||||
struct slab_realloc_context
|
||||
{
|
||||
rt_size_t size;
|
||||
rt_uint8_t magic;
|
||||
};
|
||||
|
||||
struct slab_realloc_head
|
||||
{
|
||||
struct slab_realloc_context **ctx_tab;
|
||||
rt_size_t count;
|
||||
rt_tick_t start;
|
||||
rt_tick_t end;
|
||||
rt_tick_t interval;
|
||||
};
|
||||
|
||||
static void slab_realloc_test(void)
|
||||
{
|
||||
struct slab_realloc_head head;
|
||||
rt_uint8_t *buf;
|
||||
rt_slab_t heap;
|
||||
rt_size_t size, idx;
|
||||
struct slab_realloc_context *ctx;
|
||||
int res;
|
||||
|
||||
size = RT_ALIGN(sizeof(struct slab_realloc_context), RT_ALIGN_SIZE) + RT_ALIGN_SIZE;
|
||||
size = TEST_SLAB_SIZE / size;
|
||||
/* init */
|
||||
head.ctx_tab = RT_NULL;
|
||||
head.count = size;
|
||||
head.start = rt_tick_get();
|
||||
head.end = rt_tick_get() + rt_tick_from_millisecond(SLAB_RANG_ALLOC_TEST_TIME * 1000);
|
||||
head.interval = (head.end - head.start) / 20;
|
||||
buf = rt_malloc(TEST_SLAB_SIZE);
|
||||
uassert_not_null(buf);
|
||||
uassert_int_equal(RT_ALIGN((rt_ubase_t)buf, RT_ALIGN_SIZE), (rt_ubase_t)buf);
|
||||
rt_memset(buf, 0xAA, TEST_SLAB_SIZE);
|
||||
heap = rt_slab_init("slab_tc", buf, TEST_SLAB_SIZE);
|
||||
/* init ctx tab */
|
||||
size = head.count * sizeof(struct slab_realloc_context *);
|
||||
head.ctx_tab = rt_slab_alloc(heap, size);
|
||||
uassert_not_null(head.ctx_tab);
|
||||
rt_memset(head.ctx_tab, 0, size);
|
||||
// test run
|
||||
while (head.end - head.start < RT_TICK_MAX / 2)
|
||||
{
|
||||
if (rt_tick_get() - head.start >= head.interval)
|
||||
{
|
||||
head.start = rt_tick_get();
|
||||
rt_kprintf("#");
|
||||
}
|
||||
size = rand() % SLAB_RANG_ALLOC_BLK_MAX + SLAB_RANG_ALLOC_BLK_MIN;
|
||||
size *= sizeof(struct slab_realloc_context);
|
||||
idx = rand() % head.count;
|
||||
ctx = rt_slab_realloc(heap, head.ctx_tab[idx], size);
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
if (head.ctx_tab[idx])
|
||||
{
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (idx = 0; idx < head.count; idx++)
|
||||
{
|
||||
ctx = head.ctx_tab[idx];
|
||||
if (rand() % 2 && ctx)
|
||||
{
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_slab_realloc(heap, ctx, 0);
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* check slab */
|
||||
if (head.ctx_tab[idx] != RT_NULL)
|
||||
{
|
||||
res = 0;
|
||||
if (ctx->size < size)
|
||||
{
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, size - sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
/* init slab */
|
||||
ctx->magic = rand() & 0xff;
|
||||
ctx->size = size;
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
rt_memset(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
}
|
||||
head.ctx_tab[idx] = ctx;
|
||||
}
|
||||
// free all slab
|
||||
for (idx = 0; idx < head.count; idx++)
|
||||
{
|
||||
ctx = head.ctx_tab[idx];
|
||||
if (ctx == RT_NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ctx->size > sizeof(*ctx))
|
||||
{
|
||||
res = _mem_cmp(&ctx[1], ctx->magic, ctx->size - sizeof(*ctx));
|
||||
if (res != 0)
|
||||
{
|
||||
uassert_int_equal(res, 0);
|
||||
}
|
||||
}
|
||||
rt_memset(ctx, 0xAA, ctx->size);
|
||||
rt_slab_realloc(heap, ctx, 0);
|
||||
head.ctx_tab[idx] = RT_NULL;
|
||||
}
|
||||
// slab heap deinit
|
||||
rt_slab_detach(heap);
|
||||
/* release test resources */
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(slab_alloc_test);
|
||||
UTEST_UNIT_RUN(slab_realloc_test);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.slab_tc", utest_tc_init, utest_tc_cleanup, 20);
|
||||
23
RT_Thread/examples/utest/testcases/kernel/smp/Kconfig
Normal file
23
RT_Thread/examples/utest/testcases/kernel/smp/Kconfig
Normal file
@ -0,0 +1,23 @@
|
||||
menu "Kernel SMP Testcase"
|
||||
|
||||
config UTEST_SMP_AFFFINITY_TC
|
||||
bool "smp affinity and thread priority test1"
|
||||
default n
|
||||
|
||||
config UTEST_SMP_ASSIGNED_IDLE_CORE_TC
|
||||
bool "smp threads auto assign to idle cores for test"
|
||||
default n
|
||||
|
||||
config UTEST_SMP_INTERRUPT_PRI_TC
|
||||
bool "smp interrupt priority test"
|
||||
default n
|
||||
|
||||
config UTEST_SMP_SPINLOCK_TC
|
||||
bool "smp spinlock test"
|
||||
default n
|
||||
|
||||
config UTEST_SMP_THREAD_PREEMPTION_TC
|
||||
bool "smp threads preemption test"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
27
RT_Thread/examples/utest/testcases/kernel/smp/SConscript
Normal file
27
RT_Thread/examples/utest/testcases/kernel/smp/SConscript
Normal file
@ -0,0 +1,27 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend(['UTEST_SMP_SPINLOCK_TC']):
|
||||
src += ['smp_spinlock_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SMP_ASSIGNED_IDLE_CORE_TC']):
|
||||
src += ['smp_assigned_idle_cores_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SMP_INTERRUPT_PRI_TC']):
|
||||
src += ['smp_interrupt_pri_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SMP_THREAD_PREEMPTION_TC']):
|
||||
src += ['smp_thread_preemption_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_SMP_AFFFINITY_TC']):
|
||||
src += ['smp_bind_affinity_tc.c']
|
||||
src += ['smp_affinity_pri1_tc.c']
|
||||
src += ['smp_affinity_pri2_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-10 RV the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
/**
|
||||
* @brief Test that threads with low-priority bound cores do not preempt high-priority threads.
|
||||
*
|
||||
* @note Create RT_CPUS_NR threads, thread 0 is bound to core 0, lower priority, the priority of the other threads
|
||||
* for the system's highest and the thread entry function does not let out the CPU control, run the specified
|
||||
* number of times in thread 0 to create a high-priority not bound to the core of the thread, the thread will
|
||||
* be preempted by the core 0 is running on the thread!
|
||||
*/
|
||||
|
||||
/* Number of thread runs */
|
||||
static int run_num = 10;
|
||||
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
|
||||
#define THREAD_PRIORITY 2
|
||||
#define LOW_PRIORITY 50
|
||||
#define THIGH_PRIORITY 10
|
||||
static rt_thread_t threads[RT_CPUS_NR];
|
||||
static rt_thread_t temp_thread;
|
||||
static struct rt_spinlock lock;
|
||||
static int thread_inc = 0;
|
||||
static int num = 0;
|
||||
|
||||
static void thread_temp_entry(void *parameter)
|
||||
{
|
||||
int id = 0;
|
||||
while (1)
|
||||
{
|
||||
id = rt_hw_cpu_id();
|
||||
uassert_int_equal(id, 0);
|
||||
extern long list_thread(void);
|
||||
list_thread();
|
||||
rt_thread_delete(temp_thread);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_entry(void *parameter)
|
||||
{
|
||||
int id = 0;
|
||||
int para = *(int *)parameter;
|
||||
while (1)
|
||||
{
|
||||
thread_inc++;
|
||||
id = rt_hw_cpu_id();
|
||||
if (para == 0)
|
||||
{
|
||||
if (thread_inc == run_num)
|
||||
{
|
||||
uassert_int_equal(id, 0);
|
||||
extern long list_thread(void);
|
||||
list_thread();
|
||||
/* Creating high-priority untied core threads */
|
||||
temp_thread = rt_thread_create("Tn", thread_temp_entry, RT_NULL, THREAD_STACK_SIZE, THIGH_PRIORITY, 20);
|
||||
|
||||
if (temp_thread != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(temp_thread);
|
||||
}
|
||||
}
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_int_not_equal(id, 0);
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void smp_affinity_pri1_tc(void)
|
||||
{
|
||||
static int params[RT_CPUS_NR] = {0};
|
||||
char thread_name[8];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
params[i] = i;
|
||||
}
|
||||
|
||||
/* Creating threads with low priority bindings to core 0 */
|
||||
threads[0] = rt_thread_create("T0", thread_entry, (int *)¶ms[0], THREAD_STACK_SIZE, LOW_PRIORITY, 20);
|
||||
|
||||
if (threads[0] != RT_NULL)
|
||||
{
|
||||
rt_thread_control(threads[0], RT_THREAD_CTRL_BIND_CPU, (void *)0);
|
||||
rt_thread_startup(threads[0]);
|
||||
}
|
||||
|
||||
/* Create high-priority unbound threads with thread functions that don't let out CPU control */
|
||||
for (i = 1; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
rt_snprintf(thread_name, sizeof(thread_name), "T%d", i);
|
||||
threads[i] = rt_thread_create(thread_name, thread_entry, (int *)¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
|
||||
|
||||
if (threads[i] != RT_NULL)
|
||||
{
|
||||
rt_thread_control(threads[i], RT_THREAD_CTRL_BIND_CPU, (void *)i);
|
||||
rt_thread_startup(threads[i]);
|
||||
}
|
||||
}
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
for (num = 0; num < RT_CPUS_NR; num++)
|
||||
{
|
||||
rt_thread_delete(threads[num]);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(smp_affinity_pri1_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.smp.affinity_pri1_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-10 RV the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
/**
|
||||
* @brief Threads are automatically balanced across cores.
|
||||
*
|
||||
* @note Create RT_CPUS_NR threads, thread 0 is not bound to core 0, higher priority, the priority of the other
|
||||
* threads for the system's highest and the thread entry function does not let out the CPU control, run the
|
||||
* specified number of times after the creation of thread 0 in thread 0, a low-priority bound to the core 0,
|
||||
* the thread will not preempt the core 0 is running on threads
|
||||
*/
|
||||
|
||||
/* Number of thread runs */
|
||||
static int run_num = 10;
|
||||
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
|
||||
#define THREAD_PRIORITY 2
|
||||
#define LOW_PRIORITY 50
|
||||
#define THIGH_PRIORITY 10
|
||||
static rt_thread_t threads[RT_CPUS_NR];
|
||||
static rt_thread_t temp_thread;
|
||||
static struct rt_spinlock lock;
|
||||
static int thread_inc = 0;
|
||||
static int run_flag = 0;
|
||||
static int num = 0;
|
||||
|
||||
static void thread_temp_entry(void *parameter)
|
||||
{
|
||||
run_flag = 1;
|
||||
rt_thread_delete(temp_thread);
|
||||
}
|
||||
|
||||
static void thread_entry(void *parameter)
|
||||
{
|
||||
int id = 0;
|
||||
int para = *(int *)parameter;
|
||||
while (1)
|
||||
{
|
||||
thread_inc++;
|
||||
id = rt_hw_cpu_id();
|
||||
if (para == 0)
|
||||
{
|
||||
if (thread_inc == run_num)
|
||||
{
|
||||
uassert_int_equal(id, 0);
|
||||
temp_thread = rt_thread_create("Tn", thread_temp_entry, RT_NULL, THREAD_STACK_SIZE, LOW_PRIORITY, 20);
|
||||
|
||||
if (temp_thread != RT_NULL)
|
||||
{
|
||||
rt_thread_control(temp_thread, RT_THREAD_CTRL_BIND_CPU, (void *)0);
|
||||
rt_thread_startup(temp_thread);
|
||||
uassert_int_not_equal(run_flag, 1);
|
||||
}
|
||||
}
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_int_not_equal(id, 0);
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void smp_affinity_pri2_tc(void)
|
||||
{
|
||||
static int params[RT_CPUS_NR] = {0};
|
||||
char thread_name[8];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
params[i] = i;
|
||||
}
|
||||
|
||||
threads[0] = rt_thread_create("T0", thread_entry, (int *)¶ms[0], THREAD_STACK_SIZE, THIGH_PRIORITY, 20);
|
||||
|
||||
if (threads[0] != RT_NULL)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_thread_startup(threads[0]);
|
||||
}
|
||||
|
||||
/* Create high-priority unbound threads with thread functions that don't let out CPU control */
|
||||
for (i = 1; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
rt_snprintf(thread_name, sizeof(thread_name), "T%d", i);
|
||||
threads[i] = rt_thread_create(thread_name, thread_entry, (int *)¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
|
||||
|
||||
if (threads[i] != RT_NULL)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_thread_control(threads[i], RT_THREAD_CTRL_BIND_CPU, (void *)i);
|
||||
rt_thread_startup(threads[i]);
|
||||
}
|
||||
}
|
||||
rt_thread_delay(50);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
for (num = 0; num < RT_CPUS_NR; num++)
|
||||
{
|
||||
rt_thread_delete(threads[num]);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(smp_affinity_pri2_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.smp.affinity_pri2_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-10 RV the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
/**
|
||||
* @brief Threads are automatically balanced across cores.
|
||||
*
|
||||
* @note Create multiple threads untied core threads, run them for a while on each core to see
|
||||
* if the threads are automatically distributed evenly, run for a while to output the threads
|
||||
* running on each core.
|
||||
*/
|
||||
|
||||
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
|
||||
#define THREAD_PRIORITY 20
|
||||
static rt_thread_t threads[RT_CPUS_NR];
|
||||
static int tick = 0, finsh_flag = 0;
|
||||
static int num = 0;
|
||||
/* thread entry function */
|
||||
static void thread_entry(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
tick++;
|
||||
if (tick == 100)
|
||||
{
|
||||
/* Output the current core running threads */
|
||||
extern long list_thread(void);
|
||||
list_thread();
|
||||
finsh_flag = 0xA55A;
|
||||
uassert_true(1);
|
||||
}
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_on_idle_core_tc(void)
|
||||
{
|
||||
static int params[RT_CPUS_NR] = {0};
|
||||
char thread_name[8];
|
||||
int i;
|
||||
|
||||
/* Initialise the thread entry parameters */
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
params[i] = i;
|
||||
}
|
||||
|
||||
/* Create RT_CPUS_NR threads and pass the entry parameters for each thread */
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
rt_snprintf(thread_name, sizeof(thread_name), "T%d", i);
|
||||
threads[i] = rt_thread_create(thread_name, thread_entry, ¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
|
||||
if (threads[i] != RT_NULL)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_thread_startup(threads[i]);
|
||||
}
|
||||
}
|
||||
/* Waiting for test cases to finish */
|
||||
while (finsh_flag != 0xA55A);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_kprintf("[Test case]: created threads are automatically assigned to run on idle cores\r\n");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
for (num = 0; num < RT_CPUS_NR; num++)
|
||||
{
|
||||
rt_thread_delete(threads[num]);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(thread_on_idle_core_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.smp.assigned_idle_cores_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-10 RV the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
/**
|
||||
* @brief Binding core affinity testcase.
|
||||
*
|
||||
* @note Create RT_CPUS_NR threads, thread 0 is bound to core 0, other threads are not bound to specific cores,
|
||||
* after running for a set number of times, count the number of times each core is run on the corresponding core,
|
||||
* thread 0 should always be run on core 0, other threads will be run on different cores.
|
||||
*/
|
||||
|
||||
/* Number of thread runs */
|
||||
static int run_num = 100;
|
||||
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
|
||||
#define THREAD_PRIORITY 20
|
||||
static rt_thread_t threads[RT_CPUS_NR];
|
||||
static struct rt_spinlock lock;
|
||||
static int thread_inc[RT_CPUS_NR] = {0};
|
||||
static int thread_tic[RT_CPUS_NR] = {0};
|
||||
static int finsh_flag = 0;
|
||||
static int num = 0;
|
||||
|
||||
static void thread_entry(void *parameter)
|
||||
{
|
||||
int id = 0;
|
||||
int para = *(int *)parameter;
|
||||
while (1)
|
||||
{
|
||||
thread_tic[para]++;
|
||||
id = rt_hw_cpu_id();
|
||||
if (para == id)
|
||||
{
|
||||
thread_inc[para]++;
|
||||
}
|
||||
|
||||
if (thread_tic[para] == run_num)
|
||||
{
|
||||
if (para == 0)
|
||||
uassert_int_equal(thread_inc[para], thread_tic[para]);
|
||||
else
|
||||
uassert_int_not_equal(thread_inc[para], thread_tic[para]);
|
||||
finsh_flag ++;
|
||||
}
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_bind_affinity_tc(void)
|
||||
{
|
||||
static int params[RT_CPUS_NR] = {0};
|
||||
char thread_name[8];
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
params[i] = i;
|
||||
}
|
||||
|
||||
/* Create RT_CPUS_NR threads Thread 0 is bound to core 0 Other threads are not bound */
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
rt_snprintf(thread_name, sizeof(thread_name), "thread%d", i);
|
||||
threads[i] = rt_thread_create(thread_name, thread_entry, (int *)¶ms[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
|
||||
if (i == 0)
|
||||
{
|
||||
rt_thread_control(threads[0], RT_THREAD_CTRL_BIND_CPU, (void *)0);
|
||||
}
|
||||
if (threads[i] != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(threads[i]);
|
||||
}
|
||||
}
|
||||
|
||||
while (finsh_flag != RT_CPUS_NR);
|
||||
|
||||
/* Displays the number of times a thread was executed on the relevant core */
|
||||
for (j = 0; j < RT_CPUS_NR; j++)
|
||||
{
|
||||
rt_spin_lock(&lock);
|
||||
rt_kprintf("Total runs[%d], Number of times thread[%d] run on [core%d]: [%4d], always run at core%d ? %s \r\n", run_num, j, j, thread_inc[j], j, (thread_inc[j] == run_num) ? "yes" : "no");
|
||||
rt_spin_unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
for (num = 0; num < RT_CPUS_NR; num++)
|
||||
{
|
||||
rt_thread_delete(threads[num]);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(thread_bind_affinity_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.smp.bind_affinity_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-10 RV the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <interrupt.h>
|
||||
|
||||
/**
|
||||
* @brief Setting the Interrupt Priority Test.
|
||||
*
|
||||
* @note Without turning off interrupts, interrupts respond in the order in which they are triggered.
|
||||
* With interrupts turned off, low and high priority interrupts are triggered sequentially,
|
||||
* and when interrupts are turned on, high priority interrupts respond first.
|
||||
*/
|
||||
|
||||
#define RES_VAL 0X0
|
||||
#define SET_VAL 0XA
|
||||
#define RT_SPI_1 1
|
||||
#define RT_SPI_2 2
|
||||
#define RT_SPI_PRI_HIGH 120
|
||||
#define RT_SPI_PRI_LOW 140
|
||||
|
||||
static int mode = 0;
|
||||
static int ipi_val[2] = {0, 0};
|
||||
|
||||
/* Software Interrupt 1 Service Functions */
|
||||
static void rt_scheduler_ipi1_handler(int vector, void *param)
|
||||
{
|
||||
ipi_val[0] = SET_VAL;
|
||||
if (mode == 0)
|
||||
{
|
||||
uassert_true(ipi_val[0] > ipi_val[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipi_val[0] = RES_VAL;
|
||||
ipi_val[1] = RES_VAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Software Interrupt 2 Service Functions */
|
||||
static void rt_scheduler_ipi2_handler(int vector, void *param)
|
||||
{
|
||||
ipi_val[1] = SET_VAL;
|
||||
if (mode == 0)
|
||||
{
|
||||
ipi_val[0] = RES_VAL;
|
||||
ipi_val[1] = RES_VAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_true(ipi_val[0] < ipi_val[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Interrupt priority testcases 1 */
|
||||
static void int_pri1_tc(void)
|
||||
{
|
||||
mode = 0;
|
||||
unsigned int pri1, pri2;
|
||||
pri1 = rt_hw_interrupt_get_priority(RT_SPI_1);
|
||||
pri2 = rt_hw_interrupt_get_priority(RT_SPI_2);
|
||||
|
||||
if (pri1 < pri2)
|
||||
uassert_true(pri1 < pri2);
|
||||
|
||||
/* Trigger interrupt */
|
||||
rt_hw_ipi_send(RT_SPI_1, 0x1);
|
||||
rt_hw_ipi_send(RT_SPI_2, 0x1);
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
|
||||
/* Interrupt priority testcases 2 */
|
||||
static void int_pri2_tc(void)
|
||||
{
|
||||
mode = 1;
|
||||
unsigned int pri1, pri2;
|
||||
pri1 = rt_hw_interrupt_get_priority(RT_SPI_1);
|
||||
pri2 = rt_hw_interrupt_get_priority(RT_SPI_2);
|
||||
|
||||
if (pri1 < pri2)
|
||||
uassert_true(pri1 < pri2);
|
||||
|
||||
rt_base_t level = rt_hw_local_irq_disable();
|
||||
/* Trigger interrupt */
|
||||
rt_hw_ipi_send(RT_SPI_1, 0x1);
|
||||
rt_hw_ipi_send(RT_SPI_2, 0x1);
|
||||
rt_hw_local_irq_enable(level);
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
/* Setting the priority of software interrupts */
|
||||
rt_hw_interrupt_set_priority(RT_SPI_1, RT_SPI_PRI_LOW);
|
||||
rt_hw_interrupt_set_priority(RT_SPI_2, RT_SPI_PRI_HIGH);
|
||||
/* Register software interrupt service functions */
|
||||
rt_hw_ipi_handler_install(RT_SPI_1, rt_scheduler_ipi1_handler);
|
||||
rt_hw_ipi_handler_install(RT_SPI_2, rt_scheduler_ipi2_handler);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(int_pri1_tc);
|
||||
UTEST_UNIT_RUN(int_pri2_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.smp.interrupt_pri_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-13 RV the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
#include <interrupt.h>
|
||||
|
||||
/**
|
||||
* @brief Spinlock testcase.
|
||||
*
|
||||
* @note Create multiple threads and use spinlocks to protect shared memory
|
||||
*/
|
||||
|
||||
#define THREAD_PRIORITY 20
|
||||
#define THREAD_TIMESLICE 20
|
||||
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
|
||||
static rt_thread_t thread1;
|
||||
static rt_thread_t thread2;
|
||||
static rt_uint8_t finsh_flag = 0;
|
||||
static struct rt_spinlock lock;
|
||||
static rt_uint8_t number1, number2 = 0;
|
||||
|
||||
static void rt_thread_entry1(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
rt_spin_lock(&lock);
|
||||
number1++;
|
||||
rt_thread_yield();
|
||||
number2++;
|
||||
rt_spin_unlock(&lock);
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
static void rt_thread_entry2(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
rt_spin_lock(&lock);
|
||||
uassert_int_equal(number1, number2);
|
||||
number1++;
|
||||
number2++;
|
||||
rt_spin_unlock(&lock);
|
||||
if (number1 >= 10)
|
||||
{
|
||||
finsh_flag = 1;
|
||||
}
|
||||
rt_thread_delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
static void smp_spinlock_tc(void)
|
||||
{
|
||||
thread1 = rt_thread_create("T1", rt_thread_entry1, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
|
||||
if (thread1 != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(thread1);
|
||||
}
|
||||
|
||||
thread2 = rt_thread_create("T2", rt_thread_entry2, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY - 1, 20);
|
||||
if (thread2 != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(thread2);
|
||||
}
|
||||
while (finsh_flag == 0);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_thread_delete(thread1);
|
||||
rt_thread_delete(thread2);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(smp_spinlock_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.smp.spinlock_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-08-10 RV the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
/**
|
||||
* @brief Thread Preemption Test with Different Priorities.
|
||||
*
|
||||
* @note Create multiple threads, low-priority threads run first,
|
||||
* high-priority threads preempt low-priority threads, and
|
||||
* print the current status of each core in the thread's entry function.
|
||||
*/
|
||||
|
||||
#define THREAD_PRIORITY_HIGH 21
|
||||
#define THREAD_PRIORITY_LOW 30
|
||||
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
|
||||
|
||||
static rt_thread_t threads[2];
|
||||
static struct rt_spinlock lock;
|
||||
|
||||
/* High Priority Thread */
|
||||
static void thread_high_entry(void *parameter)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_spin_lock(&lock);
|
||||
rt_kprintf("High priority thread is running\n");
|
||||
extern long list_thread(void);
|
||||
list_thread();
|
||||
rt_spin_unlock(&lock);
|
||||
}
|
||||
|
||||
/* Low Priority Thread */
|
||||
static void thread_low_entry(void *parameter)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_spin_lock(&lock);
|
||||
rt_kprintf("Low priority thread is running\n");
|
||||
extern long list_thread(void);
|
||||
list_thread();
|
||||
rt_spin_unlock(&lock);
|
||||
}
|
||||
|
||||
static void thread_preemptions_tc(void)
|
||||
{
|
||||
/* Creating low-priority thread */
|
||||
threads[0] = rt_thread_create("tlow", thread_low_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY_LOW, 10);
|
||||
if (threads[0] != RT_NULL)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_thread_startup(threads[0] );
|
||||
}
|
||||
|
||||
rt_thread_delay(5);
|
||||
/* Creating high-priority thread */
|
||||
threads[1] = rt_thread_create("thigh", thread_high_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY_HIGH, 10);
|
||||
if (threads[1] != RT_NULL)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_thread_startup(threads[1]);
|
||||
}
|
||||
rt_thread_delay(50);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_spin_lock_init(&lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(thread_preemptions_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.smp.thread_preemptions_tc", utest_tc_init, utest_tc_cleanup, 10);
|
||||
756
RT_Thread/examples/utest/testcases/kernel/thread_tc.c
Normal file
756
RT_Thread/examples/utest/testcases/kernel/thread_tc.c
Normal file
@ -0,0 +1,756 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define __RT_IPC_SOURCE__ /* include internal API for utest */
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
|
||||
#define THREAD_TIMESLICE 10
|
||||
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
static char thread2_stack[UTEST_THR_STACK_SIZE];
|
||||
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 volatile rt_uint32_t tid3_delay_pass_flag = 0;
|
||||
static volatile rt_uint32_t tid3_finish_flag = 0;
|
||||
static volatile rt_uint32_t tid4_finish_flag = 0;
|
||||
static volatile rt_uint32_t tid6_finish_flag = 0;
|
||||
static volatile rt_uint32_t thread5_source = 0;
|
||||
|
||||
#ifndef RT_USING_SMP
|
||||
static volatile rt_uint32_t thread_yield_flag = 0;
|
||||
#endif
|
||||
static volatile rt_uint32_t entry_idle_hook_times = 0;
|
||||
static rt_thread_t __current_thread;
|
||||
static rt_uint8_t change_priority;
|
||||
static volatile 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,
|
||||
UTEST_THR_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),
|
||||
UTEST_THR_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, latency_tick;
|
||||
tick = rt_tick_get();
|
||||
rt_thread_delay(15);
|
||||
latency_tick = rt_tick_get() - tick;
|
||||
if (latency_tick > 16 || latency_tick < 15)
|
||||
{
|
||||
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,
|
||||
UTEST_THR_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,
|
||||
UTEST_THR_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;
|
||||
thread5_source = 0;
|
||||
tid5 = rt_thread_create("thread5",
|
||||
thread5_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
UTEST_THR_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,
|
||||
UTEST_THR_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;
|
||||
rt_sched_lock_level_t slvl;
|
||||
|
||||
tid7 = rt_thread_create("thread7",
|
||||
thread7_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
UTEST_THR_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);
|
||||
|
||||
rt_sched_lock(&slvl);
|
||||
if (rt_sched_thread_get_curr_prio(tid7) != change_priority)
|
||||
{
|
||||
LOG_E("rt_thread_control failed!");
|
||||
uassert_false(1);
|
||||
rt_sched_unlock(slvl);
|
||||
goto __exit;
|
||||
}
|
||||
rt_sched_unlock(slvl);
|
||||
|
||||
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,
|
||||
UTEST_THR_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);
|
||||
|
||||
/**
|
||||
* the rt_kprints above can take few ticks to complete, maybe more than 10
|
||||
*/
|
||||
tick = rt_tick_get();
|
||||
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);
|
||||
}
|
||||
|
||||
static rt_thread_t tidA, tidB1, tidB2;
|
||||
static uint32_t timeslice_cntA, timeslice_cntB1, timeslice_cntB2;
|
||||
|
||||
static void test_timeslice_threadA_entry(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
rt_thread_delay(2);
|
||||
timeslice_cntA++;
|
||||
if (timeslice_cntA > 10) return;
|
||||
}
|
||||
}
|
||||
static void test_timeslice_threadB1_entry(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
timeslice_cntB1++;
|
||||
if (timeslice_cntA > 10) return;
|
||||
}
|
||||
}
|
||||
static void test_timeslice_threadB2_entry(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
timeslice_cntB2++;
|
||||
if (timeslice_cntA > 10) return;
|
||||
}
|
||||
}
|
||||
|
||||
void test_timeslice(void)
|
||||
{
|
||||
rt_err_t ret_startup = -RT_ERROR;
|
||||
uint32_t diff;
|
||||
|
||||
timeslice_cntA = 0;
|
||||
timeslice_cntB1 = 0;
|
||||
timeslice_cntB2 = 0;
|
||||
|
||||
tidA = rt_thread_create("timeslice", test_timeslice_threadA_entry, RT_NULL,
|
||||
2048, UTEST_THR_PRIORITY + 1, 10);
|
||||
if (!tidA)
|
||||
{
|
||||
LOG_E("rt_thread_create failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
rt_thread_control(tidA, RT_THREAD_CTRL_BIND_CPU, (void *)1);
|
||||
ret_startup = rt_thread_startup(tidA);
|
||||
if (ret_startup != RT_EOK)
|
||||
{
|
||||
LOG_E("rt_thread_startup failed!");
|
||||
uassert_false(1);
|
||||
return ;
|
||||
}
|
||||
|
||||
tidB1 = rt_thread_create("timeslice", test_timeslice_threadB1_entry, RT_NULL,
|
||||
2048, UTEST_THR_PRIORITY + 2, 2);
|
||||
if (!tidB1)
|
||||
{
|
||||
LOG_E("rt_thread_create failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
rt_thread_control(tidB1, RT_THREAD_CTRL_BIND_CPU, (void *)1);
|
||||
ret_startup = rt_thread_startup(tidB1);
|
||||
if (ret_startup != RT_EOK)
|
||||
{
|
||||
LOG_E("rt_thread_startup failed!");
|
||||
uassert_false(1);
|
||||
return ;
|
||||
}
|
||||
|
||||
tidB2 = rt_thread_create("timeslice", test_timeslice_threadB2_entry, RT_NULL,
|
||||
2048, UTEST_THR_PRIORITY + 2, 2);
|
||||
if (!tidB2)
|
||||
{
|
||||
LOG_E("rt_thread_create failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
rt_thread_control(tidB2, RT_THREAD_CTRL_BIND_CPU, (void *)1);
|
||||
ret_startup = rt_thread_startup(tidB2);
|
||||
if (ret_startup != RT_EOK)
|
||||
{
|
||||
LOG_E("rt_thread_startup failed!");
|
||||
uassert_false(1);
|
||||
return ;
|
||||
}
|
||||
do{
|
||||
rt_thread_delay(2 * 20);
|
||||
}while(timeslice_cntA <= 10);
|
||||
|
||||
rt_kprintf("A:%d,B1:%d,B2:%d\n", timeslice_cntA, timeslice_cntB1, timeslice_cntB2);
|
||||
diff = abs(timeslice_cntB1 - timeslice_cntB2);
|
||||
uassert_true(diff * 100 / timeslice_cntB1 < 30);
|
||||
uassert_true(timeslice_cntA == 11);
|
||||
}
|
||||
|
||||
#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,
|
||||
// UTEST_THR_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 = UTEST_THR_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);
|
||||
/* timeslice */
|
||||
// UTEST_UNIT_RUN(test_timeslice); /* Can not running in Github Action QEMU */
|
||||
}
|
||||
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.thread_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
|
||||
/********************* end of file ************************/
|
||||
747
RT_Thread/examples/utest/testcases/kernel/timer_tc.c
Normal file
747
RT_Thread/examples/utest/testcases/kernel/timer_tc.c
Normal file
@ -0,0 +1,747 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2019, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-08-12 luckyzjq the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#undef uassert_true
|
||||
#define uassert_true(value) \
|
||||
do \
|
||||
{ \
|
||||
if (!(value)) \
|
||||
{ \
|
||||
__utest_assert(value, "(" #value ") is false"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* notify user that the test is not corrupted */
|
||||
#define PRINT_PROGRESS(id) LOG_I("Testing on %d", id)
|
||||
|
||||
static rt_uint8_t timer_flag_oneshot[] = {
|
||||
RT_TIMER_FLAG_ONE_SHOT,
|
||||
RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
|
||||
RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER,
|
||||
};
|
||||
|
||||
static rt_uint8_t timer_flag_periodic[] = {
|
||||
RT_TIMER_FLAG_PERIODIC,
|
||||
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_HARD_TIMER,
|
||||
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER,
|
||||
};
|
||||
|
||||
typedef struct test_timer_struct
|
||||
{
|
||||
struct rt_timer static_timer; /* static timer handler */
|
||||
rt_timer_t dynamic_timer; /* dynamic timer pointer */
|
||||
rt_tick_t expect_tick; /* expect tick */
|
||||
rt_ubase_t callbacks; /* timer callback times */
|
||||
rt_bool_t is_static; /* static or dynamic timer */
|
||||
} timer_struct;
|
||||
static timer_struct timer;
|
||||
|
||||
static void timer_oneshot(void *param)
|
||||
{
|
||||
timer_struct *timer_call;
|
||||
timer_call = (timer_struct *)param;
|
||||
timer_call->callbacks++;
|
||||
|
||||
uassert_true(rt_tick_get() == timer_call->expect_tick);
|
||||
}
|
||||
|
||||
static void timer_periodic(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
timer_struct *timer_call;
|
||||
timer_call = (timer_struct *)param;
|
||||
timer_call->callbacks++;
|
||||
|
||||
uassert_true(rt_tick_get() == timer_call->expect_tick);
|
||||
|
||||
if (timer_call->is_static)
|
||||
{
|
||||
timer_call->expect_tick = rt_tick_get() + timer_call->static_timer.init_tick;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick;
|
||||
}
|
||||
|
||||
if (timer_call->callbacks == 5)
|
||||
{
|
||||
/* periodic timer can stop */
|
||||
if (timer_call->is_static)
|
||||
{
|
||||
result = rt_timer_stop(&timer_call->static_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = rt_timer_stop(timer_call->dynamic_timer);
|
||||
}
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_static_timer(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_TRUE;
|
||||
|
||||
/* one shot timer test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
|
||||
{
|
||||
rt_timer_init(&timer.static_timer,
|
||||
"static_timer",
|
||||
timer_oneshot,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_oneshot[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(3 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks == 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_detach(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* periodic timer test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_periodic); i++)
|
||||
{
|
||||
rt_timer_init(&timer.static_timer,
|
||||
"static_timer",
|
||||
timer_periodic,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_periodic[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(5 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks >= 5);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_detach(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_static_timer_start_twice(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_TRUE;
|
||||
|
||||
/* timer start twice test */
|
||||
for (int time_out = 2; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
|
||||
{
|
||||
rt_timer_init(&timer.static_timer,
|
||||
"static_timer",
|
||||
timer_oneshot,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_oneshot[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
rt_thread_delay(1);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(3 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks == 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_detach(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_control(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
timer_struct *timer_call;
|
||||
timer_call = (timer_struct *)param;
|
||||
timer_call->callbacks++;
|
||||
|
||||
uassert_true(rt_tick_get() == timer_call->expect_tick);
|
||||
|
||||
/* periodic timer can stop */
|
||||
if (timer_call->is_static)
|
||||
{
|
||||
result = rt_timer_stop(&timer_call->static_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = rt_timer_stop(timer_call->dynamic_timer);
|
||||
}
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
}
|
||||
|
||||
static void test_static_timer_control(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
int set_data;
|
||||
int get_data;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_TRUE;
|
||||
|
||||
rt_timer_init(&timer.static_timer,
|
||||
"static_timer",
|
||||
timer_control,
|
||||
&timer,
|
||||
5,
|
||||
RT_TIMER_FLAG_PERIODIC);
|
||||
|
||||
/* test set data */
|
||||
set_data = 10;
|
||||
result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* test get data */
|
||||
result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
uassert_true(set_data == get_data);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + set_data;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
rt_thread_delay(3 * set_data + 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_detach(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
uassert_true(timer.callbacks == 1);
|
||||
}
|
||||
|
||||
static void timer_start_in_callback(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
timer_struct *timer_call;
|
||||
timer_call = (timer_struct *)param;
|
||||
timer_call->callbacks++;
|
||||
|
||||
uassert_true(rt_tick_get() == timer_call->expect_tick);
|
||||
|
||||
if (timer_call->is_static)
|
||||
{
|
||||
timer_call->expect_tick = rt_tick_get() + timer_call->static_timer.init_tick;
|
||||
result = rt_timer_start(&timer_call->static_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick;
|
||||
result = rt_timer_start(timer_call->dynamic_timer);
|
||||
}
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
}
|
||||
|
||||
static void timer_start_stop_in_callback(void *param)
|
||||
{
|
||||
rt_err_t result;
|
||||
timer_struct *timer_call;
|
||||
timer_call = (timer_struct *)param;
|
||||
timer_call->callbacks++;
|
||||
|
||||
uassert_true(rt_tick_get() == timer_call->expect_tick);
|
||||
|
||||
if (timer_call->is_static)
|
||||
{
|
||||
result = rt_timer_start(&timer_call->static_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = rt_timer_start(timer_call->dynamic_timer);
|
||||
}
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
if (timer_call->is_static)
|
||||
{
|
||||
result = rt_timer_stop(&timer_call->static_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = rt_timer_stop(timer_call->dynamic_timer);
|
||||
}
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
}
|
||||
|
||||
static void test_static_timer_op_in_callback(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_TRUE;
|
||||
|
||||
/* start in callback test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
|
||||
{
|
||||
rt_timer_init(&timer.static_timer,
|
||||
"static_timer",
|
||||
timer_start_in_callback,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_oneshot[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(5 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks >= 5);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_detach(&timer.static_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* start & stop in callback test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_periodic); i++)
|
||||
{
|
||||
rt_timer_init(&timer.static_timer,
|
||||
"static_timer",
|
||||
timer_start_stop_in_callback,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_periodic[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(&timer.static_timer);
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(3 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks == 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_detach(&timer.static_timer);
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
|
||||
static void test_dynamic_timer(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_FALSE;
|
||||
|
||||
/* one shot timer test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
|
||||
{
|
||||
timer.dynamic_timer = rt_timer_create("dynamic_timer",
|
||||
timer_oneshot,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_oneshot[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(3 * time_out + 1);
|
||||
uassert_true(timer.callbacks == 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_delete(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* periodic timer test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_periodic); i++)
|
||||
{
|
||||
timer.dynamic_timer = rt_timer_create("dynamic_timer",
|
||||
timer_periodic,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_periodic[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(5 * time_out + 1);
|
||||
uassert_true(timer.callbacks >= 5);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_delete(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_dynamic_timer_control(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
int set_data;
|
||||
int get_data;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_FALSE;
|
||||
|
||||
timer.dynamic_timer = rt_timer_create("dynamic_timer",
|
||||
timer_control,
|
||||
&timer,
|
||||
5,
|
||||
RT_TIMER_FLAG_PERIODIC);
|
||||
|
||||
/* test set data */
|
||||
set_data = 10;
|
||||
result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* test get data */
|
||||
result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
uassert_true(set_data == get_data);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + set_data;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
rt_thread_delay(3 * set_data + 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_delete(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
uassert_true(timer.callbacks == 1);
|
||||
}
|
||||
|
||||
static void test_dynamic_timer_start_twice(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_FALSE;
|
||||
|
||||
/* timer start twice test */
|
||||
for (int time_out = 2; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
|
||||
{
|
||||
timer.dynamic_timer = rt_timer_create("dynamic_timer",
|
||||
timer_oneshot,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_oneshot[i]);
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
rt_thread_delay(1);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(3 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks == 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_delete(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_dynamic_timer_op_in_callback(void)
|
||||
{
|
||||
rt_err_t result;
|
||||
|
||||
timer.callbacks = 0;
|
||||
timer.is_static = RT_FALSE;
|
||||
|
||||
/* start in callback test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
|
||||
{
|
||||
timer.dynamic_timer = rt_timer_create("dynamic_timer",
|
||||
timer_start_in_callback,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_oneshot[i]);
|
||||
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(5 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks >= 5);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_delete(timer.dynamic_timer);
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* start & stop in callback test */
|
||||
for (int time_out = 1; time_out < 10; time_out++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(timer_flag_periodic); i++)
|
||||
{
|
||||
timer.dynamic_timer = rt_timer_create("dynamic_timer",
|
||||
timer_start_stop_in_callback,
|
||||
&timer,
|
||||
time_out,
|
||||
timer_flag_periodic[i]);
|
||||
/* calc expect tick */
|
||||
timer.expect_tick = rt_tick_get() + time_out;
|
||||
|
||||
/* start timer */
|
||||
result = rt_timer_start(timer.dynamic_timer);
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
/* wait for timerout */
|
||||
rt_thread_delay(3 * time_out + 1);
|
||||
|
||||
uassert_true(timer.callbacks == 1);
|
||||
|
||||
/* detach timer */
|
||||
result = rt_timer_delete(timer.dynamic_timer);
|
||||
|
||||
uassert_true(result == RT_EOK);
|
||||
|
||||
timer.callbacks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
#define TEST_TIME_S 60 // test 60 seconds
|
||||
#define STRESS_TIMERS 100
|
||||
|
||||
static struct rt_timer stress_timer[STRESS_TIMERS];
|
||||
|
||||
static void timer_stress(void *param)
|
||||
{
|
||||
rt_timer_t stress_timer = (rt_timer_t)param;
|
||||
|
||||
if (rand() % 2 == 0)
|
||||
{
|
||||
rt_timer_start(stress_timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_timer_stop(stress_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_timer_stress(void)
|
||||
{
|
||||
rt_tick_t start;
|
||||
rt_ubase_t iters = 0;
|
||||
rt_ubase_t cur_tick;
|
||||
rt_ubase_t next_print_time;
|
||||
|
||||
LOG_I("timer stress test begin, it will take %d seconds", 3*TEST_TIME_S);
|
||||
|
||||
for (int i = 0; i < sizeof(timer_flag_periodic); i++)
|
||||
{
|
||||
for (int j = 0; j < STRESS_TIMERS; j++)
|
||||
{
|
||||
rt_timer_init(&stress_timer[j],
|
||||
"stress_timer",
|
||||
timer_stress,
|
||||
&stress_timer[j],
|
||||
j + 1,
|
||||
timer_flag_periodic[i]);
|
||||
}
|
||||
|
||||
start = rt_tick_get();
|
||||
cur_tick = rt_tick_get();
|
||||
next_print_time = cur_tick + RT_TICK_PER_SECOND;
|
||||
while (cur_tick - start <= TEST_TIME_S * RT_TICK_PER_SECOND)
|
||||
{
|
||||
for (int j = 0; j < STRESS_TIMERS; j++)
|
||||
{
|
||||
if (rand() % 2 == 0)
|
||||
{
|
||||
rt_timer_start(&stress_timer[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_timer_stop(&stress_timer[j]);
|
||||
}
|
||||
}
|
||||
iters ++;
|
||||
cur_tick = rt_tick_get();
|
||||
if (cur_tick > next_print_time)
|
||||
{
|
||||
PRINT_PROGRESS(next_print_time);
|
||||
next_print_time = cur_tick + RT_TICK_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < STRESS_TIMERS; j++)
|
||||
{
|
||||
rt_timer_detach(&stress_timer[j]);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_I("success after %lu iterations", iters);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
timer.dynamic_timer = RT_NULL;
|
||||
timer.callbacks = 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
timer.dynamic_timer = RT_NULL;
|
||||
timer.callbacks = 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_static_timer);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
UTEST_UNIT_RUN(test_static_timer_control);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
UTEST_UNIT_RUN(test_static_timer_start_twice);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
UTEST_UNIT_RUN(test_static_timer_op_in_callback);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
#ifdef RT_USING_HEAP
|
||||
UTEST_UNIT_RUN(test_dynamic_timer);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
UTEST_UNIT_RUN(test_dynamic_timer_control);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
UTEST_UNIT_RUN(test_dynamic_timer_start_twice);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
UTEST_UNIT_RUN(test_dynamic_timer_op_in_callback);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
#endif /* RT_USING_HEAP */
|
||||
UTEST_UNIT_RUN(test_timer_stress);
|
||||
PRINT_PROGRESS(__LINE__);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.timer_tc", utest_tc_init, utest_tc_cleanup, 1000);
|
||||
|
||||
/*********************** end of file ****************************/
|
||||
13
RT_Thread/examples/utest/testcases/lwp/SConscript
Normal file
13
RT_Thread/examples/utest/testcases/lwp/SConscript
Normal file
@ -0,0 +1,13 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend(['UTEST_LWP_TC', 'RT_USING_SMART']):
|
||||
src += ['condvar_timedwait_tc.c', 'condvar_broadcast_tc.c', 'condvar_signal_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
156
RT_Thread/examples/utest/testcases/lwp/condvar_broadcast_tc.c
Normal file
156
RT_Thread/examples/utest/testcases/lwp/condvar_broadcast_tc.c
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-20 Shell add test suites
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "rtconfig.h"
|
||||
#include "utest_assert.h"
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rtdef.h>
|
||||
|
||||
static struct rt_mutex _local_mtx;
|
||||
static struct rt_condvar _local_cv;
|
||||
#define THREAD_NUM 8
|
||||
#define STACK_SIZE (0x2000)
|
||||
|
||||
static volatile int start_num;
|
||||
static volatile int waken_num;
|
||||
|
||||
static void thr_func(void *arg)
|
||||
{
|
||||
int rc;
|
||||
rt_mutex_t mutex = &_local_mtx;
|
||||
rt_condvar_t cond = &_local_cv;
|
||||
rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
|
||||
start_num++;
|
||||
rc = rt_condvar_timedwait(cond, mutex, RT_KILLABLE, RT_WAITING_FOREVER);
|
||||
if (rc != 0)
|
||||
{
|
||||
LOG_E("cond_wait returned %d\n", rc);
|
||||
uassert_false(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rt_mutex_get_owner(mutex) != rt_thread_self())
|
||||
{
|
||||
LOG_E("Should not be able to lock the mutex again");
|
||||
uassert_false(1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_true(1);
|
||||
}
|
||||
LOG_I("Thread was wakened and acquired the mutex again");
|
||||
waken_num++;
|
||||
|
||||
if (rt_mutex_release(mutex) != 0)
|
||||
{
|
||||
LOG_E("Failed to release the mutex");
|
||||
uassert_false(1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
static void *stack_addr[THREAD_NUM];
|
||||
|
||||
static void condvar_broadcast_tc(void)
|
||||
{
|
||||
rt_mutex_t mutex = &_local_mtx;
|
||||
rt_condvar_t cond = &_local_cv;
|
||||
struct rt_thread thread[THREAD_NUM];
|
||||
|
||||
for (size_t i = 0; i < THREAD_NUM; i++)
|
||||
{
|
||||
if (rt_thread_init(&thread[i], "utest", thr_func, RT_NULL,
|
||||
stack_addr[i], STACK_SIZE, 25, 100) != 0)
|
||||
{
|
||||
LOG_E("Fail to create thread[%d]\n", i);
|
||||
return;
|
||||
}
|
||||
rt_thread_startup(&thread[i]);
|
||||
}
|
||||
|
||||
while (start_num < THREAD_NUM)
|
||||
rt_thread_mdelay(1);
|
||||
|
||||
rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
if (rt_condvar_broadcast(cond))
|
||||
{
|
||||
uassert_false(1);
|
||||
return ;
|
||||
}
|
||||
rt_mutex_release(mutex);
|
||||
|
||||
rt_thread_mdelay(1);
|
||||
|
||||
if (waken_num < THREAD_NUM)
|
||||
{
|
||||
LOG_E("[Main thread] Not all waiters were wakened\n");
|
||||
uassert_false(1);
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
utest_int_equal(waken_num, THREAD_NUM);
|
||||
}
|
||||
LOG_I("[Main thread] all waiters were wakened\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
start_num = 0;
|
||||
waken_num = 0;
|
||||
if (rt_mutex_init(&_local_mtx, "utest", RT_IPC_FLAG_PRIO) != 0)
|
||||
{
|
||||
perror("pthread_mutex_init() error");
|
||||
uassert_false(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rt_condvar_init(&_local_cv, NULL);
|
||||
|
||||
for (size_t i = 0; i < THREAD_NUM; i++)
|
||||
{
|
||||
stack_addr[i] =
|
||||
rt_pages_alloc_ext(rt_page_bits(STACK_SIZE), PAGE_ANY_AVAILABLE);
|
||||
utest_int_not_equal(stack_addr[i], RT_NULL);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_mutex_detach(&_local_mtx);
|
||||
rt_condvar_detach(&_local_cv);
|
||||
|
||||
for (size_t i = 0; i < THREAD_NUM; i++)
|
||||
{
|
||||
rt_pages_free(stack_addr[i], rt_page_bits(STACK_SIZE));
|
||||
stack_addr[i] = 0;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(condvar_broadcast_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.ipc.condvar.broadcast", utest_tc_init,
|
||||
utest_tc_cleanup, 10);
|
||||
122
RT_Thread/examples/utest/testcases/lwp/condvar_signal_tc.c
Normal file
122
RT_Thread/examples/utest/testcases/lwp/condvar_signal_tc.c
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-20 Shell add test suites
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "utest_assert.h"
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rtdef.h>
|
||||
#define STACK_SIZE (0x2000)
|
||||
|
||||
static struct rt_mutex _local_mtx;
|
||||
static struct rt_condvar _local_cv;
|
||||
|
||||
static void waker_thr(void *param)
|
||||
{
|
||||
int err;
|
||||
rt_mutex_t mutex = &_local_mtx;
|
||||
rt_condvar_t cond = &_local_cv;
|
||||
rt_mutex_take(mutex, RT_WAITING_FOREVER);
|
||||
err = rt_condvar_signal(cond);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
LOG_E("errno=%d, ret=%d\n", errno, err);
|
||||
LOG_E("rt_condvar_signal() error");
|
||||
uassert_false(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_false(0);
|
||||
}
|
||||
rt_mutex_release(mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void condvar_signal_tc(void)
|
||||
{
|
||||
rt_thread_t waker;
|
||||
rt_mutex_t mutex = &_local_mtx;
|
||||
rt_condvar_t cond = &_local_cv;
|
||||
int err;
|
||||
|
||||
waker = rt_thread_create("waker", waker_thr, 0, STACK_SIZE, 25, 50);
|
||||
uassert_not_null(waker);
|
||||
|
||||
if (rt_mutex_take(mutex, RT_WAITING_FOREVER) != 0)
|
||||
{
|
||||
LOG_E("pthread_mutex_lock() error");
|
||||
uassert_false(1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_false(0);
|
||||
}
|
||||
|
||||
rt_thread_startup(waker);
|
||||
|
||||
err = rt_condvar_timedwait(cond, mutex, RT_KILLABLE, 100);
|
||||
if (err != 0)
|
||||
{
|
||||
if (err == -EINTR || err == -ETIMEDOUT)
|
||||
{
|
||||
puts("wait timed out");
|
||||
uassert_false(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("errno=%d, ret=%d\n", errno, err);
|
||||
LOG_E("pthread_cond_timedwait() error");
|
||||
uassert_false(1);
|
||||
}
|
||||
}
|
||||
|
||||
err = rt_mutex_release(mutex);
|
||||
if (err != 0)
|
||||
{
|
||||
LOG_E("errno=%d, ret=%d\n", errno, err);
|
||||
LOG_E("rt_mutex_release() error");
|
||||
uassert_false(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_false(0);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
if (rt_mutex_init(&_local_mtx, "utest", RT_IPC_FLAG_PRIO) != 0)
|
||||
{
|
||||
perror("pthread_mutex_init() error");
|
||||
uassert_false(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rt_condvar_init(&_local_cv, NULL);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_mutex_detach(&_local_mtx);
|
||||
rt_condvar_detach(&_local_cv);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(condvar_signal_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.ipc.condvar.signal", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-20 Shell add test suites
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "utest_assert.h"
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rtdef.h>
|
||||
|
||||
static struct rt_mutex _local_mtx;
|
||||
static struct rt_condvar _local_cv;
|
||||
|
||||
static void condvar_timedwait_tc(void)
|
||||
{
|
||||
rt_mutex_t mutex = &_local_mtx;
|
||||
rt_condvar_t cond = &_local_cv;
|
||||
int err;
|
||||
|
||||
if (rt_mutex_take(mutex, RT_WAITING_FOREVER) != 0)
|
||||
{
|
||||
LOG_E("pthread_mutex_lock() error");
|
||||
uassert_false(1);
|
||||
return;
|
||||
}
|
||||
|
||||
err = rt_condvar_timedwait(cond, mutex, RT_KILLABLE, 100);
|
||||
if (err != 0)
|
||||
{
|
||||
if (err == -EINTR || err == -ETIMEDOUT)
|
||||
{
|
||||
puts("wait timed out");
|
||||
uassert_false(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("errno=%d, ret=%d\n", errno, err);
|
||||
LOG_E("pthread_cond_timedwait() error");
|
||||
uassert_false(1);
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
if (rt_mutex_init(&_local_mtx, "utest", RT_IPC_FLAG_PRIO) != 0)
|
||||
{
|
||||
perror("pthread_mutex_init() error");
|
||||
uassert_false(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rt_condvar_init(&_local_cv, NULL);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_mutex_detach(&_local_mtx);
|
||||
rt_condvar_detach(&_local_cv);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(condvar_timedwait_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.ipc.condvar.timedwait", utest_tc_init, utest_tc_cleanup, 10);
|
||||
17
RT_Thread/examples/utest/testcases/mm/Kconfig
Normal file
17
RT_Thread/examples/utest/testcases/mm/Kconfig
Normal file
@ -0,0 +1,17 @@
|
||||
menu "Memory Management Subsytem Testcase"
|
||||
|
||||
config UTEST_MM_API_TC
|
||||
bool "Enable Utest for MM API"
|
||||
default n
|
||||
help
|
||||
The test covers the Memory Management APIs under the
|
||||
`components/mm` and `libcpu/[mmu.*|tlb.*|cache.*]`
|
||||
|
||||
config UTEST_MM_LWP_TC
|
||||
bool "Enable Utest for MM API in lwp"
|
||||
default n
|
||||
help
|
||||
The test covers the Memory Management APIs under the
|
||||
`components/lwp`.
|
||||
|
||||
endmenu
|
||||
25
RT_Thread/examples/utest/testcases/mm/SConscript
Normal file
25
RT_Thread/examples/utest/testcases/mm/SConscript
Normal file
@ -0,0 +1,25 @@
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend(['UTEST_MM_API_TC', 'RT_USING_SMART']):
|
||||
# deprecated test, will be rewrited in the future
|
||||
# src += ['mm_api_tc.c', 'mm_libcpu_tc.c']
|
||||
src += ['rt_ioremap.c']
|
||||
src += ['aspace_unmap_range_invalid_param.c', 'aspace_unmap_range_shrink.c']
|
||||
src += ['aspace_unmap_range_split.c', 'aspace_map_expand.c']
|
||||
src += ['lwp_mmap_expand.c', 'lwp_mmap_map_fixed.c', 'lwp_mmap_fix_private.c']
|
||||
src += ['lwp_mmap_fd.c', 'lwp_mmap_fd_map_fixed_merge.c', 'lwp_mmap_fd_map_fixed_split.c']
|
||||
|
||||
if GetDepend(['UTEST_MM_API_TC', 'RT_USING_MEMBLOCK']):
|
||||
src += ['mm_memblock_tc.c']
|
||||
|
||||
if GetDepend(['UTEST_MM_LWP_TC', 'RT_USING_SMART']):
|
||||
src += ['mm_lwp_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
119
RT_Thread/examples/utest/testcases/mm/aspace_map_expand.c
Normal file
119
RT_Thread/examples/utest/testcases/mm/aspace_map_expand.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-22 Shell test case for aspace_map with varea_expand
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include <mm_aspace.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
static size_t flags = MMF_PREFETCH | MMF_MAP_FIXED;
|
||||
static size_t attr = MMU_MAP_K_RWCB;
|
||||
static rt_mem_obj_t mem_obj = &rt_mm_dummy_mapper;
|
||||
|
||||
static char *ex_vaddr = (void *)0x100000000;
|
||||
static size_t ex_offset = 1024;
|
||||
static size_t map_size = 0x3000;
|
||||
|
||||
static size_t former_vsz;
|
||||
static size_t former_vcount;
|
||||
|
||||
static struct rt_lwp *lwp;
|
||||
|
||||
static int _count_vsz(rt_varea_t varea, void *arg)
|
||||
{
|
||||
rt_base_t *pvsz = arg;
|
||||
*pvsz += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_base_t count_vcount(rt_aspace_t aspace)
|
||||
{
|
||||
rt_base_t vcount = 0;
|
||||
rt_aspace_traversal(aspace, _count_vsz, &vcount);
|
||||
return vcount;
|
||||
}
|
||||
|
||||
static void test_map_varea_expand(void)
|
||||
{
|
||||
char *next_va;
|
||||
size_t next_offset;
|
||||
|
||||
/* create an existed mapping */
|
||||
next_va = ex_vaddr;
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
former_vcount = count_vcount(lwp->aspace);
|
||||
utest_int_equal(
|
||||
RT_EOK,
|
||||
rt_aspace_map(lwp->aspace, (void *)&ex_vaddr, map_size, attr, flags, mem_obj, ex_offset)
|
||||
);
|
||||
uassert_true(next_va == ex_vaddr);
|
||||
utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vsz += map_size;
|
||||
former_vcount += 1;
|
||||
|
||||
/* test the RIGHT side expansion of varea by rt_aspace_map */
|
||||
next_va = ex_vaddr + map_size;
|
||||
next_offset = ex_offset + (map_size >> MM_PAGE_SHIFT);
|
||||
utest_int_equal(
|
||||
RT_EOK,
|
||||
rt_aspace_map(lwp->aspace, (void *)&next_va, map_size, attr, flags, mem_obj, next_offset)
|
||||
);
|
||||
uassert_true(next_va == (char *)ex_vaddr + map_size);
|
||||
utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount, count_vcount(lwp->aspace));
|
||||
former_vsz += map_size;
|
||||
|
||||
/* test the LEFT side expansion of varea by rt_aspace_map */
|
||||
next_va = ex_vaddr - map_size;
|
||||
next_offset = ex_offset - (map_size >> MM_PAGE_SHIFT);
|
||||
utest_int_equal(
|
||||
RT_EOK,
|
||||
rt_aspace_map(lwp->aspace, (void *)&next_va, map_size, attr, flags, mem_obj, next_offset)
|
||||
);
|
||||
uassert_true(next_va == ex_vaddr - map_size);
|
||||
utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount, count_vcount(lwp->aspace));
|
||||
former_vsz += map_size;
|
||||
|
||||
/* test the expand varea routine from rt_aspace_map_static */
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, next_va, 3 * map_size));
|
||||
|
||||
/* test the expand varea routine from rt_aspace_map_phy */
|
||||
/* test the expand varea routine from rt_aspace_map_phy_static */
|
||||
/* these 2 from another file */
|
||||
}
|
||||
|
||||
static void aspace_map_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_map_varea_expand());
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(aspace_map_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_map.varea_expand", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-17 Shell test case for aspace_unmap_range
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include <mm_aspace.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
static void *vaddr = (void *)0x100000000;
|
||||
static size_t existed_size = 0x5000;
|
||||
static char *unmap_start;
|
||||
static size_t unmap_size = 0x2000;
|
||||
static size_t former_vsz;
|
||||
static struct rt_lwp *lwp;
|
||||
static size_t flags = MMF_PREFETCH | MMF_MAP_FIXED;
|
||||
|
||||
static void test_unmap_range_invalid_param(void)
|
||||
{
|
||||
rt_mem_obj_t notsupp_object;
|
||||
|
||||
/* create an existed mapping */
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, flags, &rt_mm_dummy_mapper, 0));
|
||||
utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
former_vsz += existed_size;
|
||||
|
||||
/* test unaligned vaddr start */
|
||||
unmap_start = (char *)vaddr - 0x1234;
|
||||
utest_int_equal(-RT_EINVAL, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size));
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
|
||||
/* test unaligned size */
|
||||
unmap_size = 0x2000;
|
||||
unmap_start = (char *)vaddr + existed_size - unmap_size;
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size - 0x123));
|
||||
utest_int_equal(former_vsz - unmap_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
|
||||
/* create another mapping binding to mem_obj without proper handler */
|
||||
notsupp_object = rt_mem_obj_create(&rt_mm_dummy_mapper);
|
||||
notsupp_object->on_varea_shrink = RT_NULL;
|
||||
|
||||
utest_int_equal(
|
||||
RT_EOK,
|
||||
rt_aspace_map(lwp->aspace, (void *)&unmap_start, unmap_size, MMU_MAP_K_RWCB, flags, notsupp_object, 0)
|
||||
);
|
||||
|
||||
utest_int_equal(-RT_EPERM, rt_aspace_unmap_range(lwp->aspace, unmap_start, 0x1000));
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size));
|
||||
rt_free(notsupp_object);
|
||||
}
|
||||
|
||||
static void aspace_unmap_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_unmap_range_invalid_param());
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(aspace_unmap_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.invalid_param", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-17 Shell test case for aspace_unmap_range
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include <mm_aspace.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
static void *vaddr = (void *)0x100000000;
|
||||
static size_t existed_size = 0x5000;
|
||||
static char *unmap_start;
|
||||
static char *unmap_end;
|
||||
static size_t former_vsz;
|
||||
static size_t unmap_size = 0x2000;
|
||||
static struct rt_lwp *lwp;
|
||||
|
||||
static void test_unmap_range_shrink(void)
|
||||
{
|
||||
/* create an existed mapping */
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0));
|
||||
utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
former_vsz += existed_size;
|
||||
|
||||
/* test the shrink mode of unmap from LEFT side */
|
||||
unmap_start = (char *)vaddr - unmap_size/2;
|
||||
uassert_true(!rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size));
|
||||
unmap_end = unmap_start + unmap_size;
|
||||
uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_end) != ARCH_MAP_FAILED);
|
||||
utest_int_equal(former_vsz - (unmap_end - (char *)vaddr), rt_aspace_count_vsz(lwp->aspace));
|
||||
former_vsz -= unmap_end - (char *)vaddr;
|
||||
|
||||
/* test the shrink mode of unmap from RIGHT side */
|
||||
unmap_start = (char *)vaddr + existed_size - unmap_size / 2;
|
||||
uassert_true(!rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size));
|
||||
uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start - 1) != ARCH_MAP_FAILED);
|
||||
utest_int_equal(former_vsz - (unmap_end - (char *)vaddr), rt_aspace_count_vsz(lwp->aspace));
|
||||
former_vsz -= unmap_end - (char *)vaddr;
|
||||
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size));
|
||||
}
|
||||
|
||||
static void aspace_unmap_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_unmap_range_shrink());
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(aspace_unmap_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.shrink", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-17 Shell test case for aspace_unmap_range
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include <mm_aspace.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
static void *vaddr = (void *)0x100000000;
|
||||
static size_t existed_size = 0x5000;
|
||||
static char *unmap_start = (char *)0x100000000 + 0x3000;
|
||||
static size_t former_vsz;
|
||||
static size_t unmap_size = 0x1000;
|
||||
static struct rt_lwp *lwp;
|
||||
|
||||
static void test_unmap_range_split(void)
|
||||
{
|
||||
/* create an existed mapping */
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0));
|
||||
utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
former_vsz += existed_size;
|
||||
|
||||
/* test the split mode of unmap */
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size));
|
||||
uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start - 1) != ARCH_MAP_FAILED);
|
||||
uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start + unmap_size) != ARCH_MAP_FAILED);
|
||||
utest_int_equal(former_vsz - unmap_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size));
|
||||
}
|
||||
|
||||
static void aspace_unmap_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_unmap_range_split());
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(aspace_unmap_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.split", utest_tc_init, utest_tc_cleanup, 10);
|
||||
81
RT_Thread/examples/utest/testcases/mm/common.h
Normal file
81
RT_Thread/examples/utest/testcases/mm/common.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c
|
||||
*/
|
||||
#ifndef __TEST_MM_COMMON_H__
|
||||
#define __TEST_MM_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utest.h>
|
||||
|
||||
#include <board.h>
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <mmu.h>
|
||||
#include <tlb.h>
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
#include <lwp_arch.h>
|
||||
#endif
|
||||
|
||||
#include <ioremap.h>
|
||||
#include <mm_aspace.h>
|
||||
#include <mm_flag.h>
|
||||
#include <mm_page.h>
|
||||
#include <mm_private.h>
|
||||
|
||||
extern rt_base_t rt_heap_lock(void);
|
||||
extern void rt_heap_unlock(rt_base_t level);
|
||||
|
||||
#define __int_compare(a, b, operator) do{long _a = (long)(a); long _b = (long)(b); __utest_assert((_a) operator (_b), "Assertion Failed: (" #a ") "#operator" (" #b ")"); if (!((_a) operator (_b)))LOG_E("\t"#a"=%ld(0x%lx), "#b"=%ld(0x%lx)", _a, _a, _b, _b);} while (0)
|
||||
#define utest_int_equal(a, b) __int_compare(a, b, ==)
|
||||
#define utest_int_less(a, b) __int_compare(a, b, <)
|
||||
#define utest_int_less_equal(a, b) __int_compare(a, b, <=)
|
||||
|
||||
/**
|
||||
* @brief During the operations, is heap still the same;
|
||||
*/
|
||||
#define CONSIST_HEAP(statement) do { \
|
||||
rt_size_t total, used, max_used; \
|
||||
rt_size_t totala, useda, max_useda; \
|
||||
rt_ubase_t level = rt_heap_lock(); \
|
||||
rt_memory_info(&total, &used, &max_used); \
|
||||
statement; \
|
||||
rt_memory_info(&totala, &useda, &max_useda); \
|
||||
rt_heap_unlock(level); \
|
||||
utest_int_equal(total, totala); \
|
||||
utest_int_equal(used, useda); \
|
||||
} while (0)
|
||||
|
||||
#ifdef STANDALONE_TC
|
||||
#define TC_ASSERT(expr) \
|
||||
((expr) \
|
||||
? 0 \
|
||||
: rt_kprintf("AssertFault(%d): %s\n", __LINE__, RT_STRINGIFY(expr)))
|
||||
#else
|
||||
#define TC_ASSERT(expr) uassert_true(expr)
|
||||
#endif
|
||||
|
||||
rt_inline int memtest(volatile char *buf, int value, size_t buf_sz)
|
||||
{
|
||||
int ret = 0;
|
||||
for (size_t i = 0; i < buf_sz; i++)
|
||||
{
|
||||
if (buf[i] != value)
|
||||
{
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __TEST_MM_COMMON_H__ */
|
||||
109
RT_Thread/examples/utest/testcases/mm/lwp_mmap_expand.c
Normal file
109
RT_Thread/examples/utest/testcases/mm/lwp_mmap_expand.c
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-22 Shell test case for aspace_map with varea_expand
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include <mm_aspace.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
static long fd = -1;
|
||||
static long pgoffset = 0;
|
||||
static size_t flags = MAP_FIXED | MAP_ANONYMOUS;
|
||||
static size_t prot1 = PROT_READ | PROT_WRITE;
|
||||
|
||||
static char *ex_vaddr = (void *)0x100000000;
|
||||
static size_t map_size = 0x3000;
|
||||
|
||||
static size_t former_vsz;
|
||||
static size_t former_vcount;
|
||||
|
||||
static struct rt_lwp *lwp;
|
||||
|
||||
static int _count_vsz(rt_varea_t varea, void *arg)
|
||||
{
|
||||
rt_base_t *pvsz = arg;
|
||||
*pvsz += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_base_t count_vcount(rt_aspace_t aspace)
|
||||
{
|
||||
rt_base_t vcount = 0;
|
||||
rt_aspace_traversal(aspace, _count_vsz, &vcount);
|
||||
return vcount;
|
||||
}
|
||||
|
||||
static void test_mmap_expand(void)
|
||||
{
|
||||
char *next_va;
|
||||
|
||||
/* map new pages at ex_vaddr to anonymous */
|
||||
next_va = ex_vaddr;
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
former_vcount = count_vcount(lwp->aspace);
|
||||
next_va = lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset);
|
||||
uassert_true(next_va == ex_vaddr);
|
||||
utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vsz += map_size;
|
||||
former_vcount += 1;
|
||||
|
||||
/* test the RIGHT side expansion of varea by lwp_mmap2 */
|
||||
next_va = ex_vaddr + map_size;
|
||||
uassert_true(
|
||||
lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset)
|
||||
== next_va
|
||||
);
|
||||
utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount, count_vcount(lwp->aspace));
|
||||
former_vsz += map_size;
|
||||
|
||||
/* test the LEFT side expansion of varea by rt_aspace_map */
|
||||
next_va = ex_vaddr - map_size;
|
||||
uassert_true(
|
||||
lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset)
|
||||
== next_va
|
||||
);
|
||||
utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount, count_vcount(lwp->aspace));
|
||||
former_vsz += map_size;
|
||||
|
||||
/* test other prot/offset/flags */
|
||||
|
||||
/* clear mapping */
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, next_va, 3 * map_size));
|
||||
}
|
||||
|
||||
static void aspace_map_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_mmap_expand());
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(aspace_map_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.expand", utest_tc_init, utest_tc_cleanup, 10);
|
||||
140
RT_Thread/examples/utest/testcases/mm/lwp_mmap_fd.c
Normal file
140
RT_Thread/examples/utest/testcases/mm/lwp_mmap_fd.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-17 Shell test case for aspace_map(MAP_FIXED)
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include "utest_assert.h"
|
||||
#include <mm_private.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define PAGE_SZ (1 << MM_PAGE_SHIFT)
|
||||
#define PAGE_COUNT ('z' - 'a' + 1)
|
||||
#define FILE_PATH "/test_mmap"
|
||||
#define FILE_SZ (PAGE_COUNT * PAGE_SZ)
|
||||
|
||||
static struct rt_lwp *lwp;
|
||||
static size_t former_vsz;
|
||||
static size_t former_vcount;
|
||||
static char page_sz_buf[PAGE_SZ];
|
||||
|
||||
static void *vaddr = (void *)0x100000000;
|
||||
static long pgoffset = 0;
|
||||
static size_t ex_prot = PROT_NONE;
|
||||
static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
|
||||
static int _count_vsz(rt_varea_t varea, void *arg)
|
||||
{
|
||||
rt_base_t *pvsz = arg;
|
||||
*pvsz += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_base_t count_vcount(rt_aspace_t aspace)
|
||||
{
|
||||
rt_base_t vcount = 0;
|
||||
rt_aspace_traversal(aspace, _count_vsz, &vcount);
|
||||
return vcount;
|
||||
}
|
||||
|
||||
static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer)
|
||||
{
|
||||
rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr);
|
||||
if (varea && varea->mem_obj && varea->mem_obj->page_read)
|
||||
{
|
||||
struct rt_aspace_io_msg io_msg;
|
||||
rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer);
|
||||
varea->mem_obj->page_read(varea, &io_msg);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _verify_file_content(const char *mmap_buf)
|
||||
{
|
||||
char ch = 'a';
|
||||
for (char *read_va = (char *)mmap_buf; read_va < mmap_buf + FILE_SZ; read_va += PAGE_SZ, ch++)
|
||||
{
|
||||
_lwp_get_user(lwp, read_va, page_sz_buf);
|
||||
utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_mmap_fd(void)
|
||||
{
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
former_vcount = count_vcount(lwp->aspace);
|
||||
|
||||
/* create an existed mapping */
|
||||
long temp_fd;
|
||||
temp_fd = open(FILE_PATH, O_RDONLY);
|
||||
LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH);
|
||||
uassert_true(temp_fd >= 0);
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, vaddr, FILE_SZ, ex_prot, ex_flags, temp_fd, pgoffset),
|
||||
vaddr);
|
||||
close(temp_fd);
|
||||
|
||||
utest_int_equal(former_vsz + FILE_SZ, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
|
||||
_verify_file_content(vaddr);
|
||||
|
||||
/* create an override mapping */
|
||||
|
||||
/* close */
|
||||
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, FILE_SZ));
|
||||
}
|
||||
|
||||
static void testcase_main(void)
|
||||
{
|
||||
test_mmap_fd();
|
||||
}
|
||||
|
||||
static void _setup_file_content(long fd)
|
||||
{
|
||||
char ch = 'a';
|
||||
|
||||
for (size_t i = 0; i < PAGE_COUNT; i++, ch++)
|
||||
{
|
||||
memset(page_sz_buf, ch, PAGE_SZ);
|
||||
write(fd, page_sz_buf, PAGE_SZ);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
/* setup file */
|
||||
long temp_file_des;
|
||||
temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777);
|
||||
LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH);
|
||||
if (temp_file_des < 0)
|
||||
return -RT_ERROR;
|
||||
_setup_file_content(temp_file_des);
|
||||
close(temp_file_des);
|
||||
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(testcase_main);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.basic", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-17 Shell test case for aspace_map(MAP_FIXED)
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include "utest_assert.h"
|
||||
#include <mm_private.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define PAGE_SZ (1 << MM_PAGE_SHIFT)
|
||||
#define PAGE_COUNT ('z' - 'a' + 1)
|
||||
#define FILE_PATH "/test_mmap"
|
||||
#define FILE_SZ (PAGE_COUNT * PAGE_SZ)
|
||||
|
||||
static struct rt_lwp *lwp;
|
||||
static size_t former_vsz;
|
||||
static size_t former_vcount;
|
||||
static char page_sz_buf[PAGE_SZ];
|
||||
|
||||
static void *ex_start = (void *)0x100000000;
|
||||
static size_t ex_size = 0x5000;
|
||||
static long pgoffset = 0;
|
||||
static size_t ex_prot = PROT_NONE;
|
||||
static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
|
||||
static char *private0 = (char *)0x100000000;
|
||||
static char *private1 = (char *)0x100000000 + 0x1000;
|
||||
static char *private2 = (char *)0x100000000 + 0x2000;
|
||||
static char *private3 = (char *)0x100000000 + 0x3000;
|
||||
static char *private4 = (char *)0x100000000 + 0x4000;
|
||||
static size_t or_size = 0x1000;
|
||||
static size_t or_prot = PROT_READ | PROT_WRITE;
|
||||
static size_t or_flags = MAP_ANON | MAP_FIXED;
|
||||
|
||||
static long anon_fd = -1;
|
||||
|
||||
static int _count_vsz(rt_varea_t varea, void *arg)
|
||||
{
|
||||
rt_base_t *pvsz = arg;
|
||||
*pvsz += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_base_t count_vcount(rt_aspace_t aspace)
|
||||
{
|
||||
rt_base_t vcount = 0;
|
||||
rt_aspace_traversal(aspace, _count_vsz, &vcount);
|
||||
return vcount;
|
||||
}
|
||||
|
||||
static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer)
|
||||
{
|
||||
rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr);
|
||||
if (varea && varea->mem_obj && varea->mem_obj->page_read)
|
||||
{
|
||||
struct rt_aspace_io_msg io_msg;
|
||||
rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer);
|
||||
varea->mem_obj->page_read(varea, &io_msg);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch)
|
||||
{
|
||||
_lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf);
|
||||
utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ));
|
||||
}
|
||||
|
||||
static void test_mmap_fd_fixed(void)
|
||||
{
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
former_vcount = count_vcount(lwp->aspace);
|
||||
|
||||
/* create an existed mapping */
|
||||
long temp_fd;
|
||||
temp_fd = open(FILE_PATH, O_RDONLY);
|
||||
LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH);
|
||||
uassert_true(temp_fd >= 0);
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, anon_fd, pgoffset),
|
||||
ex_start);
|
||||
utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vsz += ex_size;
|
||||
former_vcount += 1;
|
||||
_verify_file_content(lwp, private0, 0);
|
||||
_verify_file_content(lwp, private1, 0);
|
||||
_verify_file_content(lwp, private2, 0);
|
||||
_verify_file_content(lwp, private3, 0);
|
||||
_verify_file_content(lwp, private4, 0);
|
||||
|
||||
/* create an override mapping */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, temp_fd, 2),
|
||||
private2);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace));
|
||||
former_vcount += 2;
|
||||
_verify_file_content(lwp, private0, 0);
|
||||
_verify_file_content(lwp, private1, 0);
|
||||
_verify_file_content(lwp, private2, 'c');
|
||||
_verify_file_content(lwp, private3, 0);
|
||||
_verify_file_content(lwp, private4, 0);
|
||||
|
||||
/* fix private from left most */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, temp_fd, 0),
|
||||
private0);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vcount += 1;
|
||||
_verify_file_content(lwp, private0, 'a');
|
||||
_verify_file_content(lwp, private1, 0);
|
||||
_verify_file_content(lwp, private2, 'c');
|
||||
_verify_file_content(lwp, private3, 0);
|
||||
_verify_file_content(lwp, private4, 0);
|
||||
|
||||
/* fix private from right most */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, temp_fd, 4),
|
||||
private4);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vcount += 1;
|
||||
_verify_file_content(lwp, private0, 'a');
|
||||
_verify_file_content(lwp, private1, 0);
|
||||
_verify_file_content(lwp, private2, 'c');
|
||||
_verify_file_content(lwp, private3, 0);
|
||||
_verify_file_content(lwp, private4, 'e');
|
||||
|
||||
/* fix private from left-middle */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, temp_fd, 1),
|
||||
private1);
|
||||
rt_aspace_print_all(lwp->aspace);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
|
||||
former_vcount -= 1;
|
||||
_verify_file_content(lwp, private0, 'a');
|
||||
_verify_file_content(lwp, private1, 'b');
|
||||
_verify_file_content(lwp, private2, 'c');
|
||||
_verify_file_content(lwp, private3, 0);
|
||||
_verify_file_content(lwp, private4, 'e');
|
||||
|
||||
/* fix private from right-middle */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, temp_fd, 3),
|
||||
private3);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
|
||||
former_vcount -= 1;
|
||||
_verify_file_content(lwp, private0, 'a');
|
||||
_verify_file_content(lwp, private1, 'b');
|
||||
_verify_file_content(lwp, private2, 'c');
|
||||
_verify_file_content(lwp, private3, 'd');
|
||||
_verify_file_content(lwp, private4, 'e');
|
||||
|
||||
/* close */
|
||||
close(temp_fd);
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ));
|
||||
}
|
||||
|
||||
static void testcase_main(void)
|
||||
{
|
||||
test_mmap_fd_fixed();
|
||||
}
|
||||
|
||||
static void _setup_file_content(long fd)
|
||||
{
|
||||
char ch = 'a';
|
||||
for (size_t i = 0; i < PAGE_COUNT; i++, ch++)
|
||||
{
|
||||
memset(page_sz_buf, ch, PAGE_SZ);
|
||||
write(fd, page_sz_buf, PAGE_SZ);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
/* setup file */
|
||||
long temp_file_des;
|
||||
temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777);
|
||||
LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH);
|
||||
if (temp_file_des < 0)
|
||||
return -RT_ERROR;
|
||||
_setup_file_content(temp_file_des);
|
||||
close(temp_file_des);
|
||||
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(testcase_main);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_merge", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-17 Shell test case for aspace_map(MAP_FIXED)
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include "utest_assert.h"
|
||||
#include <mm_private.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define PAGE_SZ (1 << MM_PAGE_SHIFT)
|
||||
#define PAGE_COUNT ('z' - 'a' + 1)
|
||||
#define FILE_PATH "/test_mmap"
|
||||
#define FILE_SZ (PAGE_COUNT * PAGE_SZ)
|
||||
|
||||
static struct rt_lwp *lwp;
|
||||
static size_t former_vsz;
|
||||
static size_t former_vcount;
|
||||
static char page_sz_buf[PAGE_SZ];
|
||||
|
||||
static void *ex_start = (void *)0x100000000;
|
||||
static size_t ex_size = 0x5000;
|
||||
static long pgoffset = 0;
|
||||
static size_t ex_prot = PROT_NONE;
|
||||
static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
|
||||
static char *private0 = (char *)0x100000000;
|
||||
static char *private1 = (char *)0x100000000 + 0x1000;
|
||||
static char *private2 = (char *)0x100000000 + 0x2000;
|
||||
static char *private3 = (char *)0x100000000 + 0x3000;
|
||||
static char *private4 = (char *)0x100000000 + 0x4000;
|
||||
static size_t or_size = 0x1000;
|
||||
static size_t or_prot = PROT_READ | PROT_WRITE;
|
||||
static size_t or_flags = MAP_ANON | MAP_FIXED;
|
||||
|
||||
static long anon_fd = -1;
|
||||
|
||||
static int _count_vsz(rt_varea_t varea, void *arg)
|
||||
{
|
||||
rt_base_t *pvsz = arg;
|
||||
*pvsz += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_base_t count_vcount(rt_aspace_t aspace)
|
||||
{
|
||||
rt_base_t vcount = 0;
|
||||
rt_aspace_traversal(aspace, _count_vsz, &vcount);
|
||||
return vcount;
|
||||
}
|
||||
|
||||
static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer)
|
||||
{
|
||||
rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr);
|
||||
if (varea && varea->mem_obj && varea->mem_obj->page_read)
|
||||
{
|
||||
struct rt_aspace_io_msg io_msg;
|
||||
rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer);
|
||||
varea->mem_obj->page_read(varea, &io_msg);
|
||||
}
|
||||
else
|
||||
return -RT_ERROR;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch)
|
||||
{
|
||||
utest_int_equal(RT_EOK, _lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf));
|
||||
utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ));
|
||||
}
|
||||
|
||||
static void test_mmap_fd_fixed(void)
|
||||
{
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
former_vcount = count_vcount(lwp->aspace);
|
||||
|
||||
/* create an existed mapping */
|
||||
long temp_fd;
|
||||
temp_fd = open(FILE_PATH, O_RDONLY);
|
||||
LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH);
|
||||
uassert_true(temp_fd >= 0);
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, temp_fd, pgoffset),
|
||||
ex_start);
|
||||
utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
_verify_file_content(lwp, private0, 'a');
|
||||
_verify_file_content(lwp, private1, 'b');
|
||||
_verify_file_content(lwp, private2, 'c');
|
||||
_verify_file_content(lwp, private3, 'd');
|
||||
_verify_file_content(lwp, private4, 'e');
|
||||
former_vsz += ex_size;
|
||||
former_vcount += 1;
|
||||
|
||||
/* create an override mapping */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, anon_fd, pgoffset),
|
||||
private2);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace));
|
||||
former_vcount += 2;
|
||||
_verify_file_content(lwp, private0, 'a');
|
||||
_verify_file_content(lwp, private1, 'b');
|
||||
_verify_file_content(lwp, private2, 0);
|
||||
_verify_file_content(lwp, private3, 'd');
|
||||
_verify_file_content(lwp, private4, 'e');
|
||||
|
||||
/* fix private from left most */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, anon_fd, pgoffset),
|
||||
private0);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vcount += 1;
|
||||
_verify_file_content(lwp, private0, 0);
|
||||
_verify_file_content(lwp, private1, 'b');
|
||||
_verify_file_content(lwp, private2, 0);
|
||||
_verify_file_content(lwp, private3, 'd');
|
||||
_verify_file_content(lwp, private4, 'e');
|
||||
|
||||
/* fix private from right most */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, anon_fd, pgoffset),
|
||||
private4);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vcount += 1;
|
||||
_verify_file_content(lwp, private0, 0);
|
||||
_verify_file_content(lwp, private1, 'b');
|
||||
_verify_file_content(lwp, private2, 0);
|
||||
_verify_file_content(lwp, private3, 'd');
|
||||
_verify_file_content(lwp, private4, 0);
|
||||
|
||||
/* fix private from left-middle */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, anon_fd, pgoffset),
|
||||
private1);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
|
||||
former_vcount -= 1;
|
||||
_verify_file_content(lwp, private0, 0);
|
||||
_verify_file_content(lwp, private1, 0);
|
||||
_verify_file_content(lwp, private2, 0);
|
||||
_verify_file_content(lwp, private3, 'd');
|
||||
_verify_file_content(lwp, private4, 0);
|
||||
|
||||
/* fix private from right-middle */
|
||||
utest_int_equal(
|
||||
lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, anon_fd, pgoffset),
|
||||
private3);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
|
||||
former_vcount -= 1;
|
||||
_verify_file_content(lwp, private0, 0);
|
||||
_verify_file_content(lwp, private1, 0);
|
||||
_verify_file_content(lwp, private2, 0);
|
||||
_verify_file_content(lwp, private3, 0);
|
||||
_verify_file_content(lwp, private4, 0);
|
||||
|
||||
/* close */
|
||||
close(temp_fd);
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ));
|
||||
}
|
||||
|
||||
static void testcase_main(void)
|
||||
{
|
||||
test_mmap_fd_fixed();
|
||||
}
|
||||
|
||||
static void _setup_file_content(long fd)
|
||||
{
|
||||
char ch = 'a';
|
||||
for (size_t i = 0; i < PAGE_COUNT; i++, ch++)
|
||||
{
|
||||
memset(page_sz_buf, ch, PAGE_SZ);
|
||||
write(fd, page_sz_buf, PAGE_SZ);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
/* setup file */
|
||||
long temp_file_des;
|
||||
temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777);
|
||||
LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH);
|
||||
if (temp_file_des < 0)
|
||||
return -RT_ERROR;
|
||||
_setup_file_content(temp_file_des);
|
||||
close(temp_file_des);
|
||||
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(testcase_main);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_split", utest_tc_init, utest_tc_cleanup, 10);
|
||||
138
RT_Thread/examples/utest/testcases/mm/lwp_mmap_fix_private.c
Normal file
138
RT_Thread/examples/utest/testcases/mm/lwp_mmap_fix_private.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-22 Shell test case for aspace_map with varea_expand
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include "mm_fault.h"
|
||||
#include <mm_aspace.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
static long fd = -1;
|
||||
static long pgoffset = 0;
|
||||
static size_t flags = MAP_FIXED | MAP_ANONYMOUS;
|
||||
static size_t prot = PROT_READ | PROT_WRITE;
|
||||
|
||||
static char *ex_vaddr = (char *)0x100000000;
|
||||
static size_t ex_size = 0x5000;
|
||||
static char *private0 = (char *)0x100000000;
|
||||
static char *private1 = (char *)0x100000000 + 0x1000;
|
||||
static char *private2 = (char *)0x100000000 + 0x2000;
|
||||
static char *private3 = (char *)0x100000000 + 0x3000;
|
||||
static char *private4 = (char *)0x100000000 + 0x4000;
|
||||
|
||||
/**
|
||||
* todo: suppoprt prefetch pages, so more than 1 page can install to private at a time
|
||||
* static size_t priv_size = 0x1000;
|
||||
*/
|
||||
|
||||
static size_t former_vsz;
|
||||
static size_t former_vcount;
|
||||
|
||||
static struct rt_lwp *lwp;
|
||||
|
||||
static int _count_vsz(rt_varea_t varea, void *arg)
|
||||
{
|
||||
rt_base_t *pvsz = arg;
|
||||
*pvsz += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_base_t count_vcount(rt_aspace_t aspace)
|
||||
{
|
||||
rt_base_t vcount = 0;
|
||||
rt_aspace_traversal(aspace, _count_vsz, &vcount);
|
||||
return vcount;
|
||||
}
|
||||
|
||||
static void test_mmap_fix_private(void)
|
||||
{
|
||||
char *next_va;
|
||||
struct rt_aspace_fault_msg msg;
|
||||
msg.fault_op = MM_FAULT_OP_WRITE;
|
||||
msg.fault_type = MM_FAULT_TYPE_RWX_PERM;
|
||||
|
||||
/* map new pages at ex_vaddr to anonymous */
|
||||
next_va = ex_vaddr;
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
former_vcount = count_vcount(lwp->aspace);
|
||||
next_va = lwp_mmap2(lwp, next_va, ex_size, prot, flags, fd, pgoffset);
|
||||
uassert_true(next_va == ex_vaddr);
|
||||
utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vsz += ex_size;
|
||||
former_vcount += 1;
|
||||
|
||||
/* fix private in the middle */
|
||||
msg.fault_vaddr = private2;
|
||||
utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg));
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace));
|
||||
former_vcount += 2;
|
||||
|
||||
/* fix private from left most */
|
||||
msg.fault_vaddr = private0;
|
||||
utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg));
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vcount += 1;
|
||||
|
||||
/* fix private from right most */
|
||||
msg.fault_vaddr = private4;
|
||||
utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg));
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vcount += 1;
|
||||
|
||||
/* fix private from left-middle */
|
||||
msg.fault_vaddr = private1;
|
||||
utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg));
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
|
||||
former_vcount -= 1;
|
||||
|
||||
/* fix private from right-middle */
|
||||
msg.fault_vaddr = private3;
|
||||
utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg));
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
|
||||
former_vcount -= 1;
|
||||
|
||||
/* clear mapping */
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_vaddr, ex_size));
|
||||
rt_free(lwp->aspace->private_object);
|
||||
lwp->aspace->private_object = RT_NULL;
|
||||
}
|
||||
|
||||
static void testcase_main(void)
|
||||
{
|
||||
CONSIST_HEAP(test_mmap_fix_private());
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(testcase_main);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.fix_private", utest_tc_init, utest_tc_cleanup, 10);
|
||||
117
RT_Thread/examples/utest/testcases/mm/lwp_mmap_map_fixed.c
Normal file
117
RT_Thread/examples/utest/testcases/mm/lwp_mmap_map_fixed.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-17 Shell test case for aspace_map(MAP_FIXED)
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include "utest_assert.h"
|
||||
#include <mm_aspace.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
static struct rt_lwp *lwp;
|
||||
static size_t former_vsz;
|
||||
static size_t former_vcount;
|
||||
|
||||
static void *vaddr = (void *)0x100000000;
|
||||
static size_t ex_size = 0x5000;
|
||||
static char *override_start;
|
||||
static size_t override_size = 0x2000;
|
||||
static long fd = -1;
|
||||
static long pgoffset = 0;
|
||||
static size_t ex_prot = PROT_NONE;
|
||||
static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
static size_t override_prot = PROT_READ | PROT_WRITE;
|
||||
static size_t override_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
||||
|
||||
static int _count_vsz(rt_varea_t varea, void *arg)
|
||||
{
|
||||
rt_base_t *pvsz = arg;
|
||||
*pvsz += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_base_t count_vcount(rt_aspace_t aspace)
|
||||
{
|
||||
rt_base_t vcount = 0;
|
||||
rt_aspace_traversal(aspace, _count_vsz, &vcount);
|
||||
return vcount;
|
||||
}
|
||||
|
||||
static char put_data[] = "hello,world";
|
||||
|
||||
static void test_map_fixed(void)
|
||||
{
|
||||
void *effect_override;
|
||||
|
||||
former_vsz = rt_aspace_count_vsz(lwp->aspace);
|
||||
former_vcount = count_vcount(lwp->aspace);
|
||||
|
||||
/* create an existed mapping */
|
||||
vaddr = lwp_mmap2(lwp, vaddr, ex_size, ex_prot, ex_flags, fd, pgoffset);
|
||||
uassert_true((long)vaddr > 0);
|
||||
utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
|
||||
former_vsz += ex_size;
|
||||
former_vcount += 1;
|
||||
|
||||
/* fix private in the middle */
|
||||
override_start = (char *)vaddr + 0x1000;
|
||||
effect_override = lwp_mmap2(lwp, override_start, override_size, override_prot, override_flags, fd, pgoffset);
|
||||
uassert_true(effect_override == override_start);
|
||||
utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
|
||||
utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace));
|
||||
utest_int_equal(
|
||||
lwp_data_put(lwp, effect_override, put_data, sizeof(put_data)),
|
||||
sizeof(put_data)
|
||||
);
|
||||
|
||||
utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, ex_size));
|
||||
}
|
||||
|
||||
static void aspace_unmap_tc(void)
|
||||
{
|
||||
test_map_fixed();
|
||||
}
|
||||
|
||||
static rt_size_t total, used, max_used;
|
||||
static rt_size_t totala, useda, max_useda;
|
||||
static rt_ubase_t level;
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
lwp = lwp_create(0);
|
||||
if (lwp)
|
||||
lwp_user_space_init(lwp, 1);
|
||||
else
|
||||
return -RT_ENOMEM;
|
||||
|
||||
/* stats */
|
||||
level = rt_heap_lock();
|
||||
rt_memory_info(&total, &used, &max_used);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
lwp_ref_dec(lwp);
|
||||
|
||||
/* check */
|
||||
rt_memory_info(&totala, &useda, &max_useda);
|
||||
rt_heap_unlock(level);
|
||||
utest_int_equal(total, totala);
|
||||
utest_int_less_equal(useda, used);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(aspace_unmap_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.fix_private", utest_tc_init, utest_tc_cleanup, 10);
|
||||
113
RT_Thread/examples/utest/testcases/mm/mm_api_tc.c
Normal file
113
RT_Thread/examples/utest/testcases/mm/mm_api_tc.c
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-14 WangXiaoyao the first version
|
||||
* 2023-03-20 WangXiaoyao Format & add more testcases for API under mm_aspace.h
|
||||
*/
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* @brief Testing all APIs under components/mm
|
||||
*/
|
||||
|
||||
void ioremap_tc(void);
|
||||
void flag_tc(void);
|
||||
|
||||
#ifdef STANDALONE_TC
|
||||
#define TC_ASSERT(expr) \
|
||||
((expr) \
|
||||
? 0 \
|
||||
: rt_kprintf("AssertFault(%d): %s\n", __LINE__, RT_STRINGIFY(expr)))
|
||||
#else
|
||||
#define TC_ASSERT(expr) uassert_true(expr)
|
||||
#endif
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#include "test_aspace_api.h"
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
aspace_tc();
|
||||
ioremap_tc();
|
||||
flag_tc();
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.mm.api_tc", utest_tc_init, utest_tc_cleanup, 20);
|
||||
|
||||
void ioremap_tc(void)
|
||||
{
|
||||
const size_t bufsz = 0x1000;
|
||||
void *paddr = (void *)rt_pages_alloc(rt_page_bits(bufsz)) + PV_OFFSET;
|
||||
int *vaddr;
|
||||
vaddr = rt_ioremap_cached(paddr, bufsz);
|
||||
if (vaddr)
|
||||
{
|
||||
TC_ASSERT(*vaddr == *(int *)(paddr - PV_OFFSET));
|
||||
|
||||
rt_iounmap(vaddr);
|
||||
rt_pages_free(paddr - PV_OFFSET, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void flag_tc(void)
|
||||
{
|
||||
size_t flags;
|
||||
|
||||
flags = MMF_CREATE(MMF_MAP_FIXED, 0x4000);
|
||||
TC_ASSERT(MMF_GET_CNTL(flags) == (MMF_MAP_FIXED | MMF_REQUEST_ALIGN));
|
||||
TC_ASSERT((1 << MMF_GET_ALIGN(flags)) == 0x4000);
|
||||
|
||||
flags = MMF_CREATE(MMF_MAP_FIXED, 0);
|
||||
TC_ASSERT(MMF_GET_CNTL(flags) == MMF_MAP_FIXED);
|
||||
TC_ASSERT(MMF_GET_ALIGN(flags) == 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#define BUF_SIZE (4ul << 20)
|
||||
static char ALIGN(BUF_SIZE) buf[BUF_SIZE];
|
||||
|
||||
void buddy_tc(void)
|
||||
{
|
||||
size_t total, free;
|
||||
rt_page_get_info(&total, &free);
|
||||
|
||||
rt_region_t region = {
|
||||
.start = (size_t)buf,
|
||||
.end = (size_t)buf + BUF_SIZE,
|
||||
};
|
||||
|
||||
size_t new_total, new_free;
|
||||
rt_page_install(region);
|
||||
rt_page_get_info(&new_total, &new_free);
|
||||
TC_ASSERT(new_total - total == (BUF_SIZE >> ARCH_PAGE_SHIFT));
|
||||
TC_ASSERT(new_free > free);
|
||||
}
|
||||
|
||||
void mmu_page_tc()
|
||||
{
|
||||
mm_aspace_t aspace = ASPACE_NEW();
|
||||
size_t total, free;
|
||||
rt_page_get_info(&total, &free);
|
||||
rt_hw_mmu_map(aspace, (void *)0x3fffffffff, 0, ARCH_PAGE_SIZE,
|
||||
MMU_MAP_K_RWCB);
|
||||
rt_hw_mmu_unmap(aspace, (void *)0x3fffffffff, ARCH_PAGE_SIZE);
|
||||
|
||||
size_t new_total, new_free;
|
||||
rt_page_get_info(&new_total, &new_free);
|
||||
TC_ASSERT(new_free == free);
|
||||
mm_aspace_delete(aspace);
|
||||
}
|
||||
#endif
|
||||
16
RT_Thread/examples/utest/testcases/mm/mm_libcpu_tc.c
Normal file
16
RT_Thread/examples/utest/testcases/mm/mm_libcpu_tc.c
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-17 WangXiaoyao cache API unit test
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef ARCH_RISCV64
|
||||
#include "test_cache_rv64.h"
|
||||
#elif defined(ARCH_ARMV8)
|
||||
#include "test_cache_aarch64.h"
|
||||
#endif
|
||||
141
RT_Thread/examples/utest/testcases/mm/mm_lwp_tc.c
Normal file
141
RT_Thread/examples/utest/testcases/mm/mm_lwp_tc.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-27 WangXiaoyao testcase for lwp
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <lwp.h>
|
||||
#include "lwp_arch.h"
|
||||
#include "lwp_user_mm.h"
|
||||
#include "mm_aspace.h"
|
||||
#include "mm_flag.h"
|
||||
#include "mmu.h"
|
||||
|
||||
/**
|
||||
* @brief user map API
|
||||
* rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size);
|
||||
* rt_varea_t lwp_map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags);
|
||||
*/
|
||||
#if 1 /* make it clear to identify the block :) */
|
||||
/* for testing on _aspace_traverse */
|
||||
static void *_prev_end;
|
||||
static size_t _count;
|
||||
static int _test_increase(rt_varea_t varea, void *param)
|
||||
{
|
||||
uassert_true(varea->start >= _prev_end);
|
||||
_prev_end = varea->start + varea->size;
|
||||
_count += 1;
|
||||
return 0;
|
||||
}
|
||||
#define TEST_VAREA_INSERT(statement, aspace) do {\
|
||||
size_t _prev_count; \
|
||||
_count = 0; \
|
||||
_prev_end = 0; \
|
||||
rt_aspace_traversal((aspace), _test_increase, NULL);\
|
||||
_prev_count = _count; \
|
||||
statement; \
|
||||
_count = 0; \
|
||||
_prev_end = 0; \
|
||||
rt_aspace_traversal((aspace), _test_increase, NULL);\
|
||||
uassert_true(_prev_count + 1 == _count); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static void test_user_map_varea(void)
|
||||
{
|
||||
const size_t buf_sz = ARCH_PAGE_SIZE * 4;
|
||||
struct rt_lwp *lwp;
|
||||
rt_varea_t varea;
|
||||
lwp = lwp_create(LWP_CREATE_FLAG_NONE);
|
||||
|
||||
/* prepare environment */
|
||||
uassert_true(!!lwp);
|
||||
uassert_true(!lwp_user_space_init(lwp, 1));
|
||||
TEST_VAREA_INSERT(
|
||||
varea = lwp_map_user_varea(lwp, 0, buf_sz),
|
||||
lwp->aspace);
|
||||
uassert_true(!!varea);
|
||||
uassert_true(varea->attr == (MMU_MAP_U_RWCB));
|
||||
uassert_true(varea->size == buf_sz);
|
||||
uassert_true(varea->aspace == lwp->aspace);
|
||||
uassert_true(varea->flag == MMF_MAP_PRIVATE);
|
||||
uassert_true(varea->start != 0);
|
||||
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
|
||||
|
||||
uassert_true(!(lwp_ref_dec(lwp) - 1));
|
||||
}
|
||||
|
||||
static void test_user_map_varea_ext(void)
|
||||
{
|
||||
const size_t buf_sz = ARCH_PAGE_SIZE * 4;
|
||||
struct rt_lwp *lwp;
|
||||
rt_varea_t varea;
|
||||
lwp = lwp_create(LWP_CREATE_FLAG_NONE);
|
||||
|
||||
uassert_true(!!lwp);
|
||||
uassert_true(!lwp_user_space_init(lwp, 1));
|
||||
|
||||
TEST_VAREA_INSERT(
|
||||
varea = lwp_map_user_varea_ext(lwp, 0, buf_sz, LWP_MAP_FLAG_NOCACHE),
|
||||
lwp->aspace);
|
||||
uassert_true(!!varea);
|
||||
uassert_true(varea->attr == (MMU_MAP_U_RW));
|
||||
uassert_true(varea->size == buf_sz);
|
||||
uassert_true(varea->aspace == lwp->aspace);
|
||||
uassert_true(varea->flag == MMF_MAP_PRIVATE);
|
||||
uassert_true(varea->start != 0);
|
||||
uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP);
|
||||
|
||||
uassert_true(!(lwp_ref_dec(lwp) - 1));
|
||||
}
|
||||
|
||||
static void user_map_varea_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_user_map_varea());
|
||||
CONSIST_HEAP(test_user_map_varea_ext());
|
||||
}
|
||||
|
||||
static void test_user_accessible(void)
|
||||
{
|
||||
/* Prepare Environment */
|
||||
char *test_address = (char *)(USER_STACK_VEND);
|
||||
struct rt_lwp *lwp;
|
||||
lwp = lwp_create(LWP_CREATE_FLAG_NONE);
|
||||
uassert_true(!!lwp);
|
||||
uassert_true(!lwp_user_space_init(lwp, 0));
|
||||
|
||||
/* test if user accessible can operate */
|
||||
uassert_true(!lwp_user_accessible_ext(lwp, test_address + 0x1, 0x1));
|
||||
/* test if mapping exist, accessible can fill the page and return True */
|
||||
uassert_true(lwp_user_accessible_ext(lwp, test_address - 0x10, 0x10));
|
||||
|
||||
/* Cleanup */
|
||||
lwp_ref_dec(lwp);
|
||||
}
|
||||
|
||||
static void accessible_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_user_accessible());
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(user_map_varea_tc);
|
||||
UTEST_UNIT_RUN(accessible_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.lwp.mm_tc", utest_tc_init, utest_tc_cleanup, 20);
|
||||
387
RT_Thread/examples/utest/testcases/mm/mm_memblock_tc.c
Normal file
387
RT_Thread/examples/utest/testcases/mm/mm_memblock_tc.c
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-28 zmshahaha the first version
|
||||
*/
|
||||
|
||||
#include <mm_memblock.h>
|
||||
#include "common.h"
|
||||
#include <rtservice.h>
|
||||
|
||||
#define SZ_128M 0x08000000
|
||||
#define SZ_256M 0x10000000
|
||||
#define SZ_512M 0x20000000
|
||||
#define SZ_1G 0x40000000
|
||||
|
||||
static struct rt_memblock *mmblk_memory;
|
||||
static struct rt_memblock *mmblk_reserved;
|
||||
|
||||
void rt_memblock_next_free_region_init(void);
|
||||
void rt_memblock_next_free_region(mmblk_flag_t flags, rt_size_t *out_start, rt_size_t *out_end);
|
||||
rt_bool_t rt_memblock_is_last_free(void);
|
||||
void rt_memblock_merge(void);
|
||||
|
||||
struct rt_mmblk_reg *_nth_reg(struct rt_memblock *memblock, rt_uint32_t n)
|
||||
{
|
||||
struct rt_mmblk_reg *ret = RT_NULL;
|
||||
|
||||
rt_slist_for_each_entry(ret, &(memblock->reg_list), node)
|
||||
{
|
||||
if (--n == 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rt_uint32_t _reg_cnt(struct rt_memblock *memblock)
|
||||
{
|
||||
rt_uint32_t ret = 0;
|
||||
struct rt_mmblk_reg *reg;
|
||||
|
||||
rt_slist_for_each_entry(reg, &(memblock->reg_list), node)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void _reset_memblock(void)
|
||||
{
|
||||
struct rt_mmblk_reg *reg;
|
||||
|
||||
rt_slist_for_each_entry(reg, &(mmblk_memory->reg_list), node)
|
||||
{
|
||||
reg->alloc = RT_FALSE;
|
||||
}
|
||||
rt_slist_for_each_entry(reg, &(mmblk_reserved->reg_list), node)
|
||||
{
|
||||
reg->alloc = RT_FALSE;
|
||||
}
|
||||
|
||||
mmblk_memory->reg_list.next = RT_NULL;
|
||||
mmblk_reserved->reg_list.next = RT_NULL;
|
||||
}
|
||||
|
||||
static void test_memblock_add_simple(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = SZ_1G, size1 = SZ_256M;
|
||||
rt_size_t base2 = SZ_128M, size2 = SZ_128M;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
uassert_int_equal(_reg_cnt(mmblk_memory), 1);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
|
||||
|
||||
err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_HOTPLUG);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
uassert_int_equal(_reg_cnt(mmblk_memory), 2);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_HOTPLUG);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
|
||||
}
|
||||
|
||||
static void test_memblock_add_adjacent_top(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = SZ_128M, size1 = SZ_128M;
|
||||
rt_size_t base2 = SZ_256M, size2 = SZ_128M;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
uassert_int_equal(_reg_cnt(mmblk_memory), 2);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base2 + size2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
|
||||
}
|
||||
|
||||
static void test_memblock_add_adjacent_bottom(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = SZ_256M, size1 = SZ_128M;
|
||||
rt_size_t base2 = SZ_128M, size2 = SZ_128M;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
uassert_int_equal(_reg_cnt(mmblk_memory), 2);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
|
||||
}
|
||||
|
||||
static void test_memblock_add_between(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = SZ_512M, size1 = SZ_256M;
|
||||
rt_size_t base2 = SZ_1G, size2 = SZ_512M;
|
||||
rt_size_t base3 = SZ_512M + SZ_256M, size3 = SZ_256M;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
uassert_int_equal(_reg_cnt(mmblk_memory), 3);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base2 + size2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE);
|
||||
}
|
||||
|
||||
static void test_memblock_merge(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = 0, size1 = SZ_256M;
|
||||
rt_size_t base2 = SZ_256M, size2 = SZ_256M;
|
||||
rt_size_t base3 = SZ_512M, size3 = SZ_256M;
|
||||
rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M;
|
||||
rt_size_t base5 = SZ_1G, size5 = SZ_512M;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory5", base5, base5 + size5, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_memblock_merge();
|
||||
|
||||
uassert_int_equal(_reg_cnt(mmblk_memory), 3);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG);
|
||||
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base4);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base5 + size5);
|
||||
uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE);
|
||||
}
|
||||
|
||||
static void test_memblock_add(void)
|
||||
{
|
||||
test_memblock_add_simple();
|
||||
test_memblock_add_adjacent_top();
|
||||
test_memblock_add_adjacent_bottom();
|
||||
test_memblock_add_between();
|
||||
test_memblock_merge();
|
||||
}
|
||||
|
||||
static void test_memblock_reserve_in_memory_start(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = SZ_128M, size1 = SZ_256M;
|
||||
rt_size_t baser = SZ_128M, sizer = SZ_128M;
|
||||
rt_size_t free_start, free_end;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_memblock_next_free_region_init();
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, SZ_256M);
|
||||
uassert_int_equal(free_end, SZ_128M + SZ_256M);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_memblock_reserve_in_memory_end(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = SZ_128M, size1 = SZ_256M;
|
||||
rt_size_t baser = SZ_256M, sizer = SZ_128M;
|
||||
rt_size_t free_start, free_end;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_memblock_next_free_region_init();
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, SZ_128M);
|
||||
uassert_int_equal(free_end, SZ_256M);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_memblock_reserve_many_in_one_region(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base = 0, size = SZ_1G;
|
||||
rt_size_t baser1 = 0, sizer1 = SZ_128M;
|
||||
rt_size_t baser2 = SZ_256M, sizer2 = SZ_128M;
|
||||
rt_size_t baser3 = SZ_256M + SZ_128M, sizer3 = SZ_128M;
|
||||
rt_size_t baser4 = SZ_512M + SZ_128M, sizer4 = SZ_128M;
|
||||
rt_size_t baser5 = SZ_1G - SZ_128M, sizer5 = SZ_128M;
|
||||
rt_size_t free_start, free_end;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory", base, base + size, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve1", baser1, baser1 + sizer1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve2", baser2, baser2 + sizer2, MEMBLOCK_NOMAP);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve3", baser3, baser3 + sizer3, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve4", baser4, baser4 + sizer4, MEMBLOCK_NOMAP);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve5", baser5, baser5 + sizer5, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_memblock_next_free_region_init();
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, SZ_128M);
|
||||
uassert_int_equal(free_end, SZ_256M);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, SZ_512M);
|
||||
uassert_int_equal(free_end, SZ_512M + SZ_128M);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, SZ_512M + SZ_256M);
|
||||
uassert_int_equal(free_end, SZ_1G - SZ_128M);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_memblock_reserve_large_region(void)
|
||||
{
|
||||
_reset_memblock();
|
||||
|
||||
rt_size_t base1 = 0, size1 = SZ_256M;
|
||||
rt_size_t base2 = SZ_256M, size2 = SZ_256M;
|
||||
rt_size_t base3 = SZ_512M, size3 = SZ_256M;
|
||||
rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M;
|
||||
rt_size_t baser = SZ_256M + SZ_128M, sizer = SZ_512M;
|
||||
rt_size_t free_start, free_end;
|
||||
rt_err_t err;
|
||||
|
||||
err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NOMAP);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_memblock_next_free_region_init();
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, 0);
|
||||
uassert_int_equal(free_end, SZ_256M);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, SZ_256M);
|
||||
uassert_int_equal(free_end, SZ_256M + SZ_128M);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(free_start, SZ_512M + SZ_256M + SZ_128M);
|
||||
uassert_int_equal(free_end, SZ_1G);
|
||||
|
||||
rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
|
||||
uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
|
||||
}
|
||||
|
||||
static void test_memblock_reserve(void)
|
||||
{
|
||||
test_memblock_reserve_in_memory_start();
|
||||
test_memblock_reserve_in_memory_end();
|
||||
test_memblock_reserve_many_in_one_region();
|
||||
test_memblock_reserve_large_region();
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
mmblk_memory = rt_memblock_get_memory();
|
||||
mmblk_reserved = rt_memblock_get_reserved();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(test_memblock_add);
|
||||
UTEST_UNIT_RUN(test_memblock_reserve);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.mm.memblock_tc", utest_tc_init, utest_tc_cleanup, 20);
|
||||
43
RT_Thread/examples/utest/testcases/mm/rt_ioremap.c
Normal file
43
RT_Thread/examples/utest/testcases/mm/rt_ioremap.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-12-14 WangXiaoyao the first version
|
||||
* 2023-03-20 WangXiaoyao Format & add more testcases for API under mm_aspace.h
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void ioremap_tc(void)
|
||||
{
|
||||
const size_t bufsz = 0x1000;
|
||||
void *paddr = (void *)rt_pages_alloc(rt_page_bits(bufsz)) + PV_OFFSET;
|
||||
int *vaddr;
|
||||
vaddr = rt_ioremap_cached(paddr, bufsz);
|
||||
if (vaddr)
|
||||
{
|
||||
TC_ASSERT(*vaddr == *(int *)(paddr - PV_OFFSET));
|
||||
|
||||
rt_iounmap(vaddr);
|
||||
rt_pages_free(paddr - PV_OFFSET, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void test_main(void)
|
||||
{
|
||||
CONSIST_HEAP(ioremap_tc());
|
||||
}
|
||||
UTEST_TC_EXPORT(test_main, "testcases.mm.ioremap", utest_tc_init, utest_tc_cleanup, 20);
|
||||
37
RT_Thread/examples/utest/testcases/mm/semaphore.h
Normal file
37
RT_Thread/examples/utest/testcases/mm/semaphore.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-24 WangXiaoyao Complete testcase for synchronization
|
||||
*/
|
||||
#ifndef __SEMAPHORE_H__
|
||||
#define __SEMAPHORE_H__
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
typedef struct {
|
||||
atomic_int count;
|
||||
} semaphore_t;
|
||||
|
||||
void semaphore_init(semaphore_t *sem, int count)
|
||||
{
|
||||
atomic_init(&sem->count, count);
|
||||
}
|
||||
|
||||
void semaphore_wait(semaphore_t *sem)
|
||||
{
|
||||
int count;
|
||||
do {
|
||||
count = atomic_load(&sem->count);
|
||||
} while (count == 0 || !atomic_compare_exchange_weak(&sem->count, &count, count - 1));
|
||||
}
|
||||
|
||||
void semaphore_signal(semaphore_t *sem)
|
||||
{
|
||||
atomic_fetch_add(&sem->count, 1);
|
||||
}
|
||||
|
||||
#endif /* __SEMAPHORE_H__ */
|
||||
348
RT_Thread/examples/utest/testcases/mm/test_aspace_api.h
Normal file
348
RT_Thread/examples/utest/testcases/mm/test_aspace_api.h
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c
|
||||
*/
|
||||
#ifndef __TEST_ASPACE_API_H__
|
||||
#define __TEST_ASPACE_API_H__
|
||||
|
||||
#include "common.h"
|
||||
#include "mm_aspace.h"
|
||||
#include "mm_flag.h"
|
||||
#include "test_aspace_api_internal.h"
|
||||
#include "test_synchronization.h"
|
||||
|
||||
/**
|
||||
* @brief API for aspace create/destroy
|
||||
*
|
||||
* rt_aspace_t rt_aspace_create(void *start, rt_size_t length, void *pgtbl);
|
||||
* rt_aspace_t rt_aspace_init(rt_aspace_t aspace, void *start, rt_size_t length, void *pgtbl);
|
||||
* void rt_aspace_delete(rt_aspace_t aspace);
|
||||
* void rt_aspace_detach(rt_aspace_t aspace);
|
||||
*
|
||||
* the init & detach is covered by create & detach
|
||||
*/
|
||||
|
||||
static void aspace_create_tc(void)
|
||||
{
|
||||
/* test robustness, detect failure and recover status of overall system */
|
||||
rt_aspace_t aspace;
|
||||
|
||||
CONSIST_HEAP(aspace = rt_aspace_create((void *)(0 - 0x1000), 0x1000, NULL));
|
||||
uassert_true(!aspace);
|
||||
}
|
||||
|
||||
#if 1 /* make it clear to identify the block :) */
|
||||
/* for testing on _aspace_traverse */
|
||||
static void *_prev_end;
|
||||
static size_t _count;
|
||||
static int _test_increase(rt_varea_t varea, void *param)
|
||||
{
|
||||
uassert_true(varea->start >= _prev_end);
|
||||
_prev_end = varea->start + varea->size;
|
||||
_count += 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void aspace_delete_tc(void)
|
||||
{
|
||||
/**
|
||||
* @brief Requirements: delete should recycle all types of vareas properly inside
|
||||
* and release the resource allocated for it
|
||||
*/
|
||||
rt_aspace_t aspace;
|
||||
struct rt_mm_va_hint hint = {.flags = 0,
|
||||
.map_size = 0x1000,
|
||||
.prefer = 0};
|
||||
struct rt_varea varea_phy;
|
||||
struct rt_varea varea_mobj;
|
||||
void *pgtbl;
|
||||
void *vaddr;
|
||||
|
||||
/* compatible to armv7a */
|
||||
pgtbl = rt_pages_alloc(2);
|
||||
uassert_true(!!pgtbl); /* page must be usable */
|
||||
rt_memset(pgtbl, 0, ARCH_PAGE_SIZE);
|
||||
|
||||
CONSIST_HEAP({
|
||||
aspace = rt_aspace_create((void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, pgtbl);
|
||||
uassert_true(!!aspace);
|
||||
|
||||
/* insert 4 types of vareas into this aspace */
|
||||
hint.limit_start = aspace->start;
|
||||
hint.limit_range_size = aspace->size;
|
||||
uassert_true(!rt_aspace_map_phy(aspace, &hint, MMU_MAP_K_RWCB, 0, &vaddr));
|
||||
uassert_true(!rt_aspace_map_phy_static(aspace, &varea_phy, &hint, MMU_MAP_K_RWCB, 0, &vaddr));
|
||||
uassert_true(!rt_aspace_map(aspace, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(!rt_aspace_map_static(aspace, &varea_mobj, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
|
||||
|
||||
/* for testing on _aspace_traverse */
|
||||
_count = 0;
|
||||
_prev_end = 0;
|
||||
uassert_true(!rt_aspace_traversal(aspace, _test_increase, 0));
|
||||
/* ensure the mapping is done */
|
||||
uassert_true(_count == 4);
|
||||
|
||||
rt_aspace_delete(aspace);
|
||||
|
||||
uassert_true(rt_pages_free(pgtbl, 2) == 1); /* page free must success */
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Memory Map on Virtual Address Space to Mappable Object
|
||||
* int rt_aspace_map(rt_aspace_t aspace, void **addr, rt_size_t length, rt_size_t attr,
|
||||
* mm_flag_t flags, rt_mem_obj_t mem_obj, rt_size_t offset);
|
||||
* int rt_aspace_map_static(rt_aspace_t aspace, rt_varea_t varea, void **addr,
|
||||
* rt_size_t length, rt_size_t attr, mm_flag_t flags,
|
||||
* rt_mem_obj_t mem_obj, rt_size_t offset);
|
||||
*/
|
||||
static void aspace_map_tc(void)
|
||||
{
|
||||
/**
|
||||
* @brief Requirement:
|
||||
* Robustness, filter out invalid input
|
||||
*/
|
||||
void *vaddr = RT_NULL;
|
||||
uassert_true(rt_aspace_map(0, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(vaddr == RT_NULL);
|
||||
|
||||
vaddr = (void *)USER_VADDR_START;
|
||||
uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(vaddr == RT_NULL);
|
||||
|
||||
uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, -1, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(vaddr == RT_NULL);
|
||||
|
||||
/**
|
||||
* @brief Requirement:
|
||||
* in _rt_aspace_map:_varea_install
|
||||
* not covering an existed varea if a named mapping is mandatory
|
||||
*/
|
||||
// vaddr = (void *)((rt_ubase_t)aspace_map_tc & ~ARCH_PAGE_MASK);
|
||||
// CONSIST_HEAP(
|
||||
// uassert_true(
|
||||
// rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)));
|
||||
// uassert_true(vaddr == RT_NULL);
|
||||
|
||||
/**
|
||||
* @brief Requirement:
|
||||
* in _rt_aspace_map:_varea_install:_find_free
|
||||
* verify that this routine can choose a free region with specified size
|
||||
* and specified alignment requirement
|
||||
*/
|
||||
#define ALIGN_REQ (0x04000000)
|
||||
CONSIST_HEAP({
|
||||
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_CREATE(0, ALIGN_REQ), &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(!((rt_ubase_t)vaddr & (ALIGN_REQ - 1)));
|
||||
rt_aspace_unmap(&rt_kernel_space, vaddr);
|
||||
});
|
||||
|
||||
/* test internal APIs */
|
||||
test_find_free();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Page frames mapping to varea
|
||||
* complete the page table on specified varea, and handle tlb maintenance
|
||||
* There are 2 variants of this API
|
||||
*
|
||||
* int rt_varea_map_page(rt_varea_t varea, void *vaddr, void *page);
|
||||
* int rt_varea_map_range(rt_varea_t varea, void *vaddr, void *paddr, rt_size_t length);
|
||||
*/
|
||||
|
||||
static rt_varea_t _create_varea(const size_t size)
|
||||
{
|
||||
rt_varea_t varea;
|
||||
void *vaddr = rt_ioremap_start;
|
||||
|
||||
varea = rt_malloc(sizeof(*varea));
|
||||
uassert_true(!!varea);
|
||||
uassert_true(!rt_aspace_map_static(&rt_kernel_space, varea, &vaddr, size, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
|
||||
varea->flag &= ~MMF_STATIC_ALLOC;
|
||||
uassert_true(!!vaddr);
|
||||
return varea;
|
||||
}
|
||||
|
||||
static void test_varea_map_page(void)
|
||||
{
|
||||
/**
|
||||
* @brief rt_varea_map_page
|
||||
* Requirements: complete the page table entry
|
||||
*/
|
||||
const size_t buf_sz = 4 * ARCH_PAGE_SIZE;
|
||||
rt_varea_t varea = _create_varea(buf_sz);
|
||||
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
|
||||
{
|
||||
void *page = rt_pages_alloc(0);
|
||||
uassert_true(!!page);
|
||||
uassert_true(!rt_varea_map_page(varea, varea->start + i, page));
|
||||
uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET));
|
||||
|
||||
/* let page manager handle the free of page */
|
||||
rt_varea_pgmgr_insert(varea, page);
|
||||
uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET));
|
||||
}
|
||||
|
||||
uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start));
|
||||
}
|
||||
|
||||
static void test_varea_map_range(void)
|
||||
{
|
||||
/**
|
||||
* @brief rt_varea_map_range
|
||||
* Requirements: complete the page table entry
|
||||
*/
|
||||
const size_t buf_sz = 4 * ARCH_PAGE_SIZE;
|
||||
rt_varea_t varea = _create_varea(buf_sz);
|
||||
void *page = rt_pages_alloc(rt_page_bits(buf_sz));
|
||||
uassert_true(!!page);
|
||||
uassert_true(!rt_varea_map_range(varea, varea->start, page + PV_OFFSET, buf_sz));
|
||||
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
|
||||
{
|
||||
uassert_true(rt_kmem_v2p(varea->start + i) == (page + i + PV_OFFSET));
|
||||
}
|
||||
|
||||
uassert_true(rt_pages_free(page, rt_page_bits(buf_sz)));
|
||||
uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief rt_varea_unmap_page
|
||||
* Requirements: cancel the page table entry
|
||||
*/
|
||||
static void test_varea_unmap_page(void)
|
||||
{
|
||||
/* Prepare environment */
|
||||
const size_t buf_sz = 4 * ARCH_PAGE_SIZE;
|
||||
rt_varea_t varea = _create_varea(buf_sz);
|
||||
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
|
||||
{
|
||||
void *page = rt_pages_alloc(0);
|
||||
uassert_true(!!page);
|
||||
uassert_true(!rt_varea_map_page(varea, varea->start + i, page));
|
||||
|
||||
/* let page manager handle the free of page */
|
||||
rt_varea_pgmgr_insert(varea, page);
|
||||
uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET));
|
||||
}
|
||||
|
||||
/* test if unmap is success */
|
||||
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
|
||||
{
|
||||
uassert_true(rt_varea_unmap_page(varea, varea->start + i) == RT_EOK);
|
||||
uassert_true(rt_kmem_v2p(varea->start + i) == ARCH_MAP_FAILED);
|
||||
}
|
||||
|
||||
uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief rt_varea_map_range
|
||||
* Requirements: complete the page table entry
|
||||
*/
|
||||
static void test_varea_unmap_range(void)
|
||||
{
|
||||
const size_t buf_sz = 4 * ARCH_PAGE_SIZE;
|
||||
rt_varea_t varea = _create_varea(buf_sz);
|
||||
void *page = rt_pages_alloc(rt_page_bits(buf_sz));
|
||||
uassert_true(!!page);
|
||||
uassert_true(!rt_varea_map_range(varea, varea->start, page + PV_OFFSET, buf_sz));
|
||||
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
|
||||
{
|
||||
uassert_true(rt_kmem_v2p(varea->start + i) == (page + i + PV_OFFSET));
|
||||
}
|
||||
|
||||
/* test if unmap is success */
|
||||
uassert_true(rt_varea_unmap_range(varea, varea->start, buf_sz) == RT_EOK);
|
||||
for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE)
|
||||
{
|
||||
uassert_true(rt_kmem_v2p(varea->start + i) == ARCH_MAP_FAILED);
|
||||
}
|
||||
|
||||
uassert_true(rt_pages_free(page, rt_page_bits(buf_sz)));
|
||||
uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start));
|
||||
}
|
||||
|
||||
static void varea_map_tc(void)
|
||||
{
|
||||
CONSIST_HEAP(test_varea_map_page());
|
||||
CONSIST_HEAP(test_varea_map_range());
|
||||
CONSIST_HEAP(test_varea_unmap_page());
|
||||
CONSIST_HEAP(test_varea_unmap_range());
|
||||
}
|
||||
|
||||
static void aspace_traversal_tc(void)
|
||||
{
|
||||
/**
|
||||
* @brief Requirement
|
||||
* Iterate over each varea in the kernel space
|
||||
*/
|
||||
CONSIST_HEAP(aspace_delete_tc());
|
||||
uassert_true(4 == _count);
|
||||
}
|
||||
|
||||
#ifdef ARCH_ARMV8
|
||||
static void aspace_control_tc(void)
|
||||
{
|
||||
/* this case is designed only for one page size */
|
||||
const size_t buf_sz = ARCH_PAGE_SIZE;
|
||||
void *vaddr = RT_NULL;
|
||||
volatile char *remap_nocache;
|
||||
int platform_cache_probe;
|
||||
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(!!vaddr);
|
||||
|
||||
/* map non-cacheable region to verify cache */
|
||||
remap_nocache = rt_ioremap(rt_kmem_v2p(vaddr), buf_sz);
|
||||
uassert_true(!!remap_nocache);
|
||||
|
||||
/* pre probing */
|
||||
rt_memset(vaddr, 0xba, buf_sz);
|
||||
/* no need to sync transaction on same core */
|
||||
platform_cache_probe = memtest(remap_nocache, 0xab, buf_sz);
|
||||
|
||||
if (!platform_cache_probe)
|
||||
{
|
||||
LOG_I("Cannot distinguish cache attribution on current platform");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("Ready to verify attribution of cached & non-cacheable");
|
||||
}
|
||||
|
||||
/* verify cache */
|
||||
uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_NONCACHE));
|
||||
rt_memset(vaddr, 0, buf_sz);
|
||||
uassert_true(!memtest(remap_nocache, 0, buf_sz));
|
||||
|
||||
/* another option as MMU_CNTL_CACHE */
|
||||
uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_CACHE));
|
||||
|
||||
rt_iounmap(remap_nocache);
|
||||
uassert_true(!rt_aspace_unmap(&rt_kernel_space, vaddr));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void aspace_tc(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(aspace_create_tc);
|
||||
UTEST_UNIT_RUN(aspace_delete_tc);
|
||||
UTEST_UNIT_RUN(aspace_map_tc);
|
||||
UTEST_UNIT_RUN(aspace_traversal_tc);
|
||||
#ifdef ARCH_ARMV8
|
||||
UTEST_UNIT_RUN(aspace_control_tc);
|
||||
#endif
|
||||
UTEST_UNIT_RUN(varea_map_tc);
|
||||
|
||||
/* functionality */
|
||||
UTEST_UNIT_RUN(synchronization_tc);
|
||||
return ;
|
||||
}
|
||||
|
||||
#endif /* __TEST_ASPACE_API_H__ */
|
||||
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-23 WangXiaoyao Complete testcase for internal APIs
|
||||
*/
|
||||
#ifndef __TEST_ASPACE_API_INTERNAL_H__
|
||||
#define __TEST_ASPACE_API_INTERNAL_H__
|
||||
|
||||
#include "common.h"
|
||||
#include "mmu.h"
|
||||
#include "test_bst_adpt.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief 3 cases for find free:
|
||||
* with prefer & MAP_FIXED
|
||||
* with prefer
|
||||
* without prefer
|
||||
*
|
||||
* the requirement of find free:
|
||||
* it will return a subset in address space that is free
|
||||
* the subset contains `length` contiguous elements
|
||||
* the alignment is satisfied
|
||||
*/
|
||||
static void test_find_free(void)
|
||||
{
|
||||
void *top_page = rt_kernel_space.start + rt_kernel_space.size - 0x1000;
|
||||
void *vaddr = top_page;
|
||||
|
||||
CONSIST_HEAP({
|
||||
/* type 1, on success */
|
||||
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(vaddr == top_page);
|
||||
/* type 1, on failure */
|
||||
// uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0));
|
||||
// uassert_true(!vaddr);
|
||||
|
||||
/* type 2, on success */
|
||||
vaddr = top_page;
|
||||
uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(vaddr < top_page);
|
||||
uassert_true(!!vaddr);
|
||||
rt_aspace_unmap(&rt_kernel_space, vaddr);
|
||||
/* type 2, on failure */
|
||||
vaddr = rt_kernel_space.start;
|
||||
uassert_true(-RT_ENOSPC == rt_aspace_map(&rt_kernel_space, &vaddr, rt_kernel_space.size - 0x08000000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0));
|
||||
uassert_true(!vaddr);
|
||||
|
||||
/* type 3, on success is covered by ioremap */
|
||||
/* type 3, on failure */
|
||||
size_t map_size = ARCH_PAGE_SIZE;
|
||||
while (1)
|
||||
{
|
||||
void *va = rt_ioremap(0, map_size);
|
||||
if (va)
|
||||
{
|
||||
uassert_true(1);
|
||||
rt_iounmap(va);
|
||||
map_size <<= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uassert_true(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* free top page */
|
||||
rt_aspace_unmap(&rt_kernel_space, top_page);
|
||||
});
|
||||
|
||||
/* test mm_private.h */
|
||||
CONSIST_HEAP(test_bst_adpt());
|
||||
}
|
||||
|
||||
#endif /* __TEST_ASPACE_API_INTERNAL_H__ */
|
||||
106
RT_Thread/examples/utest/testcases/mm/test_bst_adpt.h
Normal file
106
RT_Thread/examples/utest/testcases/mm/test_bst_adpt.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-23 WangXiaoyao Complete testcase for internal APIs
|
||||
*/
|
||||
#ifndef __TEST_BST_ADPT_H__
|
||||
#define __TEST_BST_ADPT_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
#include "lwp_user_mm.h"
|
||||
#include "mm_aspace.h"
|
||||
#include "mm_flag.h"
|
||||
#include <mm_private.h>
|
||||
#include <lwp_pid.h>
|
||||
|
||||
void test_bst_adpt(void)
|
||||
{
|
||||
size_t flags = MMF_MAP_FIXED;
|
||||
void *target_va = (void *)USER_VADDR_START + 0x3000;
|
||||
size_t map_size = 0x1000;
|
||||
void *prev_va = target_va - map_size;
|
||||
void *next_va = target_va + map_size + 1;
|
||||
struct rt_lwp *lwp;
|
||||
rt_aspace_t aspace;
|
||||
rt_mem_obj_t mem_obj;
|
||||
|
||||
/* create aspace by lwp */
|
||||
lwp = lwp_create(LWP_CREATE_FLAG_NONE);
|
||||
uassert_true(!!lwp);
|
||||
uassert_true(!lwp_user_space_init(lwp, 0));
|
||||
aspace = lwp->aspace;
|
||||
mem_obj = &rt_mm_dummy_mapper;
|
||||
uassert_true(!!aspace);
|
||||
uassert_true(!!mem_obj);
|
||||
|
||||
/* _aspace_bst_search not cover */
|
||||
uassert_true(!_aspace_bst_search(aspace, target_va)); // ret == NULL
|
||||
|
||||
uassert_true(
|
||||
!rt_aspace_map(aspace, &target_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0));
|
||||
/* 2 wrappers */
|
||||
uassert_true(
|
||||
!rt_aspace_map(aspace, &prev_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0));
|
||||
uassert_true(
|
||||
!rt_aspace_map(aspace, &next_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0));
|
||||
|
||||
/* _aspace_bst_search */
|
||||
uassert_true(!!_aspace_bst_search(aspace, target_va));
|
||||
uassert_true(!_aspace_bst_search(aspace, target_va + map_size));
|
||||
uassert_true(!_aspace_bst_search(aspace, target_va - 1));
|
||||
|
||||
/**
|
||||
* @brief _aspace_bst_search_exceed
|
||||
* for given map [start, end]
|
||||
*/
|
||||
rt_varea_t find;
|
||||
find = _aspace_bst_search_exceed(aspace, target_va);
|
||||
uassert_true(!!find);
|
||||
uassert_true(find->start == target_va);
|
||||
|
||||
rt_varea_t last = ASPACE_VAREA_LAST(aspace);
|
||||
find = _aspace_bst_search_exceed(aspace, last->start + 1);
|
||||
uassert_true(!find);
|
||||
|
||||
/**
|
||||
* @brief _aspace_bst_search_overlap
|
||||
* for given map [start, end], five types of overlapping
|
||||
*/
|
||||
/* 1. all below */
|
||||
struct _mm_range range = {.start = prev_va - 2, .end = prev_va - 1};
|
||||
find = _aspace_bst_search_overlap(aspace, range);
|
||||
uassert_true(!find);
|
||||
/* 2. start below */
|
||||
range.end = prev_va;
|
||||
find = _aspace_bst_search_overlap(aspace, range);
|
||||
uassert_true(!!find);
|
||||
uassert_true(find->start == prev_va);
|
||||
/* 3. all wrapped */
|
||||
range.start = prev_va;
|
||||
range.end = prev_va + 1;
|
||||
find = _aspace_bst_search_overlap(aspace, range);
|
||||
uassert_true(!!find);
|
||||
uassert_true(find->start == prev_va);
|
||||
/* 4. end exceed */
|
||||
range.start = next_va;
|
||||
range.end = next_va + map_size + 1;
|
||||
find = _aspace_bst_search_overlap(aspace, range);
|
||||
uassert_true(!!find);
|
||||
uassert_true(find->start == next_va);
|
||||
/* 5. all exceed */
|
||||
range.start = next_va + map_size;
|
||||
find = _aspace_bst_search_overlap(aspace, range);
|
||||
uassert_true(!find);
|
||||
|
||||
lwp_ref_dec(lwp);
|
||||
}
|
||||
|
||||
#endif /* RT_USING_SMART */
|
||||
|
||||
#endif /* __TEST_BST_ADPT_H__ */
|
||||
115
RT_Thread/examples/utest/testcases/mm/test_cache_aarch64.h
Normal file
115
RT_Thread/examples/utest/testcases/mm/test_cache_aarch64.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-03-17 WangXiaoyao cache API unit test
|
||||
*/
|
||||
#ifndef __TEST_CACHE_AARCH64_H__
|
||||
#define __TEST_CACHE_AARCH64_H__
|
||||
|
||||
#include "common.h"
|
||||
#include <cache.h>
|
||||
|
||||
const char *platform_cache_not_guarantee = "Cannot guarantee cache operation works";
|
||||
|
||||
/**
|
||||
* ==============================================================
|
||||
* TEST FEATURE
|
||||
* API under cache.h
|
||||
*
|
||||
* void rt_hw_icache_invalidate_range(unsigned long start_addr, int size);
|
||||
* void rt_hw_cpu_icache_invalidate(void *addr, rt_size_t size);
|
||||
* void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, rt_size_t size);
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
static int _get1_const(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get1(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get2(void)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* hot patching codes and test if the value can be seen by icache */
|
||||
static void _test_icache_invalidate_range(void)
|
||||
{
|
||||
/* reset _get1 */
|
||||
rt_memcpy(_get1, _get1_const, _get2 - _get1);
|
||||
rt_hw_cpu_dcache_clean(_get1, _get2 - _get1);
|
||||
rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1);
|
||||
uassert_true(1 == _get1());
|
||||
|
||||
/* now copy _get2 to _get1 */
|
||||
rt_memcpy(_get1, _get2, _get2 - _get1);
|
||||
if (1 != _get1())
|
||||
LOG_W(platform_cache_not_guarantee);
|
||||
|
||||
rt_hw_cpu_dcache_clean(_get1, _get2 - _get1);
|
||||
rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1);
|
||||
__asm__ volatile("isb");
|
||||
uassert_true(2 == _get1());
|
||||
LOG_I("%s ok", __func__);
|
||||
}
|
||||
|
||||
/* due to hardware feature of cortex-a, we should done this on 2 separated cpu */
|
||||
static void _test_dcache_clean_and_invalidate(void)
|
||||
{
|
||||
const size_t padding = 1024 * 2;
|
||||
const size_t buf_sz = ARCH_PAGE_SIZE * 2;
|
||||
volatile char *remap_nocache;
|
||||
char *page = rt_pages_alloc(rt_page_bits(buf_sz));
|
||||
uassert_true(!!page);
|
||||
|
||||
rt_memset(page, 0xab, buf_sz);
|
||||
rt_hw_cpu_dcache_invalidate(page, buf_sz);
|
||||
|
||||
int _outdate_flag = 0;
|
||||
if (memtest(page, 0xab, buf_sz))
|
||||
_outdate_flag = 1;
|
||||
|
||||
/* after ioremap, we can access system memory to verify outcome */
|
||||
remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz);
|
||||
|
||||
rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE);
|
||||
memtest(remap_nocache + padding, 0xab, ARCH_PAGE_SIZE);
|
||||
|
||||
if (!_outdate_flag)
|
||||
LOG_W(platform_cache_not_guarantee);
|
||||
else
|
||||
LOG_I("%s ok", __func__);
|
||||
|
||||
rt_pages_free(page, 0);
|
||||
rt_iounmap(remap_nocache);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
/* todo: format API under cache.h first */
|
||||
UTEST_UNIT_RUN(_test_icache_invalidate_range);
|
||||
UTEST_UNIT_RUN(_test_dcache_clean_and_invalidate);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10);
|
||||
|
||||
#endif /* __TEST_CACHE_AARCH64_H__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user