diff --git a/VERSIONING.md b/VERSIONING.md index 41fc738e4f00689f35b67e8d8cafee30b04d18bd..6966cd69dff226210c79351c1d320bc9c83c59a2 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -52,4 +52,4 @@ - `master` - `v5.0.x` - +- `v5.1.x` \ No newline at end of file diff --git a/rt-thread-version/rt-thread-standard/api-released-log/kernel-api-released-log.md b/rt-thread-version/rt-thread-standard/api-released-log/kernel-api-released-log.md index e9274d32f67493e0120ed101ce77c28f838d409f..b0e062178d0ee362a71bc76a5f57fe142d9801a5 100644 --- a/rt-thread-version/rt-thread-standard/api-released-log/kernel-api-released-log.md +++ b/rt-thread-version/rt-thread-standard/api-released-log/kernel-api-released-log.md @@ -4,6 +4,55 @@ 注:暂未包含 SMP 相关的接口,日志内容含:API 增加、API 删除、API 变更。 +## 5.1.0 + +#### API 变更: + +```c +/* ----- kservice.c ----- */ +/* 内存钩子函数参数更新,由内存块指针改为内存块地址指针 */ +void rt_malloc_sethook(void (*hook)(void **ptr, rt_size_t size)) /* 5.1.0 */ +void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)) /* 5.0.1 */ + +void rt_free_sethook(void (*hook)(void **ptr)) /* 5.1.0 */ +void rt_free_sethook(void (*hook)(void *ptr)) /* 5.0.1 */ + +/* ----- scheduler_up.c / scheduler_mp.c ----- */ +/* 进入临界区接口返回嵌套层级,并新增安全退出接口 */ +rt_base_t rt_enter_critical(void) /* 5.1.0 */ +void rt_enter_critical(void) /* 5.0.1 */ + +void rt_exit_critical_safe(rt_base_t critical_level) /* 5.1.0 */ +``` + +#### 宏变更: + +```c +/* ----- rtdef.h ----- */ +/* 新增 RT_TIMER_FLAG_PROCESSING 后,周期定时器 / 软件定时器 flag 值后移 */ +#define RT_TIMER_FLAG_PERIODIC 0x4 /* 5.1.0 */ +#define RT_TIMER_FLAG_PERIODIC 0x2 /* 5.0.1 */ + +#define RT_TIMER_FLAG_SOFT_TIMER 0x8 /* 5.1.0 */ +#define RT_TIMER_FLAG_SOFT_TIMER 0x4 /* 5.0.1 */ +``` + +#### 结构体变更: + +```c +/* ----- rtdef.h ----- */ +/* IPC / 内存池 / 对象容器控制块增加自旋锁或自旋锁相关字段 */ +struct rt_semaphore /* 新增 max_value, spinlock */ +struct rt_mutex /* 字段重构,新增 ceiling_priority / priority / taken_list / spinlock */ +struct rt_event /* 新增 spinlock */ +struct rt_mailbox /* 新增 spinlock */ +struct rt_messagequeue /* 新增 spinlock */ +struct rt_mempool /* 新增 spinlock,删除 suspend_thread_count */ +struct rt_object_information /* 新增 spinlock */ +struct rt_thread /* 调度字段迁移到 RT_SCHED_THREAD_CTX,新增 spinlock */ +struct rt_timer /* timeout_func 类型由函数指针改为 rt_timer_func_t */ +``` + ## 5.0.1 #### API 增加: diff --git a/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md b/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md index 44fd338620799bcb084aaf6bd808b02b92736200..060d01fa65dd7a63629afff07d453ce3e5e70268 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/basic/basic.md @@ -454,6 +454,8 @@ struct rt_object_information rt_list_t object_list; /* 对象大小 */ rt_size_t object_size; + /* 自旋锁 */ + struct rt_spinlock spinlock; }; ``` @@ -743,18 +745,18 @@ RT-Thread 中经常使用一些宏定义,举例 Keil 编译环境下一些常 #define rt_inline static __inline ``` -2)RT_USED,定义如下,该宏的作用是向编译器说明这段代码有用,即使函数中没有调用也要保留编译。例如 RT-Thread 自动初始化功能使用了自定义的段,使用 RT_USED 会将自定义的代码段保留。 +2)rt_used,定义如下,该宏的作用是向编译器说明这段代码有用,即使函数中没有调用也要保留编译。例如 RT-Thread 自动初始化功能使用了自定义的段,使用 rt_used 会将自定义的代码段保留。 > 注意:RT-Thread 5.0 及更高的版本将 `RT_USED` 关键字改成了 `rt_used`,使用时注意修改。 ```c -#define RT_USED __attribute__((used)) +#define rt_used __attribute__((used)) ``` -3)RT_UNUSED,定义如下,表示函数或变量可能不使用,这个属性可以避免编译器产生警告信息。 +3)RT_UNUSED(x),定义如下,表示函数或变量可能不使用,这个属性可以避免编译器产生警告信息。 ```c -#define RT_UNUSED ((void)x) +#define RT_UNUSED(x) ((void)x) ``` 4)rt_weak,定义如下,常用于定义函数,编译器在链接函数时会优先链接没有该关键字前缀的函数,如果找不到则再链接由 weak 修饰的函数。 @@ -778,4 +780,3 @@ RT-Thread 中经常使用一些宏定义,举例 Keil 编译环境下一些常 ```c #define RT_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1)) ``` - diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/completion/completion.md b/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/completion/completion.md index bb843dca4bb9a227c057a3053db447a153e1a873..d90c2dba18b9f3c54fb71aa1f45b6037bad2951d 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/completion/completion.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/completion/completion.md @@ -17,16 +17,14 @@ completion 可以称之为**完成量**,是一种轻量级的线程间(`IPC` 在 RT-Thread 中,完成量控制块是操作系统用于管理完成量的一个数据结构,由结构体 `struct rt_completion` 表示,完成量控制块的详细定义如下: ```c -struct rt_completion -{ - rt_uint32_t flag; - - /* suspended list */ - rt_list_t suspended_list; -}; -``` - -其中 flag,表征当前完成量对象的状态,用下面的两个宏表示,即当 flag 值为 `RT_COMPLETED` 时,表征当前完成量对象已完成了某一个工作,可以继续下一个工作; 当 flag 值为 `RT_UNCOMPLETED` 时,表征当前需要等待某一个工作结束才能继续下一个工作。 +struct rt_completion +{ + /* suspended thread, and completed flag */ + rt_base_t susp_thread_n_flag; +}; +``` + +其中 `susp_thread_n_flag` 使用一个 CPU 字长同时保存等待线程指针和完成状态标志,最低位用于表示完成状态,其余位用于保存等待线程。完成状态在内部用下面的两个宏表示,即当标志为 `RT_COMPLETED` 时,表征当前完成量对象已完成了某一个工作,可以继续下一个工作; 当标志为 `RT_UNCOMPLETED` 时,表征当前需要等待某一个工作结束才能继续下一个工作。 ```c #define RT_COMPLETED 1 @@ -55,7 +53,7 @@ void rt_completion_init(struct rt_completion *completion) 1. 完成量的创建只支持静态对象初始化,不支持动态生成对象,在调用初始化接口时,需要传递一个静态的完成量对象的指针。 -2. 在完成量初始化接口中,只完成两件事,设置 flag 为 `RT_UNCOMPLETED`,然后初始化完成量对象的 suspend 线程链表。 +2. 在完成量初始化接口中,会将完成状态设置为 `RT_UNCOMPLETED`,并将等待线程指针置空。 ### 等待完成 @@ -86,9 +84,9 @@ rt_err_t rt_completion_wait(struct rt_completion *completion, 1. 调用 `rt_thread_self` 获取当前线程对象,为后续挂起当前线程做准备。 2. 调用 `rt_hw_interrupt_disable` 和 `rt_hw_interrupt_enable` 完成接下来的原子操作。 3. 如果调用该接口前,已经调用 `rt_completion_done` 指示完成了某个工作,那么直接设置 flag 为 `RT_UNCOMPLETED`,为下一次等待做准备,函数退出。 -4. 如果调用该接口时,还未完成某个工作,判断当前完成量对象的等待线程链(`suspended_list`)是否已经有线程在等待该完成量了,如果已经有,则程序直接异常挂起,如果没有正在等待的线程,那么流程继续。 -5. 执行挂起当前线程的动作(因为挂起的时当前线程,因此需要后续执行 `rt_schedule` 才会真正执行挂起)。 -6. 将当前线程挂在了完成量对象的 `suspended_list` 链表中。 +4. 如果调用该接口时,还未完成某个工作,判断当前完成量对象的 `susp_thread_n_flag` 中是否已经记录了等待线程。如果已经有线程在等待,则程序直接异常挂起;如果没有正在等待的线程,那么流程继续。 +5. 执行挂起当前线程的动作(因为挂起的时当前线程,因此需要后续执行 `rt_schedule` 才会真正执行挂起)。 +6. 将当前线程记录到完成量对象的 `susp_thread_n_flag` 中,并保持完成状态为 `RT_UNCOMPLETED`。 7. 执行 `RT_DEBUG_NOT_IN_INTERRUPT`,确保当前函数不是在中断函数中执行。 8. 启动定时器,设置超时唤醒当前线程的逻辑。 9. 执行 `rt_schedule();` ,真正挂起当前线程。 diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/workqueue/workqueue.md b/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/workqueue/workqueue.md index 0ab632ce4d2c8d6a92edc7c17a7eac89cc6b6a81..67dd9dfddc17dc358ef7364dca82e38eca781901 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/workqueue/workqueue.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/device-ipc/workqueue/workqueue.md @@ -44,6 +44,7 @@ struct rt_workqueue struct rt_semaphore sem; rt_thread_t work_thread; + struct rt_spinlock spinlock; }; ``` @@ -295,4 +296,4 @@ MSH_CMD_EXPORT(workqueue_example, workqueue example); 运行效果如下,与工作项绑定的任务被异步执行了,而且工作项 1 延迟了 2 个 tick 才执行: -![](figures/workqueue_example.png) \ No newline at end of file +![](figures/workqueue_example.png) diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc.md b/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc.md index bd2cc4200442ee2b32a83716bf7da4f69e8c0a0d..a00fa3310120aee9ed61944964a6f3cbaad7f0b2 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc.md @@ -69,7 +69,7 @@ adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME); 在读取 ADC 设备数据前需要先使能设备,通过如下函数使能设备: ```c -rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel); +rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_int8_t channel); ``` | **参数** | **描述** | @@ -98,7 +98,7 @@ rt_adc_enable(adc_dev, ADC_DEV_CHANNEL); 读取 ADC 通道采样值可通过如下函数完成: ```c -rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel); +rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_int8_t channel); ``` | **参数** | **描述** | @@ -136,7 +136,7 @@ rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100); 关闭 ADC 通道可通过如下函数完成: ```c -rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel); +rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_int8_t channel); ``` | **参数** | **描述** | @@ -268,4 +268,3 @@ MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample); ### Q: menuconfig 找不到 ADC 设备的配置选项? **A:** 使用的源代码还不支持 ADC 设备驱动框架。建议更新源代码。 - diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/cputime/cputime.md b/rt-thread-version/rt-thread-standard/programming-manual/device/cputime/cputime.md index a89b30a2ad031206da5fc7426646e209f6dd82ff..252066192aa720e768221a4f31406c16981e1668 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/device/cputime/cputime.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/device/cputime/cputime.md @@ -51,7 +51,7 @@ void (*hwtimer_timeout)(void *param); void *parameter = RT_NULL; /* 精度 ns */ -static double cortexm_cputime_getres(void) +static uint64_t cortexm_cputime_getres(void) { return 10000; } @@ -72,7 +72,7 @@ static int cortexm_cputime_settimeout(uint64_t tick, void (*timeout)(void *param } /* 定义 ops */ -const static struct rt_clock_cputime_ops _cortexm_ops = +static struct rt_clock_cputime_ops _cortexm_ops = { cortexm_cputime_getres, cortexm_cputime_gettime, diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/device.md b/rt-thread-version/rt-thread-standard/programming-manual/device/device.md index 544fa14e8396a0b4670cf7d625a8076ebf28fa92..1fcdaa2bd7394406f9d9aacfa23aa467794ff6f4 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/device/device.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/device/device.md @@ -50,6 +50,16 @@ RT-Thread 的设备模型是建立在内核对象模型基础之上的,设备 struct rt_device { struct rt_object parent; /* 内核对象基类 */ + +#ifdef RT_USING_DM + struct rt_bus *bus; /* 挂载的总线 */ + rt_list_t node; /* 总线节点 */ + struct rt_driver *drv; /* 设备驱动 */ +#ifdef RT_USING_OFW + void *ofw_node; /* 设备树节点 */ +#endif +#endif + enum rt_device_class_type type; /* 设备类型 */ rt_uint16_t flag; /* 设备参数 */ rt_uint16_t open_flag; /* 设备打开标志 */ @@ -60,7 +70,23 @@ struct rt_device rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size); rt_err_t (*tx_complete)(rt_device_t dev, void *buffer); - const struct rt_device_ops *ops; /* 设备操作方法 */ +#ifdef RT_USING_DEVICE_OPS + const struct rt_device_ops *ops; /* 设备操作方法 */ +#else + rt_err_t (*init) (rt_device_t dev); + rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag); + rt_err_t (*close) (rt_device_t dev); + rt_ssize_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); + rt_ssize_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); + rt_err_t (*control)(rt_device_t dev, int cmd, void *args); +#endif + +#ifdef RT_USING_POSIX_DEVIO + const struct dfs_file_ops *fops; + struct rt_wqueue wait_queue; +#endif + + rt_err_t (*readlink)(rt_device_t dev, char *buf, int len); /* 设备的私有数据 */ void *user_data; diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/pin/pin.md b/rt-thread-version/rt-thread-standard/programming-manual/device/pin/pin.md index 0dcfb1d648a27863a61d421ae0a18fb85e049385..340cb2a9c45eb1657e82660123063bffa2bc2ef8 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/device/pin/pin.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/device/pin/pin.md @@ -120,7 +120,7 @@ rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT); 设置引脚输出电平的函数如下所示: ```c -void rt_pin_write(rt_base_t pin, rt_uint8_t value); +void rt_pin_write(rt_base_t pin, rt_ssize_t value); ``` | **参数** | **描述** | @@ -144,7 +144,7 @@ rt_pin_write(BEEP_PIN_NUM, PIN_LOW); 读取引脚电平的函数如下所示: ```c -rt_int8_t rt_pin_read(rt_base_t pin); +rt_ssize_t rt_pin_read(rt_base_t pin); ``` | **参数** | **描述** | diff --git a/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi.md b/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi.md index 9ca2bca1650e2d452afa3be8fc27cd68cb32548a..1d18b53fbbe0263c583102b3953fd0ca1307a09e 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi.md @@ -540,7 +540,19 @@ msg2.cs_release = 1; msg2.next = RT_NULL; ``` -SPI 设备管理模块还提供 `rt_spi_sendrecv8()` 和 `rt_spi_sendrecv16()` 函数,这两个函数都是对此函数的封装,`rt_spi_sendrecv8()` 发送一个字节数据同时收到一个字节数据,`rt_spi_sendrecv16()` 发送 2 个字节数据同时收到 2 个字节数据。 +SPI 设备管理模块还提供 `rt_spi_sendrecv8()` 和 `rt_spi_sendrecv16()` 函数,这两个函数都是对此函数的封装。接口定义如下: + +```c +rt_err_t rt_spi_sendrecv8(struct rt_spi_device *device, + rt_uint8_t senddata, + rt_uint8_t *recvdata); + +rt_err_t rt_spi_sendrecv16(struct rt_spi_device *device, + rt_uint16_t senddata, + rt_uint16_t *recvdata); +``` + +`rt_spi_sendrecv8()` 发送一个字节数据并通过 `recvdata` 输出接收到的一个字节数据,`rt_spi_sendrecv16()` 发送 2 个字节数据并通过 `recvdata` 输出接收到的 2 个字节数据。两个函数执行成功返回 `RT_EOK`,失败返回错误码。 ## 访问 QSPI 设备 diff --git a/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md b/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md index b0451041f4ba47340f16cab38b1334ca7e6ddd43..074fd9afcdae0222fb3cd66b602d1b113f39d524 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/ipc1/ipc1.md @@ -20,6 +20,8 @@ 2)调用 rt_enter_critical() 进入临界区,调用 rt_exit_critical() 退出临界区。 +`rt_enter_critical()` 会返回进入临界区后的嵌套层级。需要按进入时的层级安全退出时,可调用 `rt_exit_critical_safe(level)`。 + 本章将介绍多种同步方式:**信号量**(semaphore)、**互斥量**(mutex)、和**事件集**(event)。学习完本章,大家将学会如何使用信号量、互斥量、事件集这些对象进行线程间的同步。 ## 信号量 @@ -51,6 +53,8 @@ struct rt_semaphore { struct rt_ipc_object parent; /* 继承自 ipc_object 类 */ rt_uint16_t value; /* 信号量的值 */ + rt_uint16_t max_value; /* 信号量的最大值 */ + struct rt_spinlock spinlock; /* 自旋锁 */ }; /* rt_sem_t 是指向 semaphore 结构体的指针类型 */ typedef struct rt_semaphore* rt_sem_t; @@ -659,16 +663,20 @@ the consumer exit! ```c struct rt_mutex - { - struct rt_ipc_object parent; /* 继承自 ipc_object 类 */ - - rt_uint16_t value; /* 互斥量的值 */ - rt_uint8_t original_priority; /* 持有线程的原始优先级 */ - rt_uint8_t hold; /* 持有线程的持有次数 */ - struct rt_thread *owner; /* 当前拥有互斥量的线程 */ - }; - /* rt_mutext_t 为指向互斥量结构体的指针类型 */ - typedef struct rt_mutex* rt_mutex_t; +{ + struct rt_ipc_object parent; /* 继承自 ipc_object 类 */ + + rt_uint8_t ceiling_priority; /* 优先级天花板 */ + rt_uint8_t priority; /* 等待线程中的最高优先级 */ + rt_uint8_t hold; /* 持有线程的持有次数 */ + rt_uint8_t reserved; /* 保留字段 */ + + struct rt_thread *owner; /* 当前拥有互斥量的线程 */ + rt_list_t taken_list; /* 线程持有的对象链表 */ + struct rt_spinlock spinlock; /* 自旋锁 */ +}; +/* rt_mutex_t 为指向互斥量结构体的指针类型 */ +typedef struct rt_mutex* rt_mutex_t; ``` rt_mutex 对象从 rt_ipc_object 中派生,由 IPC 容器所管理。 @@ -1232,6 +1240,7 @@ struct rt_event /* 事件集合,每一 bit 表示 1 个事件,bit 位的值可以标记某事件是否发生 */ rt_uint32_t set; + struct rt_spinlock spinlock; }; /* rt_event_t 是指向事件结构体的指针类型 */ typedef struct rt_event* rt_event_t; @@ -1511,4 +1520,3 @@ thread1 leave. ![多事件接收示意图](figures/06event_use.png) 一个事件集中包含 32 个事件,特定线程只等待、接收它关注的事件。可以是一个线程等待多个事件的到来(线程 1、2 均等待多个事件,事件间可以使用 “与” 或者 “或” 逻辑触发线程),也可以是多个线程等待一个事件的到来(事件 25)。当有它们关注的事件发生时,线程将被唤醒并进行后续的处理动作。 - diff --git a/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md b/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md index a7e5c9fffef2357115a731eaf39bed4df488e83c..7f4efe36c2b87441de3da9ad61d82ad4fc83e561 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2.md @@ -35,6 +35,7 @@ struct rt_mailbox rt_uint16_t entry; /* 邮箱中邮件的数目 */ rt_uint16_t in_offset, out_offset; /* 邮箱缓冲的进出指针 */ rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队列 */ + struct rt_spinlock spinlock; /* 自旋锁 */ }; typedef struct rt_mailbox* rt_mailbox_t; ``` @@ -415,6 +416,7 @@ struct rt_messagequeue void* msg_queue_free; /* 空闲消息链表 */ rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队列 */ + struct rt_spinlock spinlock; /* 自旋锁 */ }; typedef struct rt_messagequeue* rt_mq_t; ``` @@ -571,10 +573,10 @@ rt_err_t rt_mq_urgent(rt_mq_t mq, const void *buffer, rt_size_t size); 当消息队列中有消息时,接收者才能接收消息,否则接收者会根据超时时间设置,或挂起在消息队列的等待线程队列上,或直接返回。接收消息函数接口如下: ```c -rt_err_t rt_mq_recv (rt_mq_t mq, +rt_ssize_t rt_mq_recv(rt_mq_t mq, void *buffer, rt_size_t size, - rt_int32_t timeout); + rt_int32_t timeout); ``` 接收消息时,接收者需指定存储消息的消息队列对象句柄,并且指定一个内存缓冲区,接收到的消息内容将被复制到该缓冲区里。此外,还需指定未能及时取到消息时的超时时间。如下图所示,接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部。下表描述了该函数的输入参数与返回值: @@ -586,9 +588,9 @@ rt_err_t rt_mq_recv (rt_mq_t mq, | size | 消息大小 | | timeout | 指定的超时时间 | |**返回** | —— | -| RT_EOK | 成功收到 | +| > 0 | 成功收到的消息长度 | | \-RT_ETIMEOUT | 超时 | -| \-RT_ERROR | 失败,返回错误 | +| 其他错误码 | 失败,返回错误 | ### 消息队列应用示例 @@ -622,7 +624,7 @@ static void thread1_entry(void *parameter) while (1) { /* 从消息队列中接收消息 */ - if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK) + if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) > 0) { rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", buf); if (cnt == 19) @@ -812,7 +814,7 @@ void message_handler() struct msg msg_ptr; /* 用于放置消息的局部变量 */ /* 从消息队列中接收消息到 msg_ptr 中 */ - if (rt_mq_recv(mq, (void*)&msg_ptr, sizeof(struct msg), RT_WAITING_FOREVER) == RT_EOK) + if (rt_mq_recv(mq, (void *)&msg_ptr, sizeof(struct msg), RT_WAITING_FOREVER) > 0) { /* 成功接收到消息,进行相应的数据处理 */ } diff --git a/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md b/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md index a105cdc9b93c7fef45697bcd9a1a3ae67287fe54..8375eee3f4aae26fa8e9509258505a40f4aa7c2c 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/memory/memory.md @@ -428,10 +428,10 @@ MSH_CMD_EXPORT(rt_calloc_sample, rt_calloc sample); 在分配内存块过程中,用户可设置一个钩子函数,调用的函数接口如下: ```c -void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)); +void rt_malloc_sethook(void (*hook)(void **ptr, rt_size_t size)); ``` -设置的钩子函数会在内存分配完成后进行回调。回调时,会把分配到的内存块地址和大小做为入口参数传递进去。下表描述了该函数的输入参数: +设置的钩子函数会在内存分配完成后进行回调。回调时,会把分配到的内存块地址指针和大小做为入口参数传递进去。下表描述了该函数的输入参数: rt_malloc_sethook() 的输入参数 @@ -442,7 +442,7 @@ void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)); 其中 hook 函数接口如下: ```c -void hook(void *ptr, rt_size_t size); +void hook(void **ptr, rt_size_t size); ``` 下表描述了 hook 函数的输入参数: @@ -451,16 +451,16 @@ void hook(void *ptr, rt_size_t size); |**参数**|**描述** | |----------|----------------------| -| ptr | 分配到的内存块指针 | +| ptr | 分配到的内存块地址指针 | | size | 分配到的内存块的大小 | 在释放内存时,用户可设置一个钩子函数,调用的函数接口如下: ```c -void rt_free_sethook(void (*hook)(void *ptr)); +void rt_free_sethook(void (*hook)(void **ptr)); ``` -设置的钩子函数会在调用内存释放完成前进行回调。回调时,释放的内存块地址会做为入口参数传递进去(此时内存块并没有被释放)。下表描述了该函数的输入参数: +设置的钩子函数会在调用内存释放完成前进行回调。回调时,释放的内存块地址指针会做为入口参数传递进去(此时内存块并没有被释放)。下表描述了该函数的输入参数: rt_free_sethook() 的输入参数 @@ -471,7 +471,7 @@ void rt_free_sethook(void (*hook)(void *ptr)); 其中 hook 函数接口如下: ```c -void hook(void *ptr); +void hook(void **ptr); ``` 下表描述了 hook 函数的输入参数: @@ -480,7 +480,7 @@ void hook(void *ptr); |**参数**|**描述** | |----------|--------------------| -| ptr | 待释放的内存块指针 | +| ptr | 待释放的内存块地址指针 | ##### 内存钩子函数示例 @@ -492,14 +492,14 @@ void hook(void *ptr); #define THREAD_TIMESLICE 5 /* 定义内存钩子函数 */ -void malloc_hook(void *ptr, rt_size_t size) +void malloc_hook(void **ptr, rt_size_t size) { - rt_kprintf("malloc: %p, size: %ld\n", ptr, size); + rt_kprintf("malloc: %p, size: %ld\n", *ptr, size); } -void free_hook(void *ptr) +void free_hook(void **ptr) { - rt_kprintf("free: %p\n", ptr); + rt_kprintf("free: %p\n", *ptr); } /* 注册内存钩子函数 */ @@ -752,8 +752,8 @@ struct rt_mempool rt_size_t block_free_count; /* 因为内存块不可用而挂起的线程列表 */ rt_list_t suspend_thread; - /* 因为内存块不可用而挂起的线程数 */ - rt_size_t suspend_thread_count; + /* 自旋锁 */ + struct rt_spinlock spinlock; }; typedef struct rt_mempool* rt_mp_t; ``` diff --git a/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md b/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md index e05dc148c44f65bd081a9e85fac8ca29ce18a0f1..844eb241972ffffb6754a8a77747e48594b76ffa 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/thread/thread.md @@ -34,13 +34,8 @@ RT-Thread 的线程调度器是抢占式的,主要的工作就是从就绪线 /* 线程控制块 */ struct rt_thread { - /* rt 对象 */ - char name[RT_NAME_MAX]; /* 线程名称 */ - rt_uint8_t type; /* 对象类型 */ - rt_uint8_t flags; /* 标志位 */ - - rt_list_t list; /* 对象列表 */ - rt_list_t tlist; /* 线程列表 */ + /* 继承自内核对象 */ + struct rt_object parent; /* 栈指针与入口指针 */ void *sp; /* 栈指针 */ @@ -51,26 +46,21 @@ struct rt_thread /* 错误代码 */ rt_err_t error; /* 线程错误代码 */ - rt_uint8_t stat; /* 线程状态 */ - /* 优先级 */ - rt_uint8_t current_priority; /* 当前优先级 */ - rt_uint8_t init_priority; /* 初始优先级 */ - rt_uint32_t number_mask; + /* 调度上下文,包含线程状态、优先级、时间片等调度相关信息 */ + RT_SCHED_THREAD_CTX ...... - rt_ubase_t init_tick; /* 线程初始化计数值 */ - rt_ubase_t remaining_tick; /* 线程剩余计数值 */ - struct rt_timer thread_timer; /* 内置线程定时器 */ - void (*cleanup)(struct rt_thread *tid); /* 线程退出清除函数 */ - rt_uint32_t user_data; /* 用户数据 */ + rt_thread_cleanup_t cleanup; /* 线程退出清除函数 */ + struct rt_spinlock spinlock; /* 自旋锁 */ + rt_ubase_t user_data; /* 用户数据 */ }; ``` -其中 init_priority 是线程创建时指定的线程优先级,在线程运行过程当中是不会被改变的(除非用户执行线程控制函数进行手动调整线程优先级)。cleanup 会在线程退出时,被空闲线程回调一次以执行用户设置的清理现场等工作。最后的一个成员 user_data 可由用户挂接一些数据信息到线程控制块中,以提供一种类似线程私有数据的实现方式。 +其中线程优先级、状态和时间片等调度相关信息由 RT_SCHED_THREAD_CTX 展开管理。cleanup 会在线程退出时,被空闲线程回调一次以执行用户设置的清理现场等工作。最后的一个成员 user_data 可由用户挂接一些数据信息到线程控制块中,以提供一种类似线程私有数据的实现方式。 ### 线程重要属性 diff --git a/rt-thread-version/rt-thread-standard/programming-manual/timer/timer.md b/rt-thread-version/rt-thread-standard/programming-manual/timer/timer.md index 39513da8e442e181675c7952100d255a8e8a4331..35c689e30a5f188a423eafc3eb4c98fc15e47b78 100644 --- a/rt-thread-version/rt-thread-standard/programming-manual/timer/timer.md +++ b/rt-thread-version/rt-thread-standard/programming-manual/timer/timer.md @@ -129,7 +129,7 @@ struct rt_timer struct rt_object parent; rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL]; /* 定时器链表节点 */ - void (*timeout_func)(void *parameter); /* 定时器超时调用的函数 */ + rt_timer_func_t timeout_func; /* 定时器超时调用的函数 */ void *parameter; /* 超时函数的参数 */ rt_tick_t init_tick; /* 定时器初始超时节拍数 */ rt_tick_t timeout_tick; /* 定时器实际超时时的节拍数 */ @@ -137,7 +137,7 @@ struct rt_timer typedef struct rt_timer *rt_timer_t; ``` -定时器控制块由 struct rt_timer 结构体定义并形成定时器内核对象,再链接到内核对象容器中进行管理,list 成员则用于把一个激活的(已经启动的)定时器链接到 rt_timer_list 链表中。 +定时器控制块由 struct rt_timer 结构体定义并形成定时器内核对象,再链接到内核对象容器中进行管理,row 成员则用于把一个激活的(已经启动的)定时器链接到 rt_timer_list 链表中。 #### 定时器跳表 (Skip List) 算法 @@ -210,10 +210,10 @@ include/rtdef.h 中定义了一些定时器相关的宏,如下: ```c #define RT_TIMER_FLAG_ONE_SHOT     0x0     /* 单次定时     */ -#define RT_TIMER_FLAG_PERIODIC     0x2     /* 周期定时     */ +#define RT_TIMER_FLAG_PERIODIC     0x4     /* 周期定时     */ #define RT_TIMER_FLAG_HARD_TIMER   0x0     /* 硬件定时器   */ -#define RT_TIMER_FLAG_SOFT_TIMER   0x4     /* 软件定时器   */ +#define RT_TIMER_FLAG_SOFT_TIMER   0x8     /* 软件定时器   */ ``` 上面 2 组值可以以 “或” 逻辑的方式赋给 flag。当指定的 flag 为 RT_TIMER_FLAG_HARD_TIMER 时,如果定时器超时,定时器的回调函数将在时钟中断的服务例程上下文中被调用;当指定的 flag 为 RT_TIMER_FLAG_SOFT_TIMER 时,如果定时器超时,定时器的回调函数将在系统时钟 timer 线程的上下文中被调用。