mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 16:56:42 +08:00
Add the coroutine readme
Add feature to bind CoTask and CoTimer to the specified CoScheduler Improve functional safety TODO: 1. Compatibility with coroutine API highly intensive IO, sockets, etc 2. Fix running fail on arm64
This commit is contained in:
parent
f2b0a31bb3
commit
bf21a64ab2
@ -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
|
||||||
@ -77,7 +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.01.00 | [link](/doc/coroutine.en.md) | [path](./source/08_coroutine) | Coroutine module
|
| coroutine | 00.02.00 | [link](/doc/coroutine.en.md) | [path](./source/08_coroutine) | Coroutine module
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|||||||
@ -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) | 不定参数,获取不定参数和指定参数的个数
|
||||||
@ -77,7 +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.01.00 | [link](/doc/coroutine.md) | [path](./source/08_coroutine) | 协程模块
|
| coroutine | 00.02.00 | [link](/doc/coroutine.md) | [path](./source/08_coroutine) | 协程模块
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
|
|||||||
@ -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
734
doc/coroutine.md
@ -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. **完善的错误处理和监控功能**
|
||||||
@ -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
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
|||||||
* \unit coroutine
|
* \unit coroutine
|
||||||
* \brief This is a C language coroutine library
|
* \brief This is a C language coroutine library
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v0.1.0
|
* \version v0.2.0
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2025 Lamdonn.
|
* \copyright Copyright (C) 2025 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
@ -19,7 +19,7 @@ extern "C" {
|
|||||||
|
|
||||||
/* Version infomation */
|
/* Version infomation */
|
||||||
#define COROUTINE_V_MAJOR 0
|
#define COROUTINE_V_MAJOR 0
|
||||||
#define COROUTINE_V_MINOR 1
|
#define COROUTINE_V_MINOR 2
|
||||||
#define COROUTINE_V_PATCH 0
|
#define COROUTINE_V_PATCH 0
|
||||||
|
|
||||||
#include "coroutine_cfg.h"
|
#include "coroutine_cfg.h"
|
||||||
@ -30,11 +30,6 @@ extern "C" {
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine scheduler
|
|
||||||
*/
|
|
||||||
typedef struct CoScheduler CoScheduler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief: Coroutine task
|
* \brief: Coroutine task
|
||||||
*/
|
*/
|
||||||
@ -57,15 +52,6 @@ typedef void *(*CoTaskEntry_t)(void *arg);
|
|||||||
*/
|
*/
|
||||||
typedef void (*CoTimerEntry_t)(void);
|
typedef void (*CoTimerEntry_t)(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine task run function
|
|
||||||
* \param pScheduler: Coroutine scheduler
|
|
||||||
* \param mark: Coroutine mark
|
|
||||||
* \note: This function must be called in the coroutine context, no matter
|
|
||||||
* whether the coroutine is running or not.
|
|
||||||
*/
|
|
||||||
typedef void (*CoTaskRun_t)(CoScheduler *pScheduler, uint32_t mark);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief: Coroutine lock function
|
* \brief: Coroutine lock function
|
||||||
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, lock
|
* \note: Use coroutines for multi-thread, protect the security of multi-thread shared resources, lock
|
||||||
@ -109,105 +95,12 @@ typedef struct
|
|||||||
uint32_t flag; /**< Event flag, 32 bit storage, each bit can individually represent an event */
|
uint32_t flag; /**< Event flag, 32 bit storage, each bit can individually represent an event */
|
||||||
} CoEvent;
|
} CoEvent;
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine task
|
|
||||||
* \note: Coroutine task is a coroutine unit, each coroutine task has its own stack,
|
|
||||||
* and can be scheduled by the coroutine scheduler.
|
|
||||||
*/
|
|
||||||
struct CoTask
|
|
||||||
{
|
|
||||||
CoTask_t next; /**< Double-link list, next coroutine task */
|
|
||||||
CoTask_t prev; /**< Double-link list, previous coroutine task */
|
|
||||||
CoScheduler *pScheduler; /**< Coroutine scheduler, point to the scheduler that created this coroutine task */
|
|
||||||
uint8_t state; /**< Coroutine task state */
|
|
||||||
void *stackBase; /**< Coroutine task stack base address */
|
|
||||||
size_t stackSize; /**< Coroutine task stack size */
|
|
||||||
#if (COROUTINE_ENABLE_STACK_CALCULATE > 0)
|
|
||||||
size_t stackMaxUsed; /**< Coroutine task stack max used size */
|
|
||||||
#endif
|
|
||||||
uint64_t nextRunTick; /**< When the coroutine task is suspended, coroutine task next run tick */
|
|
||||||
uint32_t flag; /**< Coroutine task flag */
|
|
||||||
CoTaskEntry_t entry; /**< Coroutine task entry function */
|
|
||||||
void *arg; /**< Coroutine task argument address */
|
|
||||||
CoEvent *pEvent; /**< Coroutine task event, point to the event that the coroutine task is waiting for */
|
|
||||||
jmp_buf env; /**< Coroutine task environment, used for context switch */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine timer
|
|
||||||
* \note: Coroutine timer is a coroutine unit, each coroutine timer has its own period,
|
|
||||||
* and can be scheduled by the coroutine scheduler.
|
|
||||||
*/
|
|
||||||
struct CoTimer
|
|
||||||
{
|
|
||||||
CoTimer_t next; /**< Double-link list, next coroutine timer */
|
|
||||||
CoTimer_t prev; /**< Double-link list, previous coroutine timer */
|
|
||||||
CoScheduler *pScheduler; /**< Coroutine scheduler, point to the scheduler that created this coroutine timer */
|
|
||||||
uint64_t periodTick; /**< Coroutine timer period tick */
|
|
||||||
uint64_t nextRunTick; /**< Coroutine timer next run tick */
|
|
||||||
uint32_t flag; /**< Coroutine timer flag */
|
|
||||||
CoTimerEntry_t entry; /**< Coroutine timer entry function */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine scheduler
|
|
||||||
* \note: Coroutine scheduler is a coroutine unit, each coroutine scheduler has its own coroutine task list and coroutine timer list,
|
|
||||||
* and can be scheduled by the coroutine scheduler.
|
|
||||||
*/
|
|
||||||
struct CoScheduler
|
|
||||||
{
|
|
||||||
CoScheduler *next; /**< Single-link list, next coroutine scheduler */
|
|
||||||
|
|
||||||
CoTask_t CoTaskCurrent; /**< Current coroutine task */
|
|
||||||
CoTask_t CoTaskList; /**< Coroutine task list head */
|
|
||||||
size_t CoTaskListSize; /**< Coroutine task list size */
|
|
||||||
|
|
||||||
CoTimer_t CoTimerCurrent; /**< Current coroutine timer */
|
|
||||||
CoTimer_t CoTimerList; /**< Coroutine timer list head */
|
|
||||||
size_t CoTimerListSize; /**< Coroutine timer list size */
|
|
||||||
|
|
||||||
void *stackTop; /**< Coroutine scheduler stack top address */
|
|
||||||
|
|
||||||
jmp_buf env; /**< Coroutine scheduler environment, used for context switch */
|
|
||||||
|
|
||||||
#if (COROUTINE_STATIC_TASK_MAX_NUMBER > 0)
|
|
||||||
struct CoTask sCoTasks[COROUTINE_STATIC_TASK_MAX_NUMBER]; /**< Coroutine task static array */
|
|
||||||
#endif
|
|
||||||
#if (COROUTINE_STATIC_TIMER_MAX_NUMBER > 0)
|
|
||||||
struct CoTimer sCoTimers[COROUTINE_STATIC_TIMER_MAX_NUMBER]; /**< Coroutine timer static array */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CoTick_t tick; /**< Coroutine scheduler tick function */
|
|
||||||
uint32_t tickInterval; /**< Coroutine scheduler tick interval, indicates how many us each tick is */
|
|
||||||
|
|
||||||
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
|
|
||||||
/** The results of each measurement period are added to this queue,
|
|
||||||
* so the load measured at the last `COROUTINE_LOADING_CALCULATE_QSIZE` time point is kept
|
|
||||||
* and averaged as the real-time load */
|
|
||||||
uint16_t loadQueueBase[COROUTINE_LOADING_CALCULATE_QSIZE]; /**< Coroutine scheduler loading queue base */
|
|
||||||
uint16_t loadQueueSize; /**< Coroutine scheduler loading queue size */
|
|
||||||
uint16_t loadQueueTail; /**< Coroutine scheduler loading queue tail */
|
|
||||||
|
|
||||||
uint16_t curLoad; /**< Coroutine scheduler current load */
|
|
||||||
uint16_t maxLoad; /**< Coroutine scheduler max load */
|
|
||||||
uint64_t uTick; /**< Coroutine scheduler measures and calculates the load once every `uTick` */
|
|
||||||
uint64_t sTick; /**< Coroutine scheduler tick that start measures */
|
|
||||||
uint64_t pTick; /**< Coroutine scheduler tick that previous start measurement task run */
|
|
||||||
uint64_t cTick; /**< Coroutine scheduler tick that current tick */
|
|
||||||
uint64_t rTick; /**< Coroutine scheduler tick that task running */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CoTaskRun_t CoTaskRun; /**< Coroutine scheduler task run function, prevents function compilation from being optimized inline */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief: Coroutine scheduler initialize parameter
|
* \brief: Coroutine scheduler initialize parameter
|
||||||
* \note: Coroutine scheduler initialize parameter is used to initialize the coroutine scheduler.
|
* \note: Coroutine scheduler initialize parameter is used to initialize the coroutine scheduler.
|
||||||
*/
|
*/
|
||||||
typedef struct CoSchedulerInitPara
|
typedef struct CoSchedulerInitPara
|
||||||
{
|
{
|
||||||
CoTick_t tick; /**< Coroutine scheduler tick function */
|
|
||||||
uint32_t tickInterval; /**< Coroutine scheduler tick interval, indicates how many ns each tick is */
|
|
||||||
CoLock_t lock; /**< Coroutine scheduler lock function */
|
CoLock_t lock; /**< Coroutine scheduler lock function */
|
||||||
CoUnlock_t unlock; /**< Coroutine scheduler unlock function */
|
CoUnlock_t unlock; /**< Coroutine scheduler unlock function */
|
||||||
CoMalloc_t malloc; /**< Coroutine scheduler malloc function */
|
CoMalloc_t malloc; /**< Coroutine scheduler malloc function */
|
||||||
@ -220,37 +113,34 @@ typedef struct CoSchedulerInitPara
|
|||||||
*/
|
*/
|
||||||
typedef struct CoTaskCreatePara
|
typedef struct CoTaskCreatePara
|
||||||
{
|
{
|
||||||
CoTaskEntry_t entry; /**< Coroutine task entry function */
|
|
||||||
void *pStack; /**< Coroutine task stack address */
|
void *pStack; /**< Coroutine task stack address */
|
||||||
size_t stackSize; /**< Coroutine task stack size */
|
size_t stackSize; /**< Coroutine task stack size */
|
||||||
void *arg; /**< Coroutine task argument */
|
void *arg; /**< Coroutine task argument */
|
||||||
|
int schedulerId; /**< Coroutine task scheduler id */
|
||||||
} CoTaskCreatePara;
|
} 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
|
typedef struct CoTaskWaitPara
|
||||||
{
|
{
|
||||||
CoEvent *pEvent;
|
CoEvent *pEvent; /**< Coroutine task wait event pointer */
|
||||||
uint64_t ms;
|
uint64_t ms; /**< Coroutine task wait timeout in ms */
|
||||||
uint64_t tick;
|
uint64_t tick; /**< Coroutine task wait timeout in tick */
|
||||||
} CoTaskWaitPara;
|
} CoTaskWaitPara;
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine scheduler default initialize parameter
|
|
||||||
* \note: Coroutine scheduler default initialize parameter is used to initialize the coroutine scheduler.
|
|
||||||
*/
|
|
||||||
#define COSCHEDULER_INIT_PARA(...) (CoSchedulerInitPara[1]){[0]={.tick=NULL,.tickInterval=0,.lock=NULL,.unlock=NULL,.malloc=NULL,.free=NULL},[0]={__VA_ARGS__}}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine task default create parameter
|
|
||||||
* \note: Coroutine task default create parameter is used to create a coroutine task.
|
|
||||||
*/
|
|
||||||
#define COTASK_CREATE_PARA(...) (CoTaskCreatePara[1]){[0]={.entry=NULL,.pStack=NULL,.stackSize=0,.arg=NULL},[0]={__VA_ARGS__}}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine wait default wait parameter
|
|
||||||
* \note: Coroutine wait default wait parameter is used to blocking task waiting for event or timeout.
|
|
||||||
*/
|
|
||||||
#define COTASK_WAIT_PARA(...) (CoTaskWaitPara[1]){[0]={.pEvent=NULL,.ms=0,.tick=0},[0]={__VA_ARGS__}}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief: Coroutine task create parameter default value
|
* \brief: Coroutine task create parameter default value
|
||||||
* \note: Coroutine task create parameter default value is used to create a coroutine task.
|
* \note: Coroutine task create parameter default value is used to create a coroutine task.
|
||||||
@ -272,8 +162,8 @@ typedef struct CoTaskWaitPara
|
|||||||
/**
|
/**
|
||||||
* \brief: Coroutine scheduler initialize function
|
* \brief: Coroutine scheduler initialize function
|
||||||
* \param pScheduler: [Non-default parameter] Coroutine scheduler pointer
|
* \param pScheduler: [Non-default parameter] Coroutine scheduler pointer
|
||||||
* \param tick: [Default parameter] Coroutine scheduler tick function, must be specified
|
* \param tick: [Non-default parameter] Coroutine scheduler tick function, must be specified
|
||||||
* \param tickInterval: [Default parameter] Coroutine scheduler tick interval, indicates how many us each tick is, 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,
|
* \param lock: [Default parameter] Coroutine scheduler lock function,
|
||||||
* for use on multiple threads, you must specify as follows .lock=thread_lock
|
* for use on multiple threads, you must specify as follows .lock=thread_lock
|
||||||
* \param unlock: [Default parameter] Coroutine scheduler unlock function,
|
* \param unlock: [Default parameter] Coroutine scheduler unlock function,
|
||||||
@ -297,23 +187,21 @@ typedef struct CoTaskWaitPara
|
|||||||
* \warning: The coroutine scheduler will not check the validity of the given parameter.
|
* \warning: The coroutine scheduler will not check the validity of the given parameter.
|
||||||
* You must ensure that the given parameter is valid.
|
* You must ensure that the given parameter is valid.
|
||||||
* \example:
|
* \example:
|
||||||
* CoScheduler scheduler;
|
* CoScheduler_Init(0, GetTimerMs, 1000000);
|
||||||
* CoScheduler_Init(&scheduler, GetTimerMs, 1000000);
|
|
||||||
* \example:
|
* \example:
|
||||||
* CoScheduler scheduler;
|
* CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
* CoScheduler_Init(&scheduler, GetTimerUsec, 1000);
|
|
||||||
* \example:
|
* \example:
|
||||||
* CoScheduler scheduler;
|
* CoScheduler_Init(0, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock);
|
||||||
* CoScheduler_Init(&scheduler, GetTimerUsec, 1000, .lock=thread_lock, .unlock=thread_unlock);
|
|
||||||
* \example:
|
* \example:
|
||||||
* CoScheduler scheduler;
|
* CoScheduler_Init(0, GetTimerUsec, 1000, .malloc=mallloc, .free=free);
|
||||||
* CoScheduler_Init(&scheduler, GetTimerUsec, 1000, .malloc=mallloc, .free=free);
|
|
||||||
*/
|
*/
|
||||||
#define CoScheduler_Init(pScheduler, ...) CoScheduler_InitP(pScheduler, COSCHEDULER_INIT_PARA(__VA_ARGS__))
|
#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
|
* \brief: Coroutine scheduler initialize function
|
||||||
* \param pScheduler: Coroutine scheduler pointer
|
* \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
|
* \param pPara: Coroutine scheduler initialize parameter pointer
|
||||||
* \return: Coroutine task create parameter default value, indicates success
|
* \return: Coroutine task create parameter default value, indicates success
|
||||||
* \note: Coroutine scheduler initialize function is used to initialize the coroutine scheduler.
|
* \note: Coroutine scheduler initialize function is used to initialize the coroutine scheduler.
|
||||||
@ -326,7 +214,7 @@ typedef struct CoTaskWaitPara
|
|||||||
* The coroutine scheduler will use the given malloc function to allocate memory for the tasks.
|
* 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.
|
* The coroutine scheduler will use the given free function to free memory of the tasks.
|
||||||
*/
|
*/
|
||||||
int CoScheduler_InitP(CoScheduler *pScheduler, CoSchedulerInitPara *pPara);
|
int CoScheduler_InitP(uint32_t CoSchedulerId, CoTick_t tick, uint32_t tickInterval, CoSchedulerInitPara *pPara);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief: Coroutine scheduler start function
|
* \brief: Coroutine scheduler start function
|
||||||
@ -336,12 +224,37 @@ int CoScheduler_InitP(CoScheduler *pScheduler, CoSchedulerInitPara *pPara);
|
|||||||
* It must be called once after the coroutine scheduler is initialized.
|
* It must be called once after the coroutine scheduler is initialized.
|
||||||
* It will start the coroutine scheduler and run the tasks.
|
* It will start the coroutine scheduler and run the tasks.
|
||||||
* \example:
|
* \example:
|
||||||
* CoScheduler scheduler;
|
* CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
* CoScheduler_Init(&scheduler, GetTimerUsec, 1000);
|
|
||||||
* testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest), 0);
|
* testCoroutine = CoTask_Create(test, g_StackTest, sizeof(g_StackTest), 0);
|
||||||
* CoScheduler_Start(&scheduler);
|
* CoScheduler_Start(0);
|
||||||
*/
|
*/
|
||||||
int CoScheduler_Start(CoScheduler *pScheduler);
|
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
|
* \brief: Coroutine scheduler current load function
|
||||||
@ -352,7 +265,7 @@ int CoScheduler_Start(CoScheduler *pScheduler);
|
|||||||
* The load is updated periodically with the given tick interval.
|
* The load is updated periodically with the given tick interval.
|
||||||
*/
|
*/
|
||||||
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
|
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
|
||||||
uint16_t CoScheduler_CurLoad(CoScheduler *pScheduler);
|
uint16_t CoScheduler_CurLoad(uint32_t CoSchedulerId);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,17 +277,19 @@ uint16_t CoScheduler_CurLoad(CoScheduler *pScheduler);
|
|||||||
* The load is updated periodically with the given tick interval.
|
* The load is updated periodically with the given tick interval.
|
||||||
*/
|
*/
|
||||||
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
|
#if (COROUTINE_ENABLE_LOADING_CALCULATE > 0)
|
||||||
uint16_t CoScheduler_MaxLoad(CoScheduler *pScheduler);
|
uint16_t CoScheduler_MaxLoad(uint32_t CoSchedulerId);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief: Coroutine task create function
|
* \brief: Coroutine task create function
|
||||||
* \param entry: [Default parameter] Coroutine task entry function, indicates the entry function of the coroutine task, must be specified
|
* \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.
|
* \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.
|
* 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
|
* \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`.
|
* 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 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
|
* \return: Coroutine task handle, indicates the created coroutine task
|
||||||
* \note: Coroutine task create function is used to create a coroutine task.
|
* \note: Coroutine task create function is used to create a coroutine task.
|
||||||
* It will create a coroutine task with the given parameter.
|
* It will create a coroutine task with the given parameter.
|
||||||
@ -389,7 +304,7 @@ uint16_t CoScheduler_MaxLoad(CoScheduler *pScheduler);
|
|||||||
* int arg = 4096;
|
* int arg = 4096;
|
||||||
* CoTask_t testCoroutine = CoTask_Create(test, .arg=&arg);
|
* CoTask_t testCoroutine = CoTask_Create(test, .arg=&arg);
|
||||||
*/
|
*/
|
||||||
#define CoTask_Create(...) CoTask_CreateP(COTASK_CREATE_PARA(__VA_ARGS__))
|
#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
|
* \brief: Coroutine task create function, it is recommended to use @ref `CoTask_Create` instead
|
||||||
@ -399,7 +314,7 @@ uint16_t CoScheduler_MaxLoad(CoScheduler *pScheduler);
|
|||||||
* It will create a coroutine task with the given parameter.
|
* It will create a coroutine task with the given parameter.
|
||||||
* The coroutine task will run in the coroutine scheduler.
|
* The coroutine task will run in the coroutine scheduler.
|
||||||
*/
|
*/
|
||||||
CoTask_t CoTask_CreateP(CoTaskCreatePara *pPara);
|
CoTask_t CoTask_CreateP(CoTaskEntry_t entry, CoTaskCreatePara *pPara);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief: Coroutine task delete function
|
* \brief: Coroutine task delete function
|
||||||
@ -419,6 +334,13 @@ int CoTask_Delete(CoTask_t CoTask);
|
|||||||
*/
|
*/
|
||||||
CoTask_t CoTask_Self(void);
|
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
|
* \brief: Coroutine task stack max used function
|
||||||
* \param CoTask: Coroutine task handle, indicates the coroutine task to get the stack max used
|
* \param CoTask: Coroutine task handle, indicates the coroutine task to get the stack max used
|
||||||
@ -489,7 +411,7 @@ size_t CoTask_StackCurUsed(CoTask_t CoTask);
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
#define CoTask_Wait(...) CoTask_WaitP(COTASK_WAIT_PARA(__VA_ARGS__))
|
#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
|
* \brief: Coroutine task wait function, it is recommended to use @ref `CoTask_Wait` instead
|
||||||
@ -515,6 +437,71 @@ uint32_t CoTask_WaitP(CoTaskWaitPara *pPara);
|
|||||||
#define CoTask_WaitEventMs(e, m) CoTask_Wait(.pEvent=e, .ms=m)
|
#define CoTask_WaitEventMs(e, m) CoTask_Wait(.pEvent=e, .ms=m)
|
||||||
#define CoTask_WaitEventTick(e, t) CoTask_Wait(.pEvent=e, .tick=t)
|
#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
|
* \brief: Coroutine event initialize function
|
||||||
* \param pEvent: Coroutine event pointer, indicates the event to initialize
|
* \param pEvent: Coroutine event pointer, indicates the event to initialize
|
||||||
@ -538,49 +525,6 @@ void CoEvent_Init(CoEvent *pEvent);
|
|||||||
*/
|
*/
|
||||||
void CoEvent_Notify(CoEvent *pEvent, uint32_t evs);
|
void CoEvent_Notify(CoEvent *pEvent, uint32_t evs);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine timer create tick function
|
|
||||||
* \param entry: Coroutine timer entry, indicates the timer entry function
|
|
||||||
* \param tick: Coroutine timer tick, indicates the tick interval
|
|
||||||
* \return: Coroutine timer handle, indicates the created timer
|
|
||||||
* \note: Coroutine timer create tick function is used to create a timer with the given tick interval.
|
|
||||||
* The timer will call the given entry function periodically with the given tick interval.
|
|
||||||
* \example:
|
|
||||||
* CoTimer_t timer = CoTimer_CreateTick(timer_entry, 100); // create a timer with 100 tick interval
|
|
||||||
*/
|
|
||||||
CoTimer_t CoTimer_CreateTick(CoTimerEntry_t entry, uint64_t tick);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief: Coroutine timer create ms function
|
|
||||||
* \param entry: Coroutine timer entry, indicates the timer entry function
|
|
||||||
* \param ms: Coroutine timer ms, indicates the ms 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
|
|
||||||
*/
|
|
||||||
CoTimer_t CoTimer_CreateMs(CoTimerEntry_t entry, uint32_t ms);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \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);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -6,31 +6,43 @@
|
|||||||
* \unit coroutine
|
* \unit coroutine
|
||||||
* \brief This is a C language coroutine library
|
* \brief This is a C language coroutine library
|
||||||
* \author Lamdonn
|
* \author Lamdonn
|
||||||
* \version v0.1.0
|
* \version v0.2.0
|
||||||
* \license GPL-2.0
|
* \license GPL-2.0
|
||||||
* \copyright Copyright (C) 2025 Lamdonn.
|
* \copyright Copyright (C) 2025 Lamdonn.
|
||||||
********************************************************************************************************/
|
********************************************************************************************************/
|
||||||
#ifndef __coroutine_cfg_H
|
#ifndef __coroutine_cfg_H
|
||||||
#define __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
|
* \brief Coroutine static task max number
|
||||||
* \note This macro defines the maximum number of coroutine tasks that can be created statically
|
* \note This macro defines the maximum number of coroutine tasks that can be created statically
|
||||||
*/
|
*/
|
||||||
#define COROUTINE_STATIC_TASK_MAX_NUMBER 32
|
#define COROUTINE_STATIC_TASK_MAX_NUMBER 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Coroutine static timer max number
|
* \brief Coroutine static timer max number
|
||||||
* \note This macro defines the maximum number of coroutine timers that can be created statically
|
* \note This macro defines the maximum number of coroutine timers that can be created statically
|
||||||
*/
|
*/
|
||||||
#define COROUTINE_STATIC_TIMER_MAX_NUMBER 32
|
#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
|
* \brief Coroutine stack default size
|
||||||
* \note This macro defines the default size of the coroutine stack
|
* \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
|
* \note If the coroutine stack size is not specified, this value will be used
|
||||||
*/
|
*/
|
||||||
#define COROUTINE_STACK_DEFAULT_SIZE 4096 // 10240 //
|
#define COROUTINE_STACK_DEFAULT_SIZE 10240 // 4096 //
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Coroutine enable stack calculate
|
* \brief Coroutine enable stack calculate
|
||||||
@ -68,93 +80,93 @@
|
|||||||
* \note Common platforms have been implemented, not implemented platforms need to be implemented by users
|
* \note Common platforms have been implemented, not implemented platforms need to be implemented by users
|
||||||
*/
|
*/
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %%esp, %0" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%esp, %0" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov %0, %%esp" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%esp" : : "r" (p) : "memory")
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %%rsp, %0" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%rsp, %0" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov %0, %%rsp" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%rsp" : : "r" (p) : "memory")
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__mips__)
|
#elif defined(__mips__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile(".set noreorder\n\t" "move %0, $sp\n\t" ".set reorder" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile(".set noreorder\n\t" "move %0, $sp\n\t" ".set reorder" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile(".set noreorder\n\t" "move $sp, %0\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__)
|
#elif defined(__riscv__)
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mv %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mv %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mv sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mv sp, %0" : : "r" (p) : "memory")
|
||||||
#else
|
#else
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mv %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mv %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mv sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mv sp, %0" : : "r" (p) : "memory")
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__powerpc__)
|
#elif defined(__powerpc__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__powerpc64__)
|
#elif defined(__powerpc64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__s390__)
|
#elif defined(__s390__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__s390x__)
|
#elif defined(__s390x__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__sparc__)
|
#elif defined(__sparc__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
#elif defined(__sparcv9__)
|
#elif defined(__sparcv9__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
#elif defined(__tile__)
|
#elif defined(__tile__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
#elif defined(__tilegx__)
|
#elif defined(__tilegx__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %%sp, %0" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov %0, %%sp" : : "r" (p) : "memory")
|
||||||
#elif defined(__hppa__)
|
#elif defined(__hppa__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__hppa64__)
|
#elif defined(__hppa64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__ia64__)
|
#elif defined(__ia64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0=sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0=sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp=%0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp=%0" : : "r" (p) : "memory")
|
||||||
#elif defined(__loongarch__)
|
#elif defined(__loongarch__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__m68k__)
|
#elif defined(__m68k__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__mips64__)
|
#elif defined(__mips64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__parisc__)
|
#elif defined(__parisc__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__parisc64__)
|
#elif defined(__parisc64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r1" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r1, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__s390__)
|
#elif defined(__s390__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__s390x__)
|
#elif defined(__s390x__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mr %0, r15" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mr r15, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__sh__)
|
#elif defined(__sh__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__sh64__)
|
#elif defined(__sh64__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("mov %0, sp" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("mov sp, %0" : : "r" (p) : "memory")
|
||||||
#elif defined(__xtensa__)
|
#elif defined(__xtensa__)
|
||||||
#define COROUTINE_GET_STACK(p) __asm__ volatile("rsr.a1 %0" : "=r" (p) : : "memory")
|
#define COROUTINE_GET_SP(p) __asm__ volatile("rsr.a1 %0" : "=r" (p) : : "memory")
|
||||||
#define COROUTINE_SET_STACK(p) __asm__ volatile("wsr.a1 %0" : : "r" (p) : "memory")
|
#define COROUTINE_SET_SP(p) __asm__ volatile("wsr.a1 %0" : : "r" (p) : "memory")
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform, please implement `COROUTINE_GET_STACK` and `COROUTINE_SET_STACK`"
|
#error "Unsupported platform, please implement `COROUTINE_GET_SP` and `COROUTINE_SET_SP`"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // !__coroutine_cfg_H
|
#endif // !__coroutine_cfg_H
|
||||||
|
|||||||
@ -14,6 +14,11 @@
|
|||||||
#include "coroutine.h"
|
#include "coroutine.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MUTI_THREAD_NUM 2
|
||||||
|
#if (MUTI_THREAD_NUM <= 0)
|
||||||
|
#error "MUTI_THREAD_NUM must be greater than 0"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
uint64_t GetTimerUsec(void)
|
uint64_t GetTimerUsec(void)
|
||||||
@ -36,69 +41,6 @@ uint64_t GetTimerUsec(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define MUTI_THREAD_NUM 2
|
|
||||||
static pthread_t threads[MUTI_THREAD_NUM];
|
|
||||||
static pthread_t testThread;
|
|
||||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
static CoScheduler gMutiScheduler[MUTI_THREAD_NUM];
|
|
||||||
|
|
||||||
static CoScheduler gSingleScheduler;
|
|
||||||
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 thread_lock(void)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void thread_unlock(void)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
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_Self()->pScheduler));
|
|
||||||
// CoEvent_Notify(&gEvent, 0x01 | 0x02);
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************************************************/
|
/************************************************************************************/
|
||||||
/************************************* Unit Test ************************************/
|
/************************************* Unit Test ************************************/
|
||||||
/************************************************************************************/
|
/************************************************************************************/
|
||||||
@ -142,40 +84,98 @@ static void unitt_task(void)
|
|||||||
/************************************* Base Test ************************************/
|
/************************************* Base Test ************************************/
|
||||||
/************************************************************************************/
|
/************************************************************************************/
|
||||||
|
|
||||||
static void test_base(void)
|
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)
|
void test_singleThread(void)
|
||||||
{
|
{
|
||||||
CoScheduler_Init(&gSingleScheduler, GetTimerUsec, 1000);
|
CoScheduler_Init(0, GetTimerUsec, 1000);
|
||||||
gTickCoroutine = CoTask_Create(tick, gStackTick, sizeof(gStackTick));
|
createTask(NULL);
|
||||||
gTockCoroutine = CoTask_Create(tock, gStackTock, sizeof(gStackTock));
|
CoScheduler_Start(0);
|
||||||
gTimer0Handle = CoTimer_CreateMs(timer0, 1000);
|
}
|
||||||
gTimer1Handle = CoTimer_CreateMs(timer1, 1000);
|
#else
|
||||||
CoScheduler_Start(&gSingleScheduler);
|
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)
|
static void *muti_thread_entry(void *arg)
|
||||||
{
|
{
|
||||||
int threadId = *(int *)arg;
|
CoScheduler_Start(*(int *)arg);
|
||||||
CoScheduler_Init(&gMutiScheduler[threadId], GetTimerUsec, 1000, thread_lock, thread_unlock);
|
|
||||||
if (threadId == 0)
|
|
||||||
{
|
|
||||||
gTickCoroutine = CoTask_Create(tick, gStackTick, sizeof(gStackTick));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gTockCoroutine = CoTask_Create(tock, gStackTock, sizeof(gStackTock));
|
|
||||||
}
|
|
||||||
CoScheduler_Start(&gMutiScheduler[threadId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_mutiThread(void)
|
void test_mutiThread(void)
|
||||||
{
|
{
|
||||||
int threadId[MUTI_THREAD_NUM];
|
int threadId[MUTI_THREAD_NUM];
|
||||||
for (int i = 0; i < MUTI_THREAD_NUM; i++)
|
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;
|
threadId[i] = i;
|
||||||
pthread_create(&threads[i], NULL, muti_thread_entry, &threadId[i]);
|
pthread_create(&threads[i], NULL, muti_thread_entry, &threadId[i]);
|
||||||
@ -188,7 +188,16 @@ void test_mutiThread(void)
|
|||||||
pthread_join(threads[i], NULL);
|
pthread_join(threads[i], NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void test_base(void)
|
||||||
|
{
|
||||||
|
#if (MUTI_THREAD_NUM == 1)
|
||||||
|
test_singleThread();
|
||||||
|
#else
|
||||||
|
test_mutiThread();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************/
|
/************************************************************************************/
|
||||||
/************************************* Command ************************************/
|
/************************************* Command ************************************/
|
||||||
@ -203,8 +212,6 @@ static void usage(void)
|
|||||||
" -e <execute> Specifies the function to execute, the default is the <base> test\n"
|
" -e <execute> Specifies the function to execute, the default is the <base> test\n"
|
||||||
" <base> Test base function\n"
|
" <base> Test base function\n"
|
||||||
" <ut> Unit test\n"
|
" <ut> Unit test\n"
|
||||||
" <single> Test single thread\n"
|
|
||||||
" <muti> Test muti thread\n"
|
|
||||||
" ...\n"
|
" ...\n"
|
||||||
" -h Print help\n"
|
" -h Print help\n"
|
||||||
" -v Print version\n"
|
" -v Print version\n"
|
||||||
@ -266,14 +273,6 @@ static int test(int argc, char *argv[])
|
|||||||
printf("create task %d\r\n", task_create(ut_period, unitt_task));
|
printf("create task %d\r\n", task_create(ut_period, unitt_task));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (!strcmp(execute, "single"))
|
|
||||||
{
|
|
||||||
test_singleThread();
|
|
||||||
}
|
|
||||||
else if (!strcmp(execute, "muti"))
|
|
||||||
{
|
|
||||||
test_mutiThread();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user