mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 16:56:42 +08:00
Compare commits
4 Commits
a15641c42e
...
bf21a64ab2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf21a64ab2 | ||
|
|
f2b0a31bb3 | ||
|
|
49025692ca | ||
|
|
70d1741bab |
13
README.en.md
13
README.en.md
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
[](https://gitee.com/Lamdonn/varch)
|
[](https://gitee.com/Lamdonn/varch)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](Lamdonn@163.com)
|
[](Lamdonn@163.com)
|
||||||

|

|
||||||
@ -11,14 +11,14 @@
|
|||||||
|
|
||||||
[中文版](README.md)
|
[中文版](README.md)
|
||||||
|
|
||||||
varch (we architecture, meaning our framework library) is a commonly used code module library for embedded C language, including the commonly used embedded algorithm library (search, check, filter, hash, sort, etc.), data structure/container library (general queue, stack, heap, list, dynamic array, string, set, dictionary, map, graph, etc.), parser library (csv, ini, json, xml, etc.), mathematical library (large number operation, mathematical operation), independent C language st d library, utility library, etc.
|
varch (we architecture, meaning our framework library) is a commonly used code module library for embedded C language, including the commonly used embedded algorithm library (search, check, filter, hash, sort, etc.), data structure/container library (general queue, stack, heap, list, dynamic array, string, set, dictionary, map, graph, etc.), parser library (csv, ini, json, xml, etc.), mathematical library (large number operation, mathematical operation), C language coroutine library, independent C language st d library, utility library, etc.
|
||||||
It has the characteristics of **simplicity, universality, and efficiency**, with the aim of **learning** and **using it immediately** in development, improving development efficiency and code reliability and stability.
|
It has the characteristics of **simplicity, universality, and efficiency**, with the aim of **learning** and **using it immediately** in development, improving development efficiency and code reliability and stability.
|
||||||
|
|
||||||
## Content
|
## Content
|
||||||
|
|
||||||
| module | version | usage | path | describe |
|
| module | version | usage | path | describe |
|
||||||
|:-------------|:---------|:-----------------------------|:------------------------------------------|:--------------------------------------|
|
|:-------------|:---------|:-----------------------------|:------------------------------------------|:--------------------------------------|
|
||||||
| overall | 00.03.03 | [link](README.en.md) | [path](./) | Overall
|
| overall | 00.03.05 | [link](README.en.md) | [path](./) | Overall
|
||||||
| init | 01.00.00 | [link](/doc/init.en.md) | [path](./source/00_application) | Initialize export module
|
| init | 01.00.00 | [link](/doc/init.en.md) | [path](./source/00_application) | Initialize export module
|
||||||
| console | 01.00.01 | [link](/doc/console.en.md) | [path](./source/00_application/console) | Console command input, combined with the 'command' module, parsing commands entered in the console
|
| console | 01.00.01 | [link](/doc/console.en.md) | [path](./source/00_application/console) | Console command input, combined with the 'command' module, parsing commands entered in the console
|
||||||
| arg | 01.00.00 | [link](/doc/arg.en.md) | [path](./source/01_general) | Indefinite parameters, obtain the number of indefinite parameters and specified parameters
|
| arg | 01.00.00 | [link](/doc/arg.en.md) | [path](./source/01_general) | Indefinite parameters, obtain the number of indefinite parameters and specified parameters
|
||||||
@ -45,13 +45,13 @@ It has the characteristics of **simplicity, universality, and efficiency**, with
|
|||||||
| queue | 01.00.00 | [link](/doc/queue.en.md) | [path](./source/03_container) | Universal queue container
|
| queue | 01.00.00 | [link](/doc/queue.en.md) | [path](./source/03_container) | Universal queue container
|
||||||
| stack | 01.00.00 | [link](/doc/stack.en.md) | [path](./source/03_container) | Universal stack container
|
| stack | 01.00.00 | [link](/doc/stack.en.md) | [path](./source/03_container) | Universal stack container
|
||||||
| deque | 01.00.00 | [link](/doc/deque.en.md) | [path](./source/03_container) | Universal double-end queue container
|
| deque | 01.00.00 | [link](/doc/deque.en.md) | [path](./source/03_container) | Universal double-end queue container
|
||||||
| list | 01.00.00 | [link](/doc/list.en.md) | [path](./source/03_container) | Universal list container, single-link and internal iteration
|
| list | 01.00.01 | [link](/doc/list.en.md) | [path](./source/03_container) | Universal list container, single-link and internal iteration
|
||||||
| vector | 01.00.00 | [link](/doc/vector.en.md) | [path](./source/03_container) | Universal vector(array) container
|
| vector | 01.00.00 | [link](/doc/vector.en.md) | [path](./source/03_container) | Universal vector(array) container
|
||||||
| str | 01.00.00 | [link](/doc/str.en.md) | [path](./source/03_container) | String class
|
| str | 01.00.00 | [link](/doc/str.en.md) | [path](./source/03_container) | String class
|
||||||
| dict | 01.00.00 | [link](/doc/dict.en.md) | [path](./source/03_container) | Universal dictionarie container, implementation based on hash table
|
| dict | 01.00.00 | [link](/doc/dict.en.md) | [path](./source/03_container) | Universal dictionarie container, implementation based on hash table
|
||||||
| heap | 01.00.00 | [link](/doc/heap.en.md) | [path](./source/03_container) | Universal heap container
|
| heap | 01.00.00 | [link](/doc/heap.en.md) | [path](./source/03_container) | Universal heap container
|
||||||
| set | 01.00.00 | [link](/doc/set.en.md) | [path](./source/03_container) | Universal set container, implementation based on RB-tree
|
| set | 01.00.01 | [link](/doc/set.en.md) | [path](./source/03_container) | Universal set container, implementation based on RB-tree
|
||||||
| map | 01.00.00 | [link](/doc/map.en.md) | [path](./source/03_container) | Universal map container, implementation based on RB-tree
|
| map | 01.00.01 | [link](/doc/map.en.md) | [path](./source/03_container) | Universal map container, implementation based on RB-tree
|
||||||
| tree | 01.00.00 | [link](/doc/tree.en.md) | [path](./source/03_container) | Universal tree container
|
| tree | 01.00.00 | [link](/doc/tree.en.md) | [path](./source/03_container) | Universal tree container
|
||||||
| graph | 01.00.00 | [link](/doc/graph.en.md) | [path](./source/03_container) | Universal graph container
|
| graph | 01.00.00 | [link](/doc/graph.en.md) | [path](./source/03_container) | Universal graph container
|
||||||
| check | 01.00.00 | [link](/doc/check.en.md) | [path](./source/04_algorithm) | Verification algorithm, sum check, parity check, XOR check, LRC check
|
| check | 01.00.00 | [link](/doc/check.en.md) | [path](./source/04_algorithm) | Verification algorithm, sum check, parity check, XOR check, LRC check
|
||||||
@ -77,6 +77,7 @@ It has the characteristics of **simplicity, universality, and efficiency**, with
|
|||||||
| intl | 01.01.00 | [link](/doc/intl.en.md) | [path](./source/07_math) | Large integer arithmetic module
|
| intl | 01.01.00 | [link](/doc/intl.en.md) | [path](./source/07_math) | Large integer arithmetic module
|
||||||
| floatl | 01.01.01 | [link](/doc/floatl.en.md) | [path](./source/07_math) | Large floating-point arithmetic module
|
| floatl | 01.01.01 | [link](/doc/floatl.en.md) | [path](./source/07_math) | Large floating-point arithmetic module
|
||||||
| flmath | 01.00.00 | [link](/doc/flmath.en.md) | [path](./source/07_math) | Large floating-point arithmetic math module
|
| flmath | 01.00.00 | [link](/doc/flmath.en.md) | [path](./source/07_math) | Large floating-point arithmetic math module
|
||||||
|
| coroutine | 00.02.00 | [link](/doc/coroutine.en.md) | [path](./source/08_coroutine) | Coroutine module
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|||||||
13
README.md
13
README.md
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
[](https://gitee.com/Lamdonn/varch)
|
[](https://gitee.com/Lamdonn/varch)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](Lamdonn@163.com)
|
[](Lamdonn@163.com)
|
||||||

|

|
||||||
@ -11,14 +11,14 @@
|
|||||||
|
|
||||||
[English version](README.en.md)
|
[English version](README.en.md)
|
||||||
|
|
||||||
varch(we-architecture,意为我们的框架库)是嵌入式C语言常用代码模块库,包含了嵌入式中常用的算法库(查找、校验、过滤、哈希、排序等)、数据结构/容器库(通用队列、栈、堆、列表、动态数组、字符串、集合、字典、映射、图等)、解析器库(csv、ini、json、xml等)、数学库(大数运算、数学运算)、独立C语言std库、工具库等等。
|
varch(we-architecture,意为我们的框架库)是嵌入式C语言常用代码模块库,包含了嵌入式中常用的算法库(查找、校验、过滤、哈希、排序等)、数据结构/容器库(通用队列、栈、堆、列表、动态数组、字符串、集合、字典、映射、图等)、解析器库(csv、ini、json、xml等)、数学库(大数运算、数学运算)、C语言协程库、独立C语言std库、工具库等等。
|
||||||
具有**简单, 通用, 高效**的特点,目的为了**学习**以及在开发中**拿来就用**,提高开发效率以及代码可靠稳定性。
|
具有**简单, 通用, 高效**的特点,目的为了**学习**以及在开发中**拿来就用**,提高开发效率以及代码可靠稳定性。
|
||||||
|
|
||||||
## 内容
|
## 内容
|
||||||
|
|
||||||
| module | version | usage | path | describe |
|
| module | version | usage | path | describe |
|
||||||
|:-------------|:---------|:-----------------------------|:------------------------------------------|:--------------------------------------|
|
|:-------------|:---------|:-----------------------------|:------------------------------------------|:--------------------------------------|
|
||||||
| overall | 00.03.03 | [link](README.md) | [path](./) | 整体
|
| overall | 00.03.05 | [link](README.md) | [path](./) | 整体
|
||||||
| init | 01.00.00 | [link](/doc/init.md) | [path](./source/00_application) | 初始化导出模块
|
| init | 01.00.00 | [link](/doc/init.md) | [path](./source/00_application) | 初始化导出模块
|
||||||
| console | 01.00.01 | [link](/doc/console.md) | [path](./source/00_application/console) | 控制台命令输入,结合 `command` 模块,解析在控制台中输入的命令
|
| console | 01.00.01 | [link](/doc/console.md) | [path](./source/00_application/console) | 控制台命令输入,结合 `command` 模块,解析在控制台中输入的命令
|
||||||
| arg | 01.00.00 | [link](/doc/arg.md) | [path](./source/01_general) | 不定参数,获取不定参数和指定参数的个数
|
| arg | 01.00.00 | [link](/doc/arg.md) | [path](./source/01_general) | 不定参数,获取不定参数和指定参数的个数
|
||||||
@ -45,13 +45,13 @@ varch(we-architecture,意为我们的框架库)是嵌入式C语言常用
|
|||||||
| queue | 01.00.00 | [link](/doc/queue.md) | [path](./source/03_container) | 通用队列容器
|
| queue | 01.00.00 | [link](/doc/queue.md) | [path](./source/03_container) | 通用队列容器
|
||||||
| stack | 01.00.00 | [link](/doc/stack.md) | [path](./source/03_container) | 通用栈式容器
|
| stack | 01.00.00 | [link](/doc/stack.md) | [path](./source/03_container) | 通用栈式容器
|
||||||
| deque | 01.00.00 | [link](/doc/deque.md) | [path](./source/03_container) | 通用双端队列容器
|
| deque | 01.00.00 | [link](/doc/deque.md) | [path](./source/03_container) | 通用双端队列容器
|
||||||
| list | 01.00.00 | [link](/doc/list.md) | [path](./source/03_container) | 通用列表容器,单链接和支持内部迭代器
|
| list | 01.00.01 | [link](/doc/list.md) | [path](./source/03_container) | 通用列表容器,单链接和支持内部迭代器
|
||||||
| vector | 01.00.00 | [link](/doc/vector.md) | [path](./source/03_container) | 通用向量(数组)容器
|
| vector | 01.00.00 | [link](/doc/vector.md) | [path](./source/03_container) | 通用向量(数组)容器
|
||||||
| str | 01.00.00 | [link](/doc/str.md) | [path](./source/03_container) | 字符串类
|
| str | 01.00.00 | [link](/doc/str.md) | [path](./source/03_container) | 字符串类
|
||||||
| dict | 01.00.00 | [link](/doc/dict.md) | [path](./source/03_container) | 通用字典容器,基于哈希表实现
|
| dict | 01.00.00 | [link](/doc/dict.md) | [path](./source/03_container) | 通用字典容器,基于哈希表实现
|
||||||
| heap | 01.00.00 | [link](/doc/heap.md) | [path](./source/03_container) | 通用堆容器
|
| heap | 01.00.00 | [link](/doc/heap.md) | [path](./source/03_container) | 通用堆容器
|
||||||
| set | 01.00.00 | [link](/doc/set.md) | [path](./source/03_container) | 通用集合容器,基于RB-tree实现
|
| set | 01.00.01 | [link](/doc/set.md) | [path](./source/03_container) | 通用集合容器,基于RB-tree实现
|
||||||
| map | 01.00.00 | [link](/doc/map.md) | [path](./source/03_container) | 通用映射容器,基于RB-tree实现
|
| map | 01.00.01 | [link](/doc/map.md) | [path](./source/03_container) | 通用映射容器,基于RB-tree实现
|
||||||
| tree | 01.00.00 | [link](/doc/tree.md) | [path](./source/03_container) | 通用树容器
|
| tree | 01.00.00 | [link](/doc/tree.md) | [path](./source/03_container) | 通用树容器
|
||||||
| graph | 01.00.00 | [link](/doc/graph.md) | [path](./source/03_container) | 通用图容器
|
| graph | 01.00.00 | [link](/doc/graph.md) | [path](./source/03_container) | 通用图容器
|
||||||
| check | 01.00.00 | [link](/doc/check.md) | [path](./source/04_algorithm) | 校验算法,求和校验,奇偶校验,异或校验,LRC校验
|
| check | 01.00.00 | [link](/doc/check.md) | [path](./source/04_algorithm) | 校验算法,求和校验,奇偶校验,异或校验,LRC校验
|
||||||
@ -77,6 +77,7 @@ varch(we-architecture,意为我们的框架库)是嵌入式C语言常用
|
|||||||
| intl | 01.01.00 | [link](/doc/intl.md) | [path](./source/07_math) | 大型整数运算模块
|
| intl | 01.01.00 | [link](/doc/intl.md) | [path](./source/07_math) | 大型整数运算模块
|
||||||
| floatl | 01.01.01 | [link](/doc/floatl.md) | [path](./source/07_math) | 大型浮点数运算模块
|
| floatl | 01.01.01 | [link](/doc/floatl.md) | [path](./source/07_math) | 大型浮点数运算模块
|
||||||
| flmath | 01.00.00 | [link](/doc/flmath.md) | [path](./source/07_math) | 大型浮点数数学运算模块
|
| flmath | 01.00.00 | [link](/doc/flmath.md) | [path](./source/07_math) | 大型浮点数数学运算模块
|
||||||
|
| coroutine | 00.02.00 | [link](/doc/coroutine.md) | [path](./source/08_coroutine) | 协程模块
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
|
|||||||
653
doc/coroutine.en.md
Normal file
653
doc/coroutine.en.md
Normal file
@ -0,0 +1,653 @@
|
|||||||
|
|
||||||
|
# Table of Contents
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Core Features](#core-features)
|
||||||
|
- [Architecture Design](#architecture-design)
|
||||||
|
- [API Interface Details](#api-interface-details)
|
||||||
|
- [Configuration Options](#configuration-options)
|
||||||
|
- [Usage Guide](#usage-guide)
|
||||||
|
- [Advanced Features](#advanced-features)
|
||||||
|
- [Error Handling](#error-handling)
|
||||||
|
- [Performance Optimization](#performance-optimization)
|
||||||
|
- [Platform Support](#platform-support)
|
||||||
|
- [Application Scenarios](#application-scenarios)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The coroutine module is a lightweight user-mode thread management mechanism that plays an important role in program development. It is mainly used in scenarios requiring efficient concurrency, such as resource-constrained embedded devices, network programming, asynchronous I/O, and real-time data processing.
|
||||||
|
Compared to traditional threads, it has lower resource consumption (no kernel-mode switching required) and faster context switching speed. Through the coroutine module, developers can achieve efficient task switching and concurrent execution, thereby improving program performance and response speed.
|
||||||
|
|
||||||
|
**coroutine** is a high-performance, lightweight C language coroutine library that uses an asymmetric stackful coroutine design. This library provides complete coroutine lifecycle management, supports multi-task scheduling, timer management, and event synchronization mechanisms. It offers concise APIs for creation, scheduling, and synchronization, and can be seamlessly integrated into various environments such as embedded systems and server programs. It is also relatively simple to port, requiring only compilation and linking of the module on the target platform (mainstream chip kernel architectures are already supported).
|
||||||
|
|
||||||
|
### Design Philosophy
|
||||||
|
- **Simple and Easy to Use**: Provides intuitive API interfaces
|
||||||
|
- **Easy to Port**: Requires few resource dependencies for porting
|
||||||
|
- **High Efficiency**: Low-overhead context switching
|
||||||
|
- **Stable and Reliable**: Error handling and resource management
|
||||||
|
|
||||||
|
## Core Features
|
||||||
|
|
||||||
|
### 1. Architecture Features
|
||||||
|
- **Asymmetric Stackful Coroutines**: Each coroutine has its own independent stack space
|
||||||
|
- **Multiple Scheduler Support**: Configurable with multiple independent coroutine schedulers
|
||||||
|
- **Hybrid Memory Management**: Supports both static pre-allocation and dynamic memory management
|
||||||
|
- **Cross-Platform Compatibility**: Supports various CPU architectures such as x86, x64, ARM, MIPS (not fully tested yet)
|
||||||
|
|
||||||
|
### 2. Coroutine State Management
|
||||||
|
|
||||||
|
#### Coroutine Scheduler State Definitions
|
||||||
|
#define COSCHEDULER_STATE_INTI (0) // Initialization state
|
||||||
|
#define COSCHEDULER_STATE_EXIT (1) // Exit state
|
||||||
|
#define COSCHEDULER_STATE_START (2) // Start state
|
||||||
|
#define COSCHEDULER_STATE_RUNNING (3) // Running state
|
||||||
|
#define COSCHEDULER_STATE_SCHEDULE (4) // Scheduling state
|
||||||
|
|
||||||
|
#### Coroutine Task State Definitions
|
||||||
|
#define COTASK_STATE_INTI (0) // Initialization state
|
||||||
|
#define COTASK_STATE_READY (1) // Ready state
|
||||||
|
#define COTASK_STATE_RUNNING (2) // Running state
|
||||||
|
#define COTASK_STATE_SUSPEND (3) // Suspended state
|
||||||
|
#define COTASK_STATE_DELETED (4) // Deleted state
|
||||||
|
|
||||||
|
### 3. Memory Management Configuration
|
||||||
|
|
||||||
|
#### Static Resource Limit Configuration
|
||||||
|
#define COROUTINE_SCHEDULER_NUMBER 1 // Number of schedulers
|
||||||
|
#define COROUTINE_STATIC_TASK_MAX_NUMBER 8 // Maximum number of static tasks
|
||||||
|
#define COROUTINE_STATIC_TIMER_MAX_NUMBER 8 // Maximum number of static timers
|
||||||
|
#define COROUTINE_STATIC_STACK_MAX_NUMBER 8 // Maximum number of static stacks
|
||||||
|
#define COROUTINE_STACK_DEFAULT_SIZE 10240 // Default stack size
|
||||||
|
|
||||||
|
## Architecture Design
|
||||||
|
|
||||||
|
### 1. Overall Architecture
|
||||||
|
|
||||||
|
+----------------------------------------------------+
|
||||||
|
| Architecture |
|
||||||
|
+------------------------------------+---------------+
|
||||||
|
| | +---------+ |
|
||||||
|
| +--------+ +--------+ | | CoTimer | |
|
||||||
|
| | | | | | +---------+ |
|
||||||
|
| | | CoEvent | | CoEvent +---------+ |
|
||||||
|
| | CoTask |<=======>| CoTask |<=======>| CoTimer | |
|
||||||
|
| | | | | | +---------+ |
|
||||||
|
| | | | | | +---------+ |
|
||||||
|
| +--------+ +--------+ | | CoTimer | |
|
||||||
|
+------------------------------------+ +---------+ |
|
||||||
|
| CoScheduler |
|
||||||
|
+----------------------------------------------------+
|
||||||
|
|
||||||
|
### 2. Coroutine Context Switching Mechanism
|
||||||
|
- Uses setjmp/longjmp to achieve fast context saving and restoration
|
||||||
|
- Each coroutine maintains independent stack space and environment
|
||||||
|
- Supports coroutine suspension, resumption, and deletion operations
|
||||||
|
|
||||||
|
## API Interface Details
|
||||||
|
|
||||||
|
### 1. Scheduler Management Interface
|
||||||
|
|
||||||
|
#### CoScheduler_Init - Initialize Coroutine Scheduler
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
#define CoScheduler_Init(CoSchedulerId, tick, tickInterval, ...)
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Initializes the specified coroutine scheduler, setting the clock function and clock interval. This function must be executed before calling any other coroutine functions.
|
||||||
|
It wraps the int CoScheduler_InitP(uint32_t CoSchedulerId, CoTick_t tick, uint32_t tickInterval, CoSchedulerInitPara *pPara); function, providing more initialization parameter configuration.
|
||||||
|
|
||||||
|
**Parameter Details:**
|
||||||
|
- CoSchedulerId **[Required]**: Scheduler ID, range 0 to (COROUTINE_SCHEDULER_NUMBER-1)
|
||||||
|
- tick **[Required]**: Clock function pointer, used to get the current timestamp
|
||||||
|
- tickInterval **[Required]**: Clock interval, representing the number of nanoseconds corresponding to each tick
|
||||||
|
- lock **[Optional]**: Lock function pointer, used for resource protection in multi-threaded environments
|
||||||
|
- unlock **[Optional]**: Unlock function pointer, used for resource release in multi-threaded environments
|
||||||
|
- malloc **[Optional]**: Memory allocation function pointer
|
||||||
|
- free **[Optional]**: Memory release function pointer
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- COROUTINE_E_OK (0): Initialization successful
|
||||||
|
- COROUTINE_E_INVALID_PARAMETER (-1): Invalid parameter
|
||||||
|
- COROUTINE_E_INVALID_TICK (-2): Invalid clock function
|
||||||
|
- COROUTINE_E_INVALID_TICK_INTERVAL (-3): Invalid clock interval
|
||||||
|
- COROUTINE_E_INVALID_LOCK (-4): Invalid lock function
|
||||||
|
- COROUTINE_E_INVALID_MHOOK (-5): Invalid memory hook function
|
||||||
|
|
||||||
|
**Usage Example:**
|
||||||
|
// Basic usage: use microsecond clock, 1000us interval
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
|
||||||
|
// Multi-thread support: with lock functions
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock);
|
||||||
|
|
||||||
|
// Complete configuration: with memory management functions
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000,
|
||||||
|
.lock=thread_lock,
|
||||||
|
.unlock=thread_unlock,
|
||||||
|
.malloc=malloc,
|
||||||
|
.free=free
|
||||||
|
);
|
||||||
|
|
||||||
|
#### CoScheduler_Start - Start Coroutine Scheduler
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
int CoScheduler_Start(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Starts the specified coroutine scheduler and begins coroutine task scheduling.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- CoSchedulerId: Scheduler ID
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- 0: Start successful
|
||||||
|
- Error code: Start failed
|
||||||
|
|
||||||
|
**Usage Process:**
|
||||||
|
// Complete scheduler startup process
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest));
|
||||||
|
CoScheduler_Start(0);
|
||||||
|
|
||||||
|
#### CoScheduler_Exit - Exit Coroutine Scheduler
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
int CoScheduler_Exit(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Exits the specified coroutine scheduler, stops all coroutine tasks, and cleans up resources.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- CoSchedulerId: Scheduler ID
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- COROUTINE_E_OK: Exit successful
|
||||||
|
|
||||||
|
### 2. Coroutine Task Management Interface
|
||||||
|
|
||||||
|
#### CoTask_Create - Create Coroutine Task
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
#define CoTask_Create(entry, ...)
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Creates a new coroutine task, allowing specification of stack space, parameters, and scheduler.
|
||||||
|
It wraps the CoTask_t CoTask_CreateP(CoTaskEntry_t entry, CoTaskCreatePara *pPara); function, providing more initialization parameter configuration.
|
||||||
|
|
||||||
|
**Parameter Details:**
|
||||||
|
- entry **[Required]**: Coroutine entry function pointer, type void (*)(void*)
|
||||||
|
- pStack **[Optional]**: Stack space address, automatically allocated if NULL
|
||||||
|
- stackSize **[Optional]**: Stack size, uses default value if not specified
|
||||||
|
- arg **[Optional]**: Parameter pointer passed to the coroutine
|
||||||
|
- schedulerId **[Optional]**: Scheduler ID, negative value means automatic allocation
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- CoTask_t: Successfully created coroutine task handle
|
||||||
|
- NULL: Creation failed
|
||||||
|
|
||||||
|
**Usage Example:**
|
||||||
|
// Create coroutine with default parameters
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test);
|
||||||
|
|
||||||
|
// Create coroutine with specified stack space
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest));
|
||||||
|
|
||||||
|
// Create coroutine with specified stack size
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test, .stackSize=4096);
|
||||||
|
|
||||||
|
// Create coroutine with parameters
|
||||||
|
int arg = 4096;
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test, .arg=&arg);
|
||||||
|
|
||||||
|
#### CoTask_Delete - Delete Coroutine Task
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
int CoTask_Delete(CoTask_t CoTask);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Deletes the specified coroutine task and releases related resources.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- CoTask: Coroutine task handle to be deleted
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- 0: Deletion successful
|
||||||
|
- COROUTINE_E_INVALID_PARAMETER: Invalid parameter
|
||||||
|
|
||||||
|
#### CoTask_Self - Get Current Coroutine Task
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
CoTask_t CoTask_Self(void);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the handle of the currently running coroutine task.
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- CoTask_t: Current coroutine task handle
|
||||||
|
- NULL: Not in coroutine context
|
||||||
|
|
||||||
|
#### CoTask_SchedulerId - Get Coroutine Scheduler ID
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
int CoTask_SchedulerId(void);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the scheduler ID to which the current coroutine task belongs.
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- Scheduler ID: 0 to (COROUTINE_SCHEDULER_NUMBER-1)
|
||||||
|
|
||||||
|
### 3. Coroutine Waiting Mechanism Interface
|
||||||
|
|
||||||
|
#### CoTask_Wait - Coroutine Wait Function
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
#define CoTask_Wait(...)
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Causes the current coroutine task to wait for a specified event or timeout.
|
||||||
|
It wraps the uint32_t CoTask_WaitP(CoTaskWaitPara *pPara); function, providing more waiting parameter configuration.
|
||||||
|
|
||||||
|
**Parameter Details:**
|
||||||
|
- pEvent **[Optional]**: Event pointer to wait for
|
||||||
|
- ms **[Optional]**: Number of milliseconds to wait
|
||||||
|
- tick **[Optional]**: Number of ticks to wait
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- uint32_t: Triggered event flag bits
|
||||||
|
|
||||||
|
**Usage Example:**
|
||||||
|
void *test(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
// Give up scheduler access right, similar to yield
|
||||||
|
CoTask_Wait();
|
||||||
|
|
||||||
|
// Wait for 1000ms
|
||||||
|
CoTask_Wait(.ms=1000);
|
||||||
|
|
||||||
|
// Wait for event to occur
|
||||||
|
uint32_t evs = CoTask_Wait(.pEvent=&g_Event);
|
||||||
|
if (evs & 0x01) {
|
||||||
|
printf("event 0x01 triggered\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combined wait: event + timeout
|
||||||
|
evs = CoTask_Wait(.pEvent=&g_Event, .ms=5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Wrapping CoTask_Wait can form the following commonly used methods:
|
||||||
|
#define CoTask_WaitMs(m) CoTask_Wait(.ms=m)
|
||||||
|
#define CoTask_WaitTick(t) CoTask_Wait(.tick=t)
|
||||||
|
#define CoTask_WaitEvent(e) CoTask_Wait(.pEvent=e)
|
||||||
|
#define CoTask_WaitEventMs(e, m) CoTask_Wait(.pEvent=e, .ms=m)
|
||||||
|
#define CoTask_WaitEventTick(e, t) CoTask_Wait(.pEvent=e, .tick=t)
|
||||||
|
|
||||||
|
### 4. Timer Management Interface
|
||||||
|
|
||||||
|
#### CoTimer_Create - Create Coroutine Timer
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
#define CoTimer_Create(entry, ...)
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Creates a periodic coroutine timer.
|
||||||
|
It wraps the CoTimer_t CoTimer_CreateP(CoTimerEntry_t entry, CoTimerCreatePara *pPara); function, providing more initialization parameter configuration.
|
||||||
|
|
||||||
|
**Parameter Details:**
|
||||||
|
- entry **[Required]**: Timer entry function
|
||||||
|
- ms **[Optional]**: Millisecond interval
|
||||||
|
- tick **[Optional]**: Tick interval
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- CoTimer_t: Successfully created timer handle
|
||||||
|
- NULL: Creation failed
|
||||||
|
|
||||||
|
**Usage Example:**
|
||||||
|
// Create timer with 100ms interval
|
||||||
|
CoTimer_t timer = CoTimer_Create(timer_entry, .ms=100);
|
||||||
|
|
||||||
|
#### CoTimer_Delete - Delete Coroutine Timer
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
void CoTimer_Delete(CoTimer_t Timer);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Deletes the specified coroutine timer.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- Timer: Timer handle to be deleted
|
||||||
|
|
||||||
|
#### CoTimer_Self - Get Current Timer
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
CoTimer_t CoTimer_Self(void);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the handle of the currently running coroutine timer.
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- CoTimer_t: Current timer handle
|
||||||
|
- NULL: Not in timer context
|
||||||
|
|
||||||
|
### 5. Event Synchronization Interface
|
||||||
|
|
||||||
|
#### CoEvent_Init - Initialize Event
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
void CoEvent_Init(CoEvent *pEvent);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Initializes a coroutine event, preparing it for inter-coroutine synchronization.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- pEvent: Event pointer
|
||||||
|
|
||||||
|
**Usage Example:**
|
||||||
|
CoEvent_Init(&g_Event);
|
||||||
|
|
||||||
|
This method is called at runtime, while static initialization can directly assign COEVENT_STATIC_VALUE.
|
||||||
|
CoEvent g_Event = COEVENT_STATIC_VALUE;
|
||||||
|
|
||||||
|
#### CoEvent_Notify - Notify Event
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
void CoEvent_Notify(CoEvent *pEvent, uint32_t evs);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Notifies the specified event, waking up coroutine tasks waiting for that event.
|
||||||
|
|
||||||
|
**Parameter Details:**
|
||||||
|
- pEvent: Event pointer
|
||||||
|
- evs: Event flag bits, supports simultaneous notification of multiple events
|
||||||
|
|
||||||
|
**Usage Example:**
|
||||||
|
// Notify single event
|
||||||
|
CoEvent_Notify(&g_Event, 0x01);
|
||||||
|
|
||||||
|
// Notify multiple events simultaneously
|
||||||
|
CoEvent_Notify(&g_Event, 0x01 | 0x02 | 0x04);
|
||||||
|
|
||||||
|
### 6. Monitoring Statistics Interface
|
||||||
|
|
||||||
|
#### CoTask_StackMaxUsed - Get Coroutine Stack Maximum Usage
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
size_t CoTask_StackMaxUsed(CoTask_t CoTask);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the maximum stack usage of the specified coroutine task.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- CoTask: Coroutine task handle
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- size_t: Maximum stack usage (bytes)
|
||||||
|
|
||||||
|
#### CoTask_StackCurUsed - Get Coroutine Stack Current Usage
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
size_t CoTask_StackCurUsed(CoTask_t CoTask);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the current stack usage of the specified coroutine task.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- CoTask: Coroutine task handle
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- size_t: Current stack usage (bytes)
|
||||||
|
|
||||||
|
#### CoScheduler_CurLoad - Get Current Load
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
uint16_t CoScheduler_CurLoad(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the current load of the specified scheduler.
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- uint16_t: Current load percentage (0-10000, representing 0.00%-100.00%)
|
||||||
|
|
||||||
|
#### CoScheduler_MaxLoad - Get Maximum Historical Load
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
uint16_t CoScheduler_MaxLoad(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the historical maximum load of the specified scheduler.
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- uint16_t: Maximum load percentage
|
||||||
|
|
||||||
|
### 7. Statistical Counting Interface
|
||||||
|
|
||||||
|
#### CoScheduler_TaskCount - Get Coroutine Task Count
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
int CoScheduler_TaskCount(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the number of coroutine tasks in the specified scheduler.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- CoSchedulerId: Scheduler ID
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- int: Number of coroutine tasks
|
||||||
|
|
||||||
|
#### CoScheduler_TimerCount - Get Timer Count
|
||||||
|
|
||||||
|
**Function Prototype:**
|
||||||
|
int CoScheduler_TimerCount(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
**Function Description:**
|
||||||
|
Gets the number of coroutine timers in the specified scheduler.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- CoSchedulerId: Scheduler ID
|
||||||
|
|
||||||
|
**Return Value:**
|
||||||
|
- int: Number of timers
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
### Compile-time Configuration (coroutine_cfg.h)
|
||||||
|
|
||||||
|
**Basic Configuration:**
|
||||||
|
// Scheduler configuration
|
||||||
|
#define COROUTINE_SCHEDULER_NUMBER 1 // Number of schedulers
|
||||||
|
|
||||||
|
// Static resource limits
|
||||||
|
#define COROUTINE_STATIC_TASK_MAX_NUMBER 8 // Maximum number of static tasks
|
||||||
|
#define COROUTINE_STATIC_TIMER_MAX_NUMBER 8 // Maximum number of static timers
|
||||||
|
#define COROUTINE_STATIC_STACK_MAX_NUMBER 8 // Maximum number of static stacks
|
||||||
|
|
||||||
|
// Stack configuration
|
||||||
|
#define COROUTINE_STACK_DEFAULT_SIZE 10240 // Default stack size
|
||||||
|
|
||||||
|
**Feature Switches:**
|
||||||
|
// Stack usage calculation
|
||||||
|
#define COROUTINE_ENABLE_STACK_CALCULATE 1 // Enable stack usage calculation
|
||||||
|
|
||||||
|
// Load calculation
|
||||||
|
#define COROUTINE_ENABLE_LOADING_CALCULATE 1 // Enable load calculation
|
||||||
|
|
||||||
|
// Debug support
|
||||||
|
#define COROUTINE_ENABLE_DEBUG 1 // Enable debug function
|
||||||
|
|
||||||
|
## Usage Guide
|
||||||
|
|
||||||
|
### 1. Basic Usage Process
|
||||||
|
|
||||||
|
#### Initialization Phase
|
||||||
|
#include "coroutine.h"
|
||||||
|
|
||||||
|
// Define clock function
|
||||||
|
uint64_t GetTimerUsec(void) {
|
||||||
|
// Return microsecond-level timestamp
|
||||||
|
return ...;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// Initialize scheduler 0, use microsecond clock, 1000us interval
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Coroutine Definition
|
||||||
|
// Coroutine task function
|
||||||
|
void *test_task(void *arg) {
|
||||||
|
int *p_count = (int*)arg;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Coroutine task logic
|
||||||
|
(*p_count)++;
|
||||||
|
|
||||||
|
// Voluntarily yield CPU
|
||||||
|
CoTask_Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Creation and Startup
|
||||||
|
// Create coroutine task
|
||||||
|
int count = 0;
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test_task, .arg=&count);
|
||||||
|
}
|
||||||
|
|
||||||
|
### 2. Advanced Usage Patterns
|
||||||
|
|
||||||
|
#### Event-Driven Pattern
|
||||||
|
void *event_driven_task(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
// Wait for event
|
||||||
|
uint32_t evs = CoTask_Wait(.pEvent=&g_Event);
|
||||||
|
|
||||||
|
if (evs & 0x01) {
|
||||||
|
// Handle event 0x01
|
||||||
|
handle_event_01();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evs & 0x02) {
|
||||||
|
// Handle event 0x02
|
||||||
|
handle_event_02();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Timer Pattern
|
||||||
|
void *timer_task(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
// Execute every 100ms
|
||||||
|
CoTask_Wait(.ms=100);
|
||||||
|
|
||||||
|
// Timer logic
|
||||||
|
periodic_work();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
## Advanced Features
|
||||||
|
|
||||||
|
### 1. Stack Usage Calculation
|
||||||
|
|
||||||
|
After enabling COROUTINE_ENABLE_STACK_CALCULATE, you can monitor coroutine stack usage:
|
||||||
|
|
||||||
|
// Get coroutine stack maximum usage
|
||||||
|
size_t maxUsed = CoTask_StackMaxUsed(CoTask);
|
||||||
|
|
||||||
|
// Get coroutine stack current usage
|
||||||
|
size_t curUsed = CoTask_StackCurUsed(CoTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
### 2. Load Calculation
|
||||||
|
|
||||||
|
After enabling COROUTINE_ENABLE_LOADING_CALCULATE, you can calculate the scheduler's load:
|
||||||
|
|
||||||
|
// Get current load
|
||||||
|
uint16_t curLoad = CoScheduler_CurLoad(CoSchedulerId);
|
||||||
|
|
||||||
|
// Get maximum historical load
|
||||||
|
uint16_t maxLoad = CoScheduler_MaxLoad(CoSchedulerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
### 3. Performance Monitoring
|
||||||
|
|
||||||
|
// Monitor coroutine scheduling performance
|
||||||
|
void monitor_scheduler_performance(void) {
|
||||||
|
uint16_t curLoad = CoScheduler_CurLoad(0);
|
||||||
|
uint16_t maxLoad = CoScheduler_MaxLoad(0);
|
||||||
|
|
||||||
|
if (curLoad > 8000) { // 80% load warning
|
||||||
|
printf("Warning: Scheduler load is high: %d.%02d%%\n",
|
||||||
|
curLoad/100, curLoad%100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Error Code Definitions
|
||||||
|
|
||||||
|
#define COROUTINE_E_OK (0) // Success
|
||||||
|
#define COROUTINE_E_INVALID_PARAMETER (-1) // Invalid parameter
|
||||||
|
#define COROUTINE_E_INVALID_TICK (-2) // Invalid clock function
|
||||||
|
#define COROUTINE_E_INVALID_TICK_INTERVAL (-3) // Invalid clock interval
|
||||||
|
#define COROUTINE_E_INVALID_LOCK (-4) // Invalid lock function
|
||||||
|
#define COROUTINE_E_INVALID_MHOOK (-5) // Invalid memory hook function
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### 1. Context Switching Optimization
|
||||||
|
- Uses setjmp/longjmp instead of complete context saving
|
||||||
|
- Minimizes register save and restore operations
|
||||||
|
|
||||||
|
### 2. Memory Management Optimization
|
||||||
|
- Static pre-allocation reduces dynamic memory allocation
|
||||||
|
- Stack space reuse mechanism
|
||||||
|
|
||||||
|
## Platform Support
|
||||||
|
|
||||||
|
This library implements cross-platform stack pointer operations through inline assembly:
|
||||||
|
|
||||||
|
- **x86/x64**: Uses esp/rsp registers
|
||||||
|
- **ARM**: Uses sp register
|
||||||
|
- **MIPS**: Uses sp register
|
||||||
|
- **RISC-V**: Uses sp register
|
||||||
|
- **PowerPC**: Uses r1 register
|
||||||
|
|
||||||
|
### Platform-Specific Implementation
|
||||||
|
// x86 architecture implementation
|
||||||
|
#if defined(__i386__)
|
||||||
|
#define COROUTINE_GET_STACK_POINTER(p) \
|
||||||
|
__asm__ __volatile__("movl %%esp, %0" : "=r"(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
## Application Scenarios
|
||||||
|
|
||||||
|
### 1. Embedded Systems
|
||||||
|
- Real-time task scheduling
|
||||||
|
- Low-power device management
|
||||||
|
- Sensor data processing
|
||||||
|
|
||||||
|
### 2. Network Programming
|
||||||
|
- Asynchronous I/O processing
|
||||||
|
- Connection pool management
|
||||||
|
- Protocol stack implementation
|
||||||
|
|
||||||
|
### 3. Game Development
|
||||||
|
- Game object updates
|
||||||
|
- AI behavior scheduling
|
||||||
|
- Animation system management
|
||||||
|
|
||||||
|
### 4. IoT Applications
|
||||||
|
- Device communication protocols
|
||||||
|
- Data processing pipelines
|
||||||
|
- Remote control interfaces
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
The **coroutine** coroutine library is a powerful, high-performance C language coroutine solution. It provides:
|
||||||
|
|
||||||
|
1. **Complete coroutine lifecycle management**
|
||||||
|
2. **Efficient multi-task scheduling mechanism**
|
||||||
|
3. **Flexible timer and event management**
|
||||||
|
4. **Comprehensive error handling and monitoring functions**
|
||||||
734
doc/coroutine.md
Normal file
734
doc/coroutine.md
Normal file
@ -0,0 +1,734 @@
|
|||||||
|
## 目录
|
||||||
|
- [概述](#概述)
|
||||||
|
- [核心特性](#核心特性)
|
||||||
|
- [架构设计](#架构设计)
|
||||||
|
- [API接口详解](#api接口详解)
|
||||||
|
- [配置选项](#配置选项)
|
||||||
|
- [使用指南](#使用指南)
|
||||||
|
- [高级功能](#高级功能)
|
||||||
|
- [错误处理](#错误处理)
|
||||||
|
- [性能优化](#性能优化)
|
||||||
|
- [平台支持](#平台支持)
|
||||||
|
- [应用场景](#应用场景)
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
协程模块是一种轻量级的用户态线程管理机制,在程序开发中扮演着重要角色,主要用于资源受限的嵌入式设备、网络编程、异步IO、实时数据处理等需要高效并发的场景。
|
||||||
|
相比传统线程具有更低的资源消耗(无需内核态切换)和更快的上下文切换速度,通过协程模块,开发者能够实现高效的任务切换和并发执行,从而提升程序的性能和响应速度。
|
||||||
|
|
||||||
|
**coroutine** 是一个高性能、轻量级的C语言协程库,采用非对称有栈协程设计。该库提供了完整的协程生命周期管理,支持多任务调度、定时器管理和事件同步机制,提供简洁的创建、调度与同步API接口,可无缝集成到嵌入式系统、服务器程序等多种环境中。并且移植起来也比较简单,只需要在目标平台上编译并链接该模块即可(已支持主流的芯片内核架构)。
|
||||||
|
|
||||||
|
### 设计理念
|
||||||
|
- **简单易用**:提供直观的API接口
|
||||||
|
- **移植方便**:移植所需资源依赖少
|
||||||
|
- **高效性能**:低开销的上下文切换
|
||||||
|
- **稳定可靠**:错误处理和资源管理
|
||||||
|
|
||||||
|
## 核心特性
|
||||||
|
|
||||||
|
### 1. 架构特性
|
||||||
|
- **非对称有栈协程**:每个协程拥有独立的栈空间
|
||||||
|
- **多调度器支持**:可配置多个独立的协程调度器
|
||||||
|
- **混合内存管理**:支持静态预分配和动态内存管理
|
||||||
|
- **跨平台兼容**:支持x86、x64、ARM、MIPS等多种CPU架构(尚未完全测试完)
|
||||||
|
|
||||||
|
### 2. 协程状态管理
|
||||||
|
|
||||||
|
#### 协程调度器状态定义
|
||||||
|
```c
|
||||||
|
#define COSCHEDULER_STATE_INTI (0) // 初始化状态
|
||||||
|
#define COSCHEDULER_STATE_EXIT (1) // 退出状态
|
||||||
|
#define COSCHEDULER_STATE_START (2) // 启动状态
|
||||||
|
#define COSCHEDULER_STATE_RUNNING (3) // 运行状态
|
||||||
|
#define COSCHEDULER_STATE_SCHEDULE (4) // 调度状态
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 协程任务状态定义
|
||||||
|
```c
|
||||||
|
#define COTASK_STATE_INTI (0) // 初始化状态
|
||||||
|
#define COTASK_STATE_READY (1) // 就绪状态
|
||||||
|
#define COTASK_STATE_RUNNING (2) // 运行状态
|
||||||
|
#define COTASK_STATE_SUSPEND (3) // 挂起状态
|
||||||
|
#define COTASK_STATE_DELETED (4) // 删除状态
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 内存管理配置
|
||||||
|
|
||||||
|
#### 静态资源限制配置
|
||||||
|
```c
|
||||||
|
#define COROUTINE_SCHEDULER_NUMBER 1 // 调度器数量
|
||||||
|
#define COROUTINE_STATIC_TASK_MAX_NUMBER 8 // 静态任务最大数量
|
||||||
|
#define COROUTINE_STATIC_TIMER_MAX_NUMBER 8 // 静态定时器最大数量
|
||||||
|
#define COROUTINE_STATIC_STACK_MAX_NUMBER 8 // 静态栈最大数量
|
||||||
|
#define COROUTINE_STACK_DEFAULT_SIZE 10240 // 默认栈大小
|
||||||
|
```
|
||||||
|
|
||||||
|
## 架构设计
|
||||||
|
|
||||||
|
### 1. 整体架构
|
||||||
|
|
||||||
|
```
|
||||||
|
+----------------------------------------------------+
|
||||||
|
| Architecture |
|
||||||
|
+------------------------------------+---------------+
|
||||||
|
| | +---------+ |
|
||||||
|
| +--------+ +--------+ | | CoTimer | |
|
||||||
|
| | | | | | +---------+ |
|
||||||
|
| | | CoEvent | | CoEvent +---------+ |
|
||||||
|
| | CoTask |<=======>| CoTask |<=======>| CoTimer | |
|
||||||
|
| | | | | | +---------+ |
|
||||||
|
| | | | | | +---------+ |
|
||||||
|
| +--------+ +--------+ | | CoTimer | |
|
||||||
|
+------------------------------------+ +---------+ |
|
||||||
|
| CoScheduler |
|
||||||
|
+----------------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 协程上下文切换机制
|
||||||
|
- 使用setjmp/longjmp实现快速上下文保存和恢复
|
||||||
|
- 每个协程维护独立的栈空间和环境
|
||||||
|
- 支持协程挂起、恢复和删除操作
|
||||||
|
|
||||||
|
## API接口详解
|
||||||
|
|
||||||
|
### 1. 调度器管理接口
|
||||||
|
|
||||||
|
#### CoScheduler_Init - 初始化协程调度器
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
#define CoScheduler_Init(CoSchedulerId, tick, tickInterval, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
初始化指定的协程调度器,设置时钟函数和时钟间隔。此函数必须在调用任何其他协程函数之前执行。
|
||||||
|
套用 `int CoScheduler_InitP(uint32_t CoSchedulerId, CoTick_t tick, uint32_t tickInterval, CoSchedulerInitPara *pPara);` 函数,提供更多的初始化参数配置。
|
||||||
|
|
||||||
|
**参数详解:**
|
||||||
|
- `CoSchedulerId` **[必需]**:调度器ID,范围0到(COROUTINE_SCHEDULER_NUMBER-1)
|
||||||
|
- `tick` **[必需]**:时钟函数指针,用于获取当前时间戳
|
||||||
|
- `tickInterval` **[必需]**:时钟间隔,表示每个tick对应的纳秒数
|
||||||
|
- `lock` **[可选]**:锁函数指针,用于多线程环境下的资源保护
|
||||||
|
- `unlock` **[可选]**:解锁函数指针,用于多线程环境下的资源释放
|
||||||
|
- `malloc` **[可选]**:内存分配函数指针
|
||||||
|
- `free` **[可选]**:内存释放函数指针
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `COROUTINE_E_OK` (0):初始化成功
|
||||||
|
- `COROUTINE_E_INVALID_PARAMETER` (-1):无效参数
|
||||||
|
- `COROUTINE_E_INVALID_TICK` (-2):无效时钟函数
|
||||||
|
- `COROUTINE_E_INVALID_TICK_INTERVAL` (-3):无效时钟间隔
|
||||||
|
- `COROUTINE_E_INVALID_LOCK` (-4):无效锁函数
|
||||||
|
- `COROUTINE_E_INVALID_MHOOK` (-5):无效内存钩子函数
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```c
|
||||||
|
// 基本使用:使用微秒时钟,1000us间隔
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
|
||||||
|
// 多线程支持:带锁函数
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock);
|
||||||
|
|
||||||
|
// 完整配置:带内存管理函数
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000,
|
||||||
|
.lock=thread_lock,
|
||||||
|
.unlock=thread_unlock,
|
||||||
|
.malloc=malloc,
|
||||||
|
.free=free
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CoScheduler_Start - 启动协程调度器
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
int CoScheduler_Start(uint32_t CoSchedulerId);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
启动指定的协程调度器,开始执行协程任务调度。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `CoSchedulerId`:调度器ID
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- 0:启动成功
|
||||||
|
- 错误码:启动失败
|
||||||
|
|
||||||
|
**使用流程:**
|
||||||
|
```c
|
||||||
|
// 完整的调度器启动流程
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest));
|
||||||
|
CoScheduler_Start(0);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CoScheduler_Exit - 退出协程调度器
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
int CoScheduler_Exit(uint32_t CoSchedulerId);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
退出指定的协程调度器,停止所有协程任务并清理资源。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `CoSchedulerId`:调度器ID
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `COROUTINE_E_OK`:退出成功
|
||||||
|
|
||||||
|
### 2. 协程任务管理接口
|
||||||
|
|
||||||
|
#### CoTask_Create - 创建协程任务
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
#define CoTask_Create(entry, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
创建一个新的协程任务,可以指定栈空间、参数和调度器。
|
||||||
|
套用 `CoTask_t CoTask_CreateP(CoTaskEntry_t entry, CoTaskCreatePara *pPara);` 函数,提供更多的初始化参数配置。
|
||||||
|
|
||||||
|
**参数详解:**
|
||||||
|
- `entry` **[必需]**:协程入口函数指针,类型为`void (*)(void*)`
|
||||||
|
- `pStack` **[可选]**:栈空间地址,如果为NULL则自动分配
|
||||||
|
- `stackSize` **[可选]**:栈大小,未指定时使用默认值
|
||||||
|
- `arg` **[可选]**:传递给协程的参数指针
|
||||||
|
- `schedulerId` **[可选]**:调度器ID,负值表示自动分配
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `CoTask_t`:成功创建的协程任务句柄
|
||||||
|
- `NULL`:创建失败
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```c
|
||||||
|
// 使用默认参数创建协程
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test);
|
||||||
|
|
||||||
|
// 指定栈空间创建协程
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest));
|
||||||
|
|
||||||
|
// 指定栈大小创建协程
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test, .stackSize=4096);
|
||||||
|
|
||||||
|
// 带参数创建协程
|
||||||
|
int arg = 4096;
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test, .arg=&arg);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CoTask_Delete - 删除协程任务
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
int CoTask_Delete(CoTask_t CoTask);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
删除指定的协程任务,释放相关资源。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `CoTask`:要删除的协程任务句柄
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- 0:删除成功
|
||||||
|
- `COROUTINE_E_INVALID_PARAMETER`:无效参数
|
||||||
|
|
||||||
|
#### CoTask_Self - 获取当前协程任务
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
CoTask_t CoTask_Self(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取当前正在运行的协程任务句柄。
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `CoTask_t`:当前协程任务句柄
|
||||||
|
- `NULL`:不在协程上下文中
|
||||||
|
|
||||||
|
#### CoTask_SchedulerId - 获取协程调度器ID
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
int CoTask_SchedulerId(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取当前协程任务所属的调度器ID。
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- 调度器ID:0到(COROUTINE_SCHEDULER_NUMBER-1)
|
||||||
|
|
||||||
|
### 3. 协程等待机制接口
|
||||||
|
|
||||||
|
#### CoTask_Wait - 协程等待函数
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
#define CoTask_Wait(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
使当前协程任务等待指定的事件或超时。
|
||||||
|
套用 `uint32_t CoTask_WaitP(CoTaskWaitPara *pPara);` 函数,提供更多的等待参数配置。
|
||||||
|
|
||||||
|
**参数详解:**
|
||||||
|
- `pEvent` **[可选]**:等待的事件指针
|
||||||
|
- `ms` **[可选]**:等待的毫秒数
|
||||||
|
- `tick` **[可选]**:等待的tick数
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `uint32_t`:触发的事件标志位
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```c
|
||||||
|
void *test(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
// 放弃调度器访问权,类似yield
|
||||||
|
CoTask_Wait();
|
||||||
|
|
||||||
|
// 等待1000ms
|
||||||
|
CoTask_Wait(.ms=1000);
|
||||||
|
|
||||||
|
// 等待事件发生
|
||||||
|
uint32_t evs = CoTask_Wait(.pEvent=&g_Event);
|
||||||
|
if (evs & 0x01) {
|
||||||
|
printf("event 0x01 triggered\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组合等待:事件+超时
|
||||||
|
evs = CoTask_Wait(.pEvent=&g_Event, .ms=5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
套用 `CoTask_Wait` 可以形成以下常用方法:
|
||||||
|
```c
|
||||||
|
#define CoTask_WaitMs(m) CoTask_Wait(.ms=m)
|
||||||
|
#define CoTask_WaitTick(t) CoTask_Wait(.tick=t)
|
||||||
|
#define CoTask_WaitEvent(e) CoTask_Wait(.pEvent=e)
|
||||||
|
#define CoTask_WaitEventMs(e, m) CoTask_Wait(.pEvent=e, .ms=m)
|
||||||
|
#define CoTask_WaitEventTick(e, t) CoTask_Wait(.pEvent=e, .tick=t)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 定时器管理接口
|
||||||
|
|
||||||
|
#### CoTimer_Create - 创建协程定时器
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
#define CoTimer_Create(entry, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
创建一个周期性的协程定时器。
|
||||||
|
套用 `CoTimer_t CoTimer_CreateP(CoTimerEntry_t entry, CoTimerCreatePara *pPara);` 函数,提供更多的初始化参数配置。
|
||||||
|
|
||||||
|
**参数详解:**
|
||||||
|
- `entry` **[必需]**:定时器入口函数
|
||||||
|
- `ms` **[可选]**:毫秒间隔
|
||||||
|
- `tick` **[可选]**:tick间隔
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `CoTimer_t`:成功创建的定时器句柄
|
||||||
|
- `NULL`:创建失败
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```c
|
||||||
|
// 创建100ms间隔的定时器
|
||||||
|
CoTimer_t timer = CoTimer_Create(timer_entry, .ms=100);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CoTimer_Delete - 删除协程定时器
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
void CoTimer_Delete(CoTimer_t Timer);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
删除指定的协程定时器。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `Timer`:要删除的定时器句柄
|
||||||
|
|
||||||
|
#### CoTimer_Self - 获取当前定时器
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
CoTimer_t CoTimer_Self(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取当前正在运行的协程定时器句柄。
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `CoTimer_t`:当前定时器句柄
|
||||||
|
- `NULL`:不在定时器上下文中
|
||||||
|
|
||||||
|
### 5. 事件同步接口
|
||||||
|
|
||||||
|
#### CoEvent_Init - 初始化事件
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
void CoEvent_Init(CoEvent *pEvent);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
初始化协程事件,准备用于协程间同步。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `pEvent`:事件指针
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```c
|
||||||
|
CoEvent_Init(&g_Event);
|
||||||
|
```
|
||||||
|
|
||||||
|
此方法为运行时调用,静态初始化可以直接赋值为 `COEVENT_STATIC_VALUE`。
|
||||||
|
```c
|
||||||
|
CoEvent g_Event = COEVENT_STATIC_VALUE;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CoEvent_Notify - 通知事件
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
void CoEvent_Notify(CoEvent *pEvent, uint32_t evs);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
通知指定的事件,唤醒等待该事件的协程任务。
|
||||||
|
|
||||||
|
**参数详解:**
|
||||||
|
- `pEvent`:事件指针
|
||||||
|
- `evs`:事件标志位,支持多事件同时通知
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```c
|
||||||
|
// 通知单个事件
|
||||||
|
CoEvent_Notify(&g_Event, 0x01);
|
||||||
|
|
||||||
|
// 同时通知多个事件
|
||||||
|
CoEvent_Notify(&g_Event, 0x01 | 0x02 | 0x04);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 监控统计接口
|
||||||
|
|
||||||
|
#### CoTask_StackMaxUsed - 获取协程栈最大使用量
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
size_t CoTask_StackMaxUsed(CoTask_t CoTask);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取指定协程任务栈的最大使用量。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `CoTask`:协程任务句柄
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `size_t`:栈最大使用量(字节)
|
||||||
|
|
||||||
|
#### CoTask_StackCurUsed - 获取协程栈当前使用量
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
size_t CoTask_StackCurUsed(CoTask_t CoTask);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取指定协程任务栈的当前使用量。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `CoTask`:协程任务句柄
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `size_t`:栈当前使用量(字节)
|
||||||
|
|
||||||
|
#### CoScheduler_CurLoad - 获取当前负载
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
uint16_t CoScheduler_CurLoad(uint32_t CoSchedulerId);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取指定调度器的当前负载。
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `uint16_t`:当前负载百分比(0-10000,表示0.00%-100.00%)
|
||||||
|
|
||||||
|
#### CoScheduler_MaxLoad - 获取最大历史负载
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
uint16_t CoScheduler_MaxLoad(uint32_t CoSchedulerId);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取指定调度器的历史最大负载。
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `uint16_t`:最大负载百分比
|
||||||
|
|
||||||
|
### 7. 统计计数接口
|
||||||
|
|
||||||
|
#### CoScheduler_TaskCount - 获取协程任务数量
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
int CoScheduler_TaskCount(uint32_t CoSchedulerId);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取指定调度器中的协程任务数量。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `CoSchedulerId`:调度器ID
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `int`:协程任务数量
|
||||||
|
|
||||||
|
#### CoScheduler_TimerCount - 获取定时器数量
|
||||||
|
|
||||||
|
**函数原型:**
|
||||||
|
```c
|
||||||
|
int CoScheduler_TimerCount(uint32_t CoSchedulerId);
|
||||||
|
```
|
||||||
|
|
||||||
|
**函数说明:**
|
||||||
|
获取指定调度器中的协程定时器数量。
|
||||||
|
|
||||||
|
**参数:**
|
||||||
|
- `CoSchedulerId`:调度器ID
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
- `int`:定时器数量
|
||||||
|
|
||||||
|
## 配置选项
|
||||||
|
|
||||||
|
### 编译时配置 (coroutine_cfg.h)
|
||||||
|
|
||||||
|
**基本配置:**
|
||||||
|
```c
|
||||||
|
// 调度器配置
|
||||||
|
#define COROUTINE_SCHEDULER_NUMBER 1 // 调度器数量
|
||||||
|
|
||||||
|
// 静态资源限制
|
||||||
|
#define COROUTINE_STATIC_TASK_MAX_NUMBER 8 // 静态任务最大数量
|
||||||
|
#define COROUTINE_STATIC_TIMER_MAX_NUMBER 8 // 静态定时器最大数量
|
||||||
|
#define COROUTINE_STATIC_STACK_MAX_NUMBER 8 // 静态栈最大数量
|
||||||
|
|
||||||
|
// 栈配置
|
||||||
|
#define COROUTINE_STACK_DEFAULT_SIZE 10240 // 默认栈大小
|
||||||
|
```
|
||||||
|
|
||||||
|
**功能开关:**
|
||||||
|
```c
|
||||||
|
// 栈使用量计算
|
||||||
|
#define COROUTINE_ENABLE_STACK_CALCULATE 1 // 启用栈使用量计算
|
||||||
|
|
||||||
|
// 负载计算
|
||||||
|
#define COROUTINE_ENABLE_LOADING_CALCULATE 1 // 启用负载计算
|
||||||
|
|
||||||
|
// 调试支持
|
||||||
|
#define COROUTINE_ENABLE_DEBUG 1 // 启用调试功能
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用指南
|
||||||
|
|
||||||
|
### 1. 基本使用流程
|
||||||
|
|
||||||
|
#### 初始化阶段
|
||||||
|
```c
|
||||||
|
#include "coroutine.h"
|
||||||
|
|
||||||
|
// 定义时钟函数
|
||||||
|
uint64_t GetTimerUsec(void) {
|
||||||
|
// 返回微秒级时间戳
|
||||||
|
return ...;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// 初始化调度器0,使用微秒时钟,1000us间隔
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 协程定义
|
||||||
|
```c
|
||||||
|
// 协程任务函数
|
||||||
|
void *test_task(void *arg) {
|
||||||
|
int *p_count = (int*)arg;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// 协程任务逻辑
|
||||||
|
(*p_count)++;
|
||||||
|
|
||||||
|
// 主动让出CPU
|
||||||
|
CoTask_Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 创建和启动
|
||||||
|
```c
|
||||||
|
// 创建协程任务
|
||||||
|
int count = 0;
|
||||||
|
CoTask_t testCoroutine = CoTask_Create(test_task, .arg=&count);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 高级使用模式
|
||||||
|
|
||||||
|
#### 事件驱动模式
|
||||||
|
```c
|
||||||
|
void *event_driven_task(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
// 等待事件
|
||||||
|
uint32_t evs = CoTask_Wait(.pEvent=&g_Event);
|
||||||
|
|
||||||
|
if (evs & 0x01) {
|
||||||
|
// 处理事件0x01
|
||||||
|
handle_event_01();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evs & 0x02) {
|
||||||
|
// 处理事件0x02
|
||||||
|
handle_event_02();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 定时器模式
|
||||||
|
```c
|
||||||
|
void *timer_task(void *arg) {
|
||||||
|
while (1) {
|
||||||
|
// 每100ms执行一次
|
||||||
|
CoTask_Wait(.ms=100);
|
||||||
|
|
||||||
|
// 定时器逻辑
|
||||||
|
periodic_work();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 高级功能
|
||||||
|
|
||||||
|
### 1. 栈使用量计算
|
||||||
|
|
||||||
|
启用 `COROUTINE_ENABLE_STACK_CALCULATE` 后,可以监控协程栈的使用情况:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// 获取协程栈最大使用量
|
||||||
|
size_t maxUsed = CoTask_StackMaxUsed(CoTask);
|
||||||
|
|
||||||
|
// 获取协程栈当前使用量
|
||||||
|
size_t curUsed = CoTask_StackCurUsed(CoTask);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 负载计算
|
||||||
|
|
||||||
|
启用 `COROUTINE_ENABLE_LOADING_CALCULATE` 后,可以计算调度器的负载:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// 获取当前负载
|
||||||
|
uint16_t curLoad = CoScheduler_CurLoad(CoSchedulerId);
|
||||||
|
|
||||||
|
// 获取最大历史负载
|
||||||
|
uint16_t maxLoad = CoScheduler_MaxLoad(CoSchedulerId);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 性能监控
|
||||||
|
|
||||||
|
```c
|
||||||
|
// 监控协程调度性能
|
||||||
|
void monitor_scheduler_performance(void) {
|
||||||
|
uint16_t curLoad = CoScheduler_CurLoad(0);
|
||||||
|
uint16_t maxLoad = CoScheduler_MaxLoad(0);
|
||||||
|
|
||||||
|
if (curLoad > 8000) { // 80%负载警告
|
||||||
|
printf("Warning: Scheduler load is high: %d.%02d%%\n",
|
||||||
|
curLoad/100, curLoad%100);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
### 错误码定义
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define COROUTINE_E_OK (0) // 成功
|
||||||
|
#define COROUTINE_E_INVALID_PARAMETER (-1) // 无效参数
|
||||||
|
#define COROUTINE_E_INVALID_TICK (-2) // 无效时钟函数
|
||||||
|
#define COROUTINE_E_INVALID_TICK_INTERVAL (-3) // 无效时钟间隔
|
||||||
|
#define COROUTINE_E_INVALID_LOCK (-4) // 无效锁函数
|
||||||
|
#define COROUTINE_E_INVALID_MHOOK (-5) // 无效内存钩子函数
|
||||||
|
```
|
||||||
|
|
||||||
|
## 性能优化
|
||||||
|
|
||||||
|
### 1. 上下文切换优化
|
||||||
|
- 使用setjmp/longjmp替代完整的上下文保存
|
||||||
|
- 最小化寄存器保存和恢复操作
|
||||||
|
|
||||||
|
### 2. 内存管理优化
|
||||||
|
- 静态预分配减少动态内存分配
|
||||||
|
- 栈空间复用机制
|
||||||
|
|
||||||
|
## 平台支持
|
||||||
|
|
||||||
|
该库通过内联汇编实现了跨平台的栈指针操作:
|
||||||
|
|
||||||
|
- **x86/x64**:使用esp/rsp寄存器
|
||||||
|
- **ARM**:使用sp寄存器
|
||||||
|
- **MIPS**:使用sp寄存器
|
||||||
|
- **RISC-V**:使用sp寄存器
|
||||||
|
- **PowerPC**:使用r1寄存器
|
||||||
|
|
||||||
|
### 平台特定实现
|
||||||
|
```c
|
||||||
|
// x86架构实现
|
||||||
|
#if defined(__i386__)
|
||||||
|
#define COROUTINE_GET_STACK_POINTER(p) \
|
||||||
|
__asm__ __volatile__("movl %%esp, %0" : "=r"(p))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 应用场景
|
||||||
|
|
||||||
|
### 1. 嵌入式系统
|
||||||
|
- 实时任务调度
|
||||||
|
- 低功耗设备管理
|
||||||
|
- 传感器数据处理
|
||||||
|
|
||||||
|
### 2. 网络编程
|
||||||
|
- 异步I/O处理
|
||||||
|
- 连接池管理
|
||||||
|
- 协议栈实现
|
||||||
|
|
||||||
|
### 3. 游戏开发
|
||||||
|
- 游戏对象更新
|
||||||
|
- AI行为调度
|
||||||
|
- 动画系统管理
|
||||||
|
|
||||||
|
### 4. 物联网应用
|
||||||
|
- 设备通信协议
|
||||||
|
- 数据处理流水线
|
||||||
|
- 远程控制接口
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
**coroutine** 协程库是一个功能强大、性能优异的C语言协程解决方案。它提供了:
|
||||||
|
|
||||||
|
1. **完整的协程生命周期管理**
|
||||||
|
2. **高效的多任务调度机制**
|
||||||
|
3. **灵活的定时器和事件管理**
|
||||||
|
4. **完善的错误处理和监控功能**
|
||||||
3
makefile
3
makefile
@ -21,6 +21,7 @@ ALGORITHM_PATH = $(WORKSPACE)/04_algorithm
|
|||||||
PARSER_PATH = $(WORKSPACE)/05_parser
|
PARSER_PATH = $(WORKSPACE)/05_parser
|
||||||
PERFORMANCE_PATH = $(WORKSPACE)/06_performance
|
PERFORMANCE_PATH = $(WORKSPACE)/06_performance
|
||||||
MATH_PATH = $(WORKSPACE)/07_math
|
MATH_PATH = $(WORKSPACE)/07_math
|
||||||
|
COROUTINE_PATH = $(WORKSPACE)/08_coroutine
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
### sources, libaries and head path
|
### sources, libaries and head path
|
||||||
@ -33,6 +34,7 @@ INCLUDE += $(ALGORITHM_PATH)
|
|||||||
INCLUDE += $(PARSER_PATH)
|
INCLUDE += $(PARSER_PATH)
|
||||||
INCLUDE += $(PERFORMANCE_PATH)
|
INCLUDE += $(PERFORMANCE_PATH)
|
||||||
INCLUDE += $(MATH_PATH)
|
INCLUDE += $(MATH_PATH)
|
||||||
|
INCLUDE += $(COROUTINE_PATH)
|
||||||
|
|
||||||
LIBSRCS += $(APPLICATION_PATH)/init.c
|
LIBSRCS += $(APPLICATION_PATH)/init.c
|
||||||
LIBSRCS += $(wildcard $(APPLICATION_PATH)/console/*.c)
|
LIBSRCS += $(wildcard $(APPLICATION_PATH)/console/*.c)
|
||||||
@ -43,6 +45,7 @@ LIBSRCS += $(wildcard $(ALGORITHM_PATH)/*.c)
|
|||||||
LIBSRCS += $(wildcard $(PARSER_PATH)/*.c)
|
LIBSRCS += $(wildcard $(PARSER_PATH)/*.c)
|
||||||
LIBSRCS += $(wildcard $(PERFORMANCE_PATH)/*.c)
|
LIBSRCS += $(wildcard $(PERFORMANCE_PATH)/*.c)
|
||||||
LIBSRCS += $(wildcard $(MATH_PATH)/*.c)
|
LIBSRCS += $(wildcard $(MATH_PATH)/*.c)
|
||||||
|
LIBSRCS += $(wildcard $(COROUTINE_PATH)/*.c)
|
||||||
|
|
||||||
LIBLIST += m
|
LIBLIST += m
|
||||||
LIBLIST += pthread
|
LIBLIST += pthread
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
|
version 0.3.5
|
||||||
|
date 2025.11.20
|
||||||
|
changes
|
||||||
|
1. Add the initial version coroutine
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------------------
|
||||||
|
---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
version 0.3.4
|
version 0.3.4
|
||||||
date 2025.05.10
|
date 2025.05.10
|
||||||
changes
|
changes
|
||||||
|
|||||||
4
run.sh
4
run.sh
@ -10,9 +10,9 @@ fi
|
|||||||
echo "compilling..."
|
echo "compilling..."
|
||||||
|
|
||||||
if [ "$1" == "debug" ]; then
|
if [ "$1" == "debug" ]; then
|
||||||
make CFLAG=-g
|
make -j CFLAG=-g
|
||||||
else
|
else
|
||||||
make
|
make -j
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f $exe_file ]; then
|
if [ -f $exe_file ]; then
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
* \unit list
|
* \unit list
|
||||||
* \brief This is a C language singly linked list with built-in iterators, simple, reliable, fast, small space
|
* \brief This is a C language singly linked list with built-in iterators, simple, reliable, fast, small space
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v1.0.0
|
* \version v1.0.1
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2023 Lamdonn.
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
* \unit list
|
* \unit list
|
||||||
* \brief This is a C language singly linked list with built-in iterators, simple, reliable, fast, small space
|
* \brief This is a C language singly linked list with built-in iterators, simple, reliable, fast, small space
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v1.0.0
|
* \version v1.0.1
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2023 Lamdonn.
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#define LIST_V_MAJOR 1
|
#define LIST_V_MAJOR 1
|
||||||
#define LIST_V_MINOR 0
|
#define LIST_V_MINOR 0
|
||||||
#define LIST_V_PATCH 0
|
#define LIST_V_PATCH 1
|
||||||
|
|
||||||
/* list type definition, hiding structural members, not for external use */
|
/* list type definition, hiding structural members, not for external use */
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ int list_dsize(list_t list);
|
|||||||
* \param[out] data: the address of data
|
* \param[out] data: the address of data
|
||||||
* \return 1 success or 0 fail
|
* \return 1 success or 0 fail
|
||||||
*/
|
*/
|
||||||
#define list_pop_back(list) list_erase((list), list_size(list), 1)
|
#define list_pop_back(list) list_erase((list), list_size(list) - 1, 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief clear list.
|
* \brief clear list.
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
* \unit map
|
* \unit map
|
||||||
* \brief This is a general-purpose C language map module, with common data structure
|
* \brief This is a general-purpose C language map module, with common data structure
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v1.0.0
|
* \version v1.0.1
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2023 Lamdonn.
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
@ -694,8 +694,13 @@ static NODE* node_next(map_t map, NODE* node)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (node == node->parent->left) node = node->parent;
|
NODE *parent = node->parent;
|
||||||
else node = node->parent->parent;
|
while (parent != map->nil && node == parent->right)
|
||||||
|
{
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -709,8 +714,13 @@ static NODE* node_prev(map_t map, NODE* node)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (node == node->parent->right) node = node->parent;
|
NODE *parent = node->parent;
|
||||||
else node = node->parent->parent;
|
while (parent != map->nil && node == parent->left)
|
||||||
|
{
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
* \unit map
|
* \unit map
|
||||||
* \brief This is a general-purpose C language map module, with common data structure
|
* \brief This is a general-purpose C language map module, with common data structure
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v1.0.0
|
* \version v1.0.1
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2023 Lamdonn.
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#define MAP_V_MAJOR 1
|
#define MAP_V_MAJOR 1
|
||||||
#define MAP_V_MINOR 0
|
#define MAP_V_MINOR 0
|
||||||
#define MAP_V_PATCH 0
|
#define MAP_V_PATCH 1
|
||||||
|
|
||||||
/* map type definition, hiding structural members, not for external use */
|
/* map type definition, hiding structural members, not for external use */
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
* \unit set
|
* \unit set
|
||||||
* \brief This is a general-purpose C language set module, with common data structure
|
* \brief This is a general-purpose C language set module, with common data structure
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v1.0.0
|
* \version v1.0.1
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2023 Lamdonn.
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
@ -592,8 +592,13 @@ static NODE* node_next(set_t set, NODE* node)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (node == node->parent->left) node = node->parent;
|
NODE *parent = node->parent;
|
||||||
else node = node->parent->parent;
|
while (parent != set->nil && node == parent->right)
|
||||||
|
{
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -607,8 +612,13 @@ static NODE* node_prev(set_t set, NODE* node)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (node == node->parent->right) node = node->parent;
|
NODE *parent = node->parent;
|
||||||
else node = node->parent->parent;
|
while (parent != set->nil && node == parent->left)
|
||||||
|
{
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
* \unit set
|
* \unit set
|
||||||
* \brief This is a general-purpose C language set module, with common data structure
|
* \brief This is a general-purpose C language set module, with common data structure
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v1.0.0
|
* \version v1.0.1
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2023 Lamdonn.
|
* \copyright Copyright (C) 2023 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#define SET_V_MAJOR 1
|
#define SET_V_MAJOR 1
|
||||||
#define SET_V_MINOR 0
|
#define SET_V_MINOR 0
|
||||||
#define SET_V_PATCH 0
|
#define SET_V_PATCH 1
|
||||||
|
|
||||||
/* set type definition, hiding structural members, not for external use */
|
/* set type definition, hiding structural members, not for external use */
|
||||||
|
|
||||||
|
|||||||
1607
source/08_coroutine/coroutine.c
Normal file
1607
source/08_coroutine/coroutine.c
Normal file
File diff suppressed because it is too large
Load Diff
532
source/08_coroutine/coroutine.h
Normal file
532
source/08_coroutine/coroutine.h
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
/*********************************************************************************************************
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* file description
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* \file coroutine.h
|
||||||
|
* \unit coroutine
|
||||||
|
* \brief This is a C language coroutine library
|
||||||
|
* \author Lamdonn
|
||||||
|
* \version v0.2.0
|
||||||
|
* \license GPL-2.0
|
||||||
|
* \copyright Copyright (C) 2025 Lamdonn.
|
||||||
|
********************************************************************************************************/
|
||||||
|
#ifndef __coroutine_H
|
||||||
|
#define __coroutine_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Version infomation */
|
||||||
|
#define COROUTINE_V_MAJOR 0
|
||||||
|
#define COROUTINE_V_MINOR 2
|
||||||
|
#define COROUTINE_V_PATCH 0
|
||||||
|
|
||||||
|
#include "coroutine_cfg.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task
|
||||||
|
*/
|
||||||
|
typedef struct CoTask* CoTask_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer
|
||||||
|
*/
|
||||||
|
typedef struct CoTimer* CoTimer_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task entry function
|
||||||
|
* \param arg: Task argument address
|
||||||
|
* \return: Task return value address
|
||||||
|
*/
|
||||||
|
typedef void *(*CoTaskEntry_t)(void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer entry function
|
||||||
|
*/
|
||||||
|
typedef void (*CoTimerEntry_t)(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine lock function
|
||||||
|
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, lock
|
||||||
|
*/
|
||||||
|
typedef void (*CoLock_t)(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine unlock function
|
||||||
|
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, unlock
|
||||||
|
*/
|
||||||
|
typedef void (*CoUnlock_t)(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine malloc function
|
||||||
|
* \param size: Allocate memory size
|
||||||
|
* \return: Allocate memory address
|
||||||
|
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, malloc
|
||||||
|
*/
|
||||||
|
typedef void *(*CoMalloc_t)(size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine free function
|
||||||
|
* \param block: Free memory address
|
||||||
|
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, free
|
||||||
|
*/
|
||||||
|
typedef void (*CoFree_t)(void *block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine tick function
|
||||||
|
* \return: Current tick value
|
||||||
|
* \note: The time base on which the coroutine schedule depends, such as system tick.
|
||||||
|
*/
|
||||||
|
typedef uint64_t (*CoTick_t)(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine event
|
||||||
|
* \note: Used for synchronization between coroutines
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t flag; /**< Event flag, 32 bit storage, each bit can individually represent an event */
|
||||||
|
} CoEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler initialize parameter
|
||||||
|
* \note: Coroutine scheduler initialize parameter is used to initialize the coroutine scheduler.
|
||||||
|
*/
|
||||||
|
typedef struct CoSchedulerInitPara
|
||||||
|
{
|
||||||
|
CoLock_t lock; /**< Coroutine scheduler lock function */
|
||||||
|
CoUnlock_t unlock; /**< Coroutine scheduler unlock function */
|
||||||
|
CoMalloc_t malloc; /**< Coroutine scheduler malloc function */
|
||||||
|
CoFree_t free; /**< Coroutine scheduler free function */
|
||||||
|
} CoSchedulerInitPara;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task create parameter
|
||||||
|
* \note: Coroutine task create parameter is used to create a coroutine task.
|
||||||
|
*/
|
||||||
|
typedef struct CoTaskCreatePara
|
||||||
|
{
|
||||||
|
void *pStack; /**< Coroutine task stack address */
|
||||||
|
size_t stackSize; /**< Coroutine task stack size */
|
||||||
|
void *arg; /**< Coroutine task argument */
|
||||||
|
int schedulerId; /**< Coroutine task scheduler id */
|
||||||
|
} CoTaskCreatePara;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer create parameter
|
||||||
|
* \note: Coroutine timer create parameter is used to create a coroutine timer.
|
||||||
|
*/
|
||||||
|
typedef struct CoTimerCreatePara
|
||||||
|
{
|
||||||
|
uint64_t ms; /**< Coroutine timer ms, indicates the ms interval */
|
||||||
|
uint64_t tick; /**< Coroutine timer tick, indicates the tick interval */
|
||||||
|
int schedulerId; /**< Coroutine timer scheduler id */
|
||||||
|
} CoTimerCreatePara;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task wait parameter
|
||||||
|
* \note: Coroutine task wait parameter is used to blocking task waiting for event or timeout.
|
||||||
|
*/
|
||||||
|
typedef struct CoTaskWaitPara
|
||||||
|
{
|
||||||
|
CoEvent *pEvent; /**< Coroutine task wait event pointer */
|
||||||
|
uint64_t ms; /**< Coroutine task wait timeout in ms */
|
||||||
|
uint64_t tick; /**< Coroutine task wait timeout in tick */
|
||||||
|
} CoTaskWaitPara;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task create parameter default value
|
||||||
|
* \note: Coroutine task create parameter default value is used to create a coroutine task.
|
||||||
|
*/
|
||||||
|
#define COROUTINE_E_OK (0) /**< Coroutine task create parameter default value, indicates success */
|
||||||
|
#define COROUTINE_E_INVALID_PARAMETER (-1) /**< Coroutine task create parameter default value, indicates invalid parameter */
|
||||||
|
#define COROUTINE_E_INVALID_TICK (-2) /**< Coroutine task create parameter default value, indicates invalid tick function */
|
||||||
|
#define COROUTINE_E_INVALID_TICK_INTERVAL (-3) /**< Coroutine task create parameter default value, indicates invalid tick interval */
|
||||||
|
#define COROUTINE_E_INVALID_LOCK (-4) /**< Coroutine task create parameter default value, indicates invalid lock function */
|
||||||
|
#define COROUTINE_E_INVALID_MHOOK (-5) /**< Coroutine task create parameter default value, indicates invalid memory hook function */
|
||||||
|
#define COROUTINE_E_TCB_MEM_STACK_FAIL (-6) /**< Coroutine task create parameter default value, indicates memory stack fail */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine event default value
|
||||||
|
* \note: Coroutine event default value is used to initialize the coroutine event.
|
||||||
|
*/
|
||||||
|
#define COEVENT_STATIC_VALUE ((CoEvent){.flag=0})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler initialize function
|
||||||
|
* \param pScheduler: [Non-default parameter] Coroutine scheduler pointer
|
||||||
|
* \param tick: [Non-default parameter] Coroutine scheduler tick function, must be specified
|
||||||
|
* \param tickInterval: [Non-default parameter] Coroutine scheduler tick interval, indicates how many ns each tick is, must be specified
|
||||||
|
* \param lock: [Default parameter] Coroutine scheduler lock function,
|
||||||
|
* for use on multiple threads, you must specify as follows .lock=thread_lock
|
||||||
|
* \param unlock: [Default parameter] Coroutine scheduler unlock function,
|
||||||
|
* for use on multiple threads, you must specify as follows .unlock=thread_unlock
|
||||||
|
* \param malloc: [Default parameter] Coroutine scheduler malloc function,
|
||||||
|
* if you need to allocate memory dynamically (CoTask, CoTimer, stack, etc),
|
||||||
|
* you must specify as follows .malloc=mallloc
|
||||||
|
* \param free: [Default parameter] Coroutine scheduler free function,
|
||||||
|
* if you need to free memory dynamically (CoTask, CoTimer, stack, etc),
|
||||||
|
* you must specify as follows .free=free
|
||||||
|
* \return: Coroutine task create parameter default value, indicates success
|
||||||
|
* \note: Coroutine scheduler initialize function is used to initialize the coroutine scheduler.
|
||||||
|
* It must be called once before any other coroutine scheduler function.
|
||||||
|
* Only one initialization is allowed within a single thread
|
||||||
|
* It will initialize the coroutine scheduler with the given parameter.
|
||||||
|
* The coroutine scheduler will use the given tick function to measure the load of each task.
|
||||||
|
* The tick function must be called periodically with the given tick interval.
|
||||||
|
* The coroutine scheduler will use the given lock function to protect the shared resources.
|
||||||
|
* The coroutine scheduler will use the given malloc function to allocate memory for the tasks.
|
||||||
|
* The coroutine scheduler will use the given free function to free memory of the tasks.
|
||||||
|
* \warning: The coroutine scheduler will not check the validity of the given parameter.
|
||||||
|
* You must ensure that the given parameter is valid.
|
||||||
|
* \example:
|
||||||
|
* CoScheduler_Init(0, GetTimerMs, 1000000);
|
||||||
|
* \example:
|
||||||
|
* CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
* \example:
|
||||||
|
* CoScheduler_Init(0, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock);
|
||||||
|
* \example:
|
||||||
|
* CoScheduler_Init(0, GetTimerUsec, 1000, .malloc=mallloc, .free=free);
|
||||||
|
*/
|
||||||
|
#define CoScheduler_Init(CoSchedulerId, tick, tickInterval, ...) CoScheduler_InitP(CoSchedulerId, tick, tickInterval, (CoSchedulerInitPara[1]){[0]={.lock=NULL,.unlock=NULL,.malloc=NULL,.free=NULL,__VA_ARGS__}})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler initialize function
|
||||||
|
* \param pScheduler: Coroutine scheduler pointer
|
||||||
|
* \param tick: Coroutine scheduler tick function
|
||||||
|
* \param tickInterval: Coroutine scheduler tick interval, indicates how many ns each tick is
|
||||||
|
* \param pPara: Coroutine scheduler initialize parameter pointer
|
||||||
|
* \return: Coroutine task create parameter default value, indicates success
|
||||||
|
* \note: Coroutine scheduler initialize function is used to initialize the coroutine scheduler.
|
||||||
|
* It must be called once before any other coroutine scheduler function.
|
||||||
|
* Only one initialization is allowed within a single thread
|
||||||
|
* It will initialize the coroutine scheduler with the given parameter.
|
||||||
|
* The coroutine scheduler will use the given tick function to measure the load of each task.
|
||||||
|
* The tick function must be called periodically with the given tick interval.
|
||||||
|
* The coroutine scheduler will use the given lock function to protect the shared resources.
|
||||||
|
* The coroutine scheduler will use the given malloc function to allocate memory for the tasks.
|
||||||
|
* The coroutine scheduler will use the given free function to free memory of the tasks.
|
||||||
|
*/
|
||||||
|
int CoScheduler_InitP(uint32_t CoSchedulerId, CoTick_t tick, uint32_t tickInterval, CoSchedulerInitPara *pPara);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler start function
|
||||||
|
* \param pScheduler: Coroutine scheduler pointer
|
||||||
|
* \return: Coroutine task create parameter default value, indicates success
|
||||||
|
* \note: Coroutine scheduler start function is used to start the coroutine scheduler.
|
||||||
|
* It must be called once after the coroutine scheduler is initialized.
|
||||||
|
* It will start the coroutine scheduler and run the tasks.
|
||||||
|
* \example:
|
||||||
|
* CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
* testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest), 0);
|
||||||
|
* CoScheduler_Start(0);
|
||||||
|
*/
|
||||||
|
int CoScheduler_Start(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler exit function
|
||||||
|
* \param pScheduler: Coroutine scheduler pointer
|
||||||
|
* \return: Coroutine task create parameter default value, indicates success
|
||||||
|
* \note: Coroutine scheduler exit function is used to exit the coroutine scheduler.
|
||||||
|
* It must be called once after the coroutine scheduler is started.
|
||||||
|
* It will exit the coroutine scheduler and stop the tasks.
|
||||||
|
*/
|
||||||
|
int CoScheduler_Exit(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler task count function
|
||||||
|
* \param pScheduler: Coroutine scheduler pointer
|
||||||
|
* \return: Coroutine scheduler task count, indicates the number of tasks in the coroutine scheduler
|
||||||
|
* \note: Coroutine scheduler task count function is used to get the number of tasks in the coroutine scheduler.
|
||||||
|
*/
|
||||||
|
int CoScheduler_TaskCount(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler timer count function
|
||||||
|
* \param pScheduler: Coroutine scheduler pointer
|
||||||
|
* \return: Coroutine scheduler timer count, indicates the number of timers in the coroutine scheduler
|
||||||
|
* \note: Coroutine scheduler timer count function is used to get the number of timers in the coroutine scheduler.
|
||||||
|
*/
|
||||||
|
int CoScheduler_TimerCount(uint32_t CoSchedulerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler current load function
|
||||||
|
* \param pScheduler: Coroutine scheduler pointer
|
||||||
|
* \return: Coroutine scheduler current load, indicates the load of the coroutine scheduler
|
||||||
|
* \note: Coroutine scheduler current load function is used to get the current load of the coroutine scheduler.
|
||||||
|
* The load is the number of ticks that the coroutine scheduler has run.
|
||||||
|
* The load is updated periodically with the given tick interval.
|
||||||
|
*/
|
||||||
|
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
|
||||||
|
uint16_t CoScheduler_CurLoad(uint32_t CoSchedulerId);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine scheduler maximum load function
|
||||||
|
* \param pScheduler: Coroutine scheduler pointer
|
||||||
|
* \return: Coroutine scheduler maximum load, indicates the maximum load of the coroutine scheduler
|
||||||
|
* \note: Coroutine scheduler maximum load function is used to get the maximum load of the coroutine scheduler.
|
||||||
|
* The load is the number of ticks that the coroutine scheduler has run.
|
||||||
|
* The load is updated periodically with the given tick interval.
|
||||||
|
*/
|
||||||
|
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
|
||||||
|
uint16_t CoScheduler_MaxLoad(uint32_t CoSchedulerId);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task create function
|
||||||
|
* \param entry: [Non-default parameter] Coroutine task entry function, indicates the entry function of the coroutine task, must be specified
|
||||||
|
* \param stack: [Default parameter] Coroutine task stack, indicates the stack of the coroutine task.
|
||||||
|
* If not specified, it is allocated via the scheduler's malloc function.
|
||||||
|
* \param stackSize: [Default parameter] Coroutine task stack size, indicates the size of the coroutine task stack
|
||||||
|
* If not specified, it is the default stack size `COROUTINE_STACK_DEFAULT_SIZE`.
|
||||||
|
* \param arg: [Default parameter] Coroutine task argument, indicates the argument of the coroutine task
|
||||||
|
* \param schedulerId: [Default parameter] Coroutine timer scheduler id, indicates the scheduler id of the coroutine timer
|
||||||
|
* Negative value means the auto distribution.
|
||||||
|
* \return: Coroutine task handle, indicates the created coroutine task
|
||||||
|
* \note: Coroutine task create function is used to create a coroutine task.
|
||||||
|
* It will create a coroutine task with the given parameter.
|
||||||
|
* The coroutine task will run in the coroutine scheduler.
|
||||||
|
* \example:
|
||||||
|
* CoTask_t testCoroutine = CoTask_Create(test);
|
||||||
|
* \example:
|
||||||
|
* CoTask_t testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest));
|
||||||
|
* \example:
|
||||||
|
* CoTask_t testCoroutine = CoTask_Create(test, .stackSize=4096);
|
||||||
|
* \example:
|
||||||
|
* int arg = 4096;
|
||||||
|
* CoTask_t testCoroutine = CoTask_Create(test, .arg=&arg);
|
||||||
|
*/
|
||||||
|
#define CoTask_Create(entry, ...) CoTask_CreateP(entry, (CoTaskCreatePara[1]){[0]={.pStack=NULL,.stackSize=0,.arg=NULL,.schedulerId=-1,__VA_ARGS__}})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task create function, it is recommended to use @ref `CoTask_Create` instead
|
||||||
|
* \param pPara: Coroutine task create parameter pointer
|
||||||
|
* \return: Coroutine task handle, indicates the created coroutine task
|
||||||
|
* \note: Coroutine task create function is used to create a coroutine task.
|
||||||
|
* It will create a coroutine task with the given parameter.
|
||||||
|
* The coroutine task will run in the coroutine scheduler.
|
||||||
|
*/
|
||||||
|
CoTask_t CoTask_CreateP(CoTaskEntry_t entry, CoTaskCreatePara *pPara);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task delete function
|
||||||
|
* \param CoTask: Coroutine task handle, indicates the coroutine task to be deleted
|
||||||
|
* \return: Coroutine task delete parameter default value, indicates success
|
||||||
|
* \note: Coroutine task delete function is used to delete a coroutine task.
|
||||||
|
* It will delete the given coroutine task.
|
||||||
|
* The coroutine task must be in the deleted state.
|
||||||
|
*/
|
||||||
|
int CoTask_Delete(CoTask_t CoTask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task self function
|
||||||
|
* \return: Coroutine task handle, indicates the current coroutine task
|
||||||
|
* \note: Coroutine task self function is used to get the current coroutine task.
|
||||||
|
* It will return the handle of the current coroutine task.
|
||||||
|
*/
|
||||||
|
CoTask_t CoTask_Self(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task scheduler id function
|
||||||
|
* \return: Coroutine task scheduler id, indicates the scheduler id of the coroutine task
|
||||||
|
* \note: Coroutine task scheduler id function is used to get the scheduler id of the coroutine task.
|
||||||
|
*/
|
||||||
|
int CoTask_SchedulerId(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task stack max used function
|
||||||
|
* \param CoTask: Coroutine task handle, indicates the coroutine task to get the stack max used
|
||||||
|
* \return: Coroutine task stack max used, indicates the maximum stack used of the coroutine task
|
||||||
|
* \note: Coroutine task stack max used function is used to get the maximum stack used of the coroutine task.
|
||||||
|
* The stack used is the maximum stack used of the coroutine task.
|
||||||
|
* The stack used is updated periodically with the given tick interval.
|
||||||
|
*/
|
||||||
|
#if (COROUTINE_ENABLE_STACK_CALCULATE > 0)
|
||||||
|
size_t CoTask_StackMaxUsed(CoTask_t CoTask);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task stack current used function
|
||||||
|
* \param CoTask: Coroutine task handle, indicates the coroutine task to get the stack current used
|
||||||
|
* \return: Coroutine task stack current used, indicates the current stack used of the coroutine task
|
||||||
|
* \note: Coroutine task stack current used function is used to get the current stack used of the coroutine task.
|
||||||
|
* The stack used is the current stack used of the coroutine task.
|
||||||
|
* The stack used is updated periodically with the given tick interval.
|
||||||
|
*/
|
||||||
|
#if (COROUTINE_ENABLE_STACK_CALCULATE > 0)
|
||||||
|
size_t CoTask_StackCurUsed(CoTask_t CoTask);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task wait function, blocking task waiting for event or timeout.
|
||||||
|
* \param pEvent: [Default parameter] Coroutine event pointer, indicates the event to wait
|
||||||
|
* \param ms: [Default parameter] Coroutine task wait ms, indicates the ms to wait
|
||||||
|
* \param tick: [Default parameter] Coroutine task wait tick, indicates the tick to wait
|
||||||
|
* \return: Coroutine event value, indicates the event value that triggered the coroutine task
|
||||||
|
* \note: Coroutine task wait event function is used to wait for the given event.
|
||||||
|
* @ref `CoEvent_Init` must first be called to initialize the event.
|
||||||
|
* @ref `CoEvent_Notify` notifies the occurrence of the event
|
||||||
|
* It will block the current coroutine task.
|
||||||
|
* The event value is a bit mask, each bit represents an event.
|
||||||
|
* If multiple events are triggered, the corresponding bits will be set.
|
||||||
|
* \note: Coroutine task wait ms function is used to wait for the given ms.
|
||||||
|
* It will block the current coroutine task.
|
||||||
|
* \note: Coroutine task wait tick function is used to wait for the given tick.
|
||||||
|
* It will block the current coroutine task.
|
||||||
|
* \example:
|
||||||
|
* void *test(void *arg)
|
||||||
|
* {
|
||||||
|
* while (1)
|
||||||
|
* {
|
||||||
|
* // Give up access to the scheduler without waiting, similar to yeild
|
||||||
|
* CoTask_Wait();
|
||||||
|
*
|
||||||
|
* // Wait for 1000 ms
|
||||||
|
* CoTask_Wait(.ms=1000);
|
||||||
|
*
|
||||||
|
* // Wait for 1000000 tick
|
||||||
|
* CoTask_Wait(.tick=1000000);
|
||||||
|
*
|
||||||
|
* // Wait for 1000 ms or event, if no any events occur within 1000 ms, and will timeout blocking
|
||||||
|
* CoTask_Wait(.pEvent=&g_Event, .ms=1000);
|
||||||
|
*
|
||||||
|
* // Always wait for the event, and judge every events
|
||||||
|
* uint32_t evs = CoTask_Wait(.pEvent=&g_Event);
|
||||||
|
* if (evs & 0x01)
|
||||||
|
* {
|
||||||
|
* printf("event 0x01 triggered\n");
|
||||||
|
* }
|
||||||
|
* if (evs & 0x02)
|
||||||
|
* {
|
||||||
|
* printf("event 0x02 triggered\n");
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
#define CoTask_Wait(...) CoTask_WaitP((CoTaskWaitPara[1]){[0]={.pEvent=NULL,.ms=0,.tick=0,__VA_ARGS__}})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task wait function, it is recommended to use @ref `CoTask_Wait` instead
|
||||||
|
* \param pPara: Coroutine task wait parameter pointer
|
||||||
|
* \return: Coroutine event value, indicates the event value that triggered the coroutine task
|
||||||
|
* \note: Coroutine task wait function is used to wait for the given event or timeout.
|
||||||
|
* It will block the current coroutine task.
|
||||||
|
* The event value is a bit mask, each bit represents an event.
|
||||||
|
* If multiple events are triggered, the corresponding bits will be set.
|
||||||
|
*/
|
||||||
|
uint32_t CoTask_WaitP(CoTaskWaitPara *pPara);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine task wait functions, the version of the macro definition used is often used
|
||||||
|
* \param m: Coroutine task wait ms, indicates the ms to wait
|
||||||
|
* \param t: Coroutine task wait tick, indicates the tick to wait
|
||||||
|
* \param e: Coroutine event pointer, indicates the event to wait
|
||||||
|
* \return: Coroutine event value, indicates the event value that triggered the coroutine task
|
||||||
|
*/
|
||||||
|
#define CoTask_WaitMs(m) CoTask_Wait(.ms=m)
|
||||||
|
#define CoTask_WaitTick(t) CoTask_Wait(.tick=t)
|
||||||
|
#define CoTask_WaitEvent(e) CoTask_Wait(.pEvent=e)
|
||||||
|
#define CoTask_WaitEventMs(e, m) CoTask_Wait(.pEvent=e, .ms=m)
|
||||||
|
#define CoTask_WaitEventTick(e, t) CoTask_Wait(.pEvent=e, .tick=t)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer create function
|
||||||
|
* \param entry: [Non-default parameter] Coroutine timer entry, indicates the timer entry function
|
||||||
|
* \param ms: [Default parameter] Coroutine timer ms, indicates the ms interval
|
||||||
|
* \param tick: [Default parameter] Coroutine timer tick, indicates the tick interval
|
||||||
|
* \param schedulerId: [Default parameter] Coroutine timer scheduler id, indicates the scheduler id of the coroutine timer
|
||||||
|
* Negative value means the auto distribution.
|
||||||
|
* \return: Coroutine timer handle, indicates the created timer
|
||||||
|
* \note: One of the ms and tick parameters must be set
|
||||||
|
* \note: Coroutine timer create function is used to create a timer with the given ms or tick interval.
|
||||||
|
* The timer will call the given entry function periodically with the given ms or tick interval.
|
||||||
|
* \example:
|
||||||
|
* CoTimer_t timer = CoTimer_Create(timer_entry, .ms=100); // create a timer with 100ms interval
|
||||||
|
*/
|
||||||
|
#define CoTimer_Create(entry, ...) CoTimer_CreateP(entry, (CoTimerCreatePara[1]){[0]={.ms=0,.tick=0,.schedulerId=-1,__VA_ARGS__}})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer create function, it is recommended to use @ref `CoTimer_Create` instead
|
||||||
|
* \param pPara: Coroutine timer create parameter pointer
|
||||||
|
* \return: Coroutine timer handle, indicates the created timer
|
||||||
|
* \note: Coroutine timer create function is used to create a timer with the given ms or tick interval.
|
||||||
|
* The timer will call the given entry function periodically with the given ms or tick interval.
|
||||||
|
*/
|
||||||
|
CoTimer_t CoTimer_CreateP(CoTimerEntry_t entry, CoTimerCreatePara *pPara);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer create ms function, it is recommended to use @ref `CoTimer_CreateMs` instead
|
||||||
|
* \param entry: Coroutine timer entry, indicates the timer entry function
|
||||||
|
* \param m: Coroutine timer ms, indicates the ms interval
|
||||||
|
* \param t: Coroutine timer tick, indicates the tick interval
|
||||||
|
* \return: Coroutine timer handle, indicates the created timer
|
||||||
|
* \note: Coroutine timer create ms function is used to create a timer with the given ms interval.
|
||||||
|
* The timer will call the given entry function periodically with the given ms interval.
|
||||||
|
* \example:
|
||||||
|
* CoTimer_t timer = CoTimer_CreateMs(timer_entry, 100); // create a timer with 100ms interval
|
||||||
|
*/
|
||||||
|
#define CoTimer_CreateMs(entry, m) CoTimer_Create(entry, .ms=m)
|
||||||
|
#define CoTimer_CreateTick(entry, t) CoTimer_Create(entry, .tick=t)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer delete function
|
||||||
|
* \param Timer: Coroutine timer handle, indicates the timer to delete
|
||||||
|
* \note: Coroutine timer delete function is used to delete the given timer.
|
||||||
|
* It must be called after @ref `CoTimer_CreateTick` or @ref `CoTimer_CreateMs`.
|
||||||
|
* \example:
|
||||||
|
* CoTimer_Delete(timer); // delete the timer
|
||||||
|
*/
|
||||||
|
void CoTimer_Delete(CoTimer_t Timer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer self function
|
||||||
|
* \return: Coroutine timer handle, indicates the current timer
|
||||||
|
* \note: Coroutine timer self function is used to get the handle of the current timer.
|
||||||
|
* \example:
|
||||||
|
* CoTimer_t timer = CoTimer_Self(); // get the current timer
|
||||||
|
*/
|
||||||
|
CoTimer_t CoTimer_Self(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine timer scheduler id function
|
||||||
|
* \return: Coroutine timer scheduler id, indicates the scheduler id of the coroutine timer
|
||||||
|
* \note: Coroutine timer scheduler id function is used to get the scheduler id of the coroutine timer.
|
||||||
|
*/
|
||||||
|
int CoTimer_SchedulerId(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine event initialize function
|
||||||
|
* \param pEvent: Coroutine event pointer, indicates the event to initialize
|
||||||
|
* \note: Coroutine event initialize function is used to initialize the given event.
|
||||||
|
* It must be called before @ref `CoTask_WaitEvent`.
|
||||||
|
* \example:
|
||||||
|
* CoEvent_Init(&g_Event);
|
||||||
|
*/
|
||||||
|
void CoEvent_Init(CoEvent *pEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief: Coroutine event notify function
|
||||||
|
* \param pEvent: Coroutine event pointer, indicates the event to notify
|
||||||
|
* \param evs: Coroutine event value, indicates the event value to notify
|
||||||
|
* \note: Coroutine event notify function is used to notify the occurrence of the event.
|
||||||
|
* It will set the corresponding bits in the event value.
|
||||||
|
* \example:
|
||||||
|
* CoEvent_Notify(&g_Event, 0x01); // notify event 0x01
|
||||||
|
* \example:
|
||||||
|
* CoEvent_Notify(&g_Event, 0x01 | 0x02); // notify event 0x01 and 0x02
|
||||||
|
*/
|
||||||
|
void CoEvent_Notify(CoEvent *pEvent, uint32_t evs);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // !__coroutine_H
|
||||||
172
source/08_coroutine/coroutine_cfg.h
Normal file
172
source/08_coroutine/coroutine_cfg.h
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/*********************************************************************************************************
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* file description
|
||||||
|
* ------------------------------------------------------------------------------------------------------
|
||||||
|
* \file coroutine_cfg.h
|
||||||
|
* \unit coroutine
|
||||||
|
* \brief This is a C language coroutine library
|
||||||
|
* \author Lamdonn
|
||||||
|
* \version v0.2.0
|
||||||
|
* \license GPL-2.0
|
||||||
|
* \copyright Copyright (C) 2025 Lamdonn.
|
||||||
|
********************************************************************************************************/
|
||||||
|
#ifndef __coroutine_cfg_H
|
||||||
|
#define __coroutine_cfg_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine scheduler number
|
||||||
|
* \note This macro defines the number of coroutine schedulers
|
||||||
|
*/
|
||||||
|
#define COROUTINE_SCHEDULER_NUMBER 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine static task max number
|
||||||
|
* \note This macro defines the maximum number of coroutine tasks that can be created statically
|
||||||
|
*/
|
||||||
|
#define COROUTINE_STATIC_TASK_MAX_NUMBER 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine static timer max number
|
||||||
|
* \note This macro defines the maximum number of coroutine timers that can be created statically
|
||||||
|
*/
|
||||||
|
#define COROUTINE_STATIC_TIMER_MAX_NUMBER 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine static stack max number
|
||||||
|
* \note This macro defines the maximum number of coroutine stacks that can be created statically
|
||||||
|
*/
|
||||||
|
#define COROUTINE_STATIC_STACK_MAX_NUMBER 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine stack default size
|
||||||
|
* \note This macro defines the default size of the coroutine stack
|
||||||
|
* \note If the coroutine stack size is not specified, this value will be used
|
||||||
|
*/
|
||||||
|
#define COROUTINE_STACK_DEFAULT_SIZE 10240 // 4096 //
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine enable stack calculate
|
||||||
|
* \note This macro defines whether to enable the stack calculate feature
|
||||||
|
* \note If enabled, the coroutine stack using will be calculated automatically
|
||||||
|
*/
|
||||||
|
#define COROUTINE_ENABLE_STACK_CALCULATE 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine enable loading calculate
|
||||||
|
* \note This macro defines whether to enable the loading calculate feature
|
||||||
|
* \note If enabled, the coroutine loading will be calculated automatically
|
||||||
|
*/
|
||||||
|
#define COROUTINE_ENABLE_LOADING_CALCULATE 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine loading queue size
|
||||||
|
* \note This macro defines the size of the coroutine loading queue
|
||||||
|
*/
|
||||||
|
#define COROUTINE_LOADING_CALCULATE_QSIZE 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Coroutine loading calculate period
|
||||||
|
* \note This macro defines the period of the coroutine loading calculate
|
||||||
|
* \note The unit is ms
|
||||||
|
*/
|
||||||
|
#define COROUTINE_LOADING_CALCULATE_PERIOD 100
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Stack get and set Pointers depending on the platform definition
|
||||||
|
* \param p Pointer to the stack
|
||||||
|
* \return None
|
||||||
|
* \note This macro is used to get and set the stack pointer depending on the platform definition
|
||||||
|
* \note For x86_32, the stack pointer is esp; for x86_64, the stack pointer is rsp; for arm, the stack pointer is sp
|
||||||
|
* \note Common platforms have been implemented, not implemented platforms need to be implemented by users
|
||||||
|
*/
|
||||||
|
#if defined(__i386__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%esp, %0" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%esp" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%rsp, %0" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%rsp" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__arm__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__mips__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile(".set noreorder\n\t" "move %0, $sp\n\t" ".set reorder" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile(".set noreorder\n\t" "move $sp, %0\n\t" ".set reorder" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__riscv__)
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mv %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mv sp, %0" : : "r" (p) : "memory")
|
||||||
|
#else
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mv %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mv sp, %0" : : "r" (p) : "memory")
|
||||||
|
#endif
|
||||||
|
#elif defined(__powerpc__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__powerpc64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__s390__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__s390x__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__sparc__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__sparcv9__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__tile__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__tilegx__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__hppa__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__hppa64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__ia64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0=sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp=%0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__loongarch__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__m68k__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__mips64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__parisc__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__parisc64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__s390__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__s390x__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__sh__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__sh64__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
|
#elif defined(__xtensa__)
|
||||||
|
#define COROUTINE_GET_SP(p) __asm__ volatile("rsr.a1 %0" : "=r" (p) : : "memory")
|
||||||
|
#define COROUTINE_SET_SP(p) __asm__ volatile("wsr.a1 %0" : : "r" (p) : "memory")
|
||||||
|
#else
|
||||||
|
#error "Unsupported platform, please implement `COROUTINE_GET_SP` and `COROUTINE_SET_SP`"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // !__coroutine_cfg_H
|
||||||
@ -47,3 +47,4 @@ TEST_LIST += slup
|
|||||||
# TEST_LIST += cpul
|
# TEST_LIST += cpul
|
||||||
TEST_LIST += date
|
TEST_LIST += date
|
||||||
TEST_LIST += unitt
|
TEST_LIST += unitt
|
||||||
|
TEST_LIST += coroutine
|
||||||
|
|||||||
320
test/test_coroutine.c
Normal file
320
test/test_coroutine.c
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#if defined(TEST_TARGET_coroutine)
|
||||||
|
#include <varch/command.h>
|
||||||
|
#include <varch/unitt.h>
|
||||||
|
#include <varch/coroutine.h>
|
||||||
|
#else
|
||||||
|
#include "init.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "unitt.h"
|
||||||
|
#include "kern.h"
|
||||||
|
#include "coroutine.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MUTI_THREAD_NUM 2
|
||||||
|
#if (MUTI_THREAD_NUM <= 0)
|
||||||
|
#error "MUTI_THREAD_NUM must be greater than 0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
uint64_t GetTimerUsec(void)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
LARGE_INTEGER frequency;
|
||||||
|
QueryPerformanceFrequency(&frequency);
|
||||||
|
QueryPerformanceCounter(&li);
|
||||||
|
return (uint64_t)li.QuadPart * 1000000 / frequency.QuadPart;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
uint64_t GetTimerUsec(void)
|
||||||
|
{
|
||||||
|
struct timeval mstime;
|
||||||
|
uint64_t us = 0;
|
||||||
|
gettimeofday(&mstime, NULL);
|
||||||
|
us = mstime.tv_sec * 1000000 + mstime.tv_usec;
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************************************************************************************/
|
||||||
|
/************************************* Unit Test ************************************/
|
||||||
|
/************************************************************************************/
|
||||||
|
|
||||||
|
// #define EXIT_TEST
|
||||||
|
extern uint64_t unitt_clock(void);
|
||||||
|
|
||||||
|
static int test_0(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
if (0)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if defined (EXIT_TEST)
|
||||||
|
exit(0);
|
||||||
|
#endif
|
||||||
|
return UNITT_E_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UNITT_E_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unitt_task(void)
|
||||||
|
{
|
||||||
|
static UNITT_TCASE rand_tests[] = {
|
||||||
|
UNITT_TCASE(test_0),
|
||||||
|
// UNITT_TCASE(test_1),
|
||||||
|
// UNITT_TCASE(test_2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static UNITT suites[] = {
|
||||||
|
{ "coroutine suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock },
|
||||||
|
};
|
||||||
|
|
||||||
|
UNITT_EXE(suites);
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************/
|
||||||
|
/************************************* Base Test ************************************/
|
||||||
|
/************************************************************************************/
|
||||||
|
|
||||||
|
static CoEvent gEvent = COEVENT_STATIC_VALUE;
|
||||||
|
static CoTask_t gTickCoroutine = NULL;
|
||||||
|
static CoTask_t gTockCoroutine = NULL;
|
||||||
|
static uint8_t gStackTick[1024 * 10];
|
||||||
|
static uint8_t gStackTock[1024 * 10];
|
||||||
|
static CoTimer_t gTimer0Handle = NULL;
|
||||||
|
static CoTimer_t gTimer1Handle = NULL;
|
||||||
|
|
||||||
|
static void *tick(void *arg)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
CoTask_Wait(.ms=1000);
|
||||||
|
printf("tick-running...\n");
|
||||||
|
CoEvent_Notify(&gEvent, 0x02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *tock(void *arg)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
uint32_t evs = CoTask_Wait(.pEvent=&gEvent);
|
||||||
|
if (evs & 0x01)
|
||||||
|
{
|
||||||
|
printf("event 0x01 triggered...\n");
|
||||||
|
}
|
||||||
|
if (evs & 0x02)
|
||||||
|
{
|
||||||
|
printf("event 0x02 triggered...\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer0(void)
|
||||||
|
{
|
||||||
|
printf("timer0-running...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer1(void)
|
||||||
|
{
|
||||||
|
printf("timer1-running... %d\n", CoScheduler_CurLoad(CoTimer_SchedulerId()));
|
||||||
|
// CoEvent_Notify(&gEvent, 0x01 | 0x02);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Testing begins here */
|
||||||
|
void *createTask(void *arg)
|
||||||
|
{
|
||||||
|
// CoTask_Create(tick, g_StackTick, sizeof(g_StackTick), 0);
|
||||||
|
// CoTask_Create(tock, g_StackTock, sizeof(g_StackTock), 0);
|
||||||
|
CoTask_Create(tick);
|
||||||
|
CoTask_Create(tock);
|
||||||
|
// timerHandle0 = CoTimer_CreateMs(timer0_entry, 100);
|
||||||
|
// timerHandle1 = CoTimer_CreateMs(timer1_entry, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (MUTI_THREAD_NUM == 1)
|
||||||
|
void test_singleThread(void)
|
||||||
|
{
|
||||||
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
|
createTask(NULL);
|
||||||
|
CoScheduler_Start(0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static pthread_t threads[MUTI_THREAD_NUM];
|
||||||
|
static pthread_t testThread;
|
||||||
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static void thread_lock(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void thread_unlock(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *muti_thread_entry(void *arg)
|
||||||
|
{
|
||||||
|
CoScheduler_Start(*(int *)arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_mutiThread(void)
|
||||||
|
{
|
||||||
|
int threadId[MUTI_THREAD_NUM];
|
||||||
|
for (int i = 0; i < MUTI_THREAD_NUM; i++)
|
||||||
|
{
|
||||||
|
CoScheduler_Init(i, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock);
|
||||||
|
}
|
||||||
|
createTask(NULL);
|
||||||
|
for (int i = 0; i < MUTI_THREAD_NUM; i++)
|
||||||
|
{
|
||||||
|
threadId[i] = i;
|
||||||
|
pthread_create(&threads[i], NULL, muti_thread_entry, &threadId[i]);
|
||||||
|
|
||||||
|
/* You can bind thread to specific core */
|
||||||
|
/* So that each CoScheduler can run on different core */
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MUTI_THREAD_NUM; i++)
|
||||||
|
{
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void test_base(void)
|
||||||
|
{
|
||||||
|
#if (MUTI_THREAD_NUM == 1)
|
||||||
|
test_singleThread();
|
||||||
|
#else
|
||||||
|
test_mutiThread();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************/
|
||||||
|
/************************************* Command ************************************/
|
||||||
|
/************************************************************************************/
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"Usage: coroutine [opt] [arg] ...\n"
|
||||||
|
"\n"
|
||||||
|
"options:\n"
|
||||||
|
" -e <execute> Specifies the function to execute, the default is the <base> test\n"
|
||||||
|
" <base> Test base function\n"
|
||||||
|
" <ut> Unit test\n"
|
||||||
|
" ...\n"
|
||||||
|
" -h Print help\n"
|
||||||
|
" -v Print version\n"
|
||||||
|
" -u [<period>] Unit test period, unit ms, the default is 1000ms\n"
|
||||||
|
"\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *execute = NULL;
|
||||||
|
int ut_period = 1000;
|
||||||
|
|
||||||
|
/* reset getopt */
|
||||||
|
command_opt_init();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int opt = command_getopt(argc, argv, "e:hvu::");
|
||||||
|
if (opt == -1) break;
|
||||||
|
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
// Add others opt here
|
||||||
|
case 'u' :
|
||||||
|
if (command_optarg) ut_period = atoi(command_optarg);
|
||||||
|
break;
|
||||||
|
case 'e' :
|
||||||
|
execute = command_optarg;
|
||||||
|
break;
|
||||||
|
case 'v' :
|
||||||
|
printf("coroutine version %d.%d.%d\r\n", COROUTINE_V_MAJOR, COROUTINE_V_MINOR, COROUTINE_V_PATCH);
|
||||||
|
return 0;
|
||||||
|
case '?':
|
||||||
|
printf("Unknown option `%c`\r\n", command_optopt);
|
||||||
|
return -1;
|
||||||
|
case 'h' :
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (execute)
|
||||||
|
{
|
||||||
|
if (!strcmp(execute, "base"))
|
||||||
|
{
|
||||||
|
test_base();
|
||||||
|
}
|
||||||
|
else if (!strcmp(execute, "ut"))
|
||||||
|
{
|
||||||
|
#if defined(TEST_TARGET_coroutine)
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
unitt_task();
|
||||||
|
usleep(1000 * ut_period);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
printf("create task %d\r\n", task_create(ut_period, unitt_task));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
test_base();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (1 == command_optind) // no opt
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = command_optind; index < argc; index++)
|
||||||
|
{
|
||||||
|
if (!strcmp(argv[index], "base"))
|
||||||
|
{
|
||||||
|
test_base();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 == argc)
|
||||||
|
{
|
||||||
|
test_base();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************/
|
||||||
|
/************************************ Test entry ************************************/
|
||||||
|
/************************************************************************************/
|
||||||
|
|
||||||
|
#if defined(TEST_TARGET_coroutine)
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return test(argc, argv);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void test_coroutine(void)
|
||||||
|
{
|
||||||
|
command_export("coroutine", test);
|
||||||
|
}
|
||||||
|
init_export_app(test_coroutine);
|
||||||
|
#endif
|
||||||
@ -4,6 +4,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <stdint.h>
|
||||||
#if defined(TEST_TARGET_floatl)
|
#if defined(TEST_TARGET_floatl)
|
||||||
#include <varch/command.h>
|
#include <varch/command.h>
|
||||||
#include <varch/unitt.h>
|
#include <varch/unitt.h>
|
||||||
@ -295,8 +296,8 @@ float double_to_float(double d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将 double 的二进制表示转换为 uint64_t
|
// 将 double 的二进制表示转换为 uint64_t
|
||||||
typedef unsigned long long uint64_t;
|
// typedef unsigned long long uint64_t;
|
||||||
typedef long long int64_t;
|
// typedef long long int64_t;
|
||||||
|
|
||||||
uint64_t double_to_bits(double x) {
|
uint64_t double_to_bits(double x) {
|
||||||
return *((uint64_t*)&x);
|
return *((uint64_t*)&x);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user