# RT-Thread 5.1.0# RT_USING_NANO一键配置为极简版内核,只保留了以下配置项:
内核配置Finsh 配置软件包配置资源对比可参考这篇文章
RT-Thread 裁剪分析
# RT_USING_HOOK、RT_HOOK_USING_FUNC_PTR只有同时使能这两项时,RT_OBJECT_HOOK_CALL 才会真正调用回调函数。
#ifndef RT_USING_HOOK
#define RT_OBJECT_HOOK_CALL(func, argv)
#else
/**
* @brief Add hook point in the routines
* @note Usage:
* void foo() {
* do_something();
*
* RT_OBJECT_HOOK_CALL(foo);
*
* do_other_things();
* }
*/
#define _RT_OBJECT_HOOK_CALL(func, argv) __ON_HOOK_ARGS(func, argv)
#define RT_OBJECT_HOOK_CALL(func, argv) _RT_OBJECT_HOOK_CALL(func, argv)
#ifdef RT_HOOK_USING_FUNC_PTR
#define __ON_HOOK_ARGS(__hook, argv) do {if ((__hook) != RT_NULL) __hook argv; } while (0)
#else
#define __ON_HOOK_ARGS(__hook, argv)
#endif /* RT_HOOK_USING_FUNC_PTR */
#endif /* RT_USING_HOOK */
# RT_USING_HOOKLIST# RT_OBJECT_HOOKLIST_DECLARE定义
/**
* @brief Add declaration for hook list types.
*
* @note Usage:
* This is typically used in your header. In foo.h using this like:
*
* ```foo.h
* typedef void (*bar_hook_proto_t)(arguments...);
* RT_OBJECT_HOOKLIST_DECLARE(bar_hook_proto_t, bar_myhook);
* ```
*/
#define RT_OBJECT_HOOKLIST_DECLARE(handler_type, name) \
typedef struct name##_hooklistnode \
{ \
handler_type handler; \
rt_list_t list_node; \
} *name##_hooklistnode_t; \
extern volatile rt_ubase_t name##_nested; \
void name##_sethook(name##_hooklistnode_t node); \
void name##_rmhook(name##_hooklistnode_t node)
示例
在头文件中调用,声明了 hooklist 节点和操作方法。
/**
* @brief Sets a hook function when RX indicate is called
*
* @param thread is the target thread that initializing
*/
typedef void (*rt_hw_serial_rxind_hookproto_t)(rt_device_t dev, rt_size_t size);
RT_OBJECT_HOOKLIST_DECLARE(rt_hw_serial_rxind_hookproto_t, rt_hw_serial_rxind);
=>
typedef struct rt_hw_serial_rxind_hooklistnode {
rt_hw_serial_rxind_hookproto_t handler;
rt_list_t list_node;
} *rt_hw_serial_rxind_hooklistnode_t;
extern volatile rt_ubase_t rt_hw_serial_rxind_nested;
void rt_hw_serial_rxind_sethook(rt_hw_serial_rxind_hooklistnode_t node);
void rt_hw_serial_rxind_rmhook(rt_hw_serial_rxind_hooklistnode_t node)
# RT_OBJECT_HOOKLIST_DEFINE定义
/**
* @note Usage
* Add this macro to the source file where your hook point is inserted.
*/
#define RT_OBJECT_HOOKLIST_DEFINE(name) \
static rt_list_t name##_hooklist = RT_LIST_OBJECT_INIT(name##_hooklist); \
static struct rt_spinlock name##lock = RT_SPINLOCK_INIT; \
volatile rt_ubase_t name##_nested = 0; \
void name##_sethook(name##_hooklistnode_t node) \
{ \
rt_ubase_t level = rt_spin_lock_irqsave(&name##lock); \
while (name##_nested) \
{ \
rt_spin_unlock_irqrestore(&name##lock, level); \
level = rt_spin_lock_irqsave(&name##lock); \
} \
rt_list_insert_before(&name##_hooklist, &node->list_node); \
rt_spin_unlock_irqrestore(&name##lock, level); \
} \
void name##_rmhook(name##_hooklistnode_t node) \
{ \
rt_ubase_t level = rt_spin_lock_irqsave(&name##lock); \
while (name##_nested) \
{ \
rt_spin_unlock_irqrestore(&name##lock, level); \
level = rt_spin_lock_irqsave(&name##lock); \
} \
rt_list_remove(&node->list_node); \
rt_spin_unlock_irqrestore(&name##lock, level); \
}
示例
在源文件中调用,定义 hooklist 链表头节点和操作方法。
RT_OBJECT_HOOKLIST_DEFINE(rt_hw_serial_rxind);
=>
static rt_list_t rt_hw_serial_rxind_hooklist = RT_LIST_OBJECT_INIT(rt_hw_serial_rxind_hooklist);
static struct rt_spinlock rt_hw_serial_rxindlock = {0};
volatile rt_ubase_t rt_hw_serial_rxind_nested = 0;
void rt_hw_serial_rxind_sethook(rt_hw_serial_rxind_hooklistnode_t node) {
rt_ubase_t level = rt_spin_lock_irqsave(&rt_hw_serial_rxindlock);
while (rt_hw_serial_rxind_nested) {
rt_spin_unlock_irqrestore(&rt_hw_serial_rxindlock, level);
level = rt_spin_lock_irqsave(&rt_hw_serial_rxindlock);
}
rt_list_insert_before(&rt_hw_serial_rxind_hooklist, &node->list_node);
rt_spin_unlock_irqrestore(&rt_hw_serial_rxindlock, level);
}
void rt_hw_serial_rxind_rmhook(rt_hw_serial_rxind_hooklistnode_t node) {
rt_ubase_t level = rt_spin_lock_irqsave(&rt_hw_serial_rxindlock);
while (rt_hw_serial_rxind_nested) {
rt_spin_unlock_irqrestore(&rt_hw_serial_rxindlock, level);
level = rt_spin_lock_irqsave(&rt_hw_serial_rxindlock);
}
rt_list_remove(&node->list_node);
rt_spin_unlock_irqrestore(&rt_hw_serial_rxindlock, level);
}
# RT_OBJECT_HOOKLIST_DEFINE_NODE定义
hookname 对应 RT_OBJECT_HOOKLIST_DECLARE 和 RT_OBJECT_HOOKLIST_DEFINE 中的 name,即 hooklist 节点结构体和操作方法的前缀。
hooker_handler 对应 RT_OBJECT_HOOKLIST_DECLARE 中 handler_type 类型所定义的方法。
/**
* @brief Add declaration for hook list node.
*
* @note Usage
* You can add a hook like this.
*
* ```addhook.c
* void myhook(arguments...) { do_something(); }
* RT_OBJECT_HOOKLIST_DEFINE_NODE(bar_myhook, myhook_node, myhook);
*
* void addhook(void)
* {
* bar_myhook_sethook(myhook);
* }
* ```
*
* BTW, you can also find examples codes under
* `examples/utest/testcases/kernel/hooklist_tc.c`.
*/
#define RT_OBJECT_HOOKLIST_DEFINE_NODE(hookname, nodename, hooker_handler) \
struct hookname##_hooklistnode nodename = { \
.handler = hooker_handler, \
.list_node = RT_LIST_OBJECT_INIT(nodename.list_node), \
};
示例
在源文件中调用。
_set_debug 为 rt_hw_serial_rxind_hookproto_t 类型定义的方法。
之后可通过调用 rt_hw_serial_rxind_sethook 和 rt_hw_serial_rxind_rmhook 将 hooklist 节点 _set_debug_node 注册和移除链表。
static void _set_debug(rt_device_t dev, rt_size_t size);
RT_OBJECT_HOOKLIST_DEFINE_NODE(rt_hw_serial_rxind, _set_debug_node, _set_debug);
# RT_OBJECT_HOOKLIST_CALL定义
/**
* @brief Add hook list point in the routines. Multiple hookers in the list will
* be called one by one starting from head node.
*
* @note Usage:
* void foo() {
* do_something();
*
* RT_OBJECT_HOOKLIST_CALL(foo);
*
* do_other_things();
* }
*/
#define _RT_OBJECT_HOOKLIST_CALL(nodetype, nested, list, lock, argv) \
do \
{ \
nodetype iter, next; \
rt_ubase_t level = rt_spin_lock_irqsave(&lock); \
nested += 1; \
rt_spin_unlock_irqrestore(&lock, level); \
if (!rt_list_isempty(&list)) \
{ \
rt_list_for_each_entry_safe(iter, next, &list, list_node) \
{ \
iter->handler argv; \
} \
} \
level = rt_spin_lock_irqsave(&lock); \
nested -= 1; \
rt_spin_unlock_irqrestore(&lock, level); \
} while (0)
#define RT_OBJECT_HOOKLIST_CALL(name, argv) \
_RT_OBJECT_HOOKLIST_CALL(name##_hooklistnode_t, name##_nested, \
name##_hooklist, name##lock, argv)
示例
逐个调用链表中的每个节点。
RT_OBJECT_HOOKLIST_CALL(rt_hw_serial_rxind, (dev, size));
# RT_KSERVICE_USING_STDLIB、RT_KSERVICE_USING_STDLIB_MEMORY使能后使用 C 库函数。
/* kstring */
#ifndef RT_KSERVICE_USING_STDLIB_MEMORY
void *rt_memset(void *src, int c, rt_ubase_t n);
void *rt_memcpy(void *dest, const void *src, rt_ubase_t n);
void *rt_memmove(void *dest, const void *src, rt_size_t n);
rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_size_t count);
#endif /* RT_KSERVICE_USING_STDLIB_MEMORY */
char *rt_strdup(const char *s);
rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen);
#ifndef RT_KSERVICE_USING_STDLIB
char *rt_strstr(const char *str1, const char *str2);
rt_int32_t rt_strcasecmp(const char *a, const char *b);
char *rt_strcpy(char *dst, const char *src);
char *rt_strncpy(char *dest, const char *src, rt_size_t n);
rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_size_t count);
rt_int32_t rt_strcmp(const char *cs, const char *ct);
rt_size_t rt_strlen(const char *src);
#else
#include
#ifdef RT_KSERVICE_USING_STDLIB_MEMORY
#define rt_memset(s, c, count) memset(s, c, count)
#define rt_memcpy(dst, src, count) memcpy(dst, src, count)
#define rt_memmove(dest, src, n) memmove(dest, src, n)
#define rt_memcmp(cs, ct, count) memcmp(cs, ct, count)
#endif /* RT_KSERVICE_USING_STDLIB_MEMORY */
#define rt_strstr(str1, str2) strstr(str1, str2)
#define rt_strcasecmp(a, b) strcasecmp(a, b)
#define rt_strcpy(dest, src) strcpy(dest, src)
#define rt_strncpy(dest, src, n) strncpy(dest, src, n)
#define rt_strncmp(cs, ct, count) strncmp(cs, ct, count)
#define rt_strcmp(cs, ct) strcmp(cs, ct)
#define rt_strlen(src) strlen(src)
#endif /*RT_KSERVICE_USING_STDLIB*/
# RT_KSERVICE_USING_TINY_SIZE不使能 RT_KSERVICE_USING_STDLIB_MEMORY 时,使能后 rt_memset 和 rt_memcpy 使用循环方式一个字节一个字节操作,效率低。
# RT_USING_TINY_FFS不使能 RT_USING_CPU_FFS 时,使用查表法查找第一个置位的索引。CPU 提供的方法效率最高。
使能 RT_USING_TINY_FFS
使用微型表,效率较低。
const rt_uint8_t __lowest_bit_bitmap[] =
{
/* 0 - 7 */ 0, 1, 2, 27, 3, 24, 28, 32,
/* 8 - 15 */ 4, 17, 25, 31, 29, 12, 32, 14,
/* 16 - 23 */ 5, 8, 18, 32, 26, 23, 32, 16,
/* 24 - 31 */ 30, 11, 13, 7, 32, 22, 15, 10,
/* 32 - 36 */ 6, 21, 9, 20, 19
};
/**
* @brief This function finds the first bit set (beginning with the least significant bit)
* in value and return the index of that bit.
*
* Bits are numbered starting at 1 (the least significant bit). A return value of
* zero from any of these functions means that the argument was zero.
*
* @param value is the value to find the first bit set in.
*
* @return return the index of the first bit set. If value is 0, then this function
* shall return 0.
*/
int __rt_ffs(int value)
{
return __lowest_bit_bitmap[(rt_uint32_t)(value & (value - 1) ^ value) % 37];
}
不使能 RT_USING_TINY_FFS
直接查表
const rt_uint8_t __lowest_bit_bitmap[] =
{
/* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
/* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
/**
* @brief This function finds the first bit set (beginning with the least significant bit)
* in value and return the index of that bit.
*
* Bits are numbered starting at 1 (the least significant bit). A return value of
* zero from any of these functions means that the argument was zero.
*
* @param value is the value to find the first bit set in.
*
* @return Return the index of the first bit set. If value is 0, then this function
* shall return 0.
*/
int __rt_ffs(int value)
{
if (value == 0)
{
return 0;
}
if (value & 0xff)
{
return __lowest_bit_bitmap[value & 0xff] + 1;
}
if (value & 0xff00)
{
return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;
}
if (value & 0xff0000)
{
return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;
}
return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}
# RT_USING_MEMHEAP使能 memheap 内存管理算法。
# RT_USING_MEMHEAP_AS_HEAP系统内存分配使用 memheap 内存管理算法。
# RT_USING_MEMHEAP_AUTO_BINDING将所有 memheap 对象作为内存分配堆。
# RT_USING_LEGACY支持旧版本的兼容性。
# RT_LIBC_USING_FULL_TZ_DST使用数据库对时区和夏令时进行全面版本。
会选中 PKG_USING_TZ_DATABASE 软件包。
# RT_LIBC_USING_LIGHT_TZ_DST启用轻量级时区和夏令时。与 RT_LIBC_USING_FULL_TZ_DST 互斥。
根据 RT_LIBC_TZ_DEFAULT_HOUR、RT_LIBC_TZ_DEFAULT_MIN、RT_LIBC_TZ_DEFAULT_SEC 初始化时间偏移(秒)。
可通过 rt_tz_set 和 rt_tz_get 设置和获取时间偏移(秒)。
static volatile int32_t _current_tz_offset_sec = \
RT_LIBC_TZ_DEFAULT_HOUR * 3600U + RT_LIBC_TZ_DEFAULT_MIN * 60U + RT_LIBC_TZ_DEFAULT_SEC;
/* return current timezone offset in seconds */
void rt_tz_set(int32_t offset_sec)
{
_current_tz_offset_sec = offset_sec;
}
int32_t rt_tz_get(void)
{
return _current_tz_offset_sec;
}
int8_t rt_tz_is_dst(void)
{
return 0U; /* TODO */
}