未验证 提交 3e873bf4 编写于 作者: O openharmony_ci 提交者: Gitee

!15979 Release3.2文档更新

Merge pull request !15979 from 乔克叔叔/OpenHarmony-3.2-Release
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
- [异常调测](kernel-mini-memory-exception.md) - [异常调测](kernel-mini-memory-exception.md)
- [Trace调测](kernel-mini-memory-trace.md) - [Trace调测](kernel-mini-memory-trace.md)
- [LMS调测](kernel-mini-memory-lms.md) - [LMS调测](kernel-mini-memory-lms.md)
- [SHELL](kernel-mini-debug-shell.md)
- 附录 - 附录
- [内核编码规范](kernel-mini-appx-code.md) - [内核编码规范](kernel-mini-appx-code.md)
- [标准库支持](kernel-mini-appx-lib.md) - [标准库支持](kernel-mini-appx-lib.md)
...@@ -135,7 +136,7 @@ ...@@ -135,7 +136,7 @@
- [魔法键使用方法](kernel-small-debug-shell-magickey.md) - [魔法键使用方法](kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](kernel-small-debug-shell-error.md) - [用户态异常信息说明](kernel-small-debug-shell-error.md)
- [Trace调测](kernel-small-debug-trace.md) - [Trace调测](kernel-small-debug-trace.md)
- [Perf调测](kernel-mini-memory-perf.md) - [Perf调测](kernel-small-debug-perf.md)
- [LMS调测](kernel-small-memory-lms.md) - [LMS调测](kernel-small-memory-lms.md)
- [进程调测](kernel-small-debug-process-cpu.md) - [进程调测](kernel-small-debug-process-cpu.md)
- 内核态内存调测 - 内核态内存调测
......
...@@ -58,7 +58,7 @@ OsMuxInit ...@@ -58,7 +58,7 @@ OsMuxInit
## 注释 ## 注释
一般的,尽量通过清晰的软件架构,良好的符号命名来提高代码可读性;然后在需要的时候,才辅以注释说明。 一般的,尽量通过清晰的软件架构,良好的符号命名来提高代码可读性;在需要的时候,辅以注释说明。
注释是为了帮助阅读者快速读懂代码,所以要从读者的角度出发,按需注释。 注释是为了帮助阅读者快速读懂代码,所以要从读者的角度出发,按需注释。
......
...@@ -459,6 +459,8 @@ demo功能: ...@@ -459,6 +459,8 @@ demo功能:
创建一个线程并将父线程中的信息传递给子线程,在子线程中打印传递过来的信息和自身线程id值。 创建一个线程并将父线程中的信息传递给子线程,在子线程中打印传递过来的信息和自身线程id值。
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数DemoForTest。
``` ```
#include <stdio.h> #include <stdio.h>
......
...@@ -84,7 +84,7 @@ typedef struct tagEvent { ...@@ -84,7 +84,7 @@ typedef struct tagEvent {
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 进行事件读写操作时,事件的第25位为保留位,不可以进行位设置。 > - 进行事件读写操作时,事件的第25bit(`0x02U << 24`)为保留bit位,不可以进行位设置。
> >
> - 对同一事件反复写入,算作一次写入。 > - 对同一事件反复写入,算作一次写入。
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。 任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。
可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。 可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。
消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用,可以使用队列实现任务异步通信,队列具有如下特性: 消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用,可以使用队列实现任务异步通信,队列具有如下特性:
......
# SHELL
OpenHarmony内核提供的Shell支持调试常用的基本功能,包含系统、文件、网络相关命令。同时OpenHarmony内核的Shell支持添加新的命令,可以根据需求来进行定制。
Shell功能仅供调试使用,暂不支持tab按键补全,按键回退等功能。
部分命令需要通过make menuconfig开启对应选项才可使用。
## 常用命令介绍
### cat
用于显示文本文件的内容。需开启LOSCFG_FS_VFS。
###### 命令格式
cat [FILE]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---- | ---------- | -------------- |
| FILE | 文件路径。 | 已存在的文件。 |
### cd
用来改变当前目录。需开启LOSCFG_FS_VFS。
###### 命令格式
cd [path]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---- | ---------- | -------------- |
| path | 文件路径。 | 已存在的路径。 |
### cp
拷贝文件,创建一份副本。需开启LOSCFG_FS_VFS。
###### 命令格式
cp [SOURCEFILE] [DESTFILE]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---------- | ---------------------- | ----------------------------------------- |
| SOURCEFILE | 源文件路径。文件路径。 | 目前只支持文件,不支持目录;文件不可为空。 |
| DESTFILE | 目的文件路径。 | 支持目录以及文件名;目录需有效。 |
### date
用于查询系统日期和时间。
###### 命令格式
date
###### 参数说明
### free
显示系统内存的使用情况。
###### 命令格式
free [ -k | -m ]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---- | ----------------- | -------- |
| -k | 以KiB为单位显示。 | N/A |
| -m | 以MiB为单位显示。 | N/A |
### help
显示当前操作系统内所有操作指令。
###### 命令格式
help
###### 参数说明
### ifconfig
用来查询网卡的IP地址、网络掩码、网关、硬件mac地址等参数。需开启LWIP_SHELLCMD_ENABLE。
###### 命令格式
ifconfig
###### 参数说明
### ls
用来显示当前目录的内容。需开启LOSCFG_FS_VFS。
###### 命令格式
###### ls [DIRECTORY]
| 参数 | 参数说明 | 取值范围 |
| --------- | ---------- | ------------------------------------------------------------ |
| DIRECTORY | 文件路径。 | DIRECTORY为空时,显示当前目录的内容。<br/>DIRECTORY为有效目录路径时,会显示对应目录下的内容。<br/>当前LiteOS-M不支持根目录 "/"。 |
### memusage
用来显示内存使用水线。
###### 命令格式
###### memusage [-k/-m]
| 参数 | 参数说明 | 取值范围 |
| ---- | ----------------- | -------- |
| -k | 以KiB为单位显示。 | N/A |
| -m | 以MiB为单位显示。 | N/A |
### mkdir
用来创建一个目录。需开启LOSCFG_FS_VFS。
###### 命令格式
###### mkdir [DIRECTORY]
| 参数 | 参数说明 | 取值范围 |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | 文件路径。 | DIRECTORY可以传入绝对路径和相对路径。 |
### ping
用来测试网络连接是否正常。需开启LWIP_SHELLCMD_ENABLE。
###### 命令格式
###### ping [ip]
| 参数 | 参数说明 | 取值范围 |
| ---- | ------------------------------ | -------- |
| ip | 要测试是否网络连通的IPv4地址。 | N/A |
### pwd
用来显示当前路径。需开启LOSCFG_FS_VFS。
###### 命令格式
###### pwd
### rm
用来删除文件或文件夹。需开启LOSCFG_FS_VFS。
###### 命令格式
###### rm [FILE] or rm [-r/-R] [FILE]
| 参数 | 参数说明 | 取值范围 |
| ----- | ------------------------------- | -------------------------------- |
| FILE | 文件名,可以是文件或者文件夹 。 | FILE可以传入绝对路径和相对路径。 |
| -r/-R | FILE是文件夹时需要有-r /-R。 | N/A |
### rmdir
用来删除文件夹。需开启LOSCFG_FS_VFS。
###### 命令格式
###### rmdir [DIRECTORY]
| 参数 | 参数说明 | 取值范围 |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | 文件路径。 | DIRECTORY可以传入绝对路径和相对路径。 |
### task
用来显示当前各任务状态。
###### 命令格式
###### task
显示内容主要包括任务号,优先级,状态,栈信息,信号,事件,CPU占用率,任务名称等
### touch
用来创建文件。需开启LOSCFG_FS_VFS。
###### 命令格式
###### touch [FILE]
| 参数 | 参数说明 | 取值范围 |
| ---- | -------- | -------------------------------- |
| FILE | 文件名。 | FILE可以传入绝对路径和相对路径。 |
### stack
用来查看指定任务的栈内容。需开启编译选项 LOSCFG_DEBUG_TOOLS,功能开启会影响性能。
###### 命令格式
###### stack [ID]
| 参数 | 参数说明 | 取值范围 |
| ---- | -------- | ------------------------ |
| ID | 任务ID。 | 任务ID对应的任务需存在。 |
### hwi
用来查看中断的占用率。需开启编译选项 LOSCFG_DEBUG_TOOLS,功能开启会影响性能。
###### 命令格式
###### hwi
### st
用来查看调度信息。需开启编译选项 LOSCFG_DEBUG_TOOLS,功能开启会影响性能。
###### 命令格式
###### st -s | st -e
| 参数 | 参数说明 | 取值范围 |
| ---- | ---------------------- | -------- |
| -s | 开始记录调度信息 | N/A |
| -e | 停止记录并打印调度信息 | N/A |
...@@ -5,14 +5,18 @@ ...@@ -5,14 +5,18 @@
CPU(中央处理器,Central Processing Unit)占用率分为系统CPU占用率和任务CPU占用率。 CPU(中央处理器,Central Processing Unit)占用率分为系统CPU占用率和任务CPU占用率。
系统CPU占用率(CPU Percent)是指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示系统满负荷运转。 **系统CPU占用率**:是指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其单位为百分比。100表示系统满负荷运转。
任务CPU占用率指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示在一段时间内系统一直在运行该任务。 **任务CPU占用率**:指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其单位为百分比。100表示在一段时间内系统一直在运行该任务。
用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规格。 用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规格。
通过系统中各个任务的CPU占用情况,判断各个任务的CPU占用率是否符合设计的预期。 通过系统中各个任务的CPU占用情况,判断各个任务的CPU占用率是否符合设计的预期。
此外开启CPUP的情况下,可选择开启中断占用率统计。
**中断占用率**:是指单个中断在全部中断消耗时间的占用率。占用率的有效表示范围为0~100。100表示在一段时间内仅触发该中断。
## 运行机制 ## 运行机制
...@@ -23,44 +27,51 @@ OpenHarmony LiteOS-M的CPUP(CPU Percent,系统CPU占用率)采用任务 ...@@ -23,44 +27,51 @@ OpenHarmony LiteOS-M的CPUP(CPU Percent,系统CPU占用率)采用任务
OpenHarmony LiteOS-M提供以下两种CPU占用率的信息查询: OpenHarmony LiteOS-M提供以下两种CPU占用率的信息查询:
- 系统CPU占用率。 - 系统CPU占用率。
- 任务CPU占用率。 - 任务CPU占用率。
**CPU占用率的计算方法:** 此外,系统还提供了中断占用率的信息查询能力(需同时开启CPUP和定时器)。
**占用率的计算方法:**
系统CPU占用率=系统中除idle任务外其他任务运行总时间/系统运行总时间 系统CPU占用率=系统中除idle任务外其他任务运行总时间/系统运行总时间
任务CPU占用率=任务运行总时间/系统运行总时间 任务CPU占用率=任务运行总时间/系统运行总时间
中断占用率=单个中断运行时间/中断运行总时间
## 接口说明 ## 接口说明
**表1** 功能列表 **表1** 功能列表
| 功能分类 | 接口描述 | | 功能分类 | 接口描述 |
| -------- | -------- | | -------- | -------- |
| 获取系统CPU占用率 | -&nbsp;LOS_SysCpuUsage:获取当前系统CPU占用率<br/>-&nbsp;LOS_HistorySysCpuUsage:获取系统历史CPU占用率 | | 获取系统CPU占用率 | &nbsp;LOS_SysCpuUsage:获取当前系统CPU占用率<br/>&nbsp;LOS_HistorySysCpuUsage:获取系统历史CPU占用率 |
| 获取任务CPU占用率 | -&nbsp;LOS_TaskCpuUsage:获取指定任务CPU占用率<br/>-&nbsp;LOS_HistoryTaskCpuUsage:获取指定任务历史CPU占用率<br/>-&nbsp;LOS_HistoryTaskCpuUsage:获取指定任务历史CPU占用率 | | 获取任务CPU占用率 | &nbsp;LOS_TaskCpuUsage:获取指定任务CPU占用率<br/>&nbsp;LOS_HistoryTaskCpuUsage:获取指定任务历史CPU占用率<br/>&nbsp;LOS_AllTaskCpuUsage:获取所有任务CPU占用率 |
| 输出任务CPU占用率 | LOS_CpupUsageMonitor:输出任务历史CPU占用率 | | 输出任务CPU占用率 | LOS_CpupUsageMonitor:输出任务历史CPU占用率 |
| 获取中断CPU占用率 | LOS_GetAllIrqCpuUsage:获取所有中断CPU占用率 |
## 开发流程 ## 开发流程
在kernel/liteos_m目录下执行 make menuconfig 命令配置"Kernel->Enable Cpup"中打开YES开启任务cpup;
开启后出现新选项“Enable Cpup include irq”打开YES开启中断cpup。
CPU占用率的典型开发流程: CPU占用率的典型开发流程:
1. 调用获取系统CPU使用率函数LOS_SysCpuUsage。 1. 调用获取系统CPU用率函数LOS_SysCpuUsage。
2. 调用获取系统历史CPU使用率函数LOS_HistorySysCpuUsage。 2. 调用获取系统历史CPU用率函数LOS_HistorySysCpuUsage。
3. 调用获取指定任务CPU使用率函数LOS_TaskCpuUsage。 3. 调用获取指定任务CPU用率函数LOS_TaskCpuUsage。
- 若任务已创建,则关中断,正常获取,恢复中断; - 若任务已创建,则关中断,正常获取,恢复中断;
- 若任务未创建,则返回错误码; - 若任务未创建,则返回错误码;
4. 调用获取指定任务历史CPU使用率函数LOS_HistoryTaskCpuUsage。 4. 调用获取指定任务历史CPU用率函数LOS_HistoryTaskCpuUsage。
- 若任务已创建,则关中断,根据不同模式正常获取,恢复中断; - 若任务已创建,则关中断,根据不同模式正常获取,恢复中断;
- 若任务未创建,则返回错误码; - 若任务未创建,则返回错误码;
5. 调用获取所有任务CPU使用率函数LOS_AllCpuUsage。 5. 调用获取所有任务CPU用率函数LOS_AllCpuUsage。
- 若CPUP已初始化,则关中断,根据不同模式正常获取,恢复中断; - 若CPUP已初始化,则关中断,根据不同模式正常获取,恢复中断;
- 若CPUP未初始化或有非法入参,则返回错误码; - 若CPUP未初始化或有非法入参,则返回错误码;
...@@ -87,58 +98,67 @@ CPU占用率的典型开发流程: ...@@ -87,58 +98,67 @@ CPU占用率的典型开发流程:
前提条件: 前提条件:
target_config.h中将LOSCFG_BASE_CORE_CPUP配置项打开。 kernel/liteos_m目录下执行 make menuconfig命令配置"Kernel->Enable Cpup"中开启任务cpup:
代码实现如下: 代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleCpup。
``` ```
#include "los_task.h" #include "los_task.h"
#include "los_cpup.h" #include "los_cpup.h"
#define MODE 4
UINT32 g_cpuTestTaskID; #define TEST_TASK_PRIO 5
VOID ExampleCpup(VOID) #define TASK_DELAY_TIME 100
{ VOID CpupTask(VOID)
{
printf("entry cpup test example\n"); printf("entry cpup test example\n");
while(1) { usleep(TASK_DELAY_TIME);
usleep(100); usleep(TASK_DELAY_TIME);
} printf("exit cpup test example\n");
} }
UINT32 ItCpupTest(VOID)
{ UINT32 ExampleCpup(VOID)
{
UINT32 ret; UINT32 ret;
UINT32 cpupUse; UINT32 cpupUse;
TSK_INIT_PARAM_S cpupTestTask = { 0 }; UINT32 taskID;
memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S)); TSK_INIT_PARAM_S cpupTestTask = { 0 };
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup;
cpupTestTask.pcName = "TestCpupTsk"; cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)CpupTask;
cpupTestTask.uwStackSize = 0x800; cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.usTaskPrio = 5; cpupTestTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask); cpupTestTask.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &cpupTestTask);
if(ret != LOS_OK) { if(ret != LOS_OK) {
printf("cpupTestTask create failed .\n"); printf("cpupTestTask create failed .\n");
return LOS_NOK; return LOS_NOK;
} }
usleep(100); usleep(TASK_DELAY_TIME);
/* 获取当前系统CPU占用率 */ /* 获取当前系统CPU占用率 */
cpupUse = LOS_SysCpuUsage(); cpupUse = LOS_SysCpuUsage();
printf("the current system cpu usage is: %u.%u\n", printf("the current system cpu usage is: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT); cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S); /* 获取当前系统历史CPU占用率 */
/* 获取指定任务的CPU占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */ cpupUse = LOS_HistorySysCpuUsage(CPUP_LESS_THAN_1S);
printf("the history system cpu usage in all time:%u.%u\n", printf("the history system cpu usage in all time:%u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT); cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_TaskCpuUsage(g_cpuTestTaskID);
/* 获取指定历史任务在系统启动到现在的CPU占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */ /* 获取指定任务的CPU占用率 */
cpupUse = LOS_TaskCpuUsage(taskID);
printf("cpu usage of the cpupTestTask:\n TaskID: %d\n usage: %u.%u\n", printf("cpu usage of the cpupTestTask:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT); taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S);
/* 获取指定任务在系统启动到现在的CPU占用率 */
cpupUse = LOS_HistoryTaskCpuUsage(taskID, CPUP_LESS_THAN_1S);
printf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n", printf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT); taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
return LOS_OK;
} }
``` ```
...@@ -146,11 +166,19 @@ UINT32 ItCpupTest(VOID) ...@@ -146,11 +166,19 @@ UINT32 ItCpupTest(VOID)
### 结果验证 ### 结果验证
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
entry cpup test example entry cpup test example
the current system cpu usage is : 1.5 the current system cpu usage is: 8.2
the history system cpu usage in all time: 3.0 the history system cpu usage in all time:8.9
cpu usage of the cpupTestTask: TaskID:10 usage: 0.0 cpu usage of the cpupTestTask:
cpu usage of the cpupTestTask&nbsp;in all time: TaskID:10 usage: 0.0 TaskID: 5
usage: 0.5
cpu usage of the cpupTestTask in all time:
TaskID: 5
usage: 0.5
exit cpup test example
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
# 文件系统 # 文件系统
## VFS
M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。同A核一样,通过VFS层提供了POSIX标准的操作,保持了接口的一致性,但是因为M核的资源非常紧张,VFS层非常轻薄,没有提供类似A核的高级功能(如pagecache等),主要是接口的标准化和适配工作,具体的事务由各个文件系统实际承载。M核文件系统支持的功能如下表所示:
### 基本概念
**表1** 文件操作 **VFS(Virtual File System)** 是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用关心底层的存储介质和文件系统类型,提高开发效率。
| 接口名 | 描述 | FATFS | LITTLEFS | M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。通过VFS层提供了POSIX标准的操作,保持了接口的一致性,但是因为M核的资源非常紧张,VFS层非常轻薄,没有提供类似A核的高级功能(如pagecache等),主要是接口的标准化和适配工作,具体的事务由各个文件系统实际承载。M核文件系统支持的功能如下表所示:
### 接口说明
**表1** 文件操作
| 接口名 | 描述 | FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| open | 打开文件 | 支持 | 支持 | | open | 打开文件 | 支持 | 支持 |
| close | 关闭文件 | 支持 | 支持 | | close | 关闭文件 | 支持 | 支持 |
| read | 读取文件内容 | 支持 | 支持 | | read | 读取文件内容 | 支持 | 支持 |
| write | 往文件写入内容 | 支持 | 支持 | | write | 往文件写入内容 | 支持 | 支持 |
| lseek | 设置文件偏移位置 | 支持 | 支持 | | lseek | 设置文件偏移位置 | 支持 | 支持 |
| unlink | 删除文件 | 支持 | 支持 | | stat | 通过文件路径名获取文件信息 | 支持 | 支持 |
| rename | 重命名文件 | 支持 | 支持 | | unlink | 删除文件 | 支持 | 支持 |
| fstat | 通过文件句柄获取文件信息 | 支持 | 支持 | | rename | 重命名文件 | 支持 | 支持 |
| stat | 通过文件路径名获取文件信息 | 支持 | 支持 | | fstat | 通过文件句柄获取文件信息 | 支持 | 支持 |
| fsync | 文件内容刷入存储设备 | 支持 | 支持 | | fsync | 文件内容刷入存储设备 | 支持 | 支持 |
**表2** 目录操作 **表2** 目录操作
...@@ -40,6 +47,8 @@ M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。同 ...@@ -40,6 +47,8 @@ M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。同
| umount2 | 分区卸载,可通过MNT_FORCE参数进行强制卸载 | 支持 | 不支持 | | umount2 | 分区卸载,可通过MNT_FORCE参数进行强制卸载 | 支持 | 不支持 |
| statfs | 获取分区信息 | 支持 | 不支持 | | statfs | 获取分区信息 | 支持 | 不支持 |
ioctl,fcntl等接口由不同的lib库支持,与底层文件系统无关。
## FAT ## FAT
...@@ -61,14 +70,93 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC ...@@ -61,14 +70,93 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
2、新增fs_config.h文件,配置FS_MAX_SS(存储设备最大sector大小)、FF_VOLUME_STRS(分区名)等信息,例如: 2、新增fs_config.h文件,配置FS_MAX_SS(存储设备最大sector大小)、FF_VOLUME_STRS(分区名)等信息,例如:
``` ```
#define FF_VOLUME_STRS "system", "inner", "update", "user" #define FF_VOLUME_STRS "system", "inner", "update", "user"
#define FS_MAX_SS 512 #define FS_MAX_SS 512
#define FAT_MAX_OPEN_FILES 50 #define FAT_MAX_OPEN_FILES 50
``` ```
#### 分区挂载
移植FATFS到新硬件设备上,需要在初始化flash驱动后,完成设备分区。
设备分区接口:int LOS_DiskPartition(const char *dev, const char *fsType, int *lengthArray, int *addrArray, int partNum);
- dev:设备名称, 如“spinorblk0”
- fsType:文件系统类型,”vfat“
- lengthArray:该设备上各分区的长度列表,fatfs填入百分比即可
- addrArray:该设备上各分区的起始地址列表
- partNum:分区的个数
格式化接口:int LOS_PartitionFormat(const char *partName, char *fsType, void *data);
- partName:分区名称,设备名称+ ‘p’ + 分区号,如“spinorblk0p0”
- fsType:文件系统类型,”vfat“
- data:私有数据 传入(VOID *)formatType,(如FMT_FAT, FMT_FAT32)
mount接口:int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
- source:分区名称,设备名称+ ‘p’ + 分区号,如“spinorblk0p0”
- target:挂载路径
- filesystemtype:文件系统类型,”vfat“
- mountflags:mount配置参数
- data:私有数据,传入(VOID *)formatType,(如FMT_FAT, FMT_FAT32)
本参考代码已在 ./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c 中实现,M核qemu上可直接使用,请参考并根据实际硬件修改。
#include "fatfs_conf.h"
#include "fs_config.h"
#include "los_config.h"
#include "ram_virt_flash.h"
#include "los_fs.h"
struct fs_cfg {
CHAR *mount_point;
struct PartitionCfg partCfg;
};
INT32 FatfsLowLevelInit()
{
INT32 ret;
INT32 i;
UINT32 addr;
int data = FMT_FAT32;
const char * const pathName[FF_VOLUMES] = {FF_VOLUME_STRS};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* 获取长度和起始地址的函数,请根据实际单板适配 */
INT32 lengthArray[FF_VOLUMES] = {25, 25, 25, 25};
INT32 addrArray[FF_VOLUMES];
/* 配置各分区的地址和长度,请根据实际单板适配 */
for (i = 0; i < FF_VOLUMES; i++) {
addr = halPartitionsInfo[FLASH_PARTITION_DATA1].partitionStartAddr + i * 0x10000;
addrArray[i] = addr;
FlashInfoInit(i, addr);
}
/* 配置分区信息,请根据实际单板适配 */
SetupDefaultVolToPartTable();
ret = LOS_DiskPartition("spinorblk0", "vfat", lengthArray, addrArray, FF_VOLUMES);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = LOS_PartitionFormat("spinorblk0p0", "vfat", &data);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount("spinorblk0p0", "/system", "vfat", 0, &data);
printf("%s: mount fs on '%s' %s\n", __func__, pathName[0], (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
#### 开发流程 #### 开发流程
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
...@@ -80,13 +168,11 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC ...@@ -80,13 +168,11 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
> - 读写指针未分离,例如以O_APPEND(追加写)方式打开文件后,读指针也在文件尾,从头读文件前需要用户手动置位。 > - 读写指针未分离,例如以O_APPEND(追加写)方式打开文件后,读指针也在文件尾,从头读文件前需要用户手动置位。
> - 暂不支持文件与目录的权限管理。 > - 暂不支持文件与目录的权限管理。
> - stat及fstat接口暂不支持查询修改时间、创建时间和最后访问时间。微软FAT协议不支持1980年以前的时间。 > - stat及fstat接口暂不支持查询修改时间、创建时间和最后访问时间。微软FAT协议不支持1980年以前的时间。
>
> - FATFS分区挂载与卸载: > - FATFS分区挂载与卸载:
> - 支持以只读属性挂载分区。当mount函数的入参为MS_RDONLY时,所有的带有写入的接口,如write、mkdir、unlink,以及非O_RDONLY属性的open,将均被拒绝。 > - 支持以只读属性挂载分区。当mount函数的入参为MS_RDONLY时,所有的带有写入的接口,如write、mkdir、unlink,以及非O_RDONLY属性的open,将均被拒绝。
> - mount支持通过MS_REMOUNT标记修改已挂载分区的权限。 > - mount支持通过MS_REMOUNT标记修改已挂载分区的权限。
> - 在umount操作前,需确保所有目录及文件全部关闭。 > - 在umount操作前,需确保所有目录及文件全部关闭。
> - umount2支持通过MNT_FORCE参数强制关闭所有文件与文件夹并umount,但可能造成数据丢失,请谨慎使用。 > - umount2支持通过MNT_FORCE参数强制关闭所有文件与文件夹并umount,但可能造成数据丢失,请谨慎使用。
>
> - FATFS支持重新划分存储设备分区、格式化分区,对应接口为fatfs_fdisk与fatfs_format: > - FATFS支持重新划分存储设备分区、格式化分区,对应接口为fatfs_fdisk与fatfs_format:
> - 在fatfs_format操作之前,若需要格式化的分区已挂载,需确保分区中的所有目录及文件全部关闭,并且分区umount。 > - 在fatfs_format操作之前,若需要格式化的分区已挂载,需确保分区中的所有目录及文件全部关闭,并且分区umount。
> - 在fatfs_fdisk操作前,需要该设备中的所有分区均已umount。 > - 在fatfs_fdisk操作前,需要该设备中的所有分区均已umount。
...@@ -100,9 +186,9 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC ...@@ -100,9 +186,9 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
本实例实现以下功能: 本实例实现以下功能:
1. 创建目录“user/test” 1. 创建目录“system/test”
2. 在“user/test”目录下创建文件“file.txt” 2. 在“system/test”目录下创建文件“file.txt”
3. 在文件起始位置写入“Hello OpenHarmony!” 3. 在文件起始位置写入“Hello OpenHarmony!”
...@@ -123,97 +209,102 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC ...@@ -123,97 +209,102 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
**前提条件:** **前提条件:**
系统已将MMC设备分区挂载到user目录 系统已将设备分区挂载到目录,qemu默认已挂载system。
在kernel/liteos_m目录下执行 make menuconfig 命令配置"FileSystem->Enable FS VFS"开启FS功能;
开启FS后出现新选项“Enable FAT”开启FAT。
**代码实现如下:** **代码实现如下:**
```
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define LOS_OK 0 本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleFatfs。
#define LOS_NOK -1
int FatfsTest(void) ```
{ #include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define BUF_SIZE 20
#define TEST_ROOT "system" /* 测试的根目录请根据实际情况调整 */
VOID ExampleFatfs(VOID)
{
int ret; int ret;
int fd = -1; int fd;
ssize_t len; ssize_t len;
off_t off; off_t off;
char dirName[20] = "user/test"; char dirName[BUF_SIZE] = TEST_ROOT"/test";
char fileName[20] = "user/test/file.txt"; char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
char writeBuf[20] = "Hello OpenHarmony!"; char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
char readBuf[20] = {0}; char readBuf[BUF_SIZE] = {0};
/* 创建目录“user/test” */ /* 创建测试目录 */
ret = mkdir(dirName, 0777); ret = mkdir(dirName, 0777);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("mkdir failed.\n"); printf("mkdir failed.\n");
return LOS_NOK; return;
} }
/* 创建可读写文件"user/test/file.txt" */ /* 创建可读写测试文件 */
fd = open(fileName, O_RDWR | O_CREAT, 0777); fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) { if (fd < 0) {
printf("open file failed.\n"); printf("open file failed.\n");
return LOS_NOK; return;
} }
/* 将writeBuf中的内容写入文件 */ /* 将writeBuf中的内容写入文件 */
len = write(fd, writeBuf, strlen(writeBuf)); len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) { if (len != strlen(writeBuf)) {
printf("write file failed.\n"); printf("write file failed.\n");
return LOS_NOK; return;
} }
/* 将文件内容刷入存储设备中 */ /* 将文件内容刷入存储设备中 */
ret = fsync(fd); ret = fsync(fd);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("fsync failed.\n"); printf("fsync failed.\n");
return LOS_NOK; return;
} }
/* 将读写指针偏移至文件头 */ /* 将读写指针偏移至文件头 */
off = lseek(fd, 0, SEEK_SET); off = lseek(fd, 0, SEEK_SET);
if (off != 0) { if (off != 0) {
printf("lseek failed.\n"); printf("lseek failed.\n");
return LOS_NOK; return;
} }
/* 将文件内容读出至readBuf中,读取长度为readBuf大小 */ /* 将文件内容读出至readBuf中,读取长度为readBuf大小 */
len = read(fd, readBuf, sizeof(readBuf)); len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) { if (len != strlen(writeBuf)) {
printf("read file failed.\n"); printf("read file failed.\n");
return LOS_NOK; return;
} }
printf("%s\n", readBuf); printf("%s\n", readBuf);
/* 关闭文件 */ /* 关闭测试文件 */
ret = close(fd); ret = close(fd);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("close failed.\n"); printf("close failed.\n");
return LOS_NOK; return;
} }
/* 删除文件"user/test/file.txt" */ /* 删除测试文件 */
ret = unlink(fileName); ret = unlink(fileName);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("unlink failed.\n"); printf("unlink failed.\n");
return LOS_NOK; return;
} }
/* 删除目录“user/test” */ /* 删除测试目录 */
ret = rmdir(dirName); ret = rmdir(dirName);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("rmdir failed.\n"); printf("rmdir failed.\n");
return LOS_NOK; return;
} }
return LOS_OK; return;
} }
``` ```
...@@ -221,7 +312,7 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC ...@@ -221,7 +312,7 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
Hello OpenHarmony! Hello OpenHarmony!
``` ```
...@@ -237,86 +328,198 @@ LittleFS是一个小型的Flash文件系统,它结合日志结构(log-struct ...@@ -237,86 +328,198 @@ LittleFS是一个小型的Flash文件系统,它结合日志结构(log-struct
### 开发指导 ### 开发指导
移植LittleFS到新硬件设备上,需要申明lfs_config: 移植LittleFS到新硬件设备上,需要在初始化flash驱动后,完成设备分区。
设备分区接口:int LOS_DiskPartition(const char *dev, const char *fsType, int *lengthArray, int *addrArray, int partNum);
- dev:设备名称
- fsType:文件系统类型, "littlefs"
- lengthArray:该设备上各分区的长度列表
- addrArray:该设备上各分区的起始地址列表
- partNum:分区的个数
格式化接口:int LOS_PartitionFormat(const char *partName, char *fsType, void *data);
- partName:分区名称
- fsType:文件系统类型, "littlefs"
- data:私有数据 传入(VOID *)struct fs_cfg
mount接口:int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
- source:分区名称
- target:挂载路径
- filesystemtype:文件系统类型,"littlefs"
- mountflags:mount配置参数
- data:私有数据,传入(VOID *)struct fs_cfg
本参考代码已在 ./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c 中实现,M核qemu上可直接使用,请参考并根据实际硬件修改。
``` ```
const struct lfs_config cfg = { #include "los_config.h"
// block device operations #include "ram_virt_flash.h"
.read = user_provided_block_device_read, #include "los_fs.h"
.prog = user_provided_block_device_prog,
.erase = user_provided_block_device_erase, struct fs_cfg {
.sync = user_provided_block_device_sync, CHAR *mount_point;
struct PartitionCfg partCfg;
// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
}; };
INT32 LfsLowLevelInit()
{
INT32 ret;
struct fs_cfg fs[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* 获取长度和起始地址的函数,请根据实际单板适配 */
INT32 lengthArray[2];
lengthArray[0]= halPartitionsInfo[FLASH_PARTITION_DATA0].partitionLength;
INT32 addrArray[2];
addrArray[0] = halPartitionsInfo[FLASH_PARTITION_DATA0].partitionStartAddr;
ret = LOS_DiskPartition("flash0", "littlefs", lengthArray, addrArray, 2);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
fs[0].mount_point = "/littlefs";
fs[0].partCfg.partNo = 0;
fs[0].partCfg.blockSize = 4096; /* 4096, lfs block size */
fs[0].partCfg.blockCount = 1024; /* 2048, lfs block count */
fs[0].partCfg.readFunc = virt_flash_read; /* flash读函数,请根据实际单板适配 */
fs[0].partCfg.writeFunc = virt_flash_write; /* flash写函数,请根据实际单板适配 */
fs[0].partCfg.eraseFunc = virt_flash_erase; /* flash擦函数,请根据实际单板适配 */
fs[0].partCfg.readSize = 256; /* 256, lfs read size */
fs[0].partCfg.writeSize = 256; /* 256, lfs prog size */
fs[0].partCfg.cacheSize = 256; /* 256, lfs cache size */
fs[0].partCfg.lookaheadSize = 16; /* 16, lfs lookahead size */
fs[0].partCfg.blockCycles = 1000; /* 1000, lfs block cycles */
ret = LOS_PartitionFormat("flash0", "littlefs", &fs[0].partCfg);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount(NULL, fs[0].mount_point, "littlefs", 0, &fs[0].partCfg);
printf("%s: mount fs on '%s' %s\n", __func__, fs[0].mount_point, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
``` ```
其中.read,.prog,.erase,.sync分别对应该硬件平台上的底层的读写\擦\同等接口。 其中.readFunc,.writeFunc,.eraseFunc分别对应该硬件平台上的底层的读写\擦等接口。
read_size 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。 readSize 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。
prog_size 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是read_size的整数倍,但值太大会带来更多的内存消耗。 writeSize 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是readSize的整数倍,但值太大会带来更多的内存消耗。
block_size 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是prog_size的整数倍。 blockSize 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是writeSize的整数倍。
block_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。 blockCount 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。
### 示例代码 ### 示例代码
代码实现如下: **前提条件:**
系统已将设备分区挂载到目录,qemu默认已挂载/littlefs。
在kernel/liteos_m目录下执行 make menuconfig 命令配置"FileSystem->Enable FS VFS"开启FS功能;
开启FS后出现新选项“Enable Little FS”开启littlefs。
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleLittlefs。
``` ```
#include "lfs.h" #include <stdio.h>
#include "stdio.h" #include <string.h>
lfs_t lfs; #include "sys/stat.h"
lfs_file_t file; #include "fcntl.h"
const struct lfs_config cfg = { #include "unistd.h"
// block device operations
.read = user_provided_block_device_read, #define BUF_SIZE 20
.prog = user_provided_block_device_prog, #define TEST_ROOT "/littlefs" /* 测试的根目录请根据实际情况调整 */
.erase = user_provided_block_device_erase, VOID ExampleLittlefs(VOID)
.sync = user_provided_block_device_sync, {
// block device configuration int ret;
.read_size = 16, int fd;
.prog_size = 16, ssize_t len;
.block_size = 4096, off_t off;
.block_count = 128, char dirName[BUF_SIZE] = TEST_ROOT"/test";
.cache_size = 16, char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
.lookahead_size = 16, char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
.block_cycles = 500, char readBuf[BUF_SIZE] = {0};
};
int main(void) { /* 创建测试目录 */
// mount the filesystem ret = mkdir(dirName, 0777);
int err = lfs_mount(&lfs, &cfg); if (ret != LOS_OK) {
// reformat if we can't mount the filesystem printf("mkdir failed.\n");
// this should only happen on the first boot return;
if (err) {
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
} }
// read current count
uint32_t boot_count = 0; /* 创建可读写测试文件 */
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT); fd = open(fileName, O_RDWR | O_CREAT, 0777);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count)); if (fd < 0) {
// update boot count printf("open file failed.\n");
boot_count += 1; return;
lfs_file_rewind(&lfs, &file); }
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully /* 将writeBuf中的内容写入文件 */
lfs_file_close(&lfs, &file); len = write(fd, writeBuf, strlen(writeBuf));
// release any resources we were using if (len != strlen(writeBuf)) {
lfs_unmount(&lfs); printf("write file failed.\n");
// print the boot count return;
printf("boot_count: %d\n", boot_count); }
/* 将文件内容刷入存储设备中 */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return;
}
/* 将读写指针偏移至文件头 */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return;
}
/* 将文件内容读出至readBuf中,读取长度为readBuf大小 */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) {
printf("read file failed.\n");
return;
}
printf("%s\n", readBuf);
/* 关闭测试文件 */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return;
}
/* 删除测试文件 */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return;
}
/* 删除测试目录 */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return;
}
return LOS_OK;
} }
``` ```
...@@ -325,7 +528,7 @@ int main(void) { ...@@ -325,7 +528,7 @@ int main(void) {
首次编译运行得到的结果为: 首次编译运行得到的结果为:
``` ```
Say hello 1 times. Hello OpenHarmony!
``` ```
\ No newline at end of file
...@@ -62,7 +62,9 @@ typedef struct { ...@@ -62,7 +62,9 @@ typedef struct {
#### 示例代码 #### 示例代码
代码实现如下: 代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemTest。
``` ```
#include <stdio.h> #include <stdio.h>
...@@ -71,20 +73,20 @@ typedef struct { ...@@ -71,20 +73,20 @@ typedef struct {
#include "los_memory.h" #include "los_memory.h"
#include "los_config.h" #include "los_config.h"
#define TEST_TASK_PRIO 5
void MemInfoTaskFunc(void) void MemInfoTaskFunc(void)
{ {
LOS_MEM_POOL_STATUS poolStatus = {0}; LOS_MEM_POOL_STATUS poolStatus = {0};
/* pool为要统计信息的内存地址,此处以OS_SYS_MEM_ADDR为例 */ /* pool为要统计信息的内存地址,此处以OS_SYS_MEM_ADDR为例 */
void *pool = OS_SYS_MEM_ADDR; void *pool = OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool, &poolStatus); LOS_MemInfoGet(pool, &poolStatus);
/* 算出内存池当前的碎片率百分比 */ /* 算出内存池当前的碎片率百分比 */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize; float fragment = 100 - poolStatus.maxFreeNodeSize * 100.0 / poolStatus.totalFreeSize;
/* 算出内存池当前的使用率百分比 */ /* 算出内存池当前的使用率百分比 */
unsigned char usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool); float usage = LOS_MemTotalUsedGet(pool) * 100.0 / LOS_MemPoolSizeGet(pool);
printf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize, printf("usage = %f, fragment = %f, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment,
poolStatus.totalFreeSize, poolStatus.usageWaterLine); poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
} }
int MemTest(void) int MemTest(void)
...@@ -93,9 +95,9 @@ int MemTest(void) ...@@ -93,9 +95,9 @@ int MemTest(void)
unsigned int taskID; unsigned int taskID;
TSK_INIT_PARAM_S taskStatus = {0}; TSK_INIT_PARAM_S taskStatus = {0};
taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc; taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc;
taskStatus.uwStackSize = 0x1000; taskStatus.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
taskStatus.pcName = "memInfo"; taskStatus.pcName = "memInfo";
taskStatus.usTaskPrio = 10; taskStatus.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &taskStatus); ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("task create failed\n"); printf("task create failed\n");
...@@ -112,7 +114,9 @@ int MemTest(void) ...@@ -112,7 +114,9 @@ int MemTest(void)
``` ```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414 usage = 0.458344, fragment = 0.000000, maxFreeSize = 16474928, totalFreeSize = 16474928, waterLine = 76816
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
## 内存泄漏检测 ## 内存泄漏检测
...@@ -179,6 +183,12 @@ node size LR[0] LR[1] LR[2] ...@@ -179,6 +183,12 @@ node size LR[0] LR[1] LR[2]
代码实现如下: 代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemLeakTest。
qemu平台运行时需确保target_config.h 中对应的LOSCFG_MEM_FREE_BY_TASKID为0。
由于打开内存检测后,部分平台有其他任务运行,会频繁调用内存相关打印如:psp, start = xxxxx, end = xxxxxxx,请忽略打印或删除OsStackAddrGet函数中调用的打印即可。
``` ```
#include <stdio.h> #include <stdio.h>
...@@ -198,7 +208,7 @@ void MemLeakTest(void) ...@@ -198,7 +208,7 @@ void MemLeakTest(void)
#### 结果验证 #### 结果验证
编译运行输出log如下: 编译运行输出示例log如下:
``` ```
...@@ -216,7 +226,9 @@ node size LR[0] LR[1] LR[2] ...@@ -216,7 +226,9 @@ node size LR[0] LR[1] LR[2]
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a 0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220 0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6 0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000 0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块: 对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块:
...@@ -224,7 +236,9 @@ node size LR[0] LR[1] LR[2] ...@@ -224,7 +236,9 @@ node size LR[0] LR[1] LR[2]
``` ```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6 0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000 0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
部分汇编文件如下: 部分汇编文件如下:
...@@ -246,6 +260,8 @@ node size LR[0] LR[1] LR[2] ...@@ -246,6 +260,8 @@ node size LR[0] LR[1] LR[2]
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a 0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a
0x80041f4: 0xbd10 POP {R4, PC} 0x80041f4: 0xbd10 POP {R4, PC}
0x80041f6: 0x0000 MOVS R0, R0 0x80041f6: 0x0000 MOVS R0, R0
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
其中,通过查找0x080041ee,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。 其中,通过查找0x080041ee,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。
...@@ -295,6 +311,12 @@ LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:开关宏,默认关闭;若打开这 ...@@ -295,6 +311,12 @@ LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:开关宏,默认关闭;若打开这
代码实现如下: 代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemIntegrityTest。
qemu平台运行时需确保target_config.h 中对应的LOSCFG_MEM_FREE_BY_TASKID为0。
由于执行时主动触发异常,执行结束后需要重启qemu(例如打开一个新的终端界面输入killall qemu-system-arm)
``` ```
#include <stdio.h> #include <stdio.h>
...@@ -320,20 +342,28 @@ void MemIntegrityTest(void) ...@@ -320,20 +342,28 @@ void MemIntegrityTest(void)
``` ```
[ERR][OsMemMagicCheckPrint], 2028, memory check error!
memory used but magic num wrong, magic num = 0x00000000 /* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */ /* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */
[ERR][IT_TST_INI][OsMemMagicCheckPrint], 1664, memory check error!
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020 memory used but magic num wrong, magic num = 0x0
/* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */
/* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */
broken node head LR info: /* 节点的LR信息需要开启内存检测功能才有有效输出 */ broken node head: 0x2103d7e8 0x0 0x80000020, prev node head: 0x2103c7cc 0xabcddcba 0x80000020
LR[0]:0x0800414e
LR[1]:0x08000cc2 /* 节点的LR信息需要开启前文的内存泄漏检测功能才有有效输出 */
LR[2]:0x00000000 broken node head LR info:
LR[0]:0x2101906c
pre node head LR info: /* 通过LR信息,可以在汇编文件中查找前节点是哪里申请,然后排查其使用的准确性 */ LR[1]:0x0
LR[0]:0x08004144 LR[2]:0x0
LR[1]:0x08000cc2
LR[2]:0x00000000 /* 通过LR信息,可以在汇编文件中查找前节点是哪里申请,然后排查其使用的准确性 */
[ERR]Memory interity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* 被破坏节点和其前节点的地址 */ pre node head LR info:
LR[0]:0x2101906c
LR[1]:0x0
LR[2]:0x0
/* 被破坏节点和其前节点的地址 */
[ERR][IT_TST_INI]Memory integrity check error, cur node: 0x2103d784, pre node: 0x0
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
...@@ -49,6 +49,8 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详 ...@@ -49,6 +49,8 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
1. 使用示例中有问题的代码,编译、运行工程,在串口终端中查看异常信息输出。示例代码模拟异常代码,实际产品开发时使用异常调测机制定位异常问题。 1. 使用示例中有问题的代码,编译、运行工程,在串口终端中查看异常信息输出。示例代码模拟异常代码,实际产品开发时使用异常调测机制定位异常问题。
本示例演示异常输出,包含1个任务,该任务入口函数模拟若干函数调用,最终调用一个模拟异常的函数。代码实现如下: 本示例演示异常输出,包含1个任务,该任务入口函数模拟若干函数调用,最终调用一个模拟异常的函数。代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleExcEntry。
``` ```
#include <stdio.h> #include <stdio.h>
#include "los_config.h" #include "los_config.h"
...@@ -59,29 +61,30 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详 ...@@ -59,29 +61,30 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
#define TSK_PRIOR 4 #define TSK_PRIOR 4
/* 模拟异常函数 */ /* 模拟异常函数 */
UINT32 GetResultException0(UINT16 dividend){
UINT32 Get_Result_Exception_0(UINT16 dividend){ UINT32 result = *(UINT32 *)(0xffffffff);
UINT32 divisor = 0; printf("Enter GetResultException0. %u\r\n", result);
UINT32 result = dividend / divisor;
return result; return result;
} }
UINT32 Get_Result_Exception_1(UINT16 dividend){ UINT32 GetResultException1(UINT16 dividend){
return Get_Result_Exception_0(dividend); printf("Enter GetResultException1.\r\n");
return GetResultException0(dividend);
} }
UINT32 Get_Result_Exception_2(UINT16 dividend){ UINT32 GetResultException2(UINT16 dividend){
return Get_Result_Exception_1(dividend); printf("Enter GetResultException2.\r\n");
return GetResultException1(dividend);
} }
UINT32 Example_Exc(VOID) UINT32 ExampleExc(VOID)
{ {
UINT32 ret; UINT32 ret;
printf("Enter Example_Exc Handler.\r\n"); printf("Enter Example_Exc Handler.\r\n");
/* 模拟函数调用 */ /* 模拟函数调用 */
ret = Get_Result_Exception_2(TSK_PRIOR); ret = GetResultException2(TSK_PRIOR);
printf("Divided result =%u.\r\n", ret); printf("Divided result =%u.\r\n", ret);
printf("Exit Example_Exc Handler.\r\n"); printf("Exit Example_Exc Handler.\r\n");
...@@ -90,20 +93,20 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详 ...@@ -90,20 +93,20 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
/* 任务测试入口函数,创建一个会发生异常的任务 */ /* 任务测试入口函数,创建一个会发生异常的任务 */
UINT32 Example_Exc_Entry(VOID) UINT32 ExampleExcEntry(VOID)
{ {
UINT32 ret; UINT32 ret;
TSK_INIT_PARAM_S initParam; TSK_INIT_PARAM_S initParam = { 0 };
/* 锁任务调度,防止新创建的任务比本任务高而发生调度 */ /* 锁任务调度,防止新创建的任务比本任务高而发生调度 */
LOS_TaskLock(); LOS_TaskLock();
printf("LOS_TaskLock() Success!\r\n"); printf("LOS_TaskLock() Success!\r\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Exc; initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleExc;
initParam.usTaskPrio = TSK_PRIOR; initParam.usTaskPrio = TSK_PRIOR;
initParam.pcName = "Example_Exc"; initParam.pcName = "Example_Exc";
initParam.uwStackSize = LOSCFG_SECURE_STACK_DEFAULT_SIZE; initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
/* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */ /* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */
ret = LOS_TaskCreate(&g_taskExcId, &initParam); ret = LOS_TaskCreate(&g_taskExcId, &initParam);
if (ret != LOS_OK) { if (ret != LOS_OK) {
...@@ -115,99 +118,91 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详 ...@@ -115,99 +118,91 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
printf("Example_Exc create Success!\r\n"); printf("Example_Exc create Success!\r\n");
/* 解锁任务调度,此时会发生任务调度,执行就绪队列中最高优先级任务 */ /* 解锁任务调度,此时会发生任务调度,执行就绪队列中最高优先级任务 */
LOS_TaskUnlock(); LOS_TaskUnlock();
return LOS_OK;
}
```
1. 上述代码串口终端输出异常信息如下:
return LOS_OK;
}
```
述代码串口终端输出异常信息如下:
``` ```
entering kernel init...
LOS_TaskLock() Success! LOS_TaskLock() Success!
Example_Exc create Success! Example_Exc create Success!
Entering scheduler
Enter Example_Exc Handler. Enter Example_Exc Handler.
*Exception Information** Enter GetResultException2.
Type = 10 Enter GetResultException1.
ThrdPid = 4 *************Exception Information**************
Type = 4
ThrdPid = 5
Phase = exc in task Phase = exc in task
FaultAddr = 0xabababab FaultAddr = 0xfffffffc
Current task info: Current task info:
Task name = Example_Exc Task name = Example_Exc
Task ID = 4 Task ID = 5
Task SP = 0x200051ac Task SP = 0x210549bc
Task ST = 0x20004ff0 Task ST = 0x21053a00
Task SS = 0x200 Task SS = 0x1000
Exception reg dump: Exception reg dump:
PC = 0x80037da PC = 0x2101c61a
LR = 0x80037fe LR = 0x2101c64d
SP = 0x20005190 SP = 0x210549a8
R0 = 0x4 R0 = 0x4
R1 = 0x40 R1 = 0xa
R2 = 0x4 R2 = 0x0
R3 = 0x0 R3 = 0xffffffff
R4 = 0x4040404 R4 = 0x2103fb20
R5 = 0x5050505 R5 = 0x5050505
R6 = 0x6060606 R6 = 0x6060606
R7 = 0x20005190 R7 = 0x210549a8
R8 = 0x8080808 R8 = 0x8080808
R9 = 0x9090909 R9 = 0x9090909
R10 = 0x10101010 R10 = 0x10101010
R11 = 0x11111111 R11 = 0x11111111
R12 = 0x12121212 R12 = 0x0
PriMask = 0x0 PriMask = 0x0
xPSR = 0x41000000 xPSR = 0x41000000
----- backtrace start ----- ----- backtrace start -----
backtrace 0 -- lr = 0x800381a backtrace 0 -- lr = 0x2101c64c
backtrace 1 -- lr = 0x8003836 backtrace 1 -- lr = 0x2101c674
backtrace 2 -- lr = 0x8005a4e backtrace 2 -- lr = 0x2101c696
backtrace 3 -- lr = 0x8000494 backtrace 3 -- lr = 0x2101b1ec
backtrace 4 -- lr = 0x8008620
backtrace 5 -- lr = 0x800282c
backtrace 6 -- lr = 0x80008a0
backtrace 7 -- lr = 0x80099f8
backtrace 8 -- lr = 0x800a01a
backtrace 9 -- lr = 0x800282c
backtrace 10 -- lr = 0x80008a0
backtrace 11 -- lr = 0x80099f8
backtrace 12 -- lr = 0x8009bf0
backtrace 13 -- lr = 0x8009c52
backtrace 14 -- lr = 0x80099aa
----- backtrace end ----- ----- backtrace end -----
TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID name TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID CPUUSE CPUUSE10s CPUUSE1s TaskEntry name
--- -------- -------- --------- ---------- ---------- ---------- --------- ----- ---- --- -------- -------- --------- --------- ---------- ---------- --------- ------ ------- --------- -------- ---------- ----
0 0 Pend 0x2d0 0x104 0x200029bc 0x200027f0 0x0 0xffff Swt_Task 0 0 Pend 0x1000 0xdc 0x2104730c 0x210463e8 0 0xffff 0.0 0.0 0.0 0x2101a199 Swt_Task
1 31 Ready 0x500 0x44 0x20002f84 0x20002ac8 0x0 0xffff IdleCore000 1 31 Ready 0x500 0x44 0x210478e4 0x21047428 0 0xffff 0.0 0.0 0.0 0x2101a9c9 IdleCore000
2 6 Ready 0x1000 0x44 0x20003f94 0x20002fd8 0x0 0xffff TaskSampleEntry1 2 5 PendTime 0x6000 0xd4 0x2104e8f4 0x210489c8 0 0xffff 5.7 5.7 0.0 0x21016149 tcpip_thread
3 7 Ready 0x1000 0x44 0x20004f9c 0x20003fe0 0x0 0xffff TaskSampleEntry2 3 3 Pend 0x1000 0x488 0x2104f90c 0x2104e9e8 0x1 0xffff 8.6 8.6 0.0 0x21016db5 ShellTaskEntry
4 4 Running 0x200 0xec 0x200051ac 0x20004ff0 0x0 0xffff Example_Exc 4 25 Ready 0x4000 0x460 0x21053964 0x2104f9f0 0 0xffff 9.0 8.9 0.0 0x2101c765 IT_TST_INI
5 4 Running 0x1000 0x458 0x210549bc 0x21053a00 0 0xffff 76.5 76.6 0.0 0x2101c685 Example_Exc
OS exception NVIC dump: OS exception NVIC dump:
interrupt enable register, base address: 0xe000e100, size: 0x20 interrupt enable register, base address: 0xe000e100, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x2001 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt pending register, base address: 0xe000e200, size: 0x20 interrupt pending register, base address: 0xe000e200, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt active register, base address: 0xe000e300, size: 0x20 interrupt active register, base address: 0xe000e300, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt priority register, base address: 0xe000e400, size: 0xf0 interrupt priority register, base address: 0xe000e400, size: 0xf0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt exception register, base address: 0xe000ed18, size: 0xc interrupt exception register, base address: 0xe000ed18, size: 0xc
0x0 0x0 0xf0f00000 0x0 0x0 0xf0f00000
interrupt shcsr register, base address: 0xe000ed24, size: 0x4 interrupt shcsr register, base address: 0xe000ed24, size: 0x4
0x70008 0x70002
interrupt control register, base address: 0xe000ed04, size: 0x4 interrupt control register, base address: 0xe000ed04, size: 0x4
0x400f806 0x1000e805
memory pools check: memory pools check:
system heap memcheck over, all passed! system heap memcheck over, all passed!
memory pool check end! memory pool check end!
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
...@@ -215,61 +210,68 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详 ...@@ -215,61 +210,68 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
异常接管一般的定位步骤如下: 异常接管一般的定位步骤如下:
0. 确认编译时关掉优化选项,否则下述的描述内容可能被优化掉。
1. 打开编译后生成的镜像反汇编(asm)文件。如果默认没有生成,可以使用objdump工具生成,命令为: 1. 打开编译后生成的镜像反汇编(asm)文件。如果默认没有生成,可以使用objdump工具生成,命令为:
``` ```
arm-none-eabi-objdump -S -l XXX.elf arm-none-eabi-objdump -S -l XXX.elf
``` ```
1. 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。 1. 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。
PC地址指向发生异常时程序正在执行的指令。在当前执行的二进制文件对应的asm文件中,查找PC值0x80037da,找到当前CPU正在执行的指令行,反汇编如下所示: PC地址指向发生异常时程序正在执行的指令。在当前执行的二进制文件对应的asm文件中,查找PC值0x2101c61a,找到当前CPU正在执行的指令行,反汇编如下所示:
``` ```
UINT32 Get_Result_Exception_0(UINT16 dividend){ 2101c60c <GetResultException0>:
80037c8: b480 push {r7} 2101c60c: b580 push {r7, lr}
80037ca: b085 sub sp, #20 2101c60e: b084 sub sp, #16
80037cc: af00 add r7, sp, #0 2101c610: af00 add r7, sp, #0
80037ce: 4603 mov r3, r0 2101c612: 4603 mov r3, r0
80037d0: 80fb strh r3, [r7, #6] 2101c614: 80fb strh r3, [r7, #6]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:10 2101c616: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff
UINT32 divisor = 0; 2101c61a: 681b ldr r3, [r3, #0]
80037d2: 2300 movs r3, #0 2101c61c: 60fb str r3, [r7, #12]
80037d4: 60fb str r3, [r7, #12] 2101c61e: 68f9 ldr r1, [r7, #12]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:11 2101c620: 4803 ldr r0, [pc, #12] ; (2101c630 <GetResultException0+0x24>)
UINT32 result = dividend / divisor; 2101c622: f001 f92b bl 2101d87c <printf>
80037d6: 88fa ldrh r2, [r7, #6] 2101c626: 68fb ldr r3, [r7, #12]
80037d8: 68fb ldr r3, [r7, #12] 2101c628: 4618 mov r0, r3
80037da: fbb2 f3f3 udiv r3, r2, r3 2101c62a: 3710 adds r7, #16
80037de: 60bb str r3, [r7, #8] 2101c62c: 46bd mov sp, r7
2101c62e: bd80 pop {r7, pc}
2101c630: 21025f90 .word 0x21025f90
``` ```
1. 可以看到: 1. 可以看到:
1. 异常时CPU正在执行的指令是udiv r3, r2, r3,其中r3取值为0,导致发生除零异常。 1. 异常时CPU正在执行的指令是ldr r3, [r3, #0],其中r3取值为0xffffffff,导致发生非法地址异常。
2. 异常发生在函数Get_Result_Exception_0中。 2. 异常发生在函数GetResultException0中。
2. 根据LR值查找异常函数的父函数。 2. 根据LR值查找异常函数的父函数。
包含LR值0x80037fe的反汇编如下所示: 包含LR值0x2101c64d的反汇编如下所示:
``` ```
080037ec <Get_Result_Exception_1>: 2101c634 <GetResultException1>:
Get_Result_Exception_1(): 2101c634: b580 push {r7, lr}
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:15 2101c636: b082 sub sp, #8
UINT32 Get_Result_Exception_1(UINT16 dividend){ 2101c638: af00 add r7, sp, #0
80037ec: b580 push {r7, lr} 2101c63a: 4603 mov r3, r0
80037ee: b082 sub sp, #8 2101c63c: 80fb strh r3, [r7, #6]
80037f0: af00 add r7, sp, #0 2101c63e: 4806 ldr r0, [pc, #24] ; (2101c658 <GetResultException1+0x24>)
80037f2: 4603 mov r3, r0 2101c640: f001 f91c bl 2101d87c <printf>
80037f4: 80fb strh r3, [r7, #6] 2101c644: 88fb ldrh r3, [r7, #6]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:16 2101c646: 4618 mov r0, r3
return Get_Result_Exception_0(dividend); 2101c648: f7ff ffe0 bl 2101c60c <GetResultException0>
80037f6: 88fb ldrh r3, [r7, #6] 2101c64c: 4603 mov r3, r0
80037f8: 4618 mov r0, r3 2101c64e: 4618 mov r0, r3
80037fa: f7ff ffe5 bl 80037c8 <Get_Result_Exception_0> 2101c650: 3708 adds r7, #8
80037fe: 4603 mov r3, r0 2101c652: 46bd mov sp, r7
2101c654: bd80 pop {r7, pc}
2101c656: bf00 nop
2101c658: 21025fb0 .word 0x21025fb0
``` ```
1. LR值80037fe上一行是bl 80037c8 &lt;Get_Result_Exception_0&gt;,此处调用了异常函数,调用异常函数的父函数为Get_Result_Exception_1() 1. LR值2101c648上一行是bl 2101c60c <GetResultException0&gt;,此处调用了异常函数,调用异常函数的父函数为GetResultException1
2. 重复步骤3,解析异常信息中backtrace start至backtrace end之间的LR值,得到调用产生异常的函数调用栈关系,找到异常原因。 2. 重复步骤3,解析异常信息中backtrace start至backtrace end之间的LR值,得到调用产生异常的函数调用栈关系,找到异常原因。
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## 基本概念 ## 基本概念
LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double Free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。 LMS(Lite Memory Sanitizer)是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能: OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能:
...@@ -51,7 +51,7 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信 ...@@ -51,7 +51,7 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
开启LMS调测的典型流程如下: 开启LMS调测的典型流程如下:
1. 配置LMS模块相关宏。 1. 配置LMS模块相关宏。
配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_m目录下执行 make update_config命令配置"Kernel-&gt;Enable Lite Memory Sanitizer"中打开YES 配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_m目录下执行 make menuconfig命令配置"Kernel-&gt;Enable Lite Memory Sanitizer"中打开YES(如果没有这个选项,需要先勾选Enable Backtrace)
| 宏 | menuconfig选项 | 含义 | 取值 | | 宏 | menuconfig选项 | 含义 | 取值 |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
...@@ -65,7 +65,7 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信 ...@@ -65,7 +65,7 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
增加LMS检测编译选项-fsanitize=kernel-address。为避免编译器优化,增加-O0编译选项。 增加LMS检测编译选项-fsanitize=kernel-address。为避免编译器优化,增加-O0编译选项。
gcc与clang编译选项存在差异,参照如下示例: gcc与clang编译选项存在差异,参照如下示例:
``` ```
if ("$ohos_build_compiler_specified" == "gcc") { if ("$ohos_build_compiler_specified" == "gcc") {
cflags_c = [ cflags_c = [
...@@ -103,7 +103,11 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信 ...@@ -103,7 +103,11 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
### 示例代码 ### 示例代码
实例代码如下: 实例代码如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数Example_Lms_test。
请按上文避免编译器优化一节内容,修改osTest.c对应的 ./kernel/liteos_m/testsuites/BUILD.gn。
``` ```
#define PAGE_SIZE (0x1000U) #define PAGE_SIZE (0x1000U)
#define INDEX_MAX 20 #define INDEX_MAX 20
...@@ -162,65 +166,114 @@ UINT32 Example_Lms_test(VOID){ ...@@ -162,65 +166,114 @@ UINT32 Example_Lms_test(VOID){
### 结果验证 ### 结果验证
输出结果如下 输出结果示例如下 (根据实际运行环境,数据会有差异)
``` ```
######LmsTestOsmallocOverflow start ###### ######LmsTestOsmallocOverflow start ######
[ERR]* Kernel Address Sanitizer Error Detected Start * [ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected Start *****
[ERR]Heap buffer overflow error detected [ERR][TestLmsTsk]Heap buffer overflow error detected
[ERR]Illegal READ address at: [0x4157a3c8] [ERR][TestLmsTsk]Illegal READ address at: [0x21040414]
[ERR]Shadow memory address: [0x4157be3c : 4] Shadow memory value: [2] [ERR][TestLmsTsk]Shadow memory address: [0x21041e84 : 6] Shadow memory value: [2]
OsBackTrace fp = 0x402c0f88 psp, start = 21057d88, end = 21057e80
runTask->taskName = LmsTestCaseTask taskName = TestLmsTsk
runTask->taskID = 2 taskID = 5
***backtrace begin*** ----- traceback start -----
traceback fp fixed, trace using fp = 0x402c0fd0 traceback 0 -- lr = 0x210099f4
traceback 0 -- lr = 0x400655a4 fp = 0x402c0ff8 traceback 1 -- lr = 0x2101da6e
traceback 1 -- lr = 0x40065754 fp = 0x402c1010 traceback 2 -- lr = 0x2101db38
traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038 traceback 3 -- lr = 0x2101c494
traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca ----- traceback end -----
[LMS] Dump info around address [0x4157a3c8]:
[0x4157a3a0]: 00 00 00 00 00 00 00 00 | [0x4157be3a | 0]: 1 1 [LMS] Dump info around address [0x21040414]:
[0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
[0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0 [0x21040390]: 00 00 00 00 00 00 00 00 | [0x21041e7c | 4]: 1 1
[0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0 [0x21040398]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 0]: 1 1
[0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0 [0x210403a0]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 4]: 1 1
[0x4157a3c8]: [ba] dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: [2] 2 [0x210403a8]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 0]: 1 1
[0x4157a3d0]: 2c 1a 00 00 00 00 00 00 | [0x4157be3d | 0]: 2 3 [0x210403b0]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 4]: 1 1
[0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3 [0x210403b8]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 0]: 1 1
[0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3 [0x210403c0]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 4]: 1 1
[0x4157a3e8]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 4]: 3 3 [0x210403c8]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 0]: 1 1
[0x4157a3f0]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 0]: 3 3 [0x210403d0]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 4]: 1 1
[ERR]* Kernel Address Sanitizer Error Detected End * [0x210403d8]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 0]: 1 1
str[20]=0xffffffba [0x210403e0]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 4]: 1 1
[0x210403e8]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 0]: 1 1
[0x210403f0]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 4]: 1 1
[0x210403f8]: 40 1e 04 21 05 07 00 80 | [0x21041e83 | 0]: 2 2
[0x21040400]: 00 00 00 00 00 00 00 00 | [0x21041e83 | 4]: 0 0
[0x21040408]: 00 00 00 00 00 00 00 00 | [0x21041e84 | 0]: 0 0
[0x21040410]: 00 00 00 00 [f8] 03 04 21 | [0x21041e84 | 4]: 0 [2]
[0x21040418]: 00 8b 06 00 00 00 00 00 | [0x21041e85 | 0]: 2 3
[0x21040420]: 00 00 00 00 00 00 00 00 | [0x21041e85 | 4]: 3 3
[0x21040428]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 0]: 3 3
[0x21040430]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 4]: 3 3
[0x21040438]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 0]: 3 3
[0x21040440]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 4]: 3 3
[0x21040448]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 0]: 3 3
[0x21040450]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 4]: 3 3
[0x21040458]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 0]: 3 3
[0x21040460]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 4]: 3 3
[0x21040468]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 0]: 3 3
[0x21040470]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 4]: 3 3
[0x21040478]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 0]: 3 3
[0x21040480]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 4]: 3 3
[0x21040488]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 0]: 3 3
[0x21040490]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 4]: 3 3
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected End *****
str[20]=0xfffffff8
######LmsTestOsmallocOverflow stop ###### ######LmsTestOsmallocOverflow stop ######
###### LmsTestUseAfterFree start ######
[ERR]* Kernel Address Sanitizer Error Detected Start * ######LmsTestUseAfterFree start ######
[ERR]Use after free error detected [ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected Start *****
[ERR]Illegal READ address at: [0x4157a3d4] [ERR][TestLmsTsk]Use after free error detected
[ERR]Shadow memory address: [0x4157be3d : 2] Shadow memory value: [3] [ERR][TestLmsTsk]Illegal READ address at: [0x2104041c]
OsBackTrace fp = 0x402c0f90 [ERR][TestLmsTsk]Shadow memory address: [0x21041e85 : 2] Shadow memory value: [3]
runTask->taskName = LmsTestCaseTask psp, start = 21057d90, end = 21057e80
runTask->taskID = 2 taskName = TestLmsTsk
***backtrace begin*** taskID = 5
traceback fp fixed, trace using fp = 0x402c0fd8 ----- traceback start -----
traceback 0 -- lr = 0x40065680 fp = 0x402c0ff8 traceback 0 -- lr = 0x210099f4
traceback 1 -- lr = 0x40065758 fp = 0x402c1010 traceback 1 -- lr = 0x2101daec
traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038 traceback 2 -- lr = 0x2101db3c
traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca traceback 3 -- lr = 0x2101c494
[LMS] Dump info around address [0x4157a3d4]: ----- traceback end -----
[0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
[0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0 [LMS] Dump info around address [0x2104041c]:
[0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0
[0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0 [0x21040398]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 0]: 1 1
[0x4157a3c8]: ba dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: 2 2 [0x210403a0]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 4]: 1 1
[0x4157a3d0]: 2c 1a 00 00 [00] 00 00 00 | [0x4157be3d | 0]: 2 [3] [0x210403a8]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 0]: 1 1
[0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3 [0x210403b0]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 4]: 1 1
[0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3 [0x210403b8]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 0]: 1 1
[0x4157a3e8]: ba dc cd ab c8 a3 57 41 | [0x4157be3e | 4]: 2 2 [0x210403c0]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 4]: 1 1
[0x4157a3f0]: 0c 1a 00 00 00 00 00 00 | [0x4157be3f | 0]: 2 3 [0x210403c8]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 0]: 1 1
[0x4157a3f8]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 4]: 3 3 [0x210403d0]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 4]: 1 1
[ERR]* Kernel Address Sanitizer Error Detected End * [0x210403d8]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 0]: 1 1
[0x210403e0]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 4]: 1 1
[0x210403e8]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 0]: 1 1
[0x210403f0]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 4]: 1 1
[0x210403f8]: 40 1e 04 21 05 07 00 80 | [0x21041e83 | 0]: 2 2
[0x21040400]: 00 00 00 00 00 00 00 00 | [0x21041e83 | 4]: 0 0
[0x21040408]: 00 00 00 00 00 00 00 00 | [0x21041e84 | 0]: 0 0
[0x21040410]: 00 00 00 00 f8 03 04 21 | [0x21041e84 | 4]: 0 2
[0x21040418]: 05 8b 06 00 [00] 00 00 00 | [0x21041e85 | 0]: 2 [3]
[0x21040420]: 00 00 00 00 00 00 00 00 | [0x21041e85 | 4]: 3 3
[0x21040428]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 0]: 3 3
[0x21040430]: 14 04 04 21 00 84 06 00 | [0x21041e86 | 4]: 2 2
[0x21040438]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 0]: 3 3
[0x21040440]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 4]: 3 3
[0x21040448]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 0]: 3 3
[0x21040450]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 4]: 3 3
[0x21040458]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 0]: 3 3
[0x21040460]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 4]: 3 3
[0x21040468]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 0]: 3 3
[0x21040470]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 4]: 3 3
[0x21040478]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 0]: 3 3
[0x21040480]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 4]: 3 3
[0x21040488]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 0]: 3 3
[0x21040490]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 4]: 3 3
[0x21040498]: 00 00 00 00 00 00 00 00 | [0x21041e8d | 0]: 3 3
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected End *****
str[ 0]=0x 0 str[ 0]=0x 0
######LmsTestUseAfterFree stop ###### ######LmsTestUseAfterFree stop ######
``` ```
......
...@@ -42,7 +42,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细 ...@@ -42,7 +42,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
- IDENTITY类型UINTPTR,表示事件操作的主体对象。 - IDENTITY类型UINTPTR,表示事件操作的主体对象。
- Params类型UINTPTR,表示事件的参数。 - Params类型UINTPTR,表示事件的参数。
- 对文件fd读写操作的简易插桩示例: - 对文件fd读写操作的简易插桩示例:
``` ```
/* 假设自定义读操作为type: 1, 写操作为type: 2 */ /* 假设自定义读操作为type: 1, 写操作为type: 2 */
LOS_TRACE_EASY(1, fd, flag, size); /* 在读fd文件的适当位置插入 */ LOS_TRACE_EASY(1, fd, flag, size); /* 在读fd文件的适当位置插入 */
...@@ -62,7 +62,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细 ...@@ -62,7 +62,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
2. 定义FS模块的具体事件类型 2. 定义FS模块的具体事件类型
``` ```
/* 定义规范为#TYPE# = TRACE_#MOD#_FLAG | NUMBER, */ /* 定义规范为#TYPE# = TRACE_#MOD#_FLAG | NUMBER, */
FS_READ = TRACE_FS_FLAG | 0; /* 读文件 */ FS_READ = TRACE_FS_FLAG | 0; /* 读文件 */
...@@ -71,7 +71,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细 ...@@ -71,7 +71,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
3. 定义事件参数 3. 定义事件参数
``` ```
/* 定义规范为#TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ... */ /* 定义规范为#TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ... */
#define FS_READ_PARAMS(fp, fd, flag, size) fp, fd, flag, size /* 宏定义的参数对应于Trace缓冲区中记录的事件参数,用户可对任意参数字段进行裁剪 */ #define FS_READ_PARAMS(fp, fd, flag, size) fp, fd, flag, size /* 宏定义的参数对应于Trace缓冲区中记录的事件参数,用户可对任意参数字段进行裁剪 */
...@@ -80,7 +80,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细 ...@@ -80,7 +80,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
4. 在目标代码中插桩 4. 在目标代码中插桩
``` ```
/* 定义规范为LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...)) */ /* 定义规范为LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...)) */
LOS_TRACE(FS_READ, fp, fd, flag, size); /* 读文件操作的代码桩 */ LOS_TRACE(FS_READ, fp, fd, flag, size); /* 读文件操作的代码桩 */
...@@ -178,7 +178,9 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细 ...@@ -178,7 +178,9 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
示例代码如下: 示例代码如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleTraceTest。
``` ```
#include "los_trace.h" #include "los_trace.h"
UINT32 g_traceTestTaskId; UINT32 g_traceTestTaskId;
...@@ -200,9 +202,9 @@ VOID Example_Trace(VOID) ...@@ -200,9 +202,9 @@ VOID Example_Trace(VOID)
LOS_TraceStop(); LOS_TraceStop();
LOS_TraceRecordDump(FALSE); LOS_TraceRecordDump(FALSE);
} }
UINT32 Example_Trace_test(VOID){ UINT32 ExampleTraceTest(VOID){
UINT32 ret; UINT32 ret;
TSK_INIT_PARAM_S traceTestTask; TSK_INIT_PARAM_S traceTestTask = { 0 };
/* 创建用于trace测试的任务 */ /* 创建用于trace测试的任务 */
memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S)); memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S));
traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace; traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace;
...@@ -229,7 +231,7 @@ UINT32 Example_Trace_test(VOID){ ...@@ -229,7 +231,7 @@ UINT32 Example_Trace_test(VOID){
输出结果如下: 输出结果如下:
``` ```
***TraceInfo begin*** ***TraceInfo begin***
clockFreq = 50000000 clockFreq = 50000000
...@@ -244,6 +246,8 @@ Index Time(cycles) EventType CurTask Identity params ...@@ -244,6 +246,8 @@ Index Time(cycles) EventType CurTask Identity params
6 0x3706f804 0x45 0x1 0x0 0x1f 0x4 0x0 6 0x3706f804 0x45 0x1 0x0 0x1f 0x4 0x0
7 0x37070e59 0x45 0x0 0x1 0x0 0x8 0x1f 7 0x37070e59 0x45 0x0 0x1 0x0 0x8 0x1f
***TraceInfo end*** ***TraceInfo end***
根据实际运行环境,上文中的数据会有差异,非固定结果
``` ```
输出的事件信息包括:发生时间、事件类型、事件发生在哪个任务中、事件操作的主体对象、事件的其他参数。 输出的事件信息包括:发生时间、事件类型、事件发生在哪个任务中、事件操作的主体对象、事件的其他参数。
...@@ -258,7 +262,7 @@ Index Time(cycles) EventType CurTask Identity params ...@@ -258,7 +262,7 @@ Index Time(cycles) EventType CurTask Identity params
下面以序号为0的输出项为例,进行说明。 下面以序号为0的输出项为例,进行说明。
``` ```
Index Time(cycles) EventType CurTask Identity params Index Time(cycles) EventType CurTask Identity params
0 0x366d5e88 0x45 0x1 0x0 0x1f 0x4 0 0x366d5e88 0x45 0x1 0x0 0x1f 0x4
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
| **功能分类** | **接口描述** | | **功能分类** | **接口描述** |
| -------- | -------- | | -------- | -------- |
| 置1/清0标志位 | -&nbsp;LOS_BitmapSet:对状态字的某一标志位进行置1操作<br/>-&nbsp;LOS_BitmapClr:对状态字的某一标志位进行清0操作 | | 置1/清0标志位 | -&nbsp;LOS_BitmapSet:对状态字的某一标志位进行置1操作<br/>-&nbsp;LOS_BitmapClr:对状态字的某一标志位进行清0操作 |
| 获取标志位为1的bit位 | -&nbsp;LOS_HighBitGet:获取状态字中为1的最高位<br/>-&nbsp;LOS_LowBitGet:获取状态字中为1的最低位 | | 获取标志位为1的bit位 | -&nbsp;LOS_HighBitGet:获取状态字中为1的最高位<br/>-&nbsp;LOS_LowBitGet:获取状态字中为1的最低位 |
| 连续bit位操作 | -&nbsp;LOS_BitmapSetNBits:对状态字的连续标志位进行置1操作<br/>-&nbsp;LOS_BitmapClrNBits:对状态字的连续标志位进行清0操作<br/>-&nbsp;LOS_BitmapFfz:获取从最低有效位开始的第一个0的bit位 | | 连续bit位操作 | -&nbsp;LOS_BitmapSetNBits:对状态字的连续标志位进行置1操作<br/>-&nbsp;LOS_BitmapClrNBits:对状态字的连续标志位进行清0操作<br/>-&nbsp;LOS_BitmapFfz:获取从最低有效位开始的第一个0的bit位 |
## 编程实例 ## 编程实例
...@@ -34,7 +34,10 @@ ...@@ -34,7 +34,10 @@
4. 获取标志位为1的最低bit位。 4. 获取标志位为1的最低bit位。
### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数BitSample。
``` ```
#include "los_bitmap.h" #include "los_bitmap.h"
#include "los_printf.h" #include "los_printf.h"
......
...@@ -17,10 +17,10 @@ ...@@ -17,10 +17,10 @@
| 增加节点 | -&nbsp;LOS_ListAdd:将指定节点插入到双向链表头端<br/>-&nbsp;LOS_ListHeadInsert:将指定节点插入到双向链表头端,同LOS_ListAdd<br/>-&nbsp;LOS_ListTailInsert:将指定节点插入到双向链表尾端 | | 增加节点 | -&nbsp;LOS_ListAdd:将指定节点插入到双向链表头端<br/>-&nbsp;LOS_ListHeadInsert:将指定节点插入到双向链表头端,同LOS_ListAdd<br/>-&nbsp;LOS_ListTailInsert:将指定节点插入到双向链表尾端 |
| 增加链表 | -&nbsp;LOS_ListAddList:将指定链表的头端插入到双向链表头端<br/>-&nbsp;LOS_ListHeadInsertList:将指定链表的头端插入到双向链表头端<br/>-&nbsp;LOS_ListTailInsertList:将指定链表的尾端插入到双向链表头端 | | 增加链表 | -&nbsp;LOS_ListAddList:将指定链表的头端插入到双向链表头端<br/>-&nbsp;LOS_ListHeadInsertList:将指定链表的头端插入到双向链表头端<br/>-&nbsp;LOS_ListTailInsertList:将指定链表的尾端插入到双向链表头端 |
| 删除节点 | -&nbsp;LOS_ListDelete:将指定节点从链表中删除<br/>-&nbsp;LOS_ListDelInit:将指定节点从链表中删除,并使用该节点初始化链表 | | 删除节点 | -&nbsp;LOS_ListDelete:将指定节点从链表中删除<br/>-&nbsp;LOS_ListDelInit:将指定节点从链表中删除,并使用该节点初始化链表 |
| 判断双向链表 | -&nbsp;LOS_ListEmpty:判断链表是否为空<br/>-&nbsp;LOS_DL_LIST_IS_END:判断指定链表节点是否为链表尾端LOS_DL_LIST_IS_ON_QUEUE:判断链表节点是否在双向链表里 | | 判断双向链表 | -&nbsp;LOS_ListEmpty:判断链表是否为空<br/>-&nbsp;LOS_DL_LIST_IS_END:判断指定链表节点是否为链表尾端<br/>-&nbsp;LOS_DL_LIST_IS_ON_QUEUE:判断链表节点是否在双向链表里 |
| 获取结构体信息 | -&nbsp;LOS_OFF_SET_OF:获取指定结构体内的成员相对于结构体起始地址的偏移量<br/>-&nbsp;LOS_DL_LIST_ENTRY:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称<br/>-&nbsp;LOS_ListPeekHeadType:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListRemoveHeadType:获取双向链表中第一个链表节点所在的结构体地址,并把第一个链表节点从链表中删除。接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListNextType:获取双向链表中指定链表节点的下一个节点所在的结构体地址。接口的第一个入参表示的是链表中的头节点,第二个入参是指定的链表节点,第三个入参是要获取的结构体名称,第四个入参是链表在该结构体中的名称。如果链表节点下一个为链表头结点为空,返回NULL。| | 获取结构体信息 | -&nbsp;LOS_OFF_SET_OF:获取指定结构体内的成员相对于结构体起始地址的偏移量<br/>-&nbsp;LOS_DL_LIST_ENTRY:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称<br/>-&nbsp;LOS_ListPeekHeadType:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListRemoveHeadType:获取双向链表中第一个链表节点所在的结构体地址,并把第一个链表节点从链表中删除。接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListNextType:获取双向链表中指定链表节点的下一个节点所在的结构体地址。接口的第一个入参表示的是链表中的头节点,第二个入参是指定的链表节点,第三个入参是要获取的结构体名称,第四个入参是链表在该结构体中的名称。如果链表节点下一个为链表头结点为空,返回NULL。|
| 遍历双向链表 | -&nbsp;LOS_DL_LIST_FOR_EACH:遍历双向链表<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_SAFE:遍历双向链表,并存储当前节点的后继节点用于安全校验 | | 遍历双向链表 | -&nbsp;LOS_DL_LIST_FOR_EACH:遍历双向链表<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_SAFE:遍历双向链表,并存储当前节点的后继节点用于安全校验 |
| 遍历包含双向链表的结构体 | -&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY:遍历指定双向链表,获取包含该链表节点的结构体地址<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY_SAFE:遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址 | | 遍历包含双向链表的结构体 | -&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY:遍历指定双向链表,获取包含该链表节点的结构体地址<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY_SAFE:遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址 |
## 开发流程 ## 开发流程
...@@ -48,10 +48,10 @@ ...@@ -48,10 +48,10 @@
> - 如果链表节点的内存是动态申请的,删除节点时,要注意释放内存。 > - 如果链表节点的内存是动态申请的,删除节点时,要注意释放内存。
**编程实例** ## 编程实例
**实例描述**
### 实例描述
本实例实现如下功能: 本实例实现如下功能:
...@@ -64,7 +64,11 @@ ...@@ -64,7 +64,11 @@
4. 测试操作是否成功。 4. 测试操作是否成功。
### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数ListSample
示例代码如下:
``` ```
#include "stdio.h" #include "stdio.h"
......
...@@ -15,22 +15,24 @@ musl libc库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony ...@@ -15,22 +15,24 @@ musl libc库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony
标准库支持接口的详细情况请参考C库的API文档,其中也涵盖了与POSIX标准之间的差异说明。 标准库支持接口的详细情况请参考C库的API文档,其中也涵盖了与POSIX标准之间的差异说明。
## 操作实例 ### 编程实例
#### 实例描述
在本示例中,主线程创建了THREAD_NUM个子线程,每个子线程启动后等待被主线程唤醒,主线程成功唤醒所有子线程后,子线程继续执行直至生命周期结束,同时主线程通过pthread_join方法等待所有线程执行结束。 在本示例中,主线程创建了THREAD_NUM个子线程,每个子线程启动后等待被主线程唤醒,主线程成功唤醒所有子线程后,子线程继续执行直至生命周期结束,同时主线程通过pthread_join方法等待所有线程执行结束。
#### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数ExamplePosix。
示例代码如下:
``` ```
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h> #include <pthread.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define THREAD_NUM 3 #define THREAD_NUM 3
int g_startNum = 0; /* 启动的线程数 */ int g_startNum = 0; /* 启动的线程数 */
int g_wakenNum = 0; /* 唤醒的线程数 */ int g_wakenNum = 0; /* 唤醒的线程数 */
...@@ -40,10 +42,8 @@ struct testdata { ...@@ -40,10 +42,8 @@ struct testdata {
pthread_cond_t cond; pthread_cond_t cond;
} g_td; } g_td;
/* /* 子线程入口函数 */
* 子线程入口函数 static VOID *ChildThreadFunc(VOID *arg)
*/
static void *ChildThreadFunc(void *arg)
{ {
int rc; int rc;
pthread_t self = pthread_self(); pthread_t self = pthread_self();
...@@ -51,7 +51,7 @@ static void *ChildThreadFunc(void *arg) ...@@ -51,7 +51,7 @@ static void *ChildThreadFunc(void *arg)
/* 获取mutex锁 */ /* 获取mutex锁 */
rc = pthread_mutex_lock(&g_td.mutex); rc = pthread_mutex_lock(&g_td.mutex);
if (rc != 0) { if (rc != 0) {
printf("ERROR:take mutex lock failed, error code is %d!\n", rc); dprintf("ERROR:take mutex lock failed, error code is %d!\n", rc);
goto EXIT; goto EXIT;
} }
...@@ -61,7 +61,7 @@ static void *ChildThreadFunc(void *arg) ...@@ -61,7 +61,7 @@ static void *ChildThreadFunc(void *arg)
/* 等待cond条件变量 */ /* 等待cond条件变量 */
rc = pthread_cond_wait(&g_td.cond, &g_td.mutex); rc = pthread_cond_wait(&g_td.cond, &g_td.mutex);
if (rc != 0) { if (rc != 0) {
printf("ERROR: pthread condition wait failed, error code is %d!\n", rc); dprintf("ERROR: pthread condition wait failed, error code is %d!\n", rc);
(void)pthread_mutex_unlock(&g_td.mutex); (void)pthread_mutex_unlock(&g_td.mutex);
goto EXIT; goto EXIT;
} }
...@@ -69,7 +69,7 @@ static void *ChildThreadFunc(void *arg) ...@@ -69,7 +69,7 @@ static void *ChildThreadFunc(void *arg)
/* 尝试获取mutex锁,正常场景,此处无法获取锁 */ /* 尝试获取mutex锁,正常场景,此处无法获取锁 */
rc = pthread_mutex_trylock(&g_td.mutex); rc = pthread_mutex_trylock(&g_td.mutex);
if (rc == 0) { if (rc == 0) {
printf("ERROR: mutex gets an abnormal lock!\n"); dprintf("ERROR: mutex gets an abnormal lock!\n");
goto EXIT; goto EXIT;
} }
...@@ -79,14 +79,14 @@ static void *ChildThreadFunc(void *arg) ...@@ -79,14 +79,14 @@ static void *ChildThreadFunc(void *arg)
/* 释放mutex锁 */ /* 释放mutex锁 */
rc = pthread_mutex_unlock(&g_td.mutex); rc = pthread_mutex_unlock(&g_td.mutex);
if (rc != 0) { if (rc != 0) {
printf("ERROR: mutex release failed, error code is %d!\n", rc); dprintf("ERROR: mutex release failed, error code is %d!\n", rc);
goto EXIT; goto EXIT;
} }
EXIT: EXIT:
return NULL; return NULL;
} }
static int testcase(void) static int ExamplePosix(VOID)
{ {
int i, rc; int i, rc;
pthread_t thread[THREAD_NUM]; pthread_t thread[THREAD_NUM];
...@@ -94,14 +94,14 @@ static int testcase(void) ...@@ -94,14 +94,14 @@ static int testcase(void)
/* 初始化mutex锁 */ /* 初始化mutex锁 */
rc = pthread_mutex_init(&g_td.mutex, NULL); rc = pthread_mutex_init(&g_td.mutex, NULL);
if (rc != 0) { if (rc != 0) {
printf("ERROR: mutex init failed, error code is %d!\n", rc); dprintf("ERROR: mutex init failed, error code is %d!\n", rc);
goto ERROROUT; goto ERROROUT;
} }
/* 初始化cond条件变量 */ /* 初始化cond条件变量 */
rc = pthread_cond_init(&g_td.cond, NULL); rc = pthread_cond_init(&g_td.cond, NULL);
if (rc != 0) { if (rc != 0) {
printf("ERROR: pthread condition init failed, error code is %d!\n", rc); dprintf("ERROR: pthread condition init failed, error code is %d!\n", rc);
goto ERROROUT; goto ERROROUT;
} }
...@@ -109,10 +109,11 @@ static int testcase(void) ...@@ -109,10 +109,11 @@ static int testcase(void)
for (i = 0; i < THREAD_NUM; i++) { for (i = 0; i < THREAD_NUM; i++) {
rc = pthread_create(&thread[i], NULL, ChildThreadFunc, NULL); rc = pthread_create(&thread[i], NULL, ChildThreadFunc, NULL);
if (rc != 0) { if (rc != 0) {
printf("ERROR: pthread create failed, error code is %d!\n", rc); dprintf("ERROR: pthread create failed, error code is %d!\n", rc);
goto ERROROUT; goto ERROROUT;
} }
} }
dprintf("pthread_create ok\n");
/* 等待所有子线程都完成mutex锁的获取 */ /* 等待所有子线程都完成mutex锁的获取 */
while (g_startNum < THREAD_NUM) { while (g_startNum < THREAD_NUM) {
...@@ -122,14 +123,14 @@ static int testcase(void) ...@@ -122,14 +123,14 @@ static int testcase(void)
/* 获取mutex锁,确保所有子线程都阻塞在pthread_cond_wait上 */ /* 获取mutex锁,确保所有子线程都阻塞在pthread_cond_wait上 */
rc = pthread_mutex_lock(&g_td.mutex); rc = pthread_mutex_lock(&g_td.mutex);
if (rc != 0) { if (rc != 0) {
printf("ERROR: mutex lock failed, error code is %d\n", rc); dprintf("ERROR: mutex lock failed, error code is %d\n", rc);
goto ERROROUT; goto ERROROUT;
} }
/* 释放mutex锁 */ /* 释放mutex锁 */
rc = pthread_mutex_unlock(&g_td.mutex); rc = pthread_mutex_unlock(&g_td.mutex);
if (rc != 0) { if (rc != 0) {
printf("ERROR: mutex unlock failed, error code is %d!\n", rc); dprintf("ERROR: mutex unlock failed, error code is %d!\n", rc);
goto ERROROUT; goto ERROROUT;
} }
...@@ -137,7 +138,7 @@ static int testcase(void) ...@@ -137,7 +138,7 @@ static int testcase(void)
/* 在cond条件变量上广播信号 */ /* 在cond条件变量上广播信号 */
rc = pthread_cond_signal(&g_td.cond); rc = pthread_cond_signal(&g_td.cond);
if (rc != 0) { if (rc != 0) {
printf("ERROR: pthread condition failed, error code is %d!\n", rc); dprintf("ERROR: pthread condition failed, error code is %d!\n", rc);
goto ERROROUT; goto ERROROUT;
} }
} }
...@@ -146,52 +147,42 @@ static int testcase(void) ...@@ -146,52 +147,42 @@ static int testcase(void)
/* 检查是否所有子线程都已被唤醒 */ /* 检查是否所有子线程都已被唤醒 */
if (g_wakenNum != THREAD_NUM) { if (g_wakenNum != THREAD_NUM) {
printf("ERROR: not all threads awaken, only %d thread(s) awaken!\n", g_wakenNum); dprintf("ERROR: not all threads awaken, only %d thread(s) awaken!\n", g_wakenNum);
goto ERROROUT; goto ERROROUT;
} }
dprintf("all threads awaked\n");
/* join所有子线程,即等待其结束 */ /* join所有子线程,即等待其结束 */
for (i = 0; i < THREAD_NUM; i++) { for (i = 0; i < THREAD_NUM; i++) {
rc = pthread_join(thread[i], NULL); rc = pthread_join(thread[i], NULL);
if (rc != 0) { if (rc != 0) {
printf("ERROR: pthread join failed, error code is %d!\n", rc); dprintf("ERROR: pthread join failed, error code is %d!\n", rc);
goto ERROROUT; goto ERROROUT;
} }
} }
dprintf("all threads join ok\n");
/* 销毁cond条件变量 */ /* 销毁cond条件变量 */
rc = pthread_cond_destroy(&g_td.cond); rc = pthread_cond_destroy(&g_td.cond);
if (rc != 0) { if (rc != 0) {
printf("ERROR: pthread condition destroy failed, error code is %d!\n", rc); dprintf("ERROR: pthread condition destroy failed, error code is %d!\n", rc);
goto ERROROUT; goto ERROROUT;
} }
return 0; return 0;
ERROROUT: ERROROUT:
return -1; return -1;
} }
```
/* #### 验证结果
* 示例代码主函数
*/
int main(int argc, char *argv[])
{
int rc;
/* 启动测试函数 */ 输出结果如下:
rc = testcase();
if (rc != 0) {
printf("ERROR: testcase failed!\n");
}
return 0;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
``` ```
pthread_create ok
all threads awaked
all threads join ok
```
## 与Linux标准库差异 ## 与Linux标准库差异
...@@ -209,20 +200,17 @@ int main(int argc, char *argv[]) ...@@ -209,20 +200,17 @@ int main(int argc, char *argv[])
### 内存 ### 内存
**h2与Linux mmap的差异** **与Linux mmap的差异**
mmap接口原型为:void \*mmap (void \*addr, size_t length, int prot, int flags, int fd, off_t offset)。 mmap接口原型为:void \*mmap (void \*addr, size_t length, int prot, int flags, int fd, off_t offset)。
其中,参数fd的生命周期实现与Linux glibc存在差异。具体体现在,glibc在成功调用mmap进行映射后,可以立即释放fd句柄。在OpenHarmony内核中,不允许用户在映射成功后立即关闭相关fd,只允许在取消映射munmap后再进行fd的close操作。如果用户不进行fd的close操作,操作系统将在进程退出时对该fd进行回收。 其中,参数fd的生命周期实现与Linux glibc存在差异。具体体现在,glibc在成功调用mmap进行映射后,可以立即释放fd句柄。在OpenHarmony内核中,不允许用户在映射成功后立即关闭相关fd,只允许在取消映射munmap后再进行fd的close操作。如果用户不进行fd的close操作,操作系统将在进程退出时对该fd进行回收。
**代码举例**
**h2代码举例**
Linux目前支持的情况如下: Linux目前支持的情况如下:
``` ```
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
...@@ -239,7 +227,7 @@ int main(int argc, char *argv[]) ...@@ -239,7 +227,7 @@ int main(int argc, char *argv[])
perror("mmap"); perror("mmap");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */ close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
... ...
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
...@@ -247,7 +235,7 @@ int main(int argc, char *argv[]) ...@@ -247,7 +235,7 @@ int main(int argc, char *argv[])
OpenHarmony支持的情况如下: OpenHarmony支持的情况如下:
``` ```
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
...@@ -266,7 +254,7 @@ int main(int argc, char *argv[]) ...@@ -266,7 +254,7 @@ int main(int argc, char *argv[])
} }
... ...
munmap(addr, length); munmap(addr, length);
close(fd); /* Close fd after the munmap is canceled. */ close(fd); /* Close fd after the munmap is canceled. */
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
``` ```
......
...@@ -16,19 +16,17 @@ OpenHarmony系统通过对ARMv6架构中的LDREX和STREX进行封装,向用户 ...@@ -16,19 +16,17 @@ OpenHarmony系统通过对ARMv6架构中的LDREX和STREX进行封装,向用户
- LDREX Rx, [Ry] - LDREX Rx, [Ry]
读取内存中的值,并标记对该段内存的独占访问: 读取内存中的值,并标记对该段内存的独占访问:
- 读取寄存器Ry指向的4字节内存数据,保存到Rx寄存器中。 - 读取寄存器Ry指向的4字节内存数据,保存到Rx寄存器中。
- 对Ry指向的内存区域添加独占访问标记。 - 对Ry指向的内存区域添加独占访问标记。
- STREX Rf, Rx, [Ry] - STREX Rf, Rx, [Ry]
检查内存是否有独占访问标记,如果有则更新内存值并清空标记,否则不更新内存: 检查内存是否有独占访问标记,如果有则更新内存值并清空标记,否则不更新内存:
- 有独占访问标记 - 有独占访问标记
- 将寄存器Rx中的值更新到寄存器Ry指向的内存。 - 将寄存器Rx中的值更新到寄存器Ry指向的内存。
- 标志寄存器Rf置为0。 - 标志寄存器Rf置为0。
- 没有独占访问标记 - 没有独占访问标记
- 不更新内存。 - 不更新内存。
- 标志寄存器Rf置为1。 - 标志寄存器Rf置为1。
- 判断标志寄存器 - 判断标志寄存器
- 标志寄存器为0时,退出循环,原子操作结束。 - 标志寄存器为0时,退出循环,原子操作结束。
...@@ -40,36 +38,36 @@ OpenHarmony系统通过对ARMv6架构中的LDREX和STREX进行封装,向用户 ...@@ -40,36 +38,36 @@ OpenHarmony系统通过对ARMv6架构中的LDREX和STREX进行封装,向用户
### 接口说明 ### 接口说明
OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口详细信息可以查看API参考 OpenHarmony LiteOS-A内核的原子操作模块提供以下几种功能
**表1** 原子操作接口说明 **表1** 原子操作接口说明
| 功能分类 | 接口**名称** | 描述 | | 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- | | ------------ | ----------------------- | --------------------------- |
| 读 | LOS_AtomicRead | 读取32bit原子数据 | | 读 | LOS_AtomicRead | 读取32bit原子数据 |
| 读 | LOS_Atomic64Read | 读取64bit原子数据 | | 读 | LOS_Atomic64Read | 读取64bit原子数据 |
| 写 | LOS_AtomicSet | 设置32bit原子数据 | | 写 | LOS_AtomicSet | 设置32bit原子数据 |
| 写 | LOS_Atomic64Set | 设置64bit原子数据 | | 写 | LOS_Atomic64Set | 设置64bit原子数据 |
| 加 | LOS_AtomicAdd | 对32bit原子数据做加法 | | 加 | LOS_AtomicAdd | 对32bit原子数据做加法 |
| 加 | LOS_Atomic64Add | 对64bit原子数据做加法 | | 加 | LOS_Atomic64Add | 对64bit原子数据做加法 |
| 加 | LOS_AtomicInc | 对32bit原子数据做加1 | | 加 | LOS_AtomicInc | 对32bit原子数据做加1 |
| 加 | LOS_Atomic64Inc | 对64bit原子数据做加1 | | 加 | LOS_Atomic64Inc | 对64bit原子数据做加1 |
| 加 | LOS_AtomicIncRet | 对32bit原子数据做加1并返回 | | 加 | LOS_AtomicIncRet | 对32bit原子数据做加1并返回 |
| 加 | LOS_Atomic64IncRet | 对64bit原子数据做加1并返回 | | 加 | LOS_Atomic64IncRet | 对64bit原子数据做加1并返回 |
| 减 | LOS_AtomicSub | 对32bit原子数据做减法 | | 减 | LOS_AtomicSub | 对32bit原子数据做减法 |
| 减 | LOS_Atomic64Sub | 对64bit原子数据做减法 | | 减 | LOS_Atomic64Sub | 对64bit原子数据做减法 |
| 减 | LOS_AtomicDec | 对32bit原子数据做减1 | | 减 | LOS_AtomicDec | 对32bit原子数据做减1 |
| 减 | LOS_Atomic64Dec | 对64bit原子数据做减1 | | 减 | LOS_Atomic64Dec | 对64bit原子数据做减1 |
| 减 | LOS_AtomicDecRet | 对32bit原子数据做减1并返回 | | 减 | LOS_AtomicDecRet | 对32bit原子数据做减1并返回 |
| 减 | LOS_Atomic64DecRet | 对64bit原子数据做减1并返回 | | 减 | LOS_Atomic64DecRet | 对64bit原子数据做减1并返回 |
| 交换 | LOS_AtomicXchgByte | 交换8bit内存数据 | | 交换 | LOS_AtomicXchgByte | 交换8bit内存数据 |
| 交换 | LOS_AtomicXchg16bits | 交换16bit内存数据 | | 交换 | LOS_AtomicXchg16bits | 交换16bit内存数据 |
| 交换 | LOS_AtomicXchg32bits | 交换32bit内存数据 | | 交换 | LOS_AtomicXchg32bits | 交换32bit内存数据 |
| 交换 | LOS_AtomicXchg64bits | 交换64bit内存数据 | | 交换 | LOS_AtomicXchg64bits | 交换64bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchgByte | 比较相同后交换8bit内存数据 | | 先比较后交换 | LOS_AtomicCmpXchgByte | 比较相同后交换8bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchg16bits | 比较相同后交换16bit内存数据 | | 先比较后交换 | LOS_AtomicCmpXchg16bits | 比较相同后交换16bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchg32bits | 比较相同后交换32bit内存数据 | | 先比较后交换 | LOS_AtomicCmpXchg32bits | 比较相同后交换32bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchg64bits | 比较相同后交换64bit内存数据 | | 先比较后交换 | LOS_AtomicCmpXchg64bits | 比较相同后交换64bit内存数据 |
### 开发流程 ### 开发流程
...@@ -77,7 +75,7 @@ OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口 ...@@ -77,7 +75,7 @@ OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口
有多个任务对同一个内存数据进行加减或交换等操作时,使用原子操作保证结果的可预知性。 有多个任务对同一个内存数据进行加减或交换等操作时,使用原子操作保证结果的可预知性。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 原子操作接口仅支持整型数据。 > 原子操作接口仅支持整型数据。
### 编程实例 ### 编程实例
...@@ -96,7 +94,7 @@ OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口 ...@@ -96,7 +94,7 @@ OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口
示例代码如下: 示例代码如下:
``` ```
#include "los_hwi.h" #include "los_hwi.h"
#include "los_atomic.h" #include "los_atomic.h"
...@@ -159,7 +157,7 @@ UINT32 Example_AtomicTaskEntry(VOID) ...@@ -159,7 +157,7 @@ UINT32 Example_AtomicTaskEntry(VOID)
**结果验证** **结果验证**
``` ```
g_sum = 0 g_sum = 0
``` ```
\ No newline at end of file
...@@ -3,16 +3,28 @@ ...@@ -3,16 +3,28 @@
## 基本概念 ## 基本概念
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,这个过程就叫做中断。通过中断机制,可以使CPU避免把大量时间耗费在等待、查询外设状态的操作上,大大提高系统实时性以及执行效率。 中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,出现了一个必须由CPU立即处理的事务,此时CPU暂时中止当前程序的执行转而处理这个事务,这个过程就叫做中断。通过中断机制,可以使CPU避免把大量时间耗费在等待、查询外设状态的操作上,大大提高系统实时性以及执行效率。
目前的中断支持有
+ 中断初始化
+ 中断创建
+ 开/关中断
+ 恢复中断
+ 删除中断
异常处理是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作,例如虚拟内存缺页异常、打印异常发生时函数的调用栈信息、CPU现场信息、任务的堆栈情况等。 异常处理是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作,例如虚拟内存缺页异常、打印异常发生时函数的调用栈信息、CPU现场信息、任务的堆栈情况等。
## 运行机制 ## 运行机制
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,产生一个中断信号,该信号连接至中断控制器。中断控制器是一方面接收其它外设中断引脚的输入,另一方面它会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和GIC(General Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。CPU收到中断控制器发送的中断信号后,中断当前任务来响应中断请求。 外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,产生一个中断信号,该信号连接至中断控制器。
中断控制器一方面接收其它外设中断引脚的输入,另一方面会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和GIC(General Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。
异常处理就是可以打断CPU正常运行流程的一些事情,如未定义指令异常、试图修改只读的数据异常、不对齐的地址访问异常等。当异常发生时,CPU暂停当前的程序,先处理异常事件,然后再继续执行被异常打断的程序。 CPU收到中断控制器发送的中断信号后,中断当前任务来响应中断请求。
异常指可以打断CPU正常运行流程的一些事情,如未定义指令异常、试图修改只读的数据异常、不对齐的地址访问异常等。当异常发生时,CPU暂停当前的程序,先处理异常事件,然后再继续执行被异常打断的程序。
以ARMv7-a架构为例,中断和异常处理的入口为中断向量表,中断向量表包含各个中断和异常处理的入口函数。 以ARMv7-a架构为例,中断和异常处理的入口为中断向量表,中断向量表包含各个中断和异常处理的入口函数。
...@@ -28,11 +40,27 @@ ...@@ -28,11 +40,27 @@
异常处理为内部机制,不对外提供接口,中断模块提供对外接口如下: 异常处理为内部机制,不对外提供接口,中断模块提供对外接口如下:
| 功能分类 | 接口描述 | ##### 创建删除中断
| -------- | -------- |
| 创建和删除中断 | -&nbsp;LOS_HwiCreate:中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,会调用该中断处理程序<br/>-&nbsp;LOS_HwiDelete:删除中断 | | 接口名 | 接口描述 |
| 打开和关闭所有中断 | -&nbsp;LOS_IntUnLock:打开当前处理器所有中断响应<br/>-&nbsp;LOS_IntLock:关闭当前处理器所有中断响应<br/>-&nbsp;LOS_IntRestore:恢复到使用LOS_IntLock关闭所有中断之前的状态 | | :------------ | :----------------------------------------------------------- |
| 获取系统支持的最大中断数 | LOS_GetSystemHwiMaximum:获取系统支持的最大中断数 | | LOS_HwiCreate | 中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,会调用该中断处理程序 |
| LOS_HwiDelete | 根据所提供的中断号删除中断 |
##### 开/关中断
| 接口名 | 接口描述 |
| -------------- | ------------------------------------------- |
| LOS_IntUnlock | 打开当前处理器所有中断响应 |
| LOS_IntLock | 关闭当前处理器所有中断响应 |
| LOS_IntRestore | 与LOS_IntLock配套使用,恢复到使用LOS_IntLock关闭所有中断之前的状态 |
##### 获取系统中断信息
| 接口名 | 接口描述 |
| ----------------------- | ------------------------ |
| LOS_GetSystemHwiMaximum | 获取系统支持的最大中断数 |
### 开发流程 ### 开发流程
...@@ -53,32 +81,30 @@ ...@@ -53,32 +81,30 @@
2. 删除中断。 2. 删除中断。
代码实现如下,演示如何创建中断和删除中断,当指定的中断号HWI_NUM_TEST产生中断时,会调用中断处理函数: 代码实现如下,演示如何创建中断和删除中断,当指定的中断号HWI_NUM_TEST产生中断时,会调用中断处理函数(该示例代码的测试函数可以加在kernel/liteos_a/testsuites/kernel/src/osTest.c中的TestTaskEntry中进行测试):
```c
```
#include "los_hwi.h" #include "los_hwi.h"
/*中断处理函数*/ /*中断处理函数*/
STATIC VOID HwiUsrIrq(VOID) STATIC VOID HwiUsrIrq(VOID)
{ {
printf("in the func HwiUsrIrq \n"); PRINK("in the func HwiUsrIrq \n");
} }
static UINT32 Example_Interrupt(VOID) static UINT32 Example_Interrupt(VOID)
{ {
UINT32 ret; UINT32 ret;
HWI_HANDLE_T hwiNum = 7; HWI_HANDLE_T hwiNum = 7; // 7: 使用的中断号
HWI_PRIOR_T hwiPrio = 3; HWI_PRIOR_T hwiPrio = 3; // 3: 中断优先级
HWI_MODE_T mode = 0; HWI_MODE_T mode = 0;
HWI_ARG_T arg = 0; HWI_ARG_T arg = 0;
/*创建中断*/ /*创建中断*/
ret = LOS_HwiCreate(hwiNum, hwiPrio, mode, (HWI_PROC_FUNC)HwiUsrIrq, (HwiIrqParam *)arg); ret = LOS_HwiCreate(hwiNum, hwiPrio, mode, (HWI_PROC_FUNC)HwiUsrIrq, (HwiIrqParam *)arg);
if(ret == LOS_OK){ if (ret == LOS_OK) {
printf("Hwi create success!\n"); PRINK("Hwi create success!\n");
} else { } else {
printf("Hwi create failed!\n"); PRINK("Hwi create failed!\n");
return LOS_NOK; return LOS_NOK;
} }
...@@ -86,11 +112,11 @@ static UINT32 Example_Interrupt(VOID) ...@@ -86,11 +112,11 @@ static UINT32 Example_Interrupt(VOID)
LOS_TaskDelay(50); LOS_TaskDelay(50);
/*删除中断*/ /*删除中断*/
ret = LOS_HwiDelete(hwiNum, (HwiIrqParam *)arg); ret = LOS_HwiDelete(hwiNum, (HwiIrqParam *)arg);
if(ret == LOS_OK){ if (ret == LOS_OK) {
printf("Hwi delete success!\n"); PRINK("Hwi delete success!\n");
} else { } else {
printf("Hwi delete failed!\n"); PRINK("Hwi delete failed!\n");
return LOS_NOK; return LOS_NOK;
} }
return LOS_OK; return LOS_OK;
...@@ -102,7 +128,6 @@ static UINT32 Example_Interrupt(VOID) ...@@ -102,7 +128,6 @@ static UINT32 Example_Interrupt(VOID)
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
Hwi create success! Hwi create success!
Hwi delete success! Hwi delete success!
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## 基本概念 ## 基本概念
进程是系统资源管理的最小单元。OpenHarmony LiteOS-A内核提供的进程模块主要用于实现用户态进程的隔离,内核态被视为一个进程空间,不存在其它进程(KIdle除外,KIdle进程是系统提供的空闲进程,和KProcess共享一个进程空间)。 进程是系统资源管理的最小单元。OpenHarmony LiteOS-A 内核提供的进程模块主要用于实现用户态进程的隔离,内核态被视为一个进程空间,不存在其它进程(KIdle除外,KIdle进程是系统提供的空闲进程,和KProcess共享一个进程空间。KProcess 是内核态进程的根进程,KIdle 是其子进程)。
- 进程模块主要为用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。 - 进程模块主要为用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。
...@@ -36,10 +36,10 @@ ...@@ -36,10 +36,10 @@
**进程状态迁移说明:** **进程状态迁移说明:**
- Init→Ready: - Init→Ready:
进程创建或fork时,拿到该进程控制块后进入Init状态,处于进程初始化阶段,当进程初始化完成将进程插入调度队列,此时进程进入就绪状态。 进程创建或 fork 时,拿到对应进程控制块后进入 Init 状态,即进程初始化阶段,当该阶段完成后进程将被插入调度队列,此时进程进入就绪状态。
- Ready→Running: - Ready→Running:
进程创建后进入就绪态,发生进程切换时,就绪列表中最高优先级的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存,但对外呈现的进程状态为运行态。 进程创建后进入就绪态,发生进程切换时,就绪列表中优先级最高且获得时间片的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存,但对外呈现的进程状态为运行态。
- Running→Pending: - Running→Pending:
进程在最后一个线程转为阻塞态时, 进程内所有的线程均处于阻塞态,此时进程同步进入阻塞态,然后发生进程切换。 进程在最后一个线程转为阻塞态时, 进程内所有的线程均处于阻塞态,此时进程同步进入阻塞态,然后发生进程切换。
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
进程由运行态转为就绪态的情况有以下两种: 进程由运行态转为就绪态的情况有以下两种:
1. 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。 1. 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。
2. 若进程的调度策略为LOS_SCHED_RR,且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。 2. 若进程的调度策略为 LOS_SCHED_RR(时间片轮转),且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。
- Running→Zombies: - Running→Zombies:
当进程的主线程或所有线程运行结束后,进程由运行态转为僵尸态,等待父进程回收资源。 当进程的主线程或所有线程运行结束后,进程由运行态转为僵尸态,等待父进程回收资源。
...@@ -78,16 +78,47 @@ OpenHarmony 提供的进程模块主要用于实现用户态进程的隔离, ...@@ -78,16 +78,47 @@ OpenHarmony 提供的进程模块主要用于实现用户态进程的隔离,
### 接口说明 ### 接口说明
**表1** 进程管理模块接口 ##### 表1 进程及进程组
| 接口名 | 接口描述 |
| ------------------------- | ---------------------- |
| LOS_GetCurrProcessID | 获取当前进程的进程ID |
| LOS_GetProcessGroupID | 获取指定进程的进程组ID |
| LOS_GetCurrProcessGroupID | 获取当前进程的进程组ID |
##### 表2 用户及用户组
| 接口名 | 接口描述 |
| ----------------- | ---------------------------------------- |
| LOS_GetUserID | 获取当前进程的用户ID |
| LOS_GetGroupID | 获取当前进程的用户组ID |
| LOS_CheckInGroups | 检查指定用户组ID是否在当前进程的用户组内 |
##### 表3 进程调度控制
| 接口名 | 接口 |
| ----------------------- | -------------------------------------------- |
| LOS_GetProcessScheduler | 获取指定进程的调度策略 |
| LOS_SetProcessScheduler | 设置指定进程的调度参数,包括优先级和调度策略 |
| LOS_SetProcessPriority | 设置进程优先级 |
| LOS_GetProcessPriority | 获取进程优先级 |
##### 表4 系统进程信息获取
| 接口名 | 接口描述 |
| --------------------------- | -------------------------- |
| LOS_GetSystemProcessMaximum | 获取系统支持的最大进程数目 |
| LOS_GetUsedPIDList | 获得已使用的进程ID列表 |
##### 表5 进程创建与结束
| 接口名 | 接口描述 |
| ---------- | -------------------------- |
| LOS_Fork | 创建子进程 |
| LOS_Wait | 等待子进程结束并回收子进程 |
| LOS_Waitid | 等待相应ID的进程结束 |
| LOS_Exit | 退出进程 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 进程调度参数控制 | -&nbsp;LOS_GetProcessScheduler:获取指定进程的调度策略<br/>-&nbsp;LOS_SetProcessScheduler:设置指定进程的调度参数,包括优先级和调度策略 |
| 等待回收子进程 | LOS_Wait:等待子进程结束并回收子进程 |
| 进程组 | -&nbsp;LOS_GetProcessGroupID:获取指定进程的进程组ID<br/>-&nbsp;LOS_GetCurrProcessGroupID:获取当前进程的进程组ID |
| 获取进程ID | LOS_GetCurrProcessID:获取当前进程的进程ID |
| 用户及用户组 | -&nbsp;LOS_GetUserID:获取当前进程的用户ID<br/>-&nbsp;LOS_GetGroupID:获取当前进程的用户组ID<br/>-&nbsp;LOS_CheckInGroups:检查指定用户组ID是否在当前进程的用户组内 |
| 系统支持的最大进程数 | LOS_GetSystemProcessMaximum:获取系统支持的最大进程数目 |
### 开发流程 ### 开发流程
...@@ -96,7 +127,7 @@ OpenHarmony 提供的进程模块主要用于实现用户态进程的隔离, ...@@ -96,7 +127,7 @@ OpenHarmony 提供的进程模块主要用于实现用户态进程的隔离,
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - idle线程的数量跟随CPU核心数,每个CPU均有一个相应的idle线程。 > - idle线程的数量跟随CPU核心数,每个CPU均有一个相应的idle线程。
> >
> - 不支持创建除KProcess和KIdle进程之外的其它内核态进程。 > - 不支持创建除KProcess和KIdle进程之外的其它内核态进程。
> >
> - 用户态进程通过系统调用进入内核态后创建的线程属于KProcess, 不属于当前用户态进程。 > - 用户态进程通过系统调用进入内核态后创建的线程属于KProcess, 不属于当前用户态进程。
...@@ -3,18 +3,18 @@ ...@@ -3,18 +3,18 @@
## 基本概念 ## 基本概念
OpenHarmony LiteOS-A内核 了高优先级优先+同优先级时间片轮转的抢占式调度机制,系统从启动开始基于real time的时间轴向前运行,使得该调度算法具有很好的实时性。 OpenHarmony LiteOS-A内核采用了高优先级优先 + 同优先级时间片轮转的抢占式调度机制,系统从启动开始基于real time的时间轴向前运行,使得该调度算法具有很好的实时性。
OpenHarmony 的调度算法将tickless机制天然嵌入到调度算法中,一方面使得系统具有更低的功耗,另一方面也使得tick中断按需响应,减少无用的tick中断响应,进一步提高系统的实时性。 OpenHarmony 的调度算法将 tickless 机制天然嵌入到调度算法中,一方面使得系统具有更低的功耗,另一方面也使得 tick 中断按需响应,减少无用的 tick 中断响应,进一步提高系统的实时性。
OpenHarmony 的进程调度策略支持SCHED_RR,线程调度策略支持SCHED_RR和SCHED_FIFO OpenHarmony 的进程调度策略支持 SCHED_RR(时间片轮转),线程调度策略支持 SCHED_RR 和 SCHED_FIFO(先进先出)
OpenHarmony 调度的最小单元为线程。 OpenHarmony 调度的最小单元为线程。
## 运行机制 ## 运行机制
OpenHarmony 采用进程优先级队列+线程优先级队列的方式,进程优先级范围为0-31,共有32个进程优先级桶队列,每个桶队列对应一个线程优先级桶队列;线程优先级范围也为0-31,一个线程优先级桶队列也有32个优先级队列。 OpenHarmony 采用进程优先级队列 + 线程优先级队列的方式,进程优先级范围为0-31,共有32个进程优先级桶队列,每个桶队列对应一个线程优先级桶队列;线程优先级范围也为0-31,一个线程优先级桶队列也有32个优先级队列。
**图1** 调度优先级桶队列示意图 **图1** 调度优先级桶队列示意图
...@@ -31,9 +31,13 @@ OpenHarmony 在系统启动内核初始化之后开始调度,运行过程中 ...@@ -31,9 +31,13 @@ OpenHarmony 在系统启动内核初始化之后开始调度,运行过程中
### 接口说明 ### 接口说明
| 功能分类 | 接口**名称** | 描述 | | 接口**名称** | 描述 |
| -------- | -------- | -------- | | -------- | -------- |
| 触发系统调度 | LOS_Schedule | 触发系统调度 | | LOS_Schedule | 触发系统调度 |
| LOS_GetTaskScheduler | 获取指定任务的调度策略 |
| LOS_SetTaskScheduler | 设置指定任务的调度策略 |
| LOS_GetProcessScheduler | 获取指定进程的调度策略 |
| LOS_SetProcessScheduler | 设置指定进程的调度参数,包括优先级和调度策略 |
### 开发流程 ### 开发流程
......
...@@ -52,7 +52,7 @@ OpenHarmony 内核的任务一共有32个优先级(0-31),最高优先级为0 ...@@ -52,7 +52,7 @@ OpenHarmony 内核的任务一共有32个优先级(0-31),最高优先级为0
有更高优先级任务创建或者恢复后,会发生任务调度,此刻就绪列表中最高优先级任务变为运行态,那么原先运行的任务由运行态变为就绪态,并加入就绪列表中。 有更高优先级任务创建或者恢复后,会发生任务调度,此刻就绪列表中最高优先级任务变为运行态,那么原先运行的任务由运行态变为就绪态,并加入就绪列表中。
- Running→Exit: - Running→Exit:
运行中的任务运行结束,任务状态由运行态变为退出态。若为设置了分离属性(LOS_TASK_STATUS_DETACHED)的任务,运行结束后将直接销毁。 运行中的任务运行结束,任务状态由运行态变为退出态。若为设置了分离属性( 由头文件 los_task.h 中的宏定义 LOS_TASK_STATUS_DETACHED 设置)的任务,运行结束后将直接销毁。
## 运行机制 ## 运行机制
...@@ -67,16 +67,58 @@ OpenHarmony 任务管理模块提供任务创建、任务延时、任务挂起 ...@@ -67,16 +67,58 @@ OpenHarmony 任务管理模块提供任务创建、任务延时、任务挂起
### 接口说明 ### 接口说明
| 功能分类 | 接口描述 | ##### 表1 任务的创建和删除
| -------- | -------- |
| 任务的创建和删除 | -&nbsp;LOS_TaskCreate:创建任务,并使该任务进入Init状态,不执行任务调度<br/>-&nbsp;LOS_TaskDelete:创建任务,并使该任务进入Ready状态,并调度<br/>-&nbsp;LOS_TaskDelete:删除指定的任务 | | 接口名 | 接口描述 |
| 任务状态控制 | -&nbsp;LOS_TaskResume:恢复挂起的任务<br/>-&nbsp;LOS_TaskSuspend:挂起指定的任务<br/>-&nbsp;LOS_TaskJoin:挂起当前任务,等待指定任务运行结束并回收其任务控制块资源<br/>-&nbsp;LOS_TaskDetach:修改任务的joinable属性为detach属性,detach属性的任务运行结束会自动回收任务控制块资源<br/>-&nbsp;LOS_TaskDelay:任务延时等待<br/>-&nbsp;LOS_TaskYield:显式放权,调整调用任务优先级的任务调度顺序 | | ------------------ | ------------------------------------------------------------ |
| 任务调度的控制 | -&nbsp;LOS_TaskLock:锁任务调度<br/>-&nbsp;LOS_TaskUnlock:解锁任务调度 | | LOS_TaskCreate | 创建任务,若所创建任务的优先级比当前的运行的任务优先级高且任务调度没有锁定,<br/>则该任务将被调度进入运行态 |
| 任务优先级的控制 | -&nbsp;LOS_CurTaskPriSet:设置当前任务的优先级<br/>-&nbsp;LOS_TaskPriSet:设置指定任务的优先级<br/>-&nbsp;LOS_TaskPriGet:获取指定任务的优先级 | | LOS_TaskCreateOnly | 创建任务并阻塞,任务恢复前不会将其加入就绪队列中 |
| 任务信息获取 | -&nbsp;LOS_CurTaskIDGet:获取当前任务的ID<br/>-&nbsp;LOS_TaskInfoGet:获取指定任务的信息 | | LOS_TaskDelete | 删除指定的任务,回收其任务控制块和任务栈所消耗的资源 |
| 任务绑核操作 | -&nbsp;LOS_TaskCpuAffiSet:绑定指定任务到指定CPU上运行,仅在多核下使用<br/>-&nbsp;LOS_TaskCpuAffiGet:获取指定任务的绑核信息,仅在多核下使用 |
| 任务调度参数的控制 | -&nbsp;LOS_GetTaskScheduler:获取指定任务的调度策略<br/>-&nbsp;LOS_SetTaskScheduler:设置指定任务的调度参数,包括优先级和调度策略 | ##### 表2 任务的状态控制
| 系统支持的最大任务数 | LOS_GetSystemTaskMaximum |
| 接口名 | 接口描述 |
| --------------- | ------------------------------------------------------------ |
| LOS_TaskResume | 恢复挂起的任务 |
| LOS_TaskSuspend | 挂起指定的任务,该任务将从就绪任务队列中移除 |
| LOS_TaskJoin | 阻塞当前任务,等待指定任务运行结束并回收其资源 |
| LOS_TaskDetach | 修改任务的 joinable 属性为 detach 属性,detach 属性的任务运行结束会自动回收任务控制块资源 |
| LOS_TaskDelay | 延迟当前任务的执行,在延后指定的时间(tick数)后可以被调度 |
| LOS_TaskYield | 将当前任务从具有相同优先级的任务队列,移动到就绪任务队列的末尾 |
##### 表3 任务调度
| 接口名 | 接口描述 |
| -------------------- | ------------------------------------------------------------ |
| LOS_TaskLock | 锁定任务调度,阻止任务切换 |
| LOS_TaskUnlock | 解锁任务调度。通过该接口可以使任务锁数量减1,若任务多次加锁,那么<br/>任务调度在锁数量减为0时才会完全解锁 |
| LOS_GetTaskScheduler | 获取指定任务的调度策略 |
| LOS_SetTaskScheduler | 设置指定任务的调度参数,包括优先级和调度策略 |
| LOS_Schedule | 触发主动的任务调度 |
##### 表4 任务相关信息获取
| 接口名 | 接口描述 |
| ------------------------ | ------------------------ |
| LOS_CurTaskIDGet | 获取当前任务的ID |
| LOS_TaskInfoGet | 获取指定任务的信息 |
| LOS_GetSystemTaskMaximum | 获取系统支持的最大任务数 |
##### 表5 任务优先级
| 接口名 | 接口描述 |
| ----------------- | ------------------------------ |
| LOS_CurTaskPriSet | 设置当前正在运行的任务的优先级 |
| LOS_TaskPriSet | 设置指定任务的优先级 |
| LOS_TaskPriGet | 获取指定任务的优先级 |
##### 表6 任务绑核操作
| 接口名 | 接口描述 |
| ------------------ | ------------------------------------------- |
| LOS_TaskCpuAffiSet | 绑定指定任务到指定CPU上运行,仅在多核下使用 |
| LOS_TaskCpuAffiGet | 获取指定任务的绑核信息,仅在多核下使用 |
### 开发流程 ### 开发流程
...@@ -93,78 +135,79 @@ OpenHarmony 任务管理模块提供任务创建、任务延时、任务挂起 ...@@ -93,78 +135,79 @@ OpenHarmony 任务管理模块提供任务创建、任务延时、任务挂起
2. 任务参与调度运行,执行用户指定的业务代码。 2. 任务参与调度运行,执行用户指定的业务代码。
3. 任务执行结束,如果设置了LOS_TASK_STATUS_DETACHED属性,则自动回收任务资源,如果任务设置了LOS_TASK_ATTR_JOINABLE属性,则需要调用LOS_TaskJoin回收任务资源,默认为LOS_TASK_STATUS_DETACHED属性。 3. 任务执行结束,如果设置了 LOS_TASK_STATUS_DETACHED 属性,则自动回收任务资源,如果任务设置了 LOS_TASK_ATTR_JOINABLE 属性,则需要调用LOS_TaskJoin 回收任务资源,默认为 LOS_TASK_STATUS_DETACHED 属性。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 内核态具有最高权限,可以操作任意进程内的任务。 > - 内核态具有最高权限,可以操作任意进程内的任务。
> >
> - 用户态进程通过系统调用进入内核态后创建的任务属于KProcess, 不属于当前用户态进程。 > - 用户态进程通过系统调用进入内核态后创建的任务属于KProcess, 不属于当前用户态进程。
### 编程实例 ### 编程实例
代码实现如下: 代码实现如下(该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。)
``` ```c
UINT32 g_taskLoID; UINT32 g_taskLoID;
UINT32 g_taskHiID; UINT32 g_taskHiID;
#define TSK_PRIOR_HI 4 #define TSK_PRIOR_HI 4
#define TSK_PRIOR_LO 5 #define TSK_PRIOR_LO 5
UINT32 ExampleTaskHi(VOID) UINT32 ExampleTaskHi(VOID)
{ {
UINT32 ret; UINT32 ret;
PRINTK("Enter TaskHi Handler.\n"); PRINTK("Enter TaskHi Handler.\n");
/* 延时2个Tick,延时后该任务会挂起,执行剩余任务中最高优先级的任务(g_taskLoID任务) */ /* 延时2个Tick,延时后该任务会挂起,执行剩余任务中最高优先级的任务(g_taskLoID任务) */
ret = LOS_TaskDelay(2); ret = LOS_TaskDelay(2);
if (ret != LOS_OK) { if (ret != LOS_OK) {
PRINTK("Delay Task Failed.\n"); PRINTK("Delay Task Failed.\n");
return LOS_NOK; return LOS_NOK;
} }
/* 2个Tick时间到了后,该任务恢复,继续执行 */ /* 2个Tick时间到了后,该任务恢复,继续执行 */
PRINTK("TaskHi LOS_TaskDelay Done.\n"); PRINTK("TaskHi LOS_TaskDelay Done.\n");
/* 挂起自身任务 */ /* 挂起自身任务 */
ret = LOS_TaskSuspend(g_taskHiID); ret = LOS_TaskSuspend(g_taskHiID);
if (ret != LOS_OK) { if (ret != LOS_OK) {
PRINTK("Suspend TaskHi Failed.\n"); PRINTK("Suspend TaskHi Failed.\n");
return LOS_NOK; return LOS_NOK;
} }
PRINTK("TaskHi LOS_TaskResume Success.\n"); PRINTK("TaskHi LOS_TaskResume Success.\n");
return LOS_OK; return LOS_OK;
} }
/* 低优先级任务入口函数 */ /* 低优先级任务入口函数 */
UINT32 ExampleTaskLo(VOID) UINT32 ExampleTaskLo(VOID)
{ {
UINT32 ret; UINT32 ret;
PRINTK("Enter TaskLo Handler.\n"); PRINTK("Enter TaskLo Handler.\n");
/* 延时2个Tick,延时后该任务会挂起,执行剩余任务中就高优先级的任务(背景任务) */ /* 延时2个Tick,延时后该任务会挂起,执行剩余任务中就高优先级的任务(背景任务) */
ret = LOS_TaskDelay(2); ret = LOS_TaskDelay(2);
if (ret != LOS_OK) { if (ret != LOS_OK) {
PRINTK("Delay TaskLo Failed.\n"); PRINTK("Delay TaskLo Failed.\n");
return LOS_NOK; return LOS_NOK;
} }
PRINTK("TaskHi LOS_TaskSuspend Success.\n"); PRINTK("TaskHi LOS_TaskSuspend Success.\n");
/* 恢复被挂起的任务g_taskHiID */ /* 恢复被挂起的任务g_taskHiID */
ret = LOS_TaskResume(g_taskHiID); ret = LOS_TaskResume(g_taskHiID);
if (ret != LOS_OK) { if (ret != LOS_OK) {
PRINTK("Resume TaskHi Failed.\n"); PRINTK("Resume TaskHi Failed.\n");
return LOS_NOK; return LOS_NOK;
} }
PRINTK("TaskHi LOS_TaskDelete Success.\n"); PRINTK("TaskHi LOS_TaskDelete Success.\n");
return LOS_OK; return LOS_OK;
} }
/* 任务测试入口函数,在里面创建优先级不一样的两个任务 */ /* 任务测试入口函数,在里面创建优先级不一样的两个任务 */
UINT32 ExampleTaskCaseEntry(VOID) UINT32 ExampleTaskCaseEntry(VOID)
{ {
UINT32 ret; UINT32 ret;
TSK_INIT_PARAM_S initParam = {0}; TSK_INIT_PARAM_S initParam = {0};
/* 锁任务调度 */ /* 锁任务调度 */
LOS_TaskLock(); LOS_TaskLock();
PRINTK("LOS_TaskLock() Success!\n"); PRINTK("LOS_TaskLock() Success!\n");
/* 高优先级任务的初始化参数,其资源回收需要其他任务调用 LOS_TaskJoin */
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskHi; initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskHi;
initParam.usTaskPrio = TSK_PRIOR_HI; initParam.usTaskPrio = TSK_PRIOR_HI;
initParam.pcName = "HIGH_NAME"; initParam.pcName = "HIGH_NAME";
initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE; initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE;
initParam.uwResved = LOS_TASK_ATTR_JOINABLE; initParam.uwResved = LOS_TASK_ATTR_JOINABLE;
...@@ -175,23 +218,24 @@ UINT32 ExampleTaskCaseEntry(VOID) ...@@ -175,23 +218,24 @@ UINT32 ExampleTaskCaseEntry(VOID)
LOS_TaskUnlock(); LOS_TaskUnlock();
PRINTK("ExampleTaskHi create Failed! ret=%d\n", ret); PRINTK("ExampleTaskHi create Failed! ret=%d\n", ret);
return LOS_NOK; return LOS_NOK;
} }
PRINTK("ExampleTaskHi create Success!\n"); PRINTK("ExampleTaskHi create Success!\n");
/* 低优先级任务的初始化参数,任务结束后会自行结束销毁 */
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskLo; initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskLo;
initParam.usTaskPrio = TSK_PRIOR_LO; initParam.usTaskPrio = TSK_PRIOR_LO;
initParam.pcName = "LOW_NAME"; initParam.pcName = "LOW_NAME";
initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE; initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE;
initParam.uwResved = LOS_TASK_STATUS_DETACHED; initParam.uwResved = LOS_TASK_STATUS_DETACHED;
/* 创建低优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */ /* 创建低优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */
ret = LOS_TaskCreate(&g_taskLoID, &initParam); ret = LOS_TaskCreate(&g_taskLoID, &initParam);
if (ret!= LOS_OK) { if (ret!= LOS_OK) {
LOS_TaskUnlock(); LOS_TaskUnlock();
PRINTK("ExampleTaskLo create Failed!\n"); PRINTK("ExampleTaskLo create Failed!\n");
return LOS_NOK; return LOS_NOK;
} }
PRINTK("ExampleTaskLo create Success!\n"); PRINTK("ExampleTaskLo create Success!\n");
/* 解锁任务调度,此时会发生任务调度,执行就绪列表中最高优先级任务 */ /* 解锁任务调度,此时会发生任务调度,执行就绪列表中最高优先级任务 */
LOS_TaskUnlock(); LOS_TaskUnlock();
...@@ -203,12 +247,12 @@ UINT32 ExampleTaskCaseEntry(VOID) ...@@ -203,12 +247,12 @@ UINT32 ExampleTaskCaseEntry(VOID)
} }
while(1){}; while(1){};
return LOS_OK; return LOS_OK;
} }
``` ```
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
LOS_TaskLock() Success! LOS_TaskLock() Success!
ExampleTaskHi create Success! ExampleTaskHi create Success!
......
...@@ -3,9 +3,13 @@ ...@@ -3,9 +3,13 @@
## 基本概念 ## 基本概念
软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数值后会触发用户定义的回调函数。定时精度与系统Tick时钟的周期有关。硬件定时器受硬件的限制,数量上不足以满足用户的实际需求,因此为了满足用户需求,提供更多的定时器,OpenHarmony LiteOS-A内核提供软件定时器功能。软件定时器扩展了定时器的数量,允许创建更多的定时业务。 软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数值后会触发用户定义的回调函数。定时精度与系统Tick时钟的周期有关。
软件定时器功能上支持: 硬件定时器受硬件的限制,数量上不足以满足用户的实际需求,因此为了满足用户需求,提供更多的定时器,OpenHarmony LiteOS-A内核提供软件定时器功能。
软件定时器扩展了定时器的数量,允许创建更多的定时业务。
**软件定时器支持以下功能:**
- 静态裁剪:能通过宏关闭软件定时器功能。 - 静态裁剪:能通过宏关闭软件定时器功能。
...@@ -22,13 +26,17 @@ ...@@ -22,13 +26,17 @@
## 运行机制 ## 运行机制
软件定时器是系统资源,在模块初始化的时候已经分配了一块连续的内存,系统支持的最大定时器个数由los_config.h中的LOSCFG_BASE_CORE_SWTMR_LIMIT宏配置。软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,先进先出。同一时刻设置的定时时间短的定时器总是比定时时间长的靠近队列头,满足优先被触发的准则。软件定时器以Tick为基本计时单位,当用户创建并启动一个软件定时器时,OpenHarmony系统会根据当前系统Tick时间及用户设置的定时间隔确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。 软件定时器是系统资源,在模块初始化的时候已经分配了一块连续的内存,系统支持的最大定时器个数由los_config.h中的LOSCFG_BASE_CORE_SWTMR_LIMIT宏配置。
软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,先进先出。同一时刻设置的定时时间短的定时器总是比定时时间长的靠近队列头,满足优先被触发的准则。
软件定时器以Tick为基本计时单位,当用户创建并启动一个软件定时器时,OpenHarmony系统会根据当前系统Tick时间及用户设置的定时间隔确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。
当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,看是否有定时器超时,若有则将超时的定时器记录下来。 当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,看是否有定时器超时,若有则将超时的定时器记录下来。
Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用之前记录下来的定时器的超时回调函数。 Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用之前记录下来的定时器的超时回调函数。
定时器状态 **定时器状态:**
- OS_SWTMR_STATUS_UNUSED(未使用) - OS_SWTMR_STATUS_UNUSED(未使用)
系统在定时器模块初始化的时候将系统中所有定时器资源初始化成该状态。 系统在定时器模块初始化的时候将系统中所有定时器资源初始化成该状态。
...@@ -39,9 +47,7 @@ Tick中断处理函数结束后,软件定时器任务(优先级为最高) ...@@ -39,9 +47,7 @@ Tick中断处理函数结束后,软件定时器任务(优先级为最高)
- OS_SWTMR_STATUS_TICKING(计数) - OS_SWTMR_STATUS_TICKING(计数)
在定时器创建后调用LOS_SwtmrStart接口,定时器将变成该状态,表示定时器运行时的状态。 在定时器创建后调用LOS_SwtmrStart接口,定时器将变成该状态,表示定时器运行时的状态。
定时器模式 **定时器模式:**
OpenHarmony系统的软件定时器提供三类定时器机制:
- 第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。 - 第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。
...@@ -55,20 +61,20 @@ OpenHarmony系统的软件定时器提供三类定时器机制: ...@@ -55,20 +61,20 @@ OpenHarmony系统的软件定时器提供三类定时器机制:
### 接口说明 ### 接口说明
OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接口详细信息可以查看API参考 OpenHarmony LiteOS-A内核的软件定时器模块提供以下几种功能
**表1** 软件定时器接口说明 **表1** 软件定时器接口说明
| 功能分类 | 接口描述 | | 功能分类 | 接口描述 |
| -------- | -------- | | ---------------------- | ------------------------------------------------------------ |
| 创建、删除定时器 | LOS_SwtmrCreate:创建软件定时器<br/>LOS_SwtmrDelete:删除软件定时器 | | 创建、删除定时器 | LOS_SwtmrCreate:创建软件定时器<br/>LOS_SwtmrDelete:删除软件定时器 |
| 启动、停止定时器 | LOS_SwtmrStart:启动软件定时器<br/>LOS_SwtmrStop:停止软件定时器 | | 启动、停止定时器 | LOS_SwtmrStart:启动软件定时器<br/>LOS_SwtmrStop:停止软件定时器 |
| 获得软件定时剩余Tick数 | LOS_SwtmrTimeGet:获得软件定时器剩余Tick数 | | 获得软件定时剩余Tick数 | LOS_SwtmrTimeGet:获得软件定时器剩余Tick数 |
### 开发流程 ### 开发流程
软件定时器的典型开发流程: **软件定时器的典型开发流程:**
1. 配置软件定时器。 1. 配置软件定时器。
- 确认配置项LOSCFG_BASE_CORE_SWTMR和LOSCFG_BASE_IPC_QUEUE为打开状态; - 确认配置项LOSCFG_BASE_CORE_SWTMR和LOSCFG_BASE_IPC_QUEUE为打开状态;
...@@ -88,14 +94,15 @@ OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接 ...@@ -88,14 +94,15 @@ OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接
6. 删除定时器LOS_SwtmrDelete。 6. 删除定时器LOS_SwtmrDelete。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>
> - 软件定时器的回调函数中不要做过多操作,不要使用可能引起任务挂起或者阻塞的接口或操作。 > - 软件定时器的回调函数中不要做过多操作,不要使用可能引起任务挂起或者阻塞的接口或操作。
> >
> - 软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级设定为0,且不允许修改 。 > - 软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级设定为0,且不允许修改 。
> >
> - 系统可配置的软件定时器资源个数是指:整个系统可使用的软件定时器资源总个数,而并非是用户可使用的软件定时器资源个数。例如:系统软件定时器多占用一个软件定时器资源数,那么用户能使用的软件定时器资源就会减少一个。 > - 系统可配置的软件定时器资源个数是指:整个系统可使用的软件定时器资源总个数,而并非是用户可使用的软件定时器资源个数。例如:系统软件定时器多占用一个软件定时器资源数,那么用户能使用的软件定时器资源就会减少一个。
> >
> - 创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源。 > - 创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源。
> >
> - 创建单次不自删除属性的定时器,用户需要调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。 > - 创建单次不自删除属性的定时器,用户需要调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。
...@@ -110,7 +117,7 @@ OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接 ...@@ -110,7 +117,7 @@ OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接
- 配置好OS_SWTMR_HANDLE_QUEUE_SIZE软件定时器队列最大长度。 - 配置好OS_SWTMR_HANDLE_QUEUE_SIZE软件定时器队列最大长度。
**编程示例** **编程示例**
``` ```
#include "los_swtmr.h" #include "los_swtmr.h"
...@@ -176,7 +183,7 @@ void Timer_example(void) ...@@ -176,7 +183,7 @@ void Timer_example(void)
**运行结果** **运行结果**
``` ```
create Timer1 success create Timer1 success
start Timer1 success start Timer1 success
...@@ -206,4 +213,4 @@ g_timercount2 =9 ...@@ -206,4 +213,4 @@ g_timercount2 =9
tick_last1=2101 tick_last1=2101
g_timercount2 =10 g_timercount2 =10
tick_last1=2201 tick_last1=2201
``` ```
\ No newline at end of file
...@@ -3,9 +3,11 @@ ...@@ -3,9 +3,11 @@
## 基本概念 ## 基本概念
时间管理以系统时钟为基础。时间管理提供给应用程序所有和时间有关的服务。系统时钟是由定时/计数器产生的输出脉冲触发中断而产生的,一般定义为整数或长整数。输出脉冲的周期叫做一个“时钟滴答”。系统时钟也称为时标或者Tick。一个Tick的时长可以静态配置。用户是以秒、毫秒为单位计时,而操作系统时钟计时是以Tick为单位的,当用户需要对系统操作时,例如任务挂起、延时等,输入秒为单位的数值,此时需要时间管理模块对二者进行转换。 时间管理以系统时钟为基础。时间管理提供给应用程序所有和时间有关的服务。系统时钟是由定时/计数器产生的输出脉冲触发中断而产生的,一般定义为整数或长整数。输出脉冲的周期叫做一个“时钟滴答”。
Tick与秒之间的对应关系可以配置。 系统时钟也称为时标或者Tick。一个Tick的时长可以静态配置。用户是以秒、毫秒为单位计时,而操作系统时钟计时是以Tick为单位的,当用户需要对系统操作时,例如任务挂起、延时等,输入秒为单位的数值,此时需要时间管理模块对二者进行转换。
**Tick与秒之间的对应关系可以配置。**
- **Cycle** - **Cycle**
系统最小的计时单位。Cycle的时长由系统主频决定,系统主频就是每秒钟的Cycle数。 系统最小的计时单位。Cycle的时长由系统主频决定,系统主频就是每秒钟的Cycle数。
...@@ -13,24 +15,24 @@ Tick与秒之间的对应关系可以配置。 ...@@ -13,24 +15,24 @@ Tick与秒之间的对应关系可以配置。
- **Tick** - **Tick**
Tick是操作系统的基本时间单位,对应的时长由系统主频及每秒Tick数决定,由用户配置。 Tick是操作系统的基本时间单位,对应的时长由系统主频及每秒Tick数决定,由用户配置。
OpenHarmony系统的时间管理模块提供时间转换、统计、延迟功能以满足用户对时间相关需求的实现。 **OpenHarmony系统的时间管理模块提供时间转换、统计、延迟功能以满足用户对时间相关需求的实现。**
## 开发指导 ## 开发指导
用户需要了解当前系统运行的时间以及Tick与秒、毫秒之间的转换关系时,需要使用到时间管理模块的接口。 用户需要了解当前系统运行的时间以及Tick与秒、毫秒之间的转换关系,以及需要使用到时间管理模块的接口。
### 接口说明 ### 接口说明
OpenHarmony LiteOS-A内核的时间管理提供下面几种功能,接口详细信息可以查看API参考。 OpenHarmony LiteOS-A内核的时间管理提供以下几种功能,接口详细信息可查看API参考。
**表1** 时间管理相关接口说明 **表1** 时间管理相关接口说明
| 功能分类 | 接口描述 | | 功能分类 | 接口描述 |
| -------- | -------- | | -------- | ------------------------------------------------------------ |
| 时间转换 | LOS_MS2Tick:毫秒转换成Tick<br/>LOS_Tick2MS:Tick转换成毫秒 | | 时间转换 | LOS_MS2Tick:毫秒转换成Tick<br/>LOS_Tick2MS:Tick转换成毫秒 |
| 时间统计 | LOS_TickCountGet:获取当前Tick数<br/>LOS_CyclePerTickGet:每个Tick的cycle数 | | 时间统计 | LOS_TickCountGet:获取当前Tick数<br/>LOS_CyclePerTickGet:每个Tick的cycle数 |
### 开发流程 ### 开发流程
...@@ -40,25 +42,26 @@ OpenHarmony LiteOS-A内核的时间管理提供下面几种功能,接口详细 ...@@ -40,25 +42,26 @@ OpenHarmony LiteOS-A内核的时间管理提供下面几种功能,接口详细
2. 获取系统Tick数完成时间统计等。 2. 获取系统Tick数完成时间统计等。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 获取系统Tick数需要在系统时钟使能之后。 >
> > - 获取系统Tick数需要在系统时钟使能之后。
> - 时间管理不是单独的功能模块,依赖于los_config.h中的OS_SYS_CLOCK和LOSCFG_BASE_CORE_TICK_PER_SECOND两个配置选项。 >
> > - 时间管理不是单独的功能模块,依赖于los_config.h中的OS_SYS_CLOCK和LOSCFG_BASE_CORE_TICK_PER_SECOND两个配置选项。
> - 系统的Tick数在关中断的情况下不进行计数,故系统Tick数不能作为准确时间计算。 >
> - 系统的Tick数在关中断的情况下不进行计数,故系统Tick数不能作为准确时间计算。
### 编程实例 ### 编程实例
前置条件: 前置条件:
- 配置好LOSCFG_BASE_CORE_TICK_PER_SECOND,即系统每秒的Tick数,范围(0, 1000] - 配置好LOSCFG_BASE_CORE_TICK_PER_SECOND,即系统每秒的Tick数,范围(0, 1000
- 配置好OS_SYS_CLOCK 系统时钟频率,单位:Hz。 - 配置好OS_SYS_CLOCK 系统时钟频率,单位:Hz。
**示例代码** **示例代码**
时间转换: 时间转换:
``` ```
VOID Example_TransformTime(VOID) VOID Example_TransformTime(VOID)
{ {
...@@ -73,7 +76,7 @@ VOID Example_TransformTime(VOID) ...@@ -73,7 +76,7 @@ VOID Example_TransformTime(VOID)
时间统计和时间延迟: 时间统计和时间延迟:
``` ```
VOID Example_GetTime(VOID) VOID Example_GetTime(VOID)
{ {
...@@ -106,7 +109,7 @@ VOID Example_GetTime(VOID) ...@@ -106,7 +109,7 @@ VOID Example_GetTime(VOID)
时间转换: 时间转换:
``` ```
uwTick = 10000 uwTick = 10000
uwMs = 100 uwMs = 100
...@@ -114,9 +117,9 @@ uwMs = 100 ...@@ -114,9 +117,9 @@ uwMs = 100
时间统计和时间延迟: 时间统计和时间延迟:
``` ```
LOS_CyclePerTickGet = 49500 LOS_CyclePerTickGet = 49500
LOS_TickCountGet = 5042 LOS_TickCountGet = 347931
LOS_TickCountGet after delay = 5242 LOS_TickCountGet after delay = 348134
``` ```
\ No newline at end of file
...@@ -15,7 +15,7 @@ OpenHarmony LiteOS-A的事件模块提供的事件,具有如下特点: ...@@ -15,7 +15,7 @@ OpenHarmony LiteOS-A的事件模块提供的事件,具有如下特点:
- 任务通过创建事件控制块来触发事件或等待事件。 - 任务通过创建事件控制块来触发事件或等待事件。
- 事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。第25位不可用,因此最多可支持31种事件类型。 - 事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。(0表示该时间类型未发生,1表示该事件类型已经发生,一共31种事件类型,第25bit位(`0x02U << 24`)系统保留)
- 事件仅用于任务间的同步,不提供数据传输功能。 - 事件仅用于任务间的同步,不提供数据传输功能。
...@@ -31,7 +31,7 @@ OpenHarmony LiteOS-A的事件模块提供的事件,具有如下特点: ...@@ -31,7 +31,7 @@ OpenHarmony LiteOS-A的事件模块提供的事件,具有如下特点:
### 事件控制块 ### 事件控制块
``` ```
/** /**
* 事件控制块数据结构 * 事件控制块数据结构
...@@ -80,10 +80,10 @@ OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。 ...@@ -80,10 +80,10 @@ OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。
| 功能分类 | 接口描述 | | 功能分类 | 接口描述 |
| -------- | -------- | | -------- | -------- |
| 初始化事件 | LOS_EventInit:初始化一个事件控制块 | | 初始化事件 | LOS_EventInit:初始化一个事件控制块 |
| 读/写事件 | -&nbsp;LOS_EventRead:读取指定事件类型,超时时间为相对时间:单位为Tick<br/>-&nbsp;LOS_EventWrite:写指定的事件类型 | | 读/写事件 | -&nbsp;LOS_EventRead:读取指定事件类型,超时时间为相对时间:单位为Tick<br/>-&nbsp;LOS_EventWrite写指定的事件类型 |
| 清除事件 | LOS_EventClear:清除指定的事件类型 | | 清除事件 | LOS_EventClear:清除指定的事件类型 |
| 校验事件掩码 | -&nbsp;LOS_EventPoll:根据用户传入的事件ID、事件掩码及读取模式,返回用户传入的事件是否符合预期<br/>-&nbsp;LOS_EventDestroy:销毁指定的事件控制块 | | 校验事件掩码 | -&nbsp;LOS_EventPoll根据用户传入的事件ID、事件掩码及读取模式,返回用户传入的事件是否符合预期<br/>-&nbsp;LOS_EventDestroy:销毁指定的事件控制块 |
| 销毁事件 | LOS_EventDestroy:销毁指定的事件控制块 | | 销毁事件 | LOS_EventDestroy销毁指定的事件控制块 |
### 开发流程 ### 开发流程
...@@ -103,7 +103,7 @@ OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。 ...@@ -103,7 +103,7 @@ OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。
6. 事件控制块销毁 6. 事件控制块销毁
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 进行事件读写操作时,事件的第25位为保留位,不可以进行位设置。 > - 进行事件读写操作时,事件的第25bit(`0x02U << 24`)为保留bit位,不可以进行位设置。
> >
> - 对同一事件反复写入,算作一次写入。 > - 对同一事件反复写入,算作一次写入。
...@@ -128,9 +128,10 @@ OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。 ...@@ -128,9 +128,10 @@ OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。
### 编程示例 ### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数Example_EventEntry。
示例代码如下: 示例代码如下:
``` ```
#include "los_event.h" #include "los_event.h"
#include "los_task.h" #include "los_task.h"
...@@ -143,21 +144,21 @@ UINT32 g_testTaskId; ...@@ -143,21 +144,21 @@ UINT32 g_testTaskId;
EVENT_CB_S g_exampleEvent; EVENT_CB_S g_exampleEvent;
/* 等待的事件类型 */ /* 等待的事件类型 */
#define EVENT_WAIT 0x00000001 #define EVENT_WAIT 0x00000001
#define EVENT_TIMEOUT 500
/* 用例任务入口函数 */ /* 用例任务入口函数 */
VOID Example_Event(VOID) VOID Example_Event(VOID)
{ {
UINT32 event; UINT32 event;
/* 超时等待方式读事件,超时时间为100 ticks, 若100 ticks后未读取到指定事件,读事件超时,任务直接唤醒 */ /* 超时等待方式读事件,超时时间为100 ticks, 若100 ticks后未读取到指定事件,读事件超时,任务直接唤醒 */
printf("Example_Event wait event 0x%x \n", EVENT_WAIT); dprintf("Example_Event wait event 0x%x \n", EVENT_WAIT);
event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, 100); event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, EVENT_TIMEOUT);
if (event == EVENT_WAIT) { if (event == EVENT_WAIT) {
printf("Example_Event,read event :0x%x\n", event); dprintf("Example_Event,read event :0x%x\n", event);
} else { } else {
printf("Example_Event,read event timeout\n"); dprintf("Example_Event,read event timeout\n");
} }
} }
...@@ -169,7 +170,7 @@ UINT32 Example_EventEntry(VOID) ...@@ -169,7 +170,7 @@ UINT32 Example_EventEntry(VOID)
/* 事件初始化 */ /* 事件初始化 */
ret = LOS_EventInit(&g_exampleEvent); ret = LOS_EventInit(&g_exampleEvent);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("init event failed .\n"); dprintf("init event failed .\n");
return -1; return -1;
} }
...@@ -181,30 +182,23 @@ UINT32 Example_EventEntry(VOID) ...@@ -181,30 +182,23 @@ UINT32 Example_EventEntry(VOID)
task1.usTaskPrio = 5; task1.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_testTaskId, &task1); ret = LOS_TaskCreate(&g_testTaskId, &task1);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("task create failed.\n"); dprintf("task create failed.\n");
return LOS_NOK; return LOS_NOK;
} }
/* 写g_testTaskId 等待事件 */ /* 写g_testTaskId 等待事件 */
printf("Example_TaskEntry write event.\n"); dprintf("Example_TaskEntry write event.\n");
ret = LOS_EventWrite(&g_exampleEvent, EVENT_WAIT); ret = LOS_EventWrite(&g_exampleEvent, EVENT_WAIT);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("event write failed.\n"); dprintf("event write failed.\n");
return LOS_NOK; return LOS_NOK;
} }
/* 清标志位 */ /* 清标志位 */
printf("EventMask:%d\n", g_exampleEvent.uwEventID); dprintf("EventMask:%d\n", g_exampleEvent.uwEventID);
LOS_EventClear(&g_exampleEvent, ~g_exampleEvent.uwEventID); LOS_EventClear(&g_exampleEvent, ~g_exampleEvent.uwEventID);
printf("EventMask:%d\n", g_exampleEvent.uwEventID); dprintf("EventMask:%d\n", g_exampleEvent.uwEventID);
/* 删除任务 */
ret = LOS_TaskDelete(g_testTaskId);
if (ret != LOS_OK) {
printf("task delete failed.\n");
return LOS_NOK;
}
return LOS_OK; return LOS_OK;
} }
...@@ -215,7 +209,7 @@ UINT32 Example_EventEntry(VOID) ...@@ -215,7 +209,7 @@ UINT32 Example_EventEntry(VOID)
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
Example_Event wait event 0x1 Example_Event wait event 0x1
Example_TaskEntry write event. Example_TaskEntry write event.
......
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
### 编程实例 ### 编程实例
**实例描述** #### 实例描述
本实例实现如下流程: 本实例实现如下流程:
...@@ -99,17 +99,18 @@ ...@@ -99,17 +99,18 @@
4. 100Tick休眠时间到达后,Example_MutexTask2被唤醒, 释放互斥锁,唤醒Example_MutexTask1。Example_MutexTask1成功获取到互斥锁后,释放,删除互斥锁。 4. 100Tick休眠时间到达后,Example_MutexTask2被唤醒, 释放互斥锁,唤醒Example_MutexTask1。Example_MutexTask1成功获取到互斥锁后,释放,删除互斥锁。
**示例代码** #### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数Example_MutexEntry。
示例代码如下: 示例代码如下:
``` ```
#include <string.h> #include <string.h>
#include "los_mux.h" #include "los_mux.h"
/* 互斥锁 */ /* 互斥锁 */
LosMux g_testMux; LosMux g_testMutex;
/* 任务ID */ /* 任务ID */
UINT32 g_testTaskId01; UINT32 g_testTaskId01;
UINT32 g_testTaskId02; UINT32 g_testTaskId02;
...@@ -117,48 +118,49 @@ UINT32 g_testTaskId02; ...@@ -117,48 +118,49 @@ UINT32 g_testTaskId02;
VOID Example_MutexTask1(VOID) VOID Example_MutexTask1(VOID)
{ {
UINT32 ret; UINT32 ret;
LOS_TaskDelay(50);
printf("task1 try to get mutex, wait 10 ticks.\n"); dprintf("task1 try to get mutex, wait 10 ticks.\n");
/* 申请互斥锁 */ /* 申请互斥锁 */
ret = LOS_MuxLock(&g_testMux, 10); ret = LOS_MuxLock(&g_testMutex, 10);
if (ret == LOS_OK) { if (ret == LOS_OK) {
printf("task1 get mutex g_testMux.\n"); dprintf("task1 get mutex g_testMux.\n");
/* 释放互斥锁 */ /* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux); LOS_MuxUnlock(&g_testMutex);
return; return;
} }
if (ret == LOS_ETIMEDOUT ) { if (ret == LOS_ETIMEDOUT) {
printf("task1 timeout and try to get mutex, wait forever.\n"); dprintf("task1 timeout and try to get mutex, wait forever.\n");
/* 申请互斥锁 */ /* 申请互斥锁 */
ret = LOS_MuxLock(&g_testMux, LOS_WAIT_FOREVER); ret = LOS_MuxLock(&g_testMutex, LOS_WAIT_FOREVER);
if (ret == LOS_OK) { if (ret == LOS_OK) {
printf("task1 wait forever, get mutex g_testMux.\n"); dprintf("task1 wait forever, get mutex g_testMux.\n");
/* 释放互斥锁 */ /* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux); LOS_MuxUnlock(&g_testMutex);
/* 删除互斥锁 */ /* 删除互斥锁 */
LOS_MuxDestroy(&g_testMux); LOS_MuxDestroy(&g_testMutex);
printf("task1 post and delete mutex g_testMux.\n"); dprintf("task1 post and delete mutex g_testMux.\n");
return; return;
} }
} }
return; return;
} }
VOID Example_MutexTask2(VOID) VOID Example_MutexTask2(VOID)
{ {
printf("task2 try to get mutex, wait forever.\n"); dprintf("task2 try to get mutex, wait forever.\n");
/* 申请互斥锁 */ /* 申请互斥锁 */
(VOID)LOS_MuxLock(&g_testMux, LOS_WAIT_FOREVER); (VOID)LOS_MuxLock(&g_testMutex, LOS_WAIT_FOREVER);
printf("task2 get mutex g_testMux and suspend 100 ticks.\n"); dprintf("task2 get mutex g_testMux and suspend 100 ticks.\n");
/* 任务休眠100Ticks */ /* 任务休眠100Ticks */
LOS_TaskDelay(100); LOS_TaskDelay(100);
printf("task2 resumed and post the g_testMux\n"); dprintf("task2 resumed and post the g_testMux\n");
/* 释放互斥锁 */ /* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux); LOS_MuxUnlock(&g_testMutex);
return; return;
} }
...@@ -169,7 +171,7 @@ UINT32 Example_MutexEntry(VOID) ...@@ -169,7 +171,7 @@ UINT32 Example_MutexEntry(VOID)
TSK_INIT_PARAM_S task2; TSK_INIT_PARAM_S task2;
/* 初始化互斥锁 */ /* 初始化互斥锁 */
LOS_MuxInit(&g_testMux, NULL); LOS_MuxInit(&g_testMutex, NULL);
/* 锁任务调度 */ /* 锁任务调度 */
LOS_TaskLock(); LOS_TaskLock();
...@@ -182,7 +184,7 @@ UINT32 Example_MutexEntry(VOID) ...@@ -182,7 +184,7 @@ UINT32 Example_MutexEntry(VOID)
task1.usTaskPrio = 5; task1.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_testTaskId01, &task1); ret = LOS_TaskCreate(&g_testTaskId01, &task1);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("task1 create failed.\n"); dprintf("task1 create failed.\n");
return LOS_NOK; return LOS_NOK;
} }
...@@ -194,7 +196,7 @@ UINT32 Example_MutexEntry(VOID) ...@@ -194,7 +196,7 @@ UINT32 Example_MutexEntry(VOID)
task2.usTaskPrio = 4; task2.usTaskPrio = 4;
ret = LOS_TaskCreate(&g_testTaskId02, &task2); ret = LOS_TaskCreate(&g_testTaskId02, &task2);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("task2 create failed.\n"); dprintf("task2 create failed.\n");
return LOS_NOK; return LOS_NOK;
} }
...@@ -209,11 +211,11 @@ UINT32 Example_MutexEntry(VOID) ...@@ -209,11 +211,11 @@ UINT32 Example_MutexEntry(VOID)
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
task1 try to get mutex, wait 10 ticks.
task2 try to get mutex, wait forever. task2 try to get mutex, wait forever.
task2 get mutex g_testMux and suspend 100 ticks. task2 get mutex g_testMux and suspend 100 ticks.
task1 try to get mutex, wait 10 ticks.
task1 timeout and try to get mutex, wait forever. task1 timeout and try to get mutex, wait forever.
task2 resumed and post the g_testMux task2 resumed and post the g_testMux
task1 wait forever, get mutex g_testMux. task1 wait forever, get mutex g_testMux.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。 任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。
可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。 可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。
消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用,可以使用队列实现任务异步通信,队列具有如下特性: 消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用,可以使用队列实现任务异步通信,队列具有如下特性:
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
### 队列控制块 ### 队列控制块
``` ```
/** /**
* 队列控制块数据结构 * 队列控制块数据结构
...@@ -137,9 +137,12 @@ typedef struct { ...@@ -137,9 +137,12 @@ typedef struct {
### 编程示例 ### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数ExampleQueue,
为方便用户观察,建议调用ExampleQueue前先调用 LOS_Msleep(5000) 进行短时间延时,避免其他打印过多。
示例代码如下: 示例代码如下:
``` ```
#include "los_task.h" #include "los_task.h"
#include "los_queue.h" #include "los_queue.h"
...@@ -154,7 +157,7 @@ VOID SendEntry(VOID) ...@@ -154,7 +157,7 @@ VOID SendEntry(VOID)
ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0); ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0);
if(ret != LOS_OK) { if(ret != LOS_OK) {
printf("send message failure, error: %x\n", ret); dprintf("send message failure, error: %x\n", ret);
} }
} }
...@@ -164,30 +167,36 @@ VOID RecvEntry(VOID) ...@@ -164,30 +167,36 @@ VOID RecvEntry(VOID)
CHAR readBuf[BUFFER_LEN] = {0}; CHAR readBuf[BUFFER_LEN] = {0};
UINT32 readLen = BUFFER_LEN; UINT32 readLen = BUFFER_LEN;
//休眠1s LOS_Msleep(1000);
usleep(1000000);
ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0); ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0);
if(ret != LOS_OK) { if(ret != LOS_OK) {
printf("recv message failure, error: %x\n", ret); dprintf("recv message failure, error: %x\n", ret);
} }
printf("recv message: %s\n", readBuf); dprintf("recv message: %s\n", readBuf);
ret = LOS_QueueDelete(g_queue); ret = LOS_QueueDelete(g_queue);
if(ret != LOS_OK) { if(ret != LOS_OK) {
printf("delete the queue failure, error: %x\n", ret); dprintf("delete the queue failure, error: %x\n", ret);
} }
printf("delete the queue success!\n"); dprintf("delete the queue success!\n");
} }
UINT32 ExampleQueue(VOID) UINT32 ExampleQueue(VOID)
{ {
printf("start queue example\n"); dprintf("start queue example\n");
UINT32 ret = 0; UINT32 ret = 0;
UINT32 task1, task2; UINT32 task1, task2;
TSK_INIT_PARAM_S initParam = {0}; TSK_INIT_PARAM_S initParam = {0};
ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50);
if(ret != LOS_OK) {
dprintf("create queue failure, error: %x\n", ret);
}
dprintf("create the queue success!\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry; initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry;
initParam.usTaskPrio = 9; initParam.usTaskPrio = 9;
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
...@@ -196,7 +205,8 @@ UINT32 ExampleQueue(VOID) ...@@ -196,7 +205,8 @@ UINT32 ExampleQueue(VOID)
LOS_TaskLock(); LOS_TaskLock();
ret = LOS_TaskCreate(&task1, &initParam); ret = LOS_TaskCreate(&task1, &initParam);
if(ret != LOS_OK) { if(ret != LOS_OK) {
printf("create task1 failed, error: %x\n", ret); dprintf("create task1 failed, error: %x\n", ret);
LOS_QueueDelete(g_queue);
return ret; return ret;
} }
...@@ -204,17 +214,13 @@ UINT32 ExampleQueue(VOID) ...@@ -204,17 +214,13 @@ UINT32 ExampleQueue(VOID)
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry; initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry;
ret = LOS_TaskCreate(&task2, &initParam); ret = LOS_TaskCreate(&task2, &initParam);
if(ret != LOS_OK) { if(ret != LOS_OK) {
printf("create task2 failed, error: %x\n", ret); dprintf("create task2 failed, error: %x\n", ret);
LOS_QueueDelete(g_queue);
return ret; return ret;
} }
ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50);
if(ret != LOS_OK) {
printf("create queue failure, error: %x\n", ret);
}
printf("create the queue success!\n");
LOS_TaskUnlock(); LOS_TaskUnlock();
LOS_Msleep(5000);
return ret; return ret;
} }
``` ```
...@@ -224,9 +230,9 @@ UINT32 ExampleQueue(VOID) ...@@ -224,9 +230,9 @@ UINT32 ExampleQueue(VOID)
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
start test example start queue example
create the queue success! create the queue success!
recv message: test message recv message: test message
delete the queue success! delete the queue success!
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
**信号量控制块** **信号量控制块**
``` ```
/** /**
* 信号量控制块数据结构 * 信号量控制块数据结构
...@@ -116,9 +116,10 @@ typedef struct { ...@@ -116,9 +116,10 @@ typedef struct {
### 编程示例 ### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数ExampleSem。
示例代码如下: 示例代码如下:
``` ```
#include "los_sem.h" #include "los_sem.h"
#include "securec.h" #include "securec.h"
...@@ -128,7 +129,8 @@ static UINT32 g_testTaskId01; ...@@ -128,7 +129,8 @@ static UINT32 g_testTaskId01;
static UINT32 g_testTaskId02; static UINT32 g_testTaskId02;
/* 测试任务优先级 */ /* 测试任务优先级 */
#define TASK_PRIO_TEST 5 #define TASK_PRIO_LOW 5
#define TASK_PRIO_HI 4
/* 信号量结构体id */ /* 信号量结构体id */
static UINT32 g_semId; static UINT32 g_semId;
...@@ -137,11 +139,10 @@ VOID ExampleSemTask1(VOID) ...@@ -137,11 +139,10 @@ VOID ExampleSemTask1(VOID)
{ {
UINT32 ret; UINT32 ret;
printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n"); dprintf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
/* 定时阻塞模式申请信号量,定时时间为10ticks */ /* 定时阻塞模式申请信号量,定时时间为10ticks */
ret = LOS_SemPend(g_semId, 10); ret = LOS_SemPend(g_semId, 10);
/* 申请到信号量 */ /* 申请到信号量 */
if (ret == LOS_OK) { if (ret == LOS_OK) {
LOS_SemPost(g_semId); LOS_SemPost(g_semId);
...@@ -149,12 +150,13 @@ VOID ExampleSemTask1(VOID) ...@@ -149,12 +150,13 @@ VOID ExampleSemTask1(VOID)
} }
/* 定时时间到,未申请到信号量 */ /* 定时时间到,未申请到信号量 */
if (ret == LOS_ERRNO_SEM_TIMEOUT) { if (ret == LOS_ERRNO_SEM_TIMEOUT) {
printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n"); dprintf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
/*永久阻塞模式申请信号量*/ /*永久阻塞模式申请信号量*/
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
printf("ExampleSemTask1 wait_forever and get sem g_semId.\n"); dprintf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
if (ret == LOS_OK) { if (ret == LOS_OK) {
dprintf("ExampleSemTask1 post sem g_semId.\n");
LOS_SemPost(g_semId); LOS_SemPost(g_semId);
return; return;
} }
...@@ -164,19 +166,18 @@ VOID ExampleSemTask1(VOID) ...@@ -164,19 +166,18 @@ VOID ExampleSemTask1(VOID)
VOID ExampleSemTask2(VOID) VOID ExampleSemTask2(VOID)
{ {
UINT32 ret; UINT32 ret;
printf("ExampleSemTask2 try get sem g_semId wait forever.\n"); dprintf("ExampleSemTask2 try get sem g_semId wait forever.\n");
/* 永久阻塞模式申请信号量 */ /* 永久阻塞模式申请信号量 */
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
if (ret == LOS_OK) { if (ret == LOS_OK) {
printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n"); dprintf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
} }
/* 任务休眠20 ticks */ /* 任务休眠20 ticks */
LOS_TaskDelay(20); LOS_TaskDelay(20);
printf("ExampleSemTask2 post sem g_semId.\n"); dprintf("ExampleSemTask2 post sem g_semId.\n");
/* 释放信号量 */ /* 释放信号量 */
LOS_SemPost(g_semId); LOS_SemPost(g_semId);
return; return;
...@@ -199,10 +200,10 @@ UINT32 ExampleSem(VOID) ...@@ -199,10 +200,10 @@ UINT32 ExampleSem(VOID)
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1; task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1;
task1.pcName = "TestTask1"; task1.pcName = "TestTask1";
task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task1.usTaskPrio = TASK_PRIO_TEST; task1.usTaskPrio = TASK_PRIO_LOW;
ret = LOS_TaskCreate(&g_testTaskId01, &task1); ret = LOS_TaskCreate(&g_testTaskId01, &task1);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("task1 create failed .\n"); dprintf("task1 create failed .\n");
return LOS_NOK; return LOS_NOK;
} }
...@@ -211,16 +212,19 @@ UINT32 ExampleSem(VOID) ...@@ -211,16 +212,19 @@ UINT32 ExampleSem(VOID)
task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2; task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2;
task2.pcName = "TestTask2"; task2.pcName = "TestTask2";
task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task2.usTaskPrio = (TASK_PRIO_TEST - 1); task2.usTaskPrio = TASK_PRIO_HI;
ret = LOS_TaskCreate(&g_testTaskId02, &task2); ret = LOS_TaskCreate(&g_testTaskId02, &task2);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("task2 create failed.\n"); dprintf("task2 create failed.\n");
return LOS_NOK; return LOS_NOK;
} }
/* 解锁任务调度 */ /* 解锁任务调度 */
LOS_TaskUnlock(); LOS_TaskUnlock();
/* 任务休眠400 ticks */
LOS_TaskDelay(400);
ret = LOS_SemPost(g_semId); ret = LOS_SemPost(g_semId);
/* 任务休眠400 ticks */ /* 任务休眠400 ticks */
...@@ -237,12 +241,13 @@ UINT32 ExampleSem(VOID) ...@@ -237,12 +241,13 @@ UINT32 ExampleSem(VOID)
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
ExampleSemTask2 try get sem g_semId wait forever. ExampleSemTask2 try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
ExampleSemTask1 try get sem g_semId, timeout 10 ticks. ExampleSemTask1 try get sem g_semId, timeout 10 ticks.
ExampleSemTask1 timeout and try get sem g_semId wait forever. ExampleSemTask1 timeout and try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
ExampleSemTask2 post sem g_semId. ExampleSemTask2 post sem g_semId.
ExampleSemTask1 wait_forever and get sem g_semId. ExampleSemTask1 wait_forever and get sem g_semId.
ExampleSemTask1 post sem g_semId.
``` ```
...@@ -10,26 +10,29 @@ Futex(Fast userspace mutex,用户态快速互斥锁)是内核提供的一种 ...@@ -10,26 +10,29 @@ Futex(Fast userspace mutex,用户态快速互斥锁)是内核提供的一种
当用户态线程释放锁时,先在用户态进行锁状态的判断维护,若此时没有其他线程被该锁阻塞,则直接在用户态进行解锁返回;反之,则需要进行阻塞线程的唤醒操作,通过Futex系统调用请求内核介入来唤醒阻塞队列中的线程。 当用户态线程释放锁时,先在用户态进行锁状态的判断维护,若此时没有其他线程被该锁阻塞,则直接在用户态进行解锁返回;反之,则需要进行阻塞线程的唤醒操作,通过Futex系统调用请求内核介入来唤醒阻塞队列中的线程。
## 运行机制 ## 运行机制
当用户态产生锁的竞争或释放需要进行相关线程的调度操作时,会触发Futex系统调用进入内核,此时会将用户态锁的地址传入内核,并在内核的Futex中以锁地址来区分用户态的每一把锁,因为用户态可用虚拟地址空间为1GiB,为了便于查找、管理,内核Futex采用哈希桶来存放用户态传入的锁。 当用户态产生锁的竞争或释放需要进行相关线程的调度操作时,会触发Futex系统调用进入内核,此时会将用户态锁的地址传入内核,并在内核的Futex中以锁地址来区分用户态的每一把锁,因为用户态可用虚拟地址空间为1GiB,为了便于查找、管理,内核Futex采用哈希桶来存放用户态传入的锁。
当前哈希桶共有80个,0~63号桶用于存放私有锁(以虚拟地址进行哈希),64~79号桶用于存放共享锁(以物理地址进行哈希),私有/共享属性通过用户态锁的初始化以及Futex系统调用入参确定。 当前哈希桶共有80个,~~0-63号桶用于存放私有锁(以虚拟地址进行哈希),64-79~~号桶用于存放共享锁(以物理地址进行哈希),私有/共享属性通过用户态锁的初始化以及Futex系统调用入参确定。
## Futex设计图
**图1** Futex设计图 **图1**
![zh-cn_image_0000001127535690](figures/zh-cn_image_0000001127535690.jpg) ![zh-cn_image_0000001127535690](figures/zh-cn_image_0000001127535690.jpg)
如图1,每个futex哈希桶中存放被futex_list串联起来的哈希值相同的futex node,每个futex node对应一个被挂起的task,node中key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。 如图1,每个futex哈希桶中存放被futex_list串联起来的哈希值相同的futex node,每个futex node对应一个被挂起的task,node中key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
Futex有以下三种操作: ## Futex有以下三种操作:
**表1** Futex模块接口 **Futex模块接口**
| 功能分类 | 接口**名称** | 描述 | | 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- | | -------------- | -------------- | ------------------------------------- |
| 设置线程等待 | OsFutexWait | 向Futex表中插入代表被阻塞的线程的node | | 设置线程等待 | OsFutexWait | 向Futex表中插入代表被阻塞的线程的node |
| 唤醒被阻塞线程 | OsFutexWake | 唤醒一个被指定锁阻塞的线程 | | 唤醒被阻塞线程 | OsFutexWake | 唤醒一个被指定锁阻塞的线程 |
| 调整锁的地址 | OsFutexRequeue | 调整指定锁在Futex表中的位置 | | 调整锁的地址 | OsFutexRequeue | 调整指定锁在Futex表中的位置 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> Futex系统调用通常与用户态逻辑共同组成用户态锁,故推荐使用用户态POSIX接口的锁。 > Futex系统调用通常与用户态逻辑共同组成用户态锁,故推荐使用用户态POSIX接口的锁。
\ No newline at end of file
...@@ -12,46 +12,53 @@ ...@@ -12,46 +12,53 @@
**表1** 信号的运作流程及相关接口(用户态接口) **表1** 信号的运作流程及相关接口(用户态接口)
| 功能分类 | 接口**名称** | 描述 | | 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- | | ---------------- | --------------------------------------------------- | ------------------------------------------------------------ |
| 注册信号回调函数 | signal: | 注册信号总入口及注册和去注册某信号的回调函数。 | | 注册信号回调函数 | signal | 注册信号总入口及注册和去注册某信号的回调函数。 |
| 注册信号回调函数 | sigaction | 功能同signal,但增加了信号发送相关的配置选项,目前仅支持SIGINFO结构体中的部分参数。 | | 注册信号回调函数 | sigaction | 功能同signal,但增加了信号发送相关的配置选项,目前仅支持SIGINFO结构体中的部分参数。 |
| 发送信号 | kill<br/>pthread_kill<br/>raise<br/>alarm<br/>abort | 发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。 | | 发送信号 | kill<br/>pthread_kill<br/>raise<br/>alarm<br/>abort | 发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。 |
| 触发回调 | 无 | 由系统调用与中断触发,内核态与用户态切换前会先进入用户态指定函数并处理完相应回调函数,再回到原用户态程序继续运行。 | | 触发回调 | 无 | 由系统调用与中断触发,内核态与用户态切换前会先进入用户态指定函数并处理完相应回调函数,再回到原用户态程序继续运行。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 信号机制为提供给用户态程序进程间通信的能力,故推荐使用上表1列出的用户态POSIX相关接口。 > 信号机制为提供给用户态程序进程间通信的能力,故推荐使用上表1列出的用户态POSIX相关接口。
> >
> 注册回调函数: > **注册回调函数:**
> >
> >
> ``` > ```
> void *signal(int sig, void (*func)(int))(int); > void *signal(int sig, void (*func)(int))(int);
> ``` > ```
> >
> a. 31 号信号,该信号用来注册该进程的回调函数处理入口,不可重复注册。 > - 31 号信号,该信号用来注册该进程的回调函数处理入口,不可重复注册。
> >
> b. 0-30 号信号,该信号段用来注册与去注册回调函数。 >
> > - 0-30 号信号,该信号段用来注册与去注册回调函数。
> 注册回调函数: >
> >
> > **注册回调函数:**
> ``` >
> int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict); >
> ``` > ```
> > int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict);
> 支持信号注册的配置修改和配置获取,目前仅支持SIGINFO的选项,SIGINFO内容见sigtimedwait接口内描述。 > ```
> >
> 发送信号: > 支持信号注册的配置修改和配置获取,目前仅支持SIGINFO的选项,SIGINFO内容见sigtimedwait接口内描述。
> >
> a. 进程接收信号存在默认行为,单不支持POSIX标准所给出的STOP及CONTINUE、COREDUMP功能。 > **发送信号:**
> >
> b. 进程无法屏蔽SIGSTOP、SIGKILL、SIGCONT信号。 > - 进程接收信号存在默认行为,单不支持POSIX标准所给出的STOP及CONTINUE、COREDUMP功能。
> >
> c. 某进程后被杀死后,若其父进程不回收该进程,其转为僵尸进程。 >
> > - 进程无法屏蔽SIGSTOP、SIGKILL、SIGCONT信号。
> d. 进程接收到某信号后,直到该进程被调度后才会执行信号回调。 >
> >
> e. 进程结束后会发送SIGCHLD信号给父进程,该发送动作无法取消。 > - 某进程后被杀死后,若其父进程不回收该进程,其转为僵尸进程。
> >
> f. 无法通过信号唤醒处于DELAY状态的进程。 >
> - 进程接收到某信号后,直到该进程被调度后才会执行信号回调。
>
>
> - 进程结束后会发送SIGCHLD信号给父进程,该发送动作无法取消。
>
>
> - 无法通过信号唤醒处于DELAY状态的进程。
\ No newline at end of file
...@@ -5,12 +5,20 @@ ...@@ -5,12 +5,20 @@
LiteIPC是OpenHarmony LiteOS-A内核提供的一种新型IPC(Inter-Process Communication,即进程间通信)机制,不同于传统的System V IPC机制,LiteIPC主要是为RPC(Remote Procedure Call,即远程过程调用)而设计的,而且是通过设备文件的方式对上层提供接口的,而非传统的API函数方式。 LiteIPC是OpenHarmony LiteOS-A内核提供的一种新型IPC(Inter-Process Communication,即进程间通信)机制,不同于传统的System V IPC机制,LiteIPC主要是为RPC(Remote Procedure Call,即远程过程调用)而设计的,而且是通过设备文件的方式对上层提供接口的,而非传统的API函数方式。
LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service。整个系统只能有一个ServiceManager,而Service可以有多个。ServiceManager有两个主要功能:一是负责Service的注册和注销,二是负责管理Service的访问权限(只有有权限的任务(Task)可以向对应的Service发送IPC消息)。 LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service。整个系统只能有一个ServiceManager,而Service可以有多个。
**ServiceManager有两个主要功能:**
- 一是负责Service的注册和注销,
- 二是负责管理Service的访问权限(只有有权限的任务(Task)可以向对应的Service发送IPC消息)。
## 运行机制 ## 运行机制
首先将需要接收IPC消息的任务通过ServiceManager注册成为一个Service,然后通过ServiceManager为该Service任务配置访问权限,即指定哪些任务可以向该Service任务发送IPC消息。LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层用户态程序分别提供代表收取IPC消息的读操作和代表发送IPC消息的写操作。 首先将需要接收IPC消息的任务通过ServiceManager注册成为一个Service,然后通过ServiceManager为该Service任务配置访问权限,即指定哪些任务可以向该Service任务发送IPC消息。
LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层用户态程序分别提供代表收取IPC消息的读操作和代表发送IPC消息的写操作。
## 开发指导 ## 开发指导
...@@ -20,11 +28,11 @@ LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service ...@@ -20,11 +28,11 @@ LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service
**表1** LiteIPC模块接口(仅LiteOS-A内部使用) **表1** LiteIPC模块接口(仅LiteOS-A内部使用)
| 功能分类 | 接口描述 | | 功能分类 | 接口描述 |
| -------- | -------- | | ------------- | ------------------------------------------------------------ |
| 模块初始化 | OsLiteIpcInit:初始化LiteIPC模块 | | 模块初始化 | OsLiteIpcInit:初始化LiteIPC模块 |
| IPC消息内存池 | -&nbsp;LiteIpcPoolInit:初始化进程的IPC消息内存池<br/>-&nbsp;LiteIpcPoolReInit:重新初始化进程的IPC消息内存池<br/>-&nbsp;LiteIpcPoolDelete:释放进程的IPC消息内存池 | | IPC消息内存池 | -&nbsp;LiteIpcPoolInit:初始化进程的IPC消息内存池<br/>-&nbsp;LiteIpcPoolReInit:重新初始化进程的IPC消息内存池<br/>-&nbsp;LiteIpcPoolDelete:释放进程的IPC消息内存池 |
| Service管理 | LiteIpcRemoveServiceHandle:删除指定的Service | | Service管理 | LiteIpcRemoveServiceHandle:删除指定的Service |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> LiteIPC模块接口都只在LiteOS-A内部使用。 > LiteIPC模块接口都只在LiteOS-A内部使用。
\ No newline at end of file
...@@ -16,7 +16,7 @@ OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及 ...@@ -16,7 +16,7 @@ OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及
## 运行机制 ## 运行机制
**图1** 动态加载流程 **图1** **动态加载流程**
![zh-cn_image_0000001133104502](figures/zh-cn_image_0000001133104502.png) ![zh-cn_image_0000001133104502](figures/zh-cn_image_0000001133104502.png)
1. 内核将应用程序ELF文件的PT_LOAD段信息映射至进程空间。对于ET_EXEC类型的文件,根据PT_LOAD段中p_vaddr进行固定地址映射;对于ET_DYN类型(位置无关的可执行程序,通过编译选项“-fPIE”得到)的文件,内核通过mmap接口选择base基址进行映射(load_addr = base + p_vaddr)。 1. 内核将应用程序ELF文件的PT_LOAD段信息映射至进程空间。对于ET_EXEC类型的文件,根据PT_LOAD段中p_vaddr进行固定地址映射;对于ET_DYN类型(位置无关的可执行程序,通过编译选项“-fPIE”得到)的文件,内核通过mmap接口选择base基址进行映射(load_addr = base + p_vaddr)。
...@@ -25,18 +25,18 @@ OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及 ...@@ -25,18 +25,18 @@ OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及
3. 动态链接器自举并查找应用程序依赖的所有共享库并对导入符号进行重定位,最后跳转至应用程序的e_entry(或base + e_entry),开始运行应用程序。 3. 动态链接器自举并查找应用程序依赖的所有共享库并对导入符号进行重定位,最后跳转至应用程序的e_entry(或base + e_entry),开始运行应用程序。
**图2** 程序执行流程 **图2** **程序执行流程**
![zh-cn_image_0000001133264664](figures/zh-cn_image_0000001133264664.png) ![zh-cn_image_0000001133264664](figures/zh-cn_image_0000001133264664.png)
1. 加载器与链接器调用mmap映射PT_LOAD段 1. 加载器与链接器调用mmap映射PT_LOAD段
2. 内核调用map_pages接口查找并映射pagecache已有的缓存 2. 内核调用map_pages接口查找并映射pagecache已有的缓存
3. 程序执行时,虚拟内存区间若无具体的物理内存做映射,系统将触发缺页中断,将elf文件内容读入物理内存,并将该内存块加入pagecache 3. 程序执行时,虚拟内存区间若无具体的物理内存做映射,系统将触发缺页中断,将elf文件内容读入物理内存,并将该内存块加入pagecache
4. 将已读入文件内容的物理内存与虚拟地址区间做映射 4. 将已读入文件内容的物理内存与虚拟地址区间做映射
5. 程序继续执行 5. 程序继续执行
## 开发指导 ## 开发指导
...@@ -46,11 +46,11 @@ OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及 ...@@ -46,11 +46,11 @@ OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及
**表1** 内核加载器模块接口 **表1** 内核加载器模块接口
| 功能分类 | 接口**名称** | 描述 | | 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- | | ---------- | ---------------- | -------------------------------- |
| 模块初始化 | LOS_DoExecveFile | 根据输入的参数执行指定的用户程序 | | 模块初始化 | LOS_DoExecveFile | 根据输入的参数执行指定的用户程序 |
### 开发流程 ### 开发流程
LOS_DoExecveFile接口一般由用户通过exec家族函数利用系统调用机制创建新的进程,内核不能直接调用该接口启动新进程。 LOS_DoExecveFile接口一般由用户通过exec家族函数利用系统调用机制创建新的进程,内核不能直接调用该接口启动新进程。
\ No newline at end of file
...@@ -12,7 +12,7 @@ OpenHarmony系统通过VDSO机制实现上层用户态程序可以快速读取 ...@@ -12,7 +12,7 @@ OpenHarmony系统通过VDSO机制实现上层用户态程序可以快速读取
VDSO其核心思想就是内核看护一段内存,并将这段内存映射(只读)进用户态应用程序的地址空间,应用程序通过链接vdso.so后,将某些系统调用替换为直接读取这段已映射的内存从而避免系统调用达到加速的效果。 VDSO其核心思想就是内核看护一段内存,并将这段内存映射(只读)进用户态应用程序的地址空间,应用程序通过链接vdso.so后,将某些系统调用替换为直接读取这段已映射的内存从而避免系统调用达到加速的效果。
VDSO总体可分为数据页与代码页两部分: **VDSO总体可分为数据页与代码页两部分:**
- 数据页提供内核映射给用户进程的内核时数据; - 数据页提供内核映射给用户进程的内核时数据;
...@@ -21,7 +21,7 @@ VDSO总体可分为数据页与代码页两部分: ...@@ -21,7 +21,7 @@ VDSO总体可分为数据页与代码页两部分:
**图1** VDSO系统设计 **图1** VDSO系统设计
![zh-cn_image_0000001173586763](figures/zh-cn_image_0000001173586763.jpg) ![zh-cn_image_0000001173586763](figures/zh-cn_image_0000001173586763.jpg)
如图1所示,当前VDSO机制有以下几个主要步骤: **如图1所示,当前VDSO机制有以下几个主要步骤:**
① 内核初始化时进行VDSO数据页的创建; ① 内核初始化时进行VDSO数据页的创建;
...@@ -42,6 +42,9 @@ VDSO总体可分为数据页与代码页两部分: ...@@ -42,6 +42,9 @@ VDSO总体可分为数据页与代码页两部分:
⑨ 将从VDSO数据页获取到的数据作为结果返回给用户程序; ⑨ 将从VDSO数据页获取到的数据作为结果返回给用户程序;
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 当前VDSO机制支持LibC库clock_gettime接口的CLOCK_REALTIME_COARSE与CLOCK_MONOTONIC_COARSE功能,clock_gettime接口的使用方法详见POSIX标准。用户调用C库接口clock_gettime(CLOCK_REALTIME_COARSE, &amp;ts)或者clock_gettime(CLOCK_MONOTONIC_COARSE, &amp;ts)即可使用VDSO机制。 >
> > - 当前VDSO机制支持LibC库clock_gettime接口的CLOCK_REALTIME_COARSE与CLOCK_MONOTONIC_COARSE功能,clock_gettime接口的使用方法详见POSIX标准。
> - 使用VDSO机制得到的时间精度会与系统tick中断的精度保持一致,适用于对时间没有高精度要求且短时间内会高频触发clock_gettime或gettimeofday系统调用的场景,若有高精度要求,不建议采用VDSO机制。 >
> - 用户调用C库接口clock_gettime(CLOCK_REALTIME_COARSE, &amp;ts)或者clock_gettime(CLOCK_MONOTONIC_COARSE, &amp;ts)即可使用VDSO机制。
>
> - 使用VDSO机制得到的时间精度会与系统tick中断的精度保持一致,适用于对时间没有高精度要求且短时间内会高频触发clock_gettime或gettimeofday系统调用的场景,若有高精度要求,不建议采用VDSO机制。
\ No newline at end of file
...@@ -42,11 +42,12 @@ LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:开关宏,默认关闭;若打开这 ...@@ -42,11 +42,12 @@ LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:开关宏,默认关闭;若打开这
**示例代码** **示例代码**
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试.
代码实现如下: 代码实现如下:
``` ```c
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "los_memory.h" #include "los_memory.h"
...@@ -70,12 +71,12 @@ void MemIntegrityTest(void) ...@@ -70,12 +71,12 @@ void MemIntegrityTest(void)
编译运行输出log如下: 编译运行输出log如下:
``` ```
[ERR][OsMemMagicCheckPrint], 2028, memory check error! [ERR][OsMemMagicCheckPrint], 2028, memory check error!
memory used but magic num wrong, magic num = 0x00000000 /* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */ memory used but magic num wrong, magic num = 0x00000000 /* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020 broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020
/* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */ /* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */
broken node head LR info: /* 节点的LR信息需要开启内存检测功能才有有效输出 */ broken node head LR info: /* 节点的LR信息需要开启内存检测功能才有有效输出 */
......
...@@ -7,14 +7,14 @@ ...@@ -7,14 +7,14 @@
- 内存水线:即内存池的最大使用量,每次申请和释放时,都会更新水线值,实际业务可根据该值,优化内存池大小; - 内存水线:即内存池的最大使用量,每次申请和释放时,都会更新水线值,实际业务可根据该值,优化内存池大小;
- 碎片率:衡量内存池的碎片化程度,碎片率高表现为内存池剩余内存很多,但是最大空闲内存块很小,可以用公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)来度量 - 碎片率:衡量内存池的碎片化程度,碎片率高表现为内存池剩余内存很多,但是最大空闲内存块很小,可以用公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)来度量
- 其他统计信息:调用接口LOS_MemInfoGet时,会扫描内存池的节点信息,统计出相关信息。 - 其他统计信息:调用接口LOS_MemInfoGet时,会扫描内存池的节点信息,统计出相关信息。
## 功能配置 ## 功能配置
LOSCFG_MEM_WATERLINE:开关宏,默认关闭;若需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable memory pool waterline or not”。如需获取内存水线,需要打开该配置。 LOSCFG_MEM_WATERLINE:开关宏,默认关闭;若需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable MEM Debug-&gt; Enable memory pool waterline or not”。如需获取内存水线,需要打开该配置。
## 开发指导 ## 开发指导
...@@ -24,8 +24,8 @@ LOSCFG_MEM_WATERLINE:开关宏,默认关闭;若需要打开这个功能, ...@@ -24,8 +24,8 @@ LOSCFG_MEM_WATERLINE:开关宏,默认关闭;若需要打开这个功能,
关键结构体介绍: 关键结构体介绍:
``` ```c
typedef struct { typedef struct {
UINT32 totalUsedSize; // 内存池的内存使用量 UINT32 totalUsedSize; // 内存池的内存使用量
UINT32 totalFreeSize; // 内存池的剩余内存大小 UINT32 totalFreeSize; // 内存池的剩余内存大小
...@@ -38,7 +38,7 @@ typedef struct { ...@@ -38,7 +38,7 @@ typedef struct {
} LOS_MEM_POOL_STATUS; } LOS_MEM_POOL_STATUS;
``` ```
- 内存水线获取:调用LOS_MemInfoGet接口,第1个参数是内存池首地址,第2个参数是LOS_MEM_POOL_STATUS类型的句柄,其中字段usageWaterLine即水线值。 - 内存水线获取:调用 LOS_MemInfoGet(VOID *pool, LOS_MEM_POOL_STATUS *poolStatus)接口,第1个参数是内存池首地址,第2个参数是LOS_MEM_POOL_STATUS类型的句柄,其中字段usageWaterLine即水线值。
- 内存碎片率计算:同样调用LOS_MemInfoGet接口,可以获取内存池的剩余内存大小和最大空闲内存块大小,然后根据公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)得出此时的动态内存池碎片率。 - 内存碎片率计算:同样调用LOS_MemInfoGet接口,可以获取内存池的剩余内存大小和最大空闲内存块大小,然后根据公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)得出此时的动态内存池碎片率。
...@@ -53,13 +53,13 @@ typedef struct { ...@@ -53,13 +53,13 @@ typedef struct {
3. 利用公式算出使用率及碎片率。 3. 利用公式算出使用率及碎片率。
**示例代码** **示例代码**
本演示代码在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证,在TestTaskEntry中调用验证入口函数MemTest。
代码实现如下: 代码实现如下:
``` ```c
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "los_task.h" #include "los_task.h"
...@@ -70,15 +70,14 @@ void MemInfoTaskFunc(void) ...@@ -70,15 +70,14 @@ void MemInfoTaskFunc(void)
{ {
LOS_MEM_POOL_STATUS poolStatus = {0}; LOS_MEM_POOL_STATUS poolStatus = {0};
/* pool为要统计信息的内存地址,此处以OS_SYS_MEM_ADDR为例 */ /* pool为要统计信息的内存地址,此处以OS_SYS_MEM_ADDR为例 */
void *pool = OS_SYS_MEM_ADDR; void *pool = OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool, &poolStatus); LOS_MemInfoGet(pool, &poolStatus);
/* 算出内存池当前的碎片率百分比 */ /* 算出内存池当前的碎片率百分比 */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize; unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize;
/* 算出内存池当前的使用率百分比 */ /* 算出内存池当前的使用率百分比 */
unsigned char usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool); unsigned char usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool);
printf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize, dprintf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
poolStatus.totalFreeSize, poolStatus.usageWaterLine);
} }
int MemTest(void) int MemTest(void)
...@@ -92,10 +91,10 @@ int MemTest(void) ...@@ -92,10 +91,10 @@ int MemTest(void)
taskStatus.usTaskPrio = 10; taskStatus.usTaskPrio = 10;
ret = LOS_TaskCreate(&taskID, &taskStatus); ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) { if (ret != LOS_OK) {
printf("task create failed\n"); dprintf("task create failed\n");
return -1; return LOS_NOK;
} }
return 0; return LOS_OK;
} }
``` ```
...@@ -105,8 +104,8 @@ int MemTest(void) ...@@ -105,8 +104,8 @@ int MemTest(void)
编译运行输出的结果如下: 编译运行输出的结果如下:
根据实际运行环境,数据会有差异
``` ```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414 usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
``` ```
...@@ -8,11 +8,11 @@ ...@@ -8,11 +8,11 @@
## 功能配置 ## 功能配置
1. LOSCFG_MEM_LEAKCHECK:开关宏,默认关闭;如需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable Function call stack of Mem operation recorded”。 1. LOSCFG_MEM_LEAKCHECK:开关宏,默认关闭;如需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable MEM Debug-&gt; Enable Function call stack of Mem operation recorded”。
2. LOS_RECORD_LR_CNT:记录的LR层数,默认3层;每层LR消耗sizeof(void \*)字节数的内存。 2. LOS_RECORD_LR_CNT:记录的LR层数,默认3层;每层LR消耗sizeof(void \*)字节数的内存。
3. LOS_OMIT_LR_CNT:忽略的LR层数,默认2层,即从调用LOS_MemAlloc的函数开始记录,可根据实际情况调整。为啥需要这个配置?有3点原因如下: 3. LOS_OMIT_LR_CNT:忽略的LR层数,默认2层,即从调用LOS_MemAlloc的函数开始记录,可根据实际情况调整。需要此配置原因如下:
- LOS_MemAlloc接口内部也有函数调用; - LOS_MemAlloc接口内部也有函数调用;
- 外部可能对LOS_MemAlloc接口有封装; - 外部可能对LOS_MemAlloc接口有封装;
- LOS_RECORD_LR_CNT 配置的LR层数有限; - LOS_RECORD_LR_CNT 配置的LR层数有限;
...@@ -27,17 +27,17 @@ ...@@ -27,17 +27,17 @@
该调测功能可以分析关键的代码逻辑中是否存在内存泄漏。开启这个功能,每次申请内存时,会记录LR信息。在需要检测的代码段前后,调用LOS_MemUsedNodeShow接口,每次都会打印指定内存池已使用的全部节点信息,对比前后两次的节点信息,新增的节点信息就是疑似泄漏的内存节点。通过LR,可以找到具体申请的代码位置,进一步确认是否泄漏。 该调测功能可以分析关键的代码逻辑中是否存在内存泄漏。开启这个功能,每次申请内存时,会记录LR信息。在需要检测的代码段前后,调用LOS_MemUsedNodeShow接口,每次都会打印指定内存池已使用的全部节点信息,对比前后两次的节点信息,新增的节点信息就是疑似泄漏的内存节点。通过LR,可以找到具体申请的代码位置,进一步确认是否泄漏。
调用LOS_MemUsedNodeShow接口输出的节点信息格式如下:每1行为一个节点信息;第1列为节点地址,可以根据这个地址,使用GDB等手段查看节点完整信息;第2列为节点的大小,等于节点头大小+数据域大小;第3~5列为函数调用关系LR地址,可以根据这个值,结合汇编文件,查看该节点具体申请的位置。 调用LOS_MemUsedNodeShow接口输出的节点信息格式如下:每1行为一个节点信息;第1列为节点地址,可以根据这个地址,使用GDB等工具查看节点完整信息;第2列为节点的大小,等于节点头大小+数据域大小;第3~5列为函数调用关系LR地址,可以根据这个值,结合汇编文件,查看该节点具体申请的位置。
``` ```
node size LR[0] LR[1] LR[2] node size LR[0] LR[1] LR[2]
0x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002 0x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002
0x10017848: 0xe0 0x9b02c24e 0x9b02c246 0x9b008ef0 0x10017848: 0xe0 0x9b02c24e 0x9b02c246 0x9b008ef0
0x10017928: 0x50 0x9b008ed0 0x9b068902 0x9b0687c4 0x10017928: 0x50 0x9b008ed0 0x9b068902 0x9b0687c4
0x10017978: 0x24 0x9b008ed0 0x9b068924 0x9b0687c4 0x10017978: 0x24 0x9b008ed0 0x9b068924 0x9b0687c4
0x1001799c: 0x30 0x9b02c24e 0x9b02c246 0x9b008ef0 0x1001799c: 0x30 0x9b02c24e 0x9b02c246 0x9b008ef0
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0 0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
``` ```
> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:** > ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:**
...@@ -61,21 +61,36 @@ node size LR[0] LR[1] LR[2] ...@@ -61,21 +61,36 @@ node size LR[0] LR[1] LR[2]
**示例代码** **示例代码**
本演示代码在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证,在TestTaskEntry中调用验证入口函数MemLeakTest。
为了方便展示建议创建新的内存池,需要在target_config.h 中定义 LOSCFG_MEM_MUL_POOL
代码实现如下: 代码实现如下:
``` ```c
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "los_memory.h" #include "los_memory.h"
#include "los_config.h" #include "los_config.h"
#define TEST_NEW_POOL_SIZE 2000
#define TEST_MALLOC_SIZE 8
void MemLeakTest(void) void MemLeakTest(void)
{ {
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR); VOID *pool = NULL;
void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8); /* 由于原内存池分配过多, 为了方便展示, 创建新的内存池 */
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR); pool = LOS_MemAlloc(OS_SYS_MEM_ADDR, TEST_NEW_POOL_SIZE);
(VOID)LOS_MemInit(pool, TEST_NEW_POOL_SIZE);
OsMemUsedNodeShow(pool);
void *ptr1 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
void *ptr2 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
OsMemUsedNodeShow(pool);
/* 释放内存池 */
(VOID)LOS_MemDeInit(pool);
} }
``` ```
...@@ -86,51 +101,50 @@ void MemLeakTest(void) ...@@ -86,51 +101,50 @@ void MemLeakTest(void)
编译运行输出log如下: 编译运行输出log如下:
``` ```
node size LR[0] LR[1] LR[2] /* 第一次OsMemUsedNodeShow打印,由于该内存池未分配,所以无内存节点 */
0x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc node LR[0] LR[1] LR[2]
0x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc
0x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a /* 第二次OsMemUsedNodeShow打印,有两个新的内存节点 */
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220 node LR[0] LR[1] LR[2]
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
node size LR[0] LR[1] LR[2] 0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
0x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc
0x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc
0x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
``` ```
对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块: 对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块:
``` ```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6 0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000 0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
``` ```
部分汇编文件如下: 部分汇编文件如下:
``` ```
MemLeakTest: 4009f014: 7d 1e a0 e3 mov r1, #2000
0x80041d4: 0xb510 PUSH {R4, LR} 4009f018: 00 00 90 e5 ldr r0, [r0]
0x80041d6: 0x4ca8 LDR.N R4, [PC, #0x2a0] ; g_memStart 4009f01c: 67 7a fe eb bl #-398948 <LOS_MemAlloc>
0x80041d8: 0x0020 MOVS R0, R4 4009f020: 7d 1e a0 e3 mov r1, #2000
0x80041da: 0xf7fd 0xf93e BL LOS_MemUsedNodeShow ; 0x800145a 4009f024: 00 40 a0 e1 mov r4, r0
0x80041de: 0x2108 MOVS R1, #8 4009f028: c7 79 fe eb bl #-399588 <LOS_MemInit>
0x80041e0: 0x0020 MOVS R0, R4 4009f02c: 04 00 a0 e1 mov r0, r4
0x80041e2: 0xf7fd 0xfbd9 BL LOS_MemAlloc ; 0x8001998 4009f030: 43 78 fe eb bl #-401140 <OsMemUsedNodeShow>
0x80041e6: 0x2108 MOVS R1, #8 4009f034: 04 00 a0 e1 mov r0, r4
0x80041e8: 0x0020 MOVS R0, R4 4009f038: 08 10 a0 e3 mov r1, #8
0x80041ea: 0xf7fd 0xfbd5 BL LOS_MemAlloc ; 0x8001998 4009f03c: 5f 7a fe eb bl #-398980 <LOS_MemAlloc>
0x80041ee: 0x0020 MOVS R0, R4 4009f040: 04 00 a0 e1 mov r0, r4
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a 4009f044: 08 10 a0 e3 mov r1, #8
0x80041f4: 0xbd10 POP {R4, PC} 4009f048: 5c 7a fe eb bl #-398992 <LOS_MemAlloc>
0x80041f6: 0x0000 MOVS R0, R0 4009f04c: 04 00 a0 e1 mov r0, r4
4009f050: 3b 78 fe eb bl #-401172 <OsMemUsedNodeShow>
4009f054: 3c 00 9f e5 ldr r0, [pc, #60]
4009f058: 40 b8 fe eb bl #-335616 <dprintf>
4009f05c: 04 00 a0 e1 mov r0, r4
4009f060: 2c 7a fe eb bl #-399184 <LOS_MemDeInit>
``` ```
其中,通过查找0x080041ee,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。 其中,通过查找0x4009f040,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。
# Perf调测
## 基本概念
Perf为性能分析工具,依赖PMU(Performance Monitoring Unit)对采样事件进行计数和上下文采集,统计出热点分布(hot spot)和热路径(hot path)。
## 运行机制
基于事件采样原理,以性能事件为基础,当事件发生时,相应的事件计数器溢出发生中断,在中断处理函数中记录事件信息,包括当前的pc、当前运行的任务ID以及调用栈等信息。
Perf提供2种工作模式,计数模式和采样模式。
计数模式仅统计事件发生的次数和耗时,采样模式会收集上下文数据到环形buffer中,需要IDE进行数据解析生成热点函数与热点路径。
## 接口说明
OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h)参考。
**表1** Perf模块接口说明
| 功能分类 | 接口描述 |
| -------- | -------- |
| 开启/停止Perf采样 | LOS_PerfInit : 初始化Perf<br/>LOS_PerfStart:开启采样<br/>LOS_PerfStop:停止采样 |
| 配置Perf采样事件 | LOS_PerfConfig:配置采样事件的类型、周期等 |
| 读取采样数据 | LOS_PerfDataRead:读取采样数据到指定地址 |
| 注册采样数据缓冲区的钩子函数 | LOS_PerfNotifyHookReg:注册缓冲区水线到达的处理钩子<br/>LOS_PerfFlushHookReg:注册缓冲区刷cache的钩子 |
1. Perf采样事件的结构体为PerfConfigAttr,详细字段含义及取值详见 [kernel\include\los_perf.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h)
2. 采样数据缓冲区为环形buffer,buffer中读过的区域可以覆盖写,未被读过的区域不能被覆盖写。
3. 缓冲区有限,用户可通过注册水线到达的钩子进行buffer溢出提醒或buffer读操作。默认水线值为buffer总大小的1/2。 示例如下:
```c
VOID Example_PerfNotifyHook(VOID)
{
CHAR buf[LOSCFG_PERF_BUFFER_SIZE] = {0};
UINT32 len;
PRINT_DEBUG("perf buffer reach the waterline!\n");
len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
OsPrintBuff(buf, len); /* print data */
}
LOS_PerfNotifyHookReg(Example_PerfNotifyHook);
```
4. 若perf采样的buffer涉及到CPU跨cache,则用户可通过注册刷cache的钩子,进行cache同步。 示例如下:
```c
VOID Example_PerfFlushHook(VOID *addr, UINT32 size)
{
OsCacheFlush(addr, size); /* platform interface */
}
LOS_PerfNotifyHookReg(Example_PerfFlushHook);
```
刷cache接口视具体的平台自行配置。
## 开发指导
### 内核态开发流程
开启Perf调测的典型流程如下:
1. 配置Perf模块相关宏。
配置Perf控制宏LOSCFG_KERNEL_PERF,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel-&gt;Enable Perf Feature"中打开:
| 配置项 | menuconfig选项 | 含义 | 设置值 |
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_PERF | Enable&nbsp;Perf&nbsp;Feature | Perf模块的裁剪开关 | YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_TICK | Time-consuming&nbsp;Calc&nbsp;Methods-&gt;By&nbsp;Tick | Perf计时单位为tick | YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_CYCLE | Time-consuming&nbsp;Calc&nbsp;Methods-&gt;By&nbsp;Cpu&nbsp;Cycle | Perf计时单位为cycle | YES/NO |
| LOSCFG_PERF_BUFFER_SIZE | Perf&nbsp;Sampling&nbsp;Buffer&nbsp;Size | Perf采样buffer的大小 | INT |
| LOSCFG_PERF_HW_PMU | Enable&nbsp;Hardware&nbsp;Pmu&nbsp;Events&nbsp;for&nbsp;Sampling | 使能硬件PMU事件,需要目标平台支持硬件PMU | YES/NO |
| LOSCFG_PERF_TIMED_PMU | Enable&nbsp;Hrtimer&nbsp;Period&nbsp;Events&nbsp;for&nbsp;Sampling | 使能高精度周期事件,需要目标平台支持高精度定时器 | YES/NO |
| LOSCFG_PERF_SW_PMU | Enable&nbsp;Software&nbsp;Events&nbsp;for&nbsp;Sampling | 使能软件事件,需要开启LOSCFG_KERNEL_HOOK | YES/NO |
2. 调用LOS_PerfConfig配置需要采样的事件。
Perf提供2种模式的配置,及3大类型的事件配置:
2种模式:计数模式(仅统计事件发生次数)、采样模式(收集上下文如任务ID、pc、backtrace等)。
3种事件类型:CPU硬件事件(cycle、branch、icache、dcache等)、高精度周期事件(cpu clock)、OS软件事件(task switch、mux pend、irq等)。
3. 在需要采样的代码起始点调用LOS_PerfStart(UINT32 sectionId), 入参sectionId标记不同的采样回话id。
4. 在需要采样的代码结束点调用LOS_PerfStop。
5. 调用输出缓冲区数据的接口LOS_PerfDataRead读取采样数据,并使用IDE工具进行解析。
#### 内核态编程实例
本实例实现如下功能:
1. 创建perf测试任务。
2. 配置采样事件。
3. 启动perf。
4. 执行需要统计的算法。
5. 停止perf。
6. 输出统计结果。
#### 内核态示例代码
前提条件:在menuconfig菜单中完成perf模块的配置, 并勾选Enable Hook Feature,Enable Software Events for Sampling。
为方便学习,本演示代码直接在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证即可。
实例代码如下:
```c
#include "los_perf.h"
#define TEST_MALLOC_SIZE 200
#define TEST_TIME 5
/* 验证函数中进行malloc和free */
VOID test(VOID)
{
VOID *p = NULL;
int i;
for (i = 0; i < TEST_TIME; i++) {
p = LOS_MemAlloc(m_aucSysMem1, TEST_MALLOC_SIZE);
if (p == NULL) {
PRINT_ERR("test alloc failed\n");
return;
}
(VOID)LOS_MemFree(m_aucSysMem1, p);
}
}
STATIC VOID OsPrintBuff(const CHAR *buf, UINT32 num)
{
UINT32 i = 0;
PRINTK("num: ");
for (i = 0; i < num; i++) {
PRINTK(" %02d", i);
}
PRINTK("\n");
PRINTK("hex: ");
for (i = 0; i < num; i++) {
PRINTK(" %02x", buf[i]);
}
PRINTK("\n");
}
STATIC VOID perfTestHwEvent(VOID)
{
UINT32 ret;
CHAR *buf = NULL;
UINT32 len;
//LOS_PerfInit(NULL, 0);
PerfConfigAttr attr = {
.eventsCfg = {
.type = PERF_EVENT_TYPE_SW,
.events = {
[0] = {PERF_COUNT_SW_TASK_SWITCH, 0xff}, /* 抓取调度 */
[1] = {PERF_COUNT_SW_MEM_ALLOC, 0xff}, /* 抓取内存分配 */
PERF_COUNT_SW_TASK_SWITCH
},
.eventsNr = 2,
.predivided = 1, /* cycle counter increase every 64 cycles */
},
.taskIds = {0},
.taskIdsNr = 0,
.needSample = 0,
.sampleType = PERF_RECORD_IP | PERF_RECORD_CALLCHAIN,
};
ret = LOS_PerfConfig(&attr);
if (ret != LOS_OK) {
PRINT_ERR("perf config error %u\n", ret);
return;
}
PRINTK("------count mode------\n");
LOS_PerfStart(0);
test(); /* this is any test function*/
LOS_PerfStop();
PRINTK("--------sample mode------ \n");
attr.needSample = 1;
LOS_PerfConfig(&attr);
LOS_PerfStart(2); // 2: set the section id to 2.
test(); /* this is any test function*/
LOS_PerfStop();
buf = LOS_MemAlloc(m_aucSysMem1, LOSCFG_PERF_BUFFER_SIZE);
if (buf == NULL) {
PRINT_ERR("buffer alloc failed\n");
return;
}
/* get sample data */
len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
OsPrintBuff(buf, len); /* print data */
(VOID)LOS_MemFree(m_aucSysMem1, buf);
}
UINT32 Example_Perf_test(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S perfTestTask = {0};
UINT32 taskID;
/* 创建用于perf测试的任务 */
perfTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)perfTestHwEvent;
perfTestTask.pcName = "TestPerfTsk"; /* 测试任务名称 */
perfTestTask.uwStackSize = 0x1000; // 0x8000: perf test task stack size
perfTestTask.usTaskPrio = 5; // 5: perf test task priority
ret = LOS_TaskCreate(&taskID, &perfTestTask);
if (ret != LOS_OK) {
PRINT_ERR("PerfTestTask create failed. 0x%x\n", ret);
return LOS_NOK;
}
return LOS_OK;
}
LOS_MODULE_INIT(perfTestHwEvent, LOS_INIT_LEVEL_KMOD_EXTENDED);
```
#### 内核态结果验证
输出结果如下:
```
type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 0
------count mode------
[task switch] eventType: 0x1 [core 0]: 0
[mem alloc] eventType: 0x3 [core 0]: 5
time used: 0.005000(s)
--------sample mode------
type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 1
dump perf data, addr: 0x402c3e6c length: 0x5000
time used: 0.000000(s)
num: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
hex: 00 ffffffef ffffffef ffffffef 02 00 00 00 14 00 00 00 60 00 00 00 02 00 00 00
根据实际运行环境,过程打印会有差异
```
- 针对计数模式,系统在perf stop后会打印:
事件名称(cycles)、事件类型(0xff)、事件发生的次数(5466989440)。
当采样事件为硬件PMU事件时,打印的事件类型为实际的硬件事件id,非enum PmuHWId中定义的抽象类型。
- 针对采样模式,系统在perf stop后会打印采样数据的地址和长度:
dump section data, addr: (0x8000000) length: (0x5000)
用户可以通过JTAG口导出该片内存,再使用IDE线下工具解析。
或者通过LOS_PerfDataRead将数据读到指定地址,进行查看或进一步处理。示例中OsPrintBuff为测试接口,其按字节打印Read到的采样数据,num表示第几个字节,hex表示该字节中的数值。
...@@ -6,16 +6,16 @@ ...@@ -6,16 +6,16 @@
CPU(中央处理器,Central Processing Unit)占用率分为系统CPU占用率、进程CPU占用率、任务CPU占用率和中断CPU占用率。用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规格。通过系统中各个进程/任务/中断的CPU占用情况,判断各个进程/任务/中断的CPU占用率是否符合设计的预期。 CPU(中央处理器,Central Processing Unit)占用率分为系统CPU占用率、进程CPU占用率、任务CPU占用率和中断CPU占用率。用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规格。通过系统中各个进程/任务/中断的CPU占用情况,判断各个进程/任务/中断的CPU占用率是否符合设计的预期。
- 系统CPU占用率(CPU Percent) - 系统CPU占用率(CPU Percent)
指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分。100表示系统满负荷运转。 指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分之一。100表示系统满负荷运转。
- 进程CPU占用率 - 进程CPU占用率
指单个进程的CPU占用率,用于表示单个进程在一段时间内的闲忙程度。进程CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分。100表示在一段时间内系统一直在运行该进程。 指单个进程的CPU占用率,用于表示单个进程在一段时间内的闲忙程度。进程CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分之一。100表示在一段时间内系统一直在运行该进程。
- 任务CPU占用率 - 任务CPU占用率
指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分。100表示在一段时间内系统一直在运行该任务。 指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分之一。100表示在一段时间内系统一直在运行该任务。
- 中断CPU占用率 - 中断CPU占用率
指单个中断的CPU占用率,用于表示单个中断在一段时间内的闲忙程度。中断CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分。100表示在一段时间内系统一直在运行该中断。 指单个中断的CPU占用率,用于表示单个中断在一段时间内的闲忙程度。中断CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分之一。100表示在一段时间内系统一直在运行该中断。
## 运行机制 ## 运行机制
...@@ -50,13 +50,14 @@ OpenHarmony 提供以下四种CPU占用率的信息查询: ...@@ -50,13 +50,14 @@ OpenHarmony 提供以下四种CPU占用率的信息查询:
**表1** CPUP模块接口 **表1** CPUP模块接口
| 功能分类 | 接口**名称** | 描述 | | 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| 系统CPU占用率 | LOS_HistorySysCpuUsage | 获取系统历史CPU占用率 | | 系统CPU占用率 | LOS_HistorySysCpuUsage | 获取系统历史CPU占用率 |
| 进程CPU占用率 | LOS_HistoryProcessCpuUsage | 获取指定进程历史CPU占用率 | | 进程CPU占用率 | LOS_HistoryProcessCpuUsage | 获取指定进程历史CPU占用率 |
| 进程CPU占用率 | LOS_GetAllProcessCpuUsage | 获取系统所有进程的历史CPU占用率 | | 进程CPU占用率 | LOS_GetAllProcessCpuUsage | 获取系统所有进程的历史CPU占用率 |
| 任务CPU占用率 | LOS_HistoryTaskCpuUsage | 获取指定任务历史CPU占用率 | | 任务CPU占用率 | LOS_HistoryTaskCpuUsage | 获取指定任务历史CPU占用率 |
| 中断CPU占用率 | LOS_GetAllIrqCpuUsage | 获取系统所有中断的历史CPU占用率 | | 中断CPU占用率 | LOS_GetAllIrqCpuUsage | 获取系统所有中断的历史CPU占用率 |
| 重置 | LOS_CpupReset | 重置CPU 占用率相关数据 |
### 开发流程 ### 开发流程
...@@ -102,48 +103,50 @@ CPU占用率的典型开发流程: ...@@ -102,48 +103,50 @@ CPU占用率的典型开发流程:
**示例代码** **示例代码**
本演示代码在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证,在TestTaskEntry中调用验证入口函数CpupTest。
代码实现如下: 代码实现如下:
``` ```c
#include "los_task.h" #include "los_task.h"
#include "los_cpup.h" #include "los_cpup.h"
#define MODE 4 #define MODE 4
UINT32 g_cpuTestTaskID; UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID) VOID ExampleCpup(VOID)
{ {
printf("entry cpup test example\n"); int i = 0;
while(1) { dprintf("entry cpup test example\n");
usleep(100); for (i = 0; i < 10; i++) {
usleep(100); // 100: delay for 100ms
} }
} }
UINT32 ItCpupTest(VOID) UINT32 CpupTest(VOID)
{ {
UINT32 ret; UINT32 ret;
UINT32 cpupUse; UINT32 cpupUse;
TSK_INIT_PARAM_S cpupTestTask = { 0 }; TSK_INIT_PARAM_S cpupTestTask = {0};
memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S)); memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S));
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup; cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup;
cpupTestTask.pcName = "TestCpupTsk"; cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = 0x800; cpupTestTask.uwStackSize = 0x800; // 0x800: cpup test task stack size
cpupTestTask.usTaskPrio = 5; cpupTestTask.usTaskPrio = 5; // 5: cpup test task priority
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask); ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask);
if(ret != LOS_OK) { if (ret != LOS_OK) {
printf("cpupTestTask create failed .\n"); printf("cpupTestTask create failed .\n");
return LOS_NOK; return LOS_NOK;
} }
usleep(100); usleep(100); // 100: delay for 100ms
/* 获取当前系统历史CPU占用率 */ /* 获取当前系统历史CPU占用率 */
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S); cpupUse = LOS_HistorySysCpuUsage(CPUP_LAST_ONE_SECONDS);
printf("the history system cpu usage in all time:%u.%u\n", dprintf("the history system cpu usage in all time:%u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT); cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
/* 获取指定任务的CPU占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */ /* 获取指定任务的CPU占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S); cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPUP_LAST_ONE_SECONDS);
printf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n", dprintf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT); g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK; return LOS_OK;
} }
``` ```
...@@ -151,9 +154,11 @@ UINT32 ItCpupTest(VOID) ...@@ -151,9 +154,11 @@ UINT32 ItCpupTest(VOID)
编译运行得到的结果为: 编译运行得到的结果为:
``` ```
entry cpup test example entry cpup test example
the history system cpu usage in all time: 3.0 the history system cpu usage in all time: 3.0
cpu usage of the cpupTestTask in all time: TaskID:10 usage: 0.0 cpu usage of the cpupTestTask in all time: TaskID:10 usage: 0.0
根据实际运行环境,打印会有差异
``` ```
...@@ -13,12 +13,12 @@ cpup [_mode_] [_taskID_] ...@@ -13,12 +13,12 @@ cpup [_mode_] [_taskID_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| mode | -&nbsp;缺省:显示系统最近10s内的CPU占用率。<br/>-&nbsp;0:显示系统最近10s内的CPU占用率。<br/>-&nbsp;1:显示系统最近1s内的CPU占用率。<br/>-&nbsp;其他数字:显示系统启动至今总的CPU&nbsp;占用率。 | [0,0xFFFFFFFF] | | mode | -&nbsp;缺省:显示系统最近10s内的CPU占用率。<br/>-&nbsp;0:显示系统最近10s内的CPU占用率。<br/>-&nbsp;1:显示系统最近1s内的CPU占用率。<br/>-&nbsp;其他数字:显示系统启动至今总的CPU&nbsp;占用率。 | [0, 0xFFFFFFFF] |
| taskID | 任务ID号 | [0,0xFFFFFFFF] | | taskID | 任务ID号 | [0, 0xFFFFFFFF] |
## 使用指南 ## 使用指南
...@@ -37,8 +37,8 @@ cpup [_mode_] [_taskID_] ...@@ -37,8 +37,8 @@ cpup [_mode_] [_taskID_]
## 输出说明 ## 输出说明
**示例**:指令输出结果 **示例** 指令输出结果
``` ```
OHOS # cpup 1 5pid 5 OHOS # cpup 1 5pid 5
......
...@@ -19,13 +19,13 @@ date命令用于查询系统日期和时间。 ...@@ -19,13 +19,13 @@ date命令用于查询系统日期和时间。
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ------- | ------------------------------ | ---------------------- |
| --help | 使用帮助。 | N/A | | --help | 使用帮助。 | N/A |
| +Format | 根据Format格式打印日期和时间。 | --help中列出的占位符。 | | +Format | 根据Format格式打印日期和时间。 | --help中列出的占位符。 |
| -u | 显示UTC,而不是当前时区 | N/A | | -u | 显示UTC,而不是当前时区 | N/A |
## 使用指南 ## 使用指南
...@@ -36,6 +36,9 @@ date命令用于查询系统日期和时间。 ...@@ -36,6 +36,9 @@ date命令用于查询系统日期和时间。
- 目前命令不支持设置时间和日期。 - 目前命令不支持设置时间和日期。
## 特殊说明
date -u参数 shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -46,8 +49,8 @@ date命令用于查询系统日期和时间。 ...@@ -46,8 +49,8 @@ date命令用于查询系统日期和时间。
示例:按指定格式打印系统日期 示例:按指定格式打印系统日期
``` ```
OHOS:/$ date +%Y--%m--%d OHOS:/$ date +%Y--%m--%d
1970--01--01 1970--01--01
``` ```
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## 命令功能 ## 命令功能
dmesg命令用于显示系统启动过程和运行过程中的信息。 dmesg命令用于显示开机信息,以及系统启动过程和运行过程中的信息。
## 命令格式 ## 命令格式
...@@ -21,22 +21,22 @@ dmesg &gt; [_fileA_] ...@@ -21,22 +21,22 @@ dmesg &gt; [_fileA_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | --------------- | ---------------------------------------- | --------------- |
| -c | 打印缓存区内容并清空缓存区。 | N/A | | -c | 打印缓存区内容并清空缓存区。 | N/A |
| -C | 清空缓存区。 | N/A | | -C | 清空缓存区。 | N/A |
| -D/-E | 关闭/开启控制台打印。 | N/A | | -D/-E | 关闭/开启控制台打印。 | N/A |
| -L/-U | 关闭/开启串口打印。 | N/A | | -L/-U | 关闭/开启串口打印。 | N/A |
| -s&nbsp;size | 设置缓存区大小&nbsp;size是要设置的大小。 | N/A | | -s&nbsp;size | 设置缓存区大小&nbsp;size是要设置的大小。 | N/A |
| -l&nbsp;level | 设置缓存等级。 | 0&nbsp;-&nbsp;5 | | -l&nbsp;level | 设置缓存等级。 | [0, 5] |
| &gt;&nbsp;fileA | 将缓存区内容重定向写入文件。 | N/A | | &gt;&nbsp;fileA | 将缓存区内容重定向写入文件。 | N/A |
## 使用指南 ## 使用指南
- 该命令依赖于LOSCFG_SHELL_DMESG,使用时通过menuconfig在配置项中开启"Enable Shell dmesg": - 该命令依赖于LOSCFG_SHELL_DMESG,在kernel/liteos_a中输入make menuconfig命令。此时会弹出配置项,找到Debug选项并进入,然后在配置项中开启"Enable Shell dmesg":
Debug ---&gt; Enable a Debug Version ---&gt; Enable Shell ---&gt; Enable Shell dmesg Debug ---&gt; Enable a Debug Version ---&gt; Enable Shell ---&gt; Enable Shell dmesg
- dmesg参数缺省时,默认打印缓存区内容。 - dmesg参数缺省时,默认打印缓存区内容。
...@@ -53,9 +53,9 @@ dmesg &gt; [_fileA_] ...@@ -53,9 +53,9 @@ dmesg &gt; [_fileA_]
## 输出说明 ## 输出说明
**示例**dmesg重定向到文件 **示例** dmesg重定向到文件
``` ```
OHOS # dmesg > dmesg.log OHOS # dmesg > dmesg.log
Dmesg write log to dmesg.log success Dmesg write log to dmesg.log success
``` ```
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## 命令功能 ## 命令功能
exec命令属于shell内置命令,目前实现最基础的执行用户态程序的功能。 exec命令属于shell内置命令,在exec执行命令时,不启用新的shell进程。目前实现最基础的执行用户态程序的功能
## 命令格式 ## 命令格式
...@@ -13,11 +13,11 @@ exec &lt;_executable-file_&gt; ...@@ -13,11 +13,11 @@ exec &lt;_executable-file_&gt;
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | | --------------- | ------------------ |
| executable-file | 有效的可执行文件。 | N/A | | executable-file | 有效的可执行文件。 |
## 使用指南 ## 使用指南
...@@ -34,11 +34,11 @@ exec &lt;_executable-file_&gt; ...@@ -34,11 +34,11 @@ exec &lt;_executable-file_&gt;
## 输出说明 ## 输出说明
``` ```
OHOS # exec helloworld OHOS # exec helloworld
OHOS # hello world! OHOS # hello world!
``` ```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 可执行文件执行后,先打印“OHOS \#”提示符原因:目前Shell “exec”命令执行均为后台执行,结果可能导致提示符提前打印。 > 可执行文件执行后,先打印“OHOS \#”提示符原因:目前Shell “exec”命令执行均为后台执行,结果可能导致提示符提前打印。
\ No newline at end of file
...@@ -13,17 +13,17 @@ free [_-b | -k | -m | -g | -t_] ...@@ -13,17 +13,17 @@ free [_-b | -k | -m | -g | -t_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | | -------- | -------- |
| 无参数 | 以Byte为单位显示。 | N/A | | 无参数 | 以Byte为单位显示。 |
| --help/-h | 查看free命令支持的参数列表。 | N/A | | --help/-h | 查看free命令支持的参数列表。 |
| -b | 以Byte为单位显示。 | N/A | | -b | 以Byte为单位显示。 |
| -k | 以KiB为单位显示。 | N/A | | -k | 以KiB为单位显示。 |
| -m | 以MiB为单位显示。 | N/A | | -m | 以MiB为单位显示。 |
| -g | 以GiB为单位显示。 | N/A | | -g | 以GiB为单位显示。 |
| -t | 以TiB为单位显示。 | N/A | | -t | 以TiB为单位显示。 |
## 使用指南 ## 使用指南
...@@ -57,7 +57,7 @@ Mem: 2 2 0 0 0 ...@@ -57,7 +57,7 @@ Mem: 2 2 0 0 0
Swap: 0 0 0 Swap: 0 0 0
``` ```
**表2** 输出说明 **表2** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -13,7 +13,7 @@ help ...@@ -13,7 +13,7 @@ help
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
......
...@@ -13,7 +13,7 @@ hwi ...@@ -13,7 +13,7 @@ hwi
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
...@@ -106,7 +106,7 @@ hwi ...@@ -106,7 +106,7 @@ hwi
102: 0 0 0.0 0.0 0.0 normal SPI_HI35XX 102: 0 0 0.0 0.0 0.0 normal SPI_HI35XX
``` ```
**表1** 输出说明 **表1** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## 命令功能 ## 命令功能
命令用于发送特定信号给指定进程 kill命令用于发送特定信号给指定进程,让它去终结不正常的应用
## 命令格式 ## 命令格式
...@@ -13,31 +13,34 @@ kill [-l [_signo_] | _-s signo_ | _-signo_] _pid..._ ...@@ -13,31 +13,34 @@ kill [-l [_signo_] | _-s signo_ | _-signo_] _pid..._
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ------ | -------------------------- | ----------- |
| --help | 查看kill命令支持的参数列表 | N/A | | --help | 查看kill命令支持的参数列表 | N/A |
| -l | 列出信号名称和编号。 | N/A | | -l | 列出信号名称和编号。 | N/A |
| -s | 发送信号 | N/A | | -s | 发送信号 | N/A |
| signo | 信号ID。 | [1,30] | | signo | 信号ID。 | [1, 30] |
| pid | 进程ID。 | [1,MAX_INT] | | pid | 进程ID。 | [1, MAX_INT] |
> ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:** > ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:**
> signo有效范围为[0,64],建议取值范围为[1,30],其余为保留内容。 > signo有效范围为[0, 64],建议取值范围为[1, 30],其余为保留内容。
## 使用指南 ## 使用指南
- 必须指定发送的信号编号及进程号。 - 必须指定发送的信号编号及进程号。
- 进程编号取值范围根据系统配置变化,例如系统最大支持pid为256,则取值范围缩小为[1-256]。 - 进程编号取值范围根据系统配置变化,例如系统最大支持pid为256,则取值范围缩小为[1, 256]。
## 特殊说明
kill命令以及参数 shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
- 查看当前进程列表,查看需要杀死的进程PID(42)。 - 查看当前进程列表,查看需要杀死的进程PID(42)。
``` ```
OHOS:/$ ps OHOS:/$ ps
allCpu(%): 4.67 sys, 195.33 idle allCpu(%): 4.67 sys, 195.33 idle
...@@ -60,7 +63,7 @@ kill [-l [_signo_] | _-s signo_ | _-signo_] _pid..._ ...@@ -60,7 +63,7 @@ kill [-l [_signo_] | _-s signo_ | _-signo_] _pid..._
``` ```
- 发送信号9(SIGKILL默认行为为立即终止进程)给42号进程test_demo(用户态进程):kill -s 9 42(kill -9 42效果相同),并查看当前进程列表,42号进程已终止。 - 发送信号9(SIGKILL默认行为为立即终止进程)给42号进程test_demo(用户态进程):kill -s 9 42(kill -9 42效果相同),并查看当前进程列表,42号进程已终止。
``` ```
OHOS:/$ kill -s 9 42 OHOS:/$ kill -s 9 42
OHOS:/$ OHOS:/$
...@@ -91,9 +94,9 @@ kill [-l [_signo_] | _-s signo_ | _-signo_] _pid..._ ...@@ -91,9 +94,9 @@ kill [-l [_signo_] | _-s signo_ | _-signo_] _pid..._
发送成功或失败输出结果如下。 发送成功或失败输出结果如下。
**示例 1** 发送信号给指定进程 **示例1** 发送信号给指定进程
``` ```
OHOS:/$ kill -s 9 42 OHOS:/$ kill -s 9 42
OHOS:/$ OHOS:/$
...@@ -102,12 +105,12 @@ OHOS:/$ ...@@ -102,12 +105,12 @@ OHOS:/$
信号发送成功会显示的提示进程已被杀死。 信号发送成功会显示的提示进程已被杀死。
**示例 2** 信号发送失败 **示例2** 信号发送失败
``` ```
OHOS:/$ kill -100 31 OHOS:/$ kill -100 31
kill: Unknown signal '(null)' kill: Unknown signal '(null)'
``` ```
信号发送失败,示例2所示原因为信号发送命令参数无效,请排查信号编号及进程编号是否有效。 信号发送失败,示例2所示原因为信号发送命令参数无效,请排查信号编号及进程编号是否有效。
\ No newline at end of file
...@@ -13,11 +13,11 @@ log level [_levelNum_] ...@@ -13,11 +13,11 @@ log level [_levelNum_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| levelNum | 配置日志打印等级。 | [0,5] | | levelNum | 配置日志打印等级。 | [0, 5] |
## 使用指南 ## 使用指南
...@@ -52,9 +52,9 @@ log level [_levelNum_] ...@@ -52,9 +52,9 @@ log level [_levelNum_]
## 输出说明 ## 输出说明
**示例**:设置当前日志打印级别为3 **示例** 设置当前日志打印级别为3
``` ```
OHOS # log level 3 OHOS # log level 3
Set current log level WARN Set current log level WARN
......
...@@ -13,7 +13,7 @@ memcheck ...@@ -13,7 +13,7 @@ memcheck
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
...@@ -34,15 +34,15 @@ memcheck ...@@ -34,15 +34,15 @@ memcheck
## 输出说明 ## 输出说明
**示例1**当前没有内存越界 **示例1** 当前没有内存越界
``` ```
OHOS # memcheck OHOS # memcheck
system memcheck over, all passed! system memcheck over, all passed!
``` ```
**示例2**出现内存越界 **示例2** 出现内存越界
``` ```
[L0S DLnkCheckMenl 349, memory check [L0S DLnkCheckMenl 349, memory check
stFreeNodeInfo.pstPrev:0x7e0d31f3 is out of legal mem range[0x80ba5f40, 0х83d00000] stFreeNodeInfo.pstPrev:0x7e0d31f3 is out of legal mem range[0x80ba5f40, 0х83d00000]
......
...@@ -21,19 +21,20 @@ oom -h | --help ...@@ -21,19 +21,20 @@ oom -h | --help
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ----------------------- | ------------------------------- | ------------------------------------------------------------ |
| -i&nbsp;[interval] | 设置oom线程任务检查的时间间隔。 | 100ms&nbsp;~&nbsp;10000ms | | -i&nbsp;[interval] | 设置oom线程任务检查的时间间隔。 | [100, 10000] 单位: ms |
| -m&nbsp;[mem&nbsp;byte] | 设置低内存阈值。 | 0MB&nbsp;~&nbsp;1MB,0MB表示不做低内存阈值检查。 | | -m&nbsp;[mem&nbsp;byte] | 设置低内存阈值。 | 0MB&nbsp;~&nbsp;1MB,0MB表示不做低内存阈值检查。 |
| -r&nbsp;[mem&nbsp;byte] | 设置pagecache内存回收阈值。 | 低内存阈值&nbsp;~&nbsp;系统可用最大内存。 | | -r&nbsp;[mem&nbsp;byte] | 设置pagecache内存回收阈值。 | 低内存阈值 ~ 系统可用最大内存,一个pagecache页一般为4KB,也有16 ~ 64KB的情况。 |
| -h&nbsp;\|&nbsp;--help | 使用帮助。 | N/A | | -h&nbsp;\|&nbsp;--help | 使用帮助。 | N/A |
## 使用指南 ## 使用指南
参数缺省时,显示oom功能当前配置信息。 参数缺省时,显示oom功能当前配置信息。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 当系统内存不足时,会打印出内存不足的提示信息。 > 当系统内存不足时,会打印出内存不足的提示信息。
...@@ -49,9 +50,9 @@ oom -h | --help ...@@ -49,9 +50,9 @@ oom -h | --help
## 输出说明 ## 输出说明
**示例1:**oom缺省打印配置信息 **示例1** oom缺省打印配置信息
``` ```
OHOS:/$ oom OHOS:/$ oom
[oom] oom loop task status: enabled [oom] oom loop task status: enabled
...@@ -62,7 +63,7 @@ OHOS:/$ oom ...@@ -62,7 +63,7 @@ OHOS:/$ oom
系统内存不足时打印提示信息 系统内存不足时打印提示信息
``` ```
T:20 Enter:IT MEM 00M 001 T:20 Enter:IT MEM 00M 001
[oom] OS is in low memory state [oom] OS is in low memory state
...@@ -109,22 +110,22 @@ traceback 5 -- 1r = 0x20c4df50 fp = 0хb0b0b0b 1r in /1ib/libc.so - -> 0x62f50 ...@@ -109,22 +110,22 @@ traceback 5 -- 1r = 0x20c4df50 fp = 0хb0b0b0b 1r in /1ib/libc.so - -> 0x62f50
``` ```
**示例2**:设置 oom 线程任务检查的时间间隔 **示例2** 设置 oom 线程任务检查的时间间隔
``` ```
OHOS:/$ oom -i 100 OHOS:/$ oom -i 100
[oom] set oom check interval (100)ms successful [oom] set oom check interval (100)ms successful
``` ```
**表2** 输出说明 **表2** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | ------------------------------------------------------------ | ------------------------------------------------------------ |
| [oom]&nbsp;OS&nbsp;is&nbsp;in&nbsp;low&nbsp;memory&nbsp;state<br/>total&nbsp;physical&nbsp;memory:&nbsp;0x1bcf000(byte),&nbsp;used:&nbsp;0x1b50000(byte),&nbsp;free:&nbsp;0x7f000(byte),&nbsp;low&nbsp;memory&nbsp;threshold:&nbsp;0x80000(byte) | 操作系统处于低内存状态。<br/>整个系统可用物理内存为0x1bcf000&nbsp;byte,已经使用了&nbsp;0x1b50000&nbsp;byte,&nbsp;还剩0x7f000&nbsp;byte,当前设置的低内存阈值为0x80000&nbsp;byte。 | | [oom]&nbsp;OS&nbsp;is&nbsp;in&nbsp;low&nbsp;memory&nbsp;state<br/>total&nbsp;physical&nbsp;memory:&nbsp;0x1bcf000(byte),&nbsp;used:&nbsp;0x1b50000(byte),&nbsp;free:&nbsp;0x7f000(byte),&nbsp;low&nbsp;memory&nbsp;threshold:&nbsp;0x80000(byte) | 操作系统处于低内存状态。<br/>整个系统可用物理内存为0x1bcf000&nbsp;byte,已经使用了&nbsp;0x1b50000&nbsp;byte,&nbsp;还剩0x7f000&nbsp;byte,当前设置的低内存阈值为0x80000&nbsp;byte。 |
| [oom]&nbsp;candidate&nbsp;victim&nbsp;process&nbsp;init&nbsp;pid:&nbsp;1,&nbsp;actual&nbsp;phy&nbsp;mem&nbsp;byte:&nbsp;82602 | 打印当前各个进程的内存使用情况,init进程实际占用物理内存82602byte。 | | [oom]&nbsp;candidate&nbsp;victim&nbsp;process&nbsp;init&nbsp;pid:&nbsp;1,&nbsp;actual&nbsp;phy&nbsp;mem&nbsp;byte:&nbsp;82602 | 打印当前各个进程的内存使用情况,init进程实际占用物理内存82602byte。 |
| [oom]&nbsp;candidate&nbsp;victim&nbsp;process&nbsp;UserProcess12&nbsp;pid:&nbsp;12,&nbsp;actual&nbsp;phy&nbsp;mem&nbsp;byte:&nbsp;25951558 | UserProcess12进程实际使用25951558byte内存。 | | [oom]&nbsp;candidate&nbsp;victim&nbsp;process&nbsp;UserProcess12&nbsp;pid:&nbsp;12,&nbsp;actual&nbsp;phy&nbsp;mem&nbsp;byte:&nbsp;25951558 | UserProcess12进程实际使用25951558byte内存。 |
| [oom]&nbsp;max&nbsp;phy&nbsp;mem&nbsp;used&nbsp;process&nbsp;UserProcess12&nbsp;pid:&nbsp;12,&nbsp;actual&nbsp;phy&nbsp;mem:&nbsp;25951558 | 当前使用内存最多的进程是UserProcess12。 | | [oom]&nbsp;max&nbsp;phy&nbsp;mem&nbsp;used&nbsp;process&nbsp;UserProcess12&nbsp;pid:&nbsp;12,&nbsp;actual&nbsp;phy&nbsp;mem:&nbsp;25951558 | 当前使用内存最多的进程是UserProcess12。 |
| excFrom:&nbsp;User! | 当系统处于低内存的情况下,UserProcess12进程再去申请内存时失败退出。 | | excFrom:&nbsp;User! | 当系统处于低内存的情况下,UserProcess12进程再去申请内存时失败退出。 |
\ No newline at end of file
...@@ -28,8 +28,8 @@ Debug版本才具备的命令。 ...@@ -28,8 +28,8 @@ Debug版本才具备的命令。
## 输出说明 ## 输出说明
**示例:**查看物理页使用情况 **示例** 查看物理页使用情况
``` ```
OHOS # pmm OHOS # pmm
phys_seg base size free_pages phys_seg base size free_pages
...@@ -55,7 +55,7 @@ Vnode number = 67 ...@@ -55,7 +55,7 @@ Vnode number = 67
Vnode memory size = 10720(B) Vnode memory size = 10720(B)
``` ```
**表1** 输出说明 **表1** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -13,7 +13,7 @@ reboot ...@@ -13,7 +13,7 @@ reboot
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
...@@ -28,4 +28,4 @@ reboot ...@@ -28,4 +28,4 @@ reboot
## 输出说明 ## 输出说明
...@@ -13,7 +13,7 @@ reset ...@@ -13,7 +13,7 @@ reset
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
...@@ -28,4 +28,4 @@ reset ...@@ -28,4 +28,4 @@ reset
## 输出说明 ## 输出说明
...@@ -13,7 +13,7 @@ sem [_ID__ / fulldata_] ...@@ -13,7 +13,7 @@ sem [_ID__ / fulldata_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -40,8 +40,8 @@ sem [_ID__ / fulldata_] ...@@ -40,8 +40,8 @@ sem [_ID__ / fulldata_]
## 输出说明 ## 输出说明
**示例1**查询所有在用的信号量信息 **示例1** 查询所有在用的信号量信息
``` ```
OHOS # sem OHOS # sem
SemID Count SemID Count
...@@ -67,7 +67,7 @@ OHOS # sem ...@@ -67,7 +67,7 @@ OHOS # sem
0x00000006 0 0x00000006 0
``` ```
**表2** 输出说明 **表2** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
...@@ -79,8 +79,8 @@ OHOS # sem ...@@ -79,8 +79,8 @@ OHOS # sem
> >
> ● sem命令的ID参数在[0, 1023]范围内时,返回对应ID的信号量的状态(如果对应ID的信号量未被使用则进行提示);其他取值时返回参数错误的提示。 > ● sem命令的ID参数在[0, 1023]范围内时,返回对应ID的信号量的状态(如果对应ID的信号量未被使用则进行提示);其他取值时返回参数错误的提示。
**示例2:**查询所有在用的信号量信息 **示例2** 查询所有在用的信号量信息
``` ```
OHOS # sem fulldata OHOS # sem fulldata
Used Semaphore List: Used Semaphore List:
...@@ -113,7 +113,7 @@ Used Semaphore List: ...@@ -113,7 +113,7 @@ Used Semaphore List:
0x38 0x1 0x1 0x404978fc 0x395 0x38 0x1 0x1 0x404978fc 0x395
``` ```
**表3** 输出说明 **表3** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -13,12 +13,12 @@ stack ...@@ -13,12 +13,12 @@ stack
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
## 使用实例 ## 使用实例
...@@ -28,8 +28,8 @@ stack ...@@ -28,8 +28,8 @@ stack
## 输出说明 ## 输出说明
**示例:**系统堆栈使用情况 **示例** 系统堆栈使用情况
``` ```
OHOS # stack OHOS # stack
stack name cpu id stack addr total size used size stack name cpu id stack addr total size used size
...@@ -40,7 +40,7 @@ OHOS # stack ...@@ -40,7 +40,7 @@ OHOS # stack
exc_stack 0 0x405c9000 0x1000 0x0 exc_stack 0 0x405c9000 0x1000 0x0
``` ```
**表1** 输出说明 **表1** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -13,12 +13,12 @@ su [_uid_] [_gid_] ...@@ -13,12 +13,12 @@ su [_uid_] [_gid_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| uid | 目标用户的用户id值。 | -&nbsp;为空。<br/>-&nbsp;[0,60000] | | uid | 目标用户的用户id值。 | -&nbsp;为空。<br/>-&nbsp;[0, 60000] |
| gid | 目标用户的群组id值。 | -&nbsp;为空。<br/>-&nbsp;[0,60000] | | gid | 目标用户的群组id值。 | -&nbsp;为空。<br/>-&nbsp;[0, 60000] |
## 使用指南 ## 使用指南
...@@ -37,8 +37,8 @@ su [_uid_] [_gid_] ...@@ -37,8 +37,8 @@ su [_uid_] [_gid_]
## 输出说明 ## 输出说明
**示例:**切换到为uid为1000,gid为1000的用户 **示例** 切换到为uid为1000,gid为1000的用户
``` ```
OHOS # ls OHOS # ls
Directory /data/system/param: Directory /data/system/param:
......
...@@ -13,11 +13,11 @@ swtmr [_ID_] ...@@ -13,11 +13,11 @@ swtmr [_ID_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ID | 软件定时器ID号。 | [0,0xFFFFFFFF] | | ID | 软件定时器ID号。 | [0, 0xFFFFFFFF] |
## 使用指南 ## 使用指南
...@@ -38,8 +38,8 @@ swtmr [_ID_] ...@@ -38,8 +38,8 @@ swtmr [_ID_]
## 输出说明 ## 输出说明
**示例1:**查询所有软件定时器相关信息 **示例1** 查询所有软件定时器相关信息
``` ```
OHOS # swtmr OHOS # swtmr
SwTmrID State Mode Interval Count Arg handlerAddr SwTmrID State Mode Interval Count Arg handlerAddr
...@@ -59,8 +59,8 @@ SwTmrID State Mode Interval Count Arg handlerAddr ...@@ -59,8 +59,8 @@ SwTmrID State Mode Interval Count Arg handlerAddr
0x00000079 Ticking NSD 30000 1749 0x406189d8 0x40160e1c 0x00000079 Ticking NSD 30000 1749 0x406189d8 0x40160e1c
``` ```
**示例2:**查询对应 ID 的软件定时器信息 **示例2** 查询对应 ID 的软件定时器信息
``` ```
OHOS # swtmr 1 OHOS # swtmr 1
SwTmrID State Mode Interval Count Arg handlerAddr SwTmrID State Mode Interval Count Arg handlerAddr
......
...@@ -13,12 +13,12 @@ systeminfo ...@@ -13,12 +13,12 @@ systeminfo
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
## 使用实例 ## 使用实例
...@@ -28,8 +28,8 @@ systeminfo ...@@ -28,8 +28,8 @@ systeminfo
## 输出说明 ## 输出说明
**示例:**查看系统资源使用情况 **示例** 查看系统资源使用情况
``` ```
OHOS:/$ systeminfo OHOS:/$ systeminfo
Module Used Total Enabled Module Used Total Enabled
...@@ -40,16 +40,15 @@ OHOS:/$ systeminfo ...@@ -40,16 +40,15 @@ OHOS:/$ systeminfo
SwTmr 20 1024 YES SwTmr 20 1024 YES
``` ```
**表1** 输出说明 **表1** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | ------- | -------------- |
| Module | 模块名称。 | | Module | 模块名称。 |
| Used | 当前使用量。 | | Used | 当前使用量。 |
| Total | 最大可用量。 | | Total | 最大可用量。 |
| Enabled | 模块是否开启。 | | Enabled | 模块是否开启。 |
| Task | 任务。 | | Task | 任务。 |
| Sem | 信号量。 | | Sem | 信号量。 |
| Mutex | 互斥量。 | | Queue | 队列。 |
| Queue | 队列。 | | SwTmr | 定时器。 |
| SwTmr | 定时器。 | \ No newline at end of file
...@@ -13,7 +13,7 @@ task/task -a ...@@ -13,7 +13,7 @@ task/task -a
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -32,9 +32,8 @@ task/task -a ...@@ -32,9 +32,8 @@ task/task -a
## 输出说明 ## 输出说明
**示例:**查询任务部分信息 **示例** 查询任务部分信息
``` ```
OHOS # task OHOS # task
allCpu(%): 3.54 sys, 196.46 idle allCpu(%): 3.54 sys, 196.46 idle
...@@ -61,7 +60,7 @@ OHOS # task ...@@ -61,7 +60,7 @@ OHOS # task
7 2 0x3 -1 Pending 0x4e20 0xa5c 0.0 0 PlatformWorkerThread 7 2 0x3 -1 Pending 0x4e20 0xa5c 0.0 0 PlatformWorkerThread
``` ```
**表2** 输出说明 **表2** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -13,18 +13,21 @@ top [_-a_] ...@@ -13,18 +13,21 @@ top [_-a_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 缺省值 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | -------- | | ------ | --------------------------- |
| --help | 查看top命令支持的参数列表。 | N/A | | | --help | 查看top命令支持的参数列表。 |
| -a | 显示更详细的信息。 | N/A | | | -a | 显示更详细的信息。 |
## 使用指南 ## 使用指南
参数缺省时默认打印部分任务信息。 参数缺省时默认打印部分任务信息。
## 特殊说明
shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -33,8 +36,8 @@ top [_-a_] ...@@ -33,8 +36,8 @@ top [_-a_]
## 输出说明 ## 输出说明
**示例1** top 命令显示详情 **示例1** top 命令显示详情
``` ```
OHOS:/$ top OHOS:/$ top
allCpu(%): 4.68 sys, 195.32 idle allCpu(%): 4.68 sys, 195.32 idle
...@@ -78,19 +81,19 @@ OHOS:/$ top ...@@ -78,19 +81,19 @@ OHOS:/$ top
64 2 0x3 -1 Pending 0x4000 0x244 0.0 0 USB_NGIAN_BULK_TasK 64 2 0x3 -1 Pending 0x4000 0x244 0.0 0 USB_NGIAN_BULK_TasK
``` ```
**表2** 输出元素说明 **表2** 输出元素说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | --------- | ----------------- |
| PID | 进程ID。 | | PID | 进程ID。 |
| PPID | 父进程ID。 | | PPID | 父进程ID。 |
| PGID | 进程组ID。 | | PGID | 进程组ID。 |
| UID | 用户ID。 | | UID | 用户ID。 |
| Status | 任务当前的状态。 | | Status | 任务当前的状态。 |
| CPUUSE10s | 10秒内CPU使用率。 | | CPUUSE10s | 10秒内CPU使用率。 |
| PName | 进程名。 | | PName | 进程名。 |
| TID | 任务ID。 | | TID | 任务ID。 |
| StackSize | 任务堆栈的大小。 | | StackSize | 任务堆栈的大小。 |
| WaterLine | 栈使用的峰值。 | | WaterLine | 栈使用的峰值。 |
| MEMUSE | 内存使用量。 | | MEMUSE | 内存使用量。 |
| TaskName | 任务名。 | | TaskName | 任务名。 |
\ No newline at end of file
...@@ -11,18 +11,18 @@ uname命令用于显示当前操作系统的名称,版本创建时间,系统 ...@@ -11,18 +11,18 @@ uname命令用于显示当前操作系统的名称,版本创建时间,系统
uname [_-a | -s | -r | -m | -n | -v | --help_] uname [_-a | -s | -r | -m | -n | -v | --help_]
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | | 参数 | 参数说明 |
| -------- | -------- | | ------ | ----------------------- |
| --help | 显示uname指令格式提示。 | | --help | 显示uname指令格式提示。 |
| 无参数 | 默认显示操作系统名称。 | | 无参数 | 默认显示操作系统名称。 |
| -a | 显示全部信息。 | | -a | 显示全部信息。 |
| -s | 显示操作系统名称。 | | -s | 显示操作系统名称。 |
| -r | 显示内核发行版本。 | | -r | 显示内核发行版本。 |
| -m | 显示系统架构名称。 | | -m | 显示系统架构名称。 |
| -n | 显示主机的网络域名称。 | | -n | 显示主机的网络域名称。 |
| -v | 显示版本信息。 | | -v | 显示版本信息。 |
## 使用指南 ## 使用指南
...@@ -31,6 +31,9 @@ uname [_-a | -s | -r | -m | -n | -v | --help_] ...@@ -31,6 +31,9 @@ uname [_-a | -s | -r | -m | -n | -v | --help_]
- 除参数--help和-a以外,其他参数可以相互搭配使用;uname -a 等价于 uname -srmnv。 - 除参数--help和-a以外,其他参数可以相互搭配使用;uname -a 等价于 uname -srmnv。
## 特殊说明
-r -m -n参数暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -43,20 +46,18 @@ uname [_-a | -s | -r | -m | -n | -v | --help_] ...@@ -43,20 +46,18 @@ uname [_-a | -s | -r | -m | -n | -v | --help_]
## 输出说明 ## 输出说明
**示例1:** 查看系统信息 **示例1** 查看系统信息
``` ```
OHOS:/$ uname -a OHOS:/$ uname -a
LiteOS hisilicon 2.0.0.37 LiteOS 2.0.0.37 Oct 21 2021 17:39:32 Cortex-A7 LiteOS hisilicon 2.0.0.37 LiteOS 2.0.0.37 Oct 21 2021 17:39:32 Cortex-A7
OHOS:/$ OHOS:/$
``` ```
**示例2:** 只查看操作系统名称和系统架构名称 **示例2** 只查看操作系统名称和系统架构名称
``` ```
OHOS:/$ uname -ms OHOS:/$ uname -ms
LiteOS Cortex-A7 LiteOS Cortex-A7
OHOS:/$ OHOS:/$
``` ```
\ No newline at end of file
...@@ -15,13 +15,13 @@ ...@@ -15,13 +15,13 @@
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| -a | 输出所有进程的虚拟内存使用情况。 | N/A | | -a | 输出所有进程的虚拟内存使用情况。 | N/A |
| -h&nbsp;\|&nbsp;--help | 命令格式说明。 | N/A | | -h&nbsp;\|&nbsp;--help | 命令格式说明。 | N/A |
| pid | 进程ID,说明指定进程的虚拟内存使用情况。 | [0,63] | | pid | 进程ID,说明指定进程的虚拟内存使用情况。 | [0, 63] |
## 使用指南 ## 使用指南
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
## 输出说明 ## 输出说明
**示例:**PID为3的进程虚拟内存使用信息 **示例** PID为3的进程虚拟内存使用信息
``` ```
OHOS # vmm 3 OHOS # vmm 3
PID aspace name base size pages PID aspace name base size pages
...@@ -62,7 +62,7 @@ OHOS # vmm 3 ...@@ -62,7 +62,7 @@ OHOS # vmm 3
0x408c3ce0 /lib/libc++.so 0x23cb0000 0x00001000 CH US RD WR 1 1 0x408c3ce0 /lib/libc++.so 0x23cb0000 0x00001000 CH US RD WR 1 1
``` ```
**表2** 进程基本信息 **表2** 进程基本信息
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
...@@ -73,7 +73,7 @@ OHOS # vmm 3 ...@@ -73,7 +73,7 @@ OHOS # vmm 3
| size | 虚拟内存大小 | | size | 虚拟内存大小 |
| pages | 已使用的物理页数量 | | pages | 已使用的物理页数量 |
**表3** 虚拟内存区间信息 **表3** 虚拟内存区间信息
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -38,8 +38,8 @@ watch -n 2 -c 6 task ...@@ -38,8 +38,8 @@ watch -n 2 -c 6 task
## 输出说明 ## 输出说明
**示例**每隔2秒运行一次task命令,一共运行6次 **示例** 每隔2秒运行一次task命令,一共运行6次
``` ```
OHOS # watch -n 2 -c 6 task OHOS # watch -n 2 -c 6 task
Thu Jan 1 23:57:13 1970 Thu Jan 1 23:57:13 1970
......
...@@ -13,7 +13,7 @@ cat [_pathname_] ...@@ -13,7 +13,7 @@ cat [_pathname_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -32,8 +32,8 @@ cat用于显示文本文件的内容。 ...@@ -32,8 +32,8 @@ cat用于显示文本文件的内容。
## 输出说明 ## 输出说明
**示例**查看 hello-openharmony.txt 文件的信息 **示例** 查看 hello-openharmony.txt 文件的信息
``` ```
OHOS # cat hello-openharmony.txt OHOS # cat hello-openharmony.txt
OHOS # Hello openharmony ;) OHOS # Hello openharmony ;)
......
...@@ -13,7 +13,7 @@ cd [_path_] ...@@ -13,7 +13,7 @@ cd [_path_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -42,9 +42,8 @@ cd [_path_] ...@@ -42,9 +42,8 @@ cd [_path_]
## 输出说明 ## 输出说明
**示例**显示结果如下 **示例**显示结果如下
``` ```
OHOS:/nfs$ cd ../ OHOS:/nfs$ cd ../
OHOS:/$ ls OHOS:/$ ls
......
...@@ -13,20 +13,22 @@ chgrp [_group_] [_pathname_] ...@@ -13,20 +13,22 @@ chgrp [_group_] [_pathname_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | ---------- | -------------- |
| group | 文件群组。 | [0,0xFFFFFFFF] | | group | 文件群组。 | [0, 0xFFFFFFFF] |
| pathname | 文件路径。 | 已存在的文件。 | | pathname | 文件路径。 | 已存在的文件。 |
## 使用指南 ## 使用指南
- 在需要修改的文件名前加上文件群组值就可以修改该文件的所属组。 - 在需要修改的文件名前加上文件群组值就可以修改该文件的所属组。
- fatfs文件系统不支持修改用户组id。 - fatfs文件系统不支持修改用户组id。
## 特殊说明
shell端暂不支持。
## 使用实例 ## 使用实例
...@@ -35,8 +37,8 @@ chgrp [_group_] [_pathname_] ...@@ -35,8 +37,8 @@ chgrp [_group_] [_pathname_]
## 输出说明 ## 输出说明
**示例:**修改 dev/目录下testfile 文件的群组为100 **示例** 修改 dev/目录下testfile 文件的群组为100
``` ```
OHOS:/dev$ ll testfile OHOS:/dev$ ll testfile
-rw-r--r-- 0 0 0 0 1970-01-01 00:00 testfile -rw-r--r-- 0 0 0 0 1970-01-01 00:00 testfile
...@@ -44,4 +46,4 @@ OHOS:/dev$ chgrp 100 testfile ...@@ -44,4 +46,4 @@ OHOS:/dev$ chgrp 100 testfile
OHOS:/dev$ ll testfile OHOS:/dev$ ll testfile
-rw-r--r-- 0 0 100 0 1970-01-01 00:00 testfile -rw-r--r-- 0 0 100 0 1970-01-01 00:00 testfile
OHOS:/dev$ OHOS:/dev$
``` ```
\ No newline at end of file
...@@ -13,12 +13,12 @@ chmod [_mode_] [_filename_] ...@@ -13,12 +13,12 @@ chmod [_mode_] [_filename_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | ------------------------------------------------------------ | -------------- |
| mode | 文件或文件夹权限,用8进制表示对应User、Group、及Others(拥有者、群组、其他组)的权限。 | [0,777] | | mode | 文件或文件夹权限,用8进制表示对应User、Group、及Others(拥有者、群组、其他组)的权限。 | [0, 777] |
| filename | 文件路径。 | 已存在的文件。 | | filename | 文件路径。 | 已存在的文件。 |
## 使用指南 ## 使用指南
...@@ -27,6 +27,9 @@ chmod [_mode_] [_filename_] ...@@ -27,6 +27,9 @@ chmod [_mode_] [_filename_]
- fatfs文件系统所有创建的文件和挂载节点的权限属性保持一致,目前节点的权限只有用户读写权限,group和others权限不生效;且只允许修改用户读写权限,读写权限只有rw和ro两种。其他文件系统无限制。 - fatfs文件系统所有创建的文件和挂载节点的权限属性保持一致,目前节点的权限只有用户读写权限,group和others权限不生效;且只允许修改用户读写权限,读写权限只有rw和ro两种。其他文件系统无限制。
## 特殊说明
shell端暂不支持。
## 使用实例 ## 使用实例
...@@ -35,9 +38,8 @@ chmod [_mode_] [_filename_] ...@@ -35,9 +38,8 @@ chmod [_mode_] [_filename_]
## 输出说明 ## 输出说明
**示例:**修改/dev目录下 hello-openharmony.txt 文件的权限 **示例** 修改/dev目录下 hello-openharmony.txt 文件的权限
``` ```
OHOS:/dev$ chmod 644 hello-openharmony.txt OHOS:/dev$ chmod 644 hello-openharmony.txt
OHOS:/dev$ ll hello-openharmony.txt OHOS:/dev$ ll hello-openharmony.txt
...@@ -45,4 +47,4 @@ OHOS:/dev$ ll hello-openharmony.txt ...@@ -45,4 +47,4 @@ OHOS:/dev$ ll hello-openharmony.txt
OHOS:/dev$ chmod 777 hello-openharmony.txt OHOS:/dev$ chmod 777 hello-openharmony.txt
OHOS:/dev$ ll hello-openharmony.txt OHOS:/dev$ ll hello-openharmony.txt
-rwxrwxrwx 0 0 0 0 1970-01-01 00:00 hello-openharmony.txt -rwxrwxrwx 0 0 0 0 1970-01-01 00:00 hello-openharmony.txt
``` ```
\ No newline at end of file
...@@ -13,18 +13,21 @@ chown [_owner_] [_pathname_] ...@@ -13,18 +13,21 @@ chown [_owner_] [_pathname_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | ------------ | -------------- |
| owner | 文件拥有者。 | [0,0xFFFFFFFF] | | owner | 文件拥有者。 | [0, 0xFFFFFFFF] |
| pathname | 文件路径。 | 已存在的文件。 | | pathname | 文件路径。 | 已存在的文件。 |
## 使用指南 ## 使用指南
修改文件的所有者,目前fatfs不支持修改。 修改文件的所有者,目前fatfs不支持修改。
## 特殊说明
shell端暂不支持。
## 使用实例 ## 使用实例
...@@ -33,9 +36,8 @@ chown [_owner_] [_pathname_] ...@@ -33,9 +36,8 @@ chown [_owner_] [_pathname_]
## 输出说明 ## 输出说明
示例 1 修改 /dev下的testfile 文件的uid为100 **示例1** 修改 /dev下的testfile 文件的uid为100
``` ```
OHOS:/dev$ touch testfile OHOS:/dev$ touch testfile
OHOS:/dev$ ll testfile OHOS:/dev$ ll testfile
...@@ -43,4 +45,4 @@ OHOS:/dev$ ll testfile ...@@ -43,4 +45,4 @@ OHOS:/dev$ ll testfile
OHOS:/dev$ chown 100 testfile OHOS:/dev$ chown 100 testfile
OHOS:/dev$ ll testfile OHOS:/dev$ ll testfile
-rw-r--r-- 0 100 100 0 1970-01-01 00:00 testfile -rw-r--r-- 0 100 100 0 1970-01-01 00:00 testfile
``` ```
\ No newline at end of file
...@@ -47,9 +47,8 @@ cp [_SOURCEFILE_] [_DESTFILE_] ...@@ -47,9 +47,8 @@ cp [_SOURCEFILE_] [_DESTFILE_]
## 输出说明 ## 输出说明
**示例:**同时拷贝两个文件至指定目录 **示例** 同时拷贝两个文件至指定目录
``` ```
OHOS:/$ ls OHOS:/$ ls
bin hello-OHOS.txt proc system vendor bin hello-OHOS.txt proc system vendor
......
...@@ -13,16 +13,16 @@ du [_-kKmh_] [_file..._] ...@@ -13,16 +13,16 @@ du [_-kKmh_] [_file..._]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | | ------ | ------------------------------------------------------------ |
| --help | 查看du命令支持的参数列表。 | N/A | | --help | 查看du命令支持的参数列表。 |
| -k | 显示占用的块,每块1024bytes(默认)。 | N/A | | -k | 显示占用的块,每块1024bytes(默认)。 |
| -K | 显示占用的块,每块512bytes(posix标准)。 | N/A | | -K | 显示占用的块,每块512bytes(posix标准)。 |
| -m | 兆字节为单位。 | N/A | | -m | 兆字节为单位。 |
| -h | 以K,M,G为单位,提高信息的可读性(例如,1K&nbsp;243M&nbsp;2G)。 | N/A | | -h | 以K,M,G为单位,提高信息的可读性(例如,1K&nbsp;243M&nbsp;2G)。 |
| file | 指定的需要统计的文件。 | N/A | | file | 指定的需要统计的文件。 |
## 使用指南 ## 使用指南
...@@ -31,6 +31,9 @@ du [_-kKmh_] [_file..._] ...@@ -31,6 +31,9 @@ du [_-kKmh_] [_file..._]
- file的内容既为文件名,不能包含其所在的目录。 - file的内容既为文件名,不能包含其所在的目录。
## 特殊说明
shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -39,10 +42,9 @@ du [_-kKmh_] [_file..._] ...@@ -39,10 +42,9 @@ du [_-kKmh_] [_file..._]
## 输出说明 ## 输出说明
**示例:**显示结果如下 **示例** 显示结果如下
``` ```
OHOS:/$ du -h testfile OHOS:/$ du -h testfile
1.8K testfile 1.8K testfile
``` ```
\ No newline at end of file
...@@ -13,7 +13,7 @@ format &lt;_dev_inodename_&gt; &lt;_sectors_&gt; &lt;_option_&gt; [_label_] ...@@ -13,7 +13,7 @@ format &lt;_dev_inodename_&gt; &lt;_sectors_&gt; &lt;_option_&gt; [_label_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | | 参数 | 参数说明 |
| -------- | -------- | | -------- | -------- |
...@@ -39,9 +39,8 @@ format &lt;_dev_inodename_&gt; &lt;_sectors_&gt; &lt;_option_&gt; [_label_] ...@@ -39,9 +39,8 @@ format &lt;_dev_inodename_&gt; &lt;_sectors_&gt; &lt;_option_&gt; [_label_]
## 输出说明 ## 输出说明
**示例**:格式化mmc卡 **示例** 格式化mmc卡
``` ```
OHOS # format /dev/mmcblk1 128 2 OHOS # format /dev/mmcblk1 128 2
Format to FAT32, 128 sectors per cluster. Format to FAT32, 128 sectors per cluster.
......
...@@ -11,63 +11,71 @@ ls命令用来显示当前目录的内容。 ...@@ -11,63 +11,71 @@ ls命令用来显示当前目录的内容。
ls [_-ACHLSZacdfhiklmnopqrstux1_] [_--color_[_=auto_]] [_directory..._] ls [_-ACHLSZacdfhiklmnopqrstux1_] [_--color_[_=auto_]] [_directory..._]
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 系统启动过程中已经通过 alias 为 ls=toybox ls --color=auto 、ll = ls -alF 、 la=ls -A 和 l=ls -CF 赋能,使这几个命令的初始行为就和linux相同(详细效果见输出说明)。所以若要查看help列表,请输入'toybox ls --help'。 > 系统启动过程中已经通过 alias 为 ls=toybox ls --color=auto 、ll = ls -alF 、 la=ls -A 和 l=ls -CF 赋能,使这几个命令的初始行为就和linux相同(详细效果见输出说明)。所以若要查看help列表,请输入'toybox ls --help'。
## 参数说明 ## 参数说明
**表1** 展示功能参数说明 **表1** 展示功能参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ------ | ------------------------------------------------------------ | ----------------------------- |
| --help | 查看ls命令支持的参数列表,使用方式。 | N/A | | --help | 查看ls命令支持的参数列表,使用方式。 | N/A |
| -a | 显示所有文件包括.hidden隐藏类型的文件。 | N/A | | -a | 显示所有文件包括.hidden隐藏类型的文件。 | N/A |
| -b | 转义非图形字符。 | N/A | | -b | 转义非图形字符。 | N/A |
| -c | 使用ctime作为文件的时间戳,必须和-l参数一块使用。 | N/A | | -c | 使用ctime作为文件的时间戳,必须和-l参数一块使用。 | N/A |
| -d | 只显示path名称不显示path所包含的内容。 | N/A | | -d | 只显示path名称不显示path所包含的内容。 | N/A |
| -i | 显示文件的节点号。 | N/A | | -i | 显示文件的节点号。 | N/A |
| -p | 在path名称后放一个"/"。 | N/A | | -p | 在path名称后放一个"/"。 | N/A |
| -q | 显示不可打印字符比如'?'。 | N/A | | -q | 显示不可打印字符比如'?'。 | N/A |
| -s | 统计目录和其成员所占用的内存大小,单位为1024字节。 | N/A | | -s | 统计目录和其成员所占用的内存大小,单位为1024字节。 | N/A |
| -u | 以文件的最后访问时间为时间戳,配合&nbsp;-l&nbsp;一起使用。 | N/A | | -u | 以文件的最后访问时间为时间戳,配合&nbsp;-l&nbsp;一起使用。 | N/A |
| -A | 列出所有文件除了.和.. | N/A | | -A | 列出所有文件除了.和.. | N/A |
| -H | 跟随命令行符号链接。 | N/A | | -H | 跟随命令行符号链接。 | N/A |
| -L | 跟随符号链接。 | N/A | | -L | 跟随符号链接。 | N/A |
| -Z | 安全上下文。 | N/A | | -Z | 安全上下文。 | N/A |
| path | path为空时,显示当前目录的内容。<br/>path为无效文件名时,显示失败,提示:<br/>ls&nbsp;error:&nbsp;No&nbsp;such&nbsp;directory。<br/>path为有效目录路径时,会显示对应目录下的内容。 | 1.为空。<br/>2.有效的目录路径 | | path | path为空时,显示当前目录的内容。<br/>path为无效文件名时,显示失败,提示:<br/>ls&nbsp;error:&nbsp;No&nbsp;such&nbsp;directory。<br/>path为有效目录路径时,会显示对应目录下的内容。 | 1.为空。<br/>2.有效的目录路径 |
**表2** 输出格式参数说明 **表2** 输出格式参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | | ------- | --------------------------------------- |
| -1 | 每行列出一个文件。 | N/A | | -1 | 每行列出一个文件。 |
| -c | 列,垂直排序。 | N/A | | -c | 列,垂直排序。 |
| -g | 类似于&nbsp;-l&nbsp;但没有所有者。 | N/A | | -g | 类似于&nbsp;-l&nbsp;但没有所有者。 |
| -h | 统计path目录下文件的总大小,单位为KiB。 | N/A | | -h | 统计path目录下文件的总大小,单位为KiB。 |
| -l | 详细的显示path目录下文件的信息。 | N/A | | -l | 详细的显示path目录下文件的信息。 |
| -m | 文件之间添加逗号。 | N/A | | -m | 文件之间添加逗号。 |
| -n | 类似&nbsp;-l&nbsp;数字格式显示uid/gid。 | N/A | | -n | 类似&nbsp;-l&nbsp;数字格式显示uid/gid。 |
| -o | 类似&nbsp;-l&nbsp;但显示列表不包括组。 | N/A | | -o | 类似&nbsp;-l&nbsp;但显示列表不包括组。 |
| -x | 列,水平排序。 | N/A | | -x | 列,水平排序。 |
| -ll | 文件的时间属性显示纳秒。 | N/A | | -ll | 文件的时间属性显示纳秒。 |
| --color | 彩色打印。 | 默认配置为:device=yellow&nbsp;symlink=turquoise/red&nbsp;dir=blue&nbsp;socket=purple&nbsp;files:&nbsp;exe=green&nbsp;suid=red&nbsp;suidfile=redback&nbsp;stickydir=greenback=auto&nbsp;means&nbsp;detect&nbsp;if&nbsp;output&nbsp;is&nbsp;a&nbsp;tty. |
**表3** 排序参数说明(默认为按首字母排序)
**表3** 排序参数说明(默认为按首字母排序)
| 参数 | 参数说明 |
| 参数 | 参数说明 | 取值范围 | | ---- | ------------------------------------------ |
| -------- | -------- | -------- | | -f | 不排序。 |
| -f | 不排序。 | N/A | | -r | 按首字母反向排序。 |
| -r | 按首字母反向排序。 | N/A | | -t | 按文件的最后修改时间排序,最近时间为排头。 |
| -t | 按文件的最后修改时间排序,最近时间为排头。 | N/A | | -S | 按文件大小来排序,大文件为排头。 |
| -S | 按文件大小来排序,大文件为排头。 | N/A |
**表4** 彩色打印
| 参数 | 默认配置 |
| ---- | ------------------------------------------ |
| --color | device=yellow symlink=turquoise/red dir=blue socket=purple files: exe=green suid=red suidfile=redback stickydir=greenback=auto means detect if output is a tty. |
## 使用指南 ## 使用指南
> ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:**
> **须知:**
> fatfs的文件节点信息继承其父节点,父节点号为0。故在hi3516dv300开发板上ls -i显示的文件节点号全为0。 > fatfs的文件节点信息继承其父节点,父节点号为0。故在hi3516dv300开发板上ls -i显示的文件节点号全为0。
## 特殊说明
ls中参数shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -80,18 +88,16 @@ ls [_-ACHLSZacdfhiklmnopqrstux1_] [_--color_[_=auto_]] [_directory..._] ...@@ -80,18 +88,16 @@ ls [_-ACHLSZacdfhiklmnopqrstux1_] [_--color_[_=auto_]] [_directory..._]
## 输出说明 ## 输出说明
**示例1:**ls命令查看当前路径下的内容 **示例1** ls命令查看当前路径下的内容
``` ```
OHOS:/$ ls OHOS:/$ ls
bin etc nfs sdcard system usr bin etc nfs sdcard system usr
dev lib proc storage userdata vendor dev lib proc storage userdata vendor
``` ```
**示例2:**ll命令查看当前路径下的内容 **示例2** ll命令查看当前路径下的内容
``` ```
OHOS:/$ ll OHOS:/$ ll
total 20 total 20
...@@ -107,4 +113,4 @@ drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 system/ ...@@ -107,4 +113,4 @@ drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 system/
drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 userdata/ drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 userdata/
drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 usr/ drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 usr/
drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 vendor/ drwxrwxrwx 1 0 0 2048 2021-11-21 17:52 vendor/
``` ```
\ No newline at end of file
...@@ -23,9 +23,8 @@ lsfd命令显示当前已经打开文件的fd号以及文件的名字。 ...@@ -23,9 +23,8 @@ lsfd命令显示当前已经打开文件的fd号以及文件的名字。
## 输出说明 ## 输出说明
**示例:**lsfd输出说明 **示例** lsfd输出说明
``` ```
OHOS # lsfd OHOS # lsfd
fd filename fd filename
......
...@@ -13,24 +13,27 @@ mkdir [_-vp_] [_-m mode_] [_dirname..._] ...@@ -13,24 +13,27 @@ mkdir [_-vp_] [_-m mode_] [_dirname..._]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | | --------- | ------------------------------ |
| --help | 查看mkdir命令支持的参数列表 | N/A | | --help | 查看mkdir命令支持的参数列表 |
| -m | 设置即将创建目录的权限。 | N/A | | -m | 设置即将创建目录的权限。 |
| -p | 递归逐级创建父子目录。 | N/A | | -p | 递归逐级创建父子目录。 |
| -v | 打印创建目录过程中的详细信息。 | N/A | | -v | 打印创建目录过程中的详细信息。 |
| directory | 需要创建的目录。 | N/A | | directory | 需要创建的目录。 |
## 使用指南 ## 使用指南
> ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:** > **须知:**
> fatfs文件系统所有创建的文件和其挂载节点的权限属性保持一致,目前节点的权限只有用户读写权限,group和others权限不生效, > fatfs文件系统所有创建的文件和其挂载节点的权限属性保持一致,目前节点的权限只有用户读写权限,group和others权限不生效,
> >
> 且只有读写位可设置,有rw和ro两种,因此mkdir在附加-m参数时,创建的目录权限仅有777和555两种,可执行权限也不生效。 > 且只有读写位可设置,有rw和ro两种,因此mkdir在附加-m参数时,创建的目录权限仅有777和555两种,可执行权限也不生效。
## 特殊说明
shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -45,7 +48,7 @@ mkdir [_-vp_] [_-m mode_] [_dirname..._] ...@@ -45,7 +48,7 @@ mkdir [_-vp_] [_-m mode_] [_dirname..._]
## 输出说明 ## 输出说明
``` ```
OHOS:/tmp$ mkdir testpath OHOS:/tmp$ mkdir testpath
OHOS:/tmp$ ll OHOS:/tmp$ ll
...@@ -53,9 +56,9 @@ total 2 ...@@ -53,9 +56,9 @@ total 2
drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath/ drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath/
``` ```
示例 2 创建指定mode的目录 **示例2** 创建指定mode的目录
``` ```
OHOS:/tmp$ mkdir -m 777 testpath OHOS:/tmp$ mkdir -m 777 testpath
OHOS:/tmp$ ll OHOS:/tmp$ ll
...@@ -63,9 +66,9 @@ total 2 ...@@ -63,9 +66,9 @@ total 2
drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath/ drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath/
``` ```
示例 3 逐级创建目录 **示例3** 逐级创建目录
``` ```
OHOS:/tmp$ mkdir -pv testpath01/testpath02/testpath03 OHOS:/tmp$ mkdir -pv testpath01/testpath02/testpath03
mkdir: created directory 'testpath01' mkdir: created directory 'testpath01'
...@@ -80,4 +83,4 @@ drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath02/ ...@@ -80,4 +83,4 @@ drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath02/
OHOS:/tmp$ ll testpath01/testpath02/ OHOS:/tmp$ ll testpath01/testpath02/
total 2 total 2
drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath03/ drwxrwxrwx 1 0 0 2048 1979-12-31 00:00 testpath03/
``` ```
\ No newline at end of file
...@@ -13,22 +13,25 @@ mount [_-f_] [_-t TYPE_] [_-o OPTION,_] [[_DEVICE_] _DIR_] ...@@ -13,22 +13,25 @@ mount [_-f_] [_-t TYPE_] [_-o OPTION,_] [[_DEVICE_] _DIR_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ------ | ----------------------------------------------------------- | ------------------------------------------------------------ |
| --help | 查看mount命令支持的参数列表。 | N/A | | --help | 查看mount命令支持的参数列表。 | N/A |
| -f | 佯装挂载动作(实际不做挂载)。 | N/A | | -f | 佯装挂载动作(实际不做挂载)。 | N/A |
| -t | 文件系统的种类。 | TYPE:vfat,&nbsp;yaffs,&nbsp;jffs,&nbsp;ramfs,&nbsp;nfs,procfs,&nbsp;romfs. | | -t | 文件系统的种类。 | TYPE:vfat,&nbsp;yaffs,&nbsp;jffs,&nbsp;ramfs,&nbsp;nfs,procfs,&nbsp;romfs. |
| -o | 挂载选项。 | N/A | | -o | 挂载选项。 | N/A |
| DEVICE | 要挂载的设备(格式为设备所在路径)。 | 系统拥有的设备。 | | DEVICE | 要挂载的设备(格式为设备所在路径)。 | 系统拥有的设备。 |
| DIR | 指定目录。<br/>用户必须具有指定目录中的执行(搜索)许可权。 | N/A | | DIR | 指定目录。<br/>用户必须具有指定目录中的执行(搜索)许可权。 | N/A |
## 使用指南 ## 使用指南
mount后加需要挂载的设备信息、指定目录以及设备文件格式,就能成功挂载文件系统到指定目录。 mount后加需要挂载的设备信息、指定目录以及设备文件格式,就能成功挂载文件系统到指定目录。
## 特殊说明
shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -37,9 +40,9 @@ mount后加需要挂载的设备信息、指定目录以及设备文件格式, ...@@ -37,9 +40,9 @@ mount后加需要挂载的设备信息、指定目录以及设备文件格式,
## 输出说明 ## 输出说明
**示例:**将服务器端nfs目录192.168.1.3:/nfs挂载到当前系统下新建的/nfs目录: **示例** 将服务器端nfs目录192.168.1.3:/nfs挂载到当前系统下新建的/nfs目录:
``` ```
OHOS:/$ mkdir nfs OHOS:/$ mkdir nfs
OHOS:/$ mount -t nfs 192.168.1.3:/nfs nfs OHOS:/$ mount -t nfs 192.168.1.3:/nfs nfs
...@@ -49,4 +52,4 @@ OHOS:/$ ls nfs/ ...@@ -49,4 +52,4 @@ OHOS:/$ ls nfs/
16d.xml gpio_test ohos_test.txt userfs_vfat.img 16d.xml gpio_test ohos_test.txt userfs_vfat.img
OHOS_Image.bin hello rootfs_vfat.img OHOS_Image.bin hello rootfs_vfat.img
dev_tools mksh_rootfs_vfat.img test_demo dev_tools mksh_rootfs_vfat.img test_demo
``` ```
\ No newline at end of file
...@@ -13,22 +13,22 @@ mv [_-fivn_] _SOURCE... DEST_ ...@@ -13,22 +13,22 @@ mv [_-fivn_] _SOURCE... DEST_
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ------ | ------------------------------------------------------------ | ----------------------------------------------- |
| -help | 使用帮助。 | N/A | | -help | 使用帮助。 | N/A |
| -f | 通过删除目标文件强制复制。 | N/A | | -f | 通过删除目标文件强制复制。 | N/A |
| -i | 若指定移动的源目录或文件与目标中目录或文件同名,则会先询问是否覆盖旧文件,输入&nbsp;y&nbsp;直接覆盖,输入&nbsp;n&nbsp;取消该操作。 | N/A | | -i | 若指定移动的源目录或文件与目标中目录或文件同名,则会先询问是否覆盖旧文件,输入&nbsp;y&nbsp;直接覆盖,输入&nbsp;n&nbsp;取消该操作。 | N/A |
| -n | 不要覆盖任何已存在的文件或目录。 | N/A | | -n | 不要覆盖任何已存在的文件或目录。 | N/A |
| -v | 目前本参数toybox官方最新代码虽然支持,但同样也不生效。 | N/A | | -v | 目前本参数toybox官方最新代码虽然支持,但同样也不生效。 | N/A |
| SOURCE | 源文件路径。 | 目前只支持文件,不支持目录;支持多文件同时移动。 | | SOURCE | 源文件路径。 | 目前只支持文件,不支持目录;支持多文件同时移动。 |
| DEST | 目的文件路径。 | 支持目录以及文件。 | | DEST | 目的文件路径。 | 支持目录以及文件。 |
## 使用指南 ## 使用指南
- 源文件路径支持“\*”和“?”通配符,“\*”代表任意多个字符,“?”代表任意单个字符。目的路径不支持通配符。当源路径可匹配多个文件时,目的路径必须为目录。 - 源文件路径支持“\*”和“?”通配符,“\*”代表任意多个字符,“?”代表任意单个字符。目的路径不支持通配符。当源路径可匹配多个文件时,目的路径必须为目录。
- 目的路径为目录时,该目录必须存在。此时目的文件以源文件命名。 - 目的路径为目录时,该目录必须存在。此时目的文件以源文件命名。
...@@ -36,6 +36,9 @@ mv [_-fivn_] _SOURCE... DEST_ ...@@ -36,6 +36,9 @@ mv [_-fivn_] _SOURCE... DEST_
- 目的文件已存在则会覆盖。 - 目的文件已存在则会覆盖。
## 特殊说明
shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -48,9 +51,9 @@ mv [_-fivn_] _SOURCE... DEST_ ...@@ -48,9 +51,9 @@ mv [_-fivn_] _SOURCE... DEST_
## 输出说明 ## 输出说明
**示例 1** 显示结果如下 **示例1** 显示结果如下
``` ```
OHOS:/$ touch test.txt OHOS:/$ touch test.txt
OHOS:/$ mkdir testpath OHOS:/$ mkdir testpath
...@@ -71,9 +74,9 @@ bin etc proc storage test.txt userdata vendor ...@@ -71,9 +74,9 @@ bin etc proc storage test.txt userdata vendor
dev lib sdcard system testpath usr dev lib sdcard system testpath usr
``` ```
**示例 2** 通配符使用 **示例2** 通配符使用
``` ```
OHOS:/$ ls OHOS:/$ ls
bin etc proc storage test.txt testA.txt testpath usr bin etc proc storage test.txt testA.txt testpath usr
...@@ -84,4 +87,4 @@ bin etc proc storage test.txt userdata vendor ...@@ -84,4 +87,4 @@ bin etc proc storage test.txt userdata vendor
dev lib sdcard system testpath usr dev lib sdcard system testpath usr
OHOS:/$ ls testpath/ OHOS:/$ ls testpath/
test.txt test3.txt testA.txt test_.txt test.txt test3.txt testA.txt test_.txt
``` ```
\ No newline at end of file
...@@ -32,9 +32,9 @@ partinfo &lt;_dev_inodename_&gt; ...@@ -32,9 +32,9 @@ partinfo &lt;_dev_inodename_&gt;
## 输出说明 ## 输出说明
**示例**:查看系统分区信息 **示例** 查看系统分区信息
``` ```
OHOS # partinfo /dev/mmcblk0p0 OHOS # partinfo /dev/mmcblk0p0
part info : part info :
......
...@@ -13,7 +13,7 @@ pwd ...@@ -13,7 +13,7 @@ pwd
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
...@@ -28,9 +28,9 @@ pwd 命令将当前目录的全路径名称(从根目录)写入标准输出 ...@@ -28,9 +28,9 @@ pwd 命令将当前目录的全路径名称(从根目录)写入标准输出
## 输出说明 ## 输出说明
**示例**:查看当前路径 **示例** 查看当前路径
``` ```
OHOS:/sdcard/nfs$ pwd OHOS:/sdcard/nfs$ pwd
/sdcard/nfs /sdcard/nfs
......
...@@ -13,14 +13,14 @@ rm [_-fv_] _FILE or rm_ [_-rv_] [_PATH_ | _filename_]... ...@@ -13,14 +13,14 @@ rm [_-fv_] _FILE or rm_ [_-rv_] [_PATH_ | _filename_]...
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | | ------------- | ------------------------------------------------ |
| -r | 删除空目录或非空目录。 | N/A | | -r | 删除空目录或非空目录。 |
| -f | 强制删除:不需要确认,删除不存的文件在也不报错。 | N/A | | -f | 强制删除:不需要确认,删除不存的文件在也不报错。 |
| -v | 显示删除的过程。 | N/A | | -v | 显示删除的过程。 |
| PATH/filename | 要删除文件或文件夹的名称,支持输入路径。 | N/A | | PATH/filename | 要删除文件或文件夹的名称,支持输入路径。 |
## 使用指南 ## 使用指南
...@@ -31,6 +31,9 @@ rm [_-fv_] _FILE or rm_ [_-rv_] [_PATH_ | _filename_]... ...@@ -31,6 +31,9 @@ rm [_-fv_] _FILE or rm_ [_-rv_] [_PATH_ | _filename_]...
- 删除不存在的文件会报错。 - 删除不存在的文件会报错。
## 特殊说明
-f -v 参数shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -43,9 +46,9 @@ rm [_-fv_] _FILE or rm_ [_-rv_] [_PATH_ | _filename_]... ...@@ -43,9 +46,9 @@ rm [_-fv_] _FILE or rm_ [_-rv_] [_PATH_ | _filename_]...
## 输出说明 ## 输出说明
**示例 1** 用 rm 命令删除文件 testfile **示例1** 用 rm 命令删除文件 testfile
``` ```
OHOS:/$ ls OHOS:/$ ls
bin etc proc storage testfile usr bin etc proc storage testfile usr
...@@ -56,9 +59,9 @@ bin etc proc storage userdata vendor ...@@ -56,9 +59,9 @@ bin etc proc storage userdata vendor
dev lib sdcard system usr dev lib sdcard system usr
``` ```
**示例 2** 用 rm -r 删除非空目录 testpath **示例2** 用 rm -r 删除非空目录 testpath
``` ```
OHOS:/$ ls OHOS:/$ ls
bin etc proc storage testpath usr bin etc proc storage testpath usr
...@@ -67,4 +70,4 @@ OHOS:/$ rm -r testpath/ ...@@ -67,4 +70,4 @@ OHOS:/$ rm -r testpath/
OHOS:/$ ls OHOS:/$ ls
bin etc proc storage userdata vendor bin etc proc storage userdata vendor
dev lib sdcard system usr dev lib sdcard system usr
``` ```
\ No newline at end of file
...@@ -13,7 +13,7 @@ rmdir [_-p_] [_dirname..._] ...@@ -13,7 +13,7 @@ rmdir [_-p_] [_dirname..._]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -39,9 +39,9 @@ rmdir [_-p_] [_dirname..._] ...@@ -39,9 +39,9 @@ rmdir [_-p_] [_dirname..._]
## 输出说明 ## 输出说明
**示例:**删除一个名为 dir 的目录 **示例** 删除一个名为 dir 的目录
``` ```
OHOS:/test$ mkdir dir OHOS:/test$ mkdir dir
OHOS:/test$ ls OHOS:/test$ ls
......
...@@ -13,7 +13,7 @@ statfs [_directory_] ...@@ -13,7 +13,7 @@ statfs [_directory_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -31,8 +31,8 @@ statfs [_directory_] ...@@ -31,8 +31,8 @@ statfs [_directory_]
statfs /nfs statfs /nfs
**示例**statfs输出说明 **示例** statfs输出说明
``` ```
OHOS # statfs ./nfs OHOS # statfs ./nfs
statfs got: statfs got:
......
...@@ -13,7 +13,7 @@ sync ...@@ -13,7 +13,7 @@ sync
## 参数说明 ## 参数说明
## 使用指南 ## 使用指南
...@@ -30,4 +30,4 @@ sync ...@@ -30,4 +30,4 @@ sync
## 输出说明 ## 输出说明
...@@ -17,10 +17,10 @@ touch [_filename_] ...@@ -17,10 +17,10 @@ touch [_filename_]
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | --------------------------- | -------- |
| --help | 查看touch命令支持的参数列表 | N/A | | --help | 查看touch命令支持的参数列表 | N/A |
| filename | 需要创建文件的名称。 | N/A | | filename | 需要创建文件的名称。 | N/A |
## 使用指南 ## 使用指南
...@@ -28,9 +28,13 @@ touch [_filename_] ...@@ -28,9 +28,13 @@ touch [_filename_]
- touch命令用来创建一个空文件,该文件可读写。 - touch命令用来创建一个空文件,该文件可读写。
- 使用touch命令允许一次创建多个文件。 - 使用touch命令允许一次创建多个文件。
> ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:** > ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:**
> 在系统重要资源路径下使用touch命令创建文件,会对系统造成死机等未知影响,如在/dev路径下执行touch uartdev-0,会产生系统卡死现象。 > 在系统重要资源路径下使用touch命令创建文件,会对系统造成死机等未知影响,如在/dev路径下执行touch uartdev-0,会产生系统卡死现象。
## 特殊说明
--help参数以及同时创建多个文件,shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -45,7 +49,7 @@ touch [_filename_] ...@@ -45,7 +49,7 @@ touch [_filename_]
**示例 1** 创建一个名为 file.c 的文件 **示例 1** 创建一个名为 file.c 的文件
``` ```
OHOS:/tmp$ ls OHOS:/tmp$ ls
OHOS:/tmp$ touch file.c OHOS:/tmp$ touch file.c
...@@ -58,7 +62,7 @@ total 0 ...@@ -58,7 +62,7 @@ total 0
**示例 2** 同时创建三个文件 **示例 2** 同时创建三个文件
``` ```
*OHOS:/tmp$ *OHOS:/tmp$
OHOS:/tmp$ touch testfile1 testfile2 testfile3 OHOS:/tmp$ touch testfile1 testfile2 testfile3
...@@ -68,4 +72,4 @@ total 0 ...@@ -68,4 +72,4 @@ total 0
-rwxrwxrwx 1 0 0 0 1979-12-31 00:00 testfile2* -rwxrwxrwx 1 0 0 0 1979-12-31 00:00 testfile2*
-rwxrwxrwx 1 0 0 0 1979-12-31 00:00 testfile3* -rwxrwxrwx 1 0 0 0 1979-12-31 00:00 testfile3*
OHOS:/tmp$ OHOS:/tmp$
``` ```
\ No newline at end of file
...@@ -13,20 +13,23 @@ umount [_-a [-t TYPE]_] [_dir_] ...@@ -13,20 +13,23 @@ umount [_-a [-t TYPE]_] [_dir_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ------ | ------------------------------------------------------------ | -------------------------- |
| --help | 查看umount命令支持的参数列表。 | N/A | | --help | 查看umount命令支持的参数列表。 | N/A |
| -a | 卸载所有已挂载的目录。 | N/A | | -a | 卸载所有已挂载的目录。 | N/A |
| -t | 同-a选项一起使用,限制-a的卸载范围,只卸载-t所指定的文件系统类型的挂载目录。 | N/A | | -t | 同-a选项一起使用,限制-a的卸载范围,只卸载-t所指定的文件系统类型的挂载目录。 | N/A |
| dir | 需要卸载的文件系统对应的目录。 | 系统已挂载的文件系统的目录 | | dir | 需要卸载的文件系统对应的目录。 | 系统已挂载的文件系统的目录 |
## 使用指南 ## 使用指南
umount后加上需要卸载的指定文件系统的目录,即将指定文件系统卸载。 umount后加上需要卸载的指定文件系统的目录,即将指定文件系统卸载。
## 特殊说明
参数shell端暂不支持。切换mksh版本可全支持,方法:cd bin; ./mksh。
## 使用实例 ## 使用实例
...@@ -41,18 +44,18 @@ umount后加上需要卸载的指定文件系统的目录,即将指定文件 ...@@ -41,18 +44,18 @@ umount后加上需要卸载的指定文件系统的目录,即将指定文件
将已在./nfs挂载的文件系统卸载掉 将已在./nfs挂载的文件系统卸载掉
**示例 1** umount输出示例 **示例1** umount输出示例
``` ```
OHOS:/$ umount ./nfs/ OHOS:/$ umount ./nfs/
umount ok umount ok
``` ```
**示例 2** 卸载所有已挂载的nfs类型的目录 **示例2** 卸载所有已挂载的nfs类型的目录
``` ```
OHOS:/$ umount -a -t nfs OHOS:/$ umount -a -t nfs
umount ok umount ok
``` ```
\ No newline at end of file
...@@ -13,12 +13,12 @@ writeproc &lt;_data_&gt; &gt;&gt; /proc/&lt;_filename_&gt; ...@@ -13,12 +13,12 @@ writeproc &lt;_data_&gt; &gt;&gt; /proc/&lt;_filename_&gt;
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 |
| -------- | -------- | -------- | | -------- | ---------------------------------------------------------- |
| data | 要输入的字符串,以空格为结束符,如需输入空格,请用""包裹。 | N/A | | data | 要输入的字符串,以空格为结束符,如需输入空格,请用""包裹。 |
| filename | data要传入的proc文件。 | N/A | | filename | data要传入的proc文件。 |
## 使用指南 ## 使用指南
...@@ -28,6 +28,9 @@ proc文件实现自身的write函数,调用writeproc命令后会将入参传 ...@@ -28,6 +28,9 @@ proc文件实现自身的write函数,调用writeproc命令后会将入参传
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> procfs不支持多线程访问。 > procfs不支持多线程访问。
## 特殊说明
shell端暂不支持。
## 使用实例 ## 使用实例
...@@ -36,11 +39,13 @@ proc文件实现自身的write函数,调用writeproc命令后会将入参传 ...@@ -36,11 +39,13 @@ proc文件实现自身的write函数,调用writeproc命令后会将入参传
## 输出说明 ## 输出说明
```
OHOS \# writeproc test &gt;&gt; /proc/uptime OHOS \# writeproc test &gt;&gt; /proc/uptime
[INFO]write buf is: test [INFO]write buf is: test
test &gt;&gt; /proc/uptime test &gt;&gt; /proc/uptime
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> uptime proc文件临时实现write函数,INFO日志为实现的测试函数打印的日志。 > uptime proc文件临时实现write函数,INFO日志为实现的测试函数打印的日志。
\ No newline at end of file
...@@ -8,17 +8,18 @@ ...@@ -8,17 +8,18 @@
在中断有响应的情况下,可以通过魔法键查看task信息中 cpup(CPU占用率)看是哪个任务长时间占用CPU导致系统其他任务无响应(一般为比较高优先级任务一直抢占CPU,导致低优先级任务无响应)。 在中断有响应的情况下,可以通过魔法键查看task信息中 cpup(CPU占用率)看是哪个任务长时间占用CPU导致系统其他任务无响应(一般为比较高优先级任务一直抢占CPU,导致低优先级任务无响应)。
## 使用方法 ## 使用配置
魔法键依赖于宏LOSCFG_ENABLE_MAGICKEY,在kernel/liteos_a中输入make menuconfig命令。此时会弹出配置项,找到Debug选项并进入,在配置项中开启“Enable MAGIC KEY”:
1. 配置宏LOSCFG_ENABLE_MAGICKEY Debug ---&gt; Enable MAGIC KEY;若关闭该选项,则魔法键失效(默认为选中的)
魔法键依赖于宏LOSCFG_ENABLE_MAGICKEY,使用时通过menuconfig在配置项中开启“Enable MAGIC KEY”: > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 可以在menuconfig中,将光标移动到LOSCFG_ENABLE_MAGICKEY上,输入“?”,可以查看帮助信息。
Debug ---&gt; Enable MAGIC KEY;若关闭该选项,则魔法键失效。 ## 使用方法
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 可以在menuconfig中,将光标移动到LOSCFG_ENABLE_MAGICKEY上,输入“?”,查看帮助信息。
2. 输入“ctrl + r”键,打开魔法键检测功能。 1. 输入“ctrl + r”键,打开魔法键检测功能。
在连接UART或者USB转虚拟串口的情况下,输入“ctrl + r” 键,打开魔法键检测功能,输出 “Magic key on”;再输入一次后,则关闭魔法键检测功能,输出“Magic key off”。魔法键功能如下: 在连接UART或者USB转虚拟串口的情况下,输入“ctrl + r” 键,打开魔法键检测功能,输出 “Magic key on”;再输入一次后,则关闭魔法键检测功能,输出“Magic key off”。魔法键功能如下:
...@@ -30,5 +31,5 @@ ...@@ -30,5 +31,5 @@
- ctrl + e:系统进行简单完整性内存池检查,检查出错会输出相关错误信息,检查正常会输出“system memcheck over, all passed!”。 - ctrl + e:系统进行简单完整性内存池检查,检查出错会输出相关错误信息,检查正常会输出“system memcheck over, all passed!”。
> ![icon-notice.gif](public_sys-resources/icon-notice.gif) **须知:** > **须知:**
> 魔法键检测功能打开情况下,如果需要通过UART或者USB转虚拟串口输入特殊字符需避免与魔法键值重复,否则魔法键会被误触发,而原有设计功能可能出现错误。 > 魔法键检测功能打开情况下,如果需要通过UART或者USB转虚拟串口输入特殊字符需避免与魔法键值重复,否则魔法键会被误触发,而原有设计功能可能出现错误。
\ No newline at end of file
...@@ -17,7 +17,7 @@ arp [_-i IF_] -d _IPADDR_ ...@@ -17,7 +17,7 @@ arp [_-i IF_] -d _IPADDR_
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -40,15 +40,15 @@ arp [_-i IF_] -d _IPADDR_ ...@@ -40,15 +40,15 @@ arp [_-i IF_] -d _IPADDR_
输入arp 输入arp
**示例:**打印整个 ARP 缓存表 **示例** 打印整个 ARP 缓存表
``` ```
OHOS # arp OHOS # arp
Address HWaddress Iface Type Address HWaddress Iface Type
192.168.1.10 E6:2B:99:2C:4B:20 eth0 static 192.168.1.10 E6:2B:99:2C:4B:20 eth0 static
``` ```
**表2** 参数说明 **表2** 参数说明
| 参数 | 说明 | | 参数 | 说明 |
| -------- | -------- | | -------- | -------- |
......
...@@ -15,13 +15,13 @@ ...@@ -15,13 +15,13 @@
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | ------------------------------- | -------------------------------------------- | ---------------- |
| -h&nbsp;\|&nbsp;--help | 查看dhclient命令支持的参数列表,及使用方式。 | N/A | | -h&nbsp;\|&nbsp;--help | 查看dhclient命令支持的参数列表,及使用方式。 | N/A |
| &lt;netif&nbsp;name&gt; | 启动对应网卡的dhcp请求。 | 网卡名字,eth0。 | | &lt;netif&nbsp;name&gt; | 启动对应网卡的dhcp请求。 | 网卡名字,eth0。 |
| -x&nbsp;&lt;netif&nbsp;name&gt; | 关闭对应网卡的dhcp功能。 | 网卡名字,eth0。 | | -x&nbsp;&lt;netif&nbsp;name&gt; | 关闭对应网卡的dhcp功能。 | 网卡名字,eth0。 |
## 使用指南 ## 使用指南
...@@ -32,12 +32,15 @@ ...@@ -32,12 +32,15 @@
- dhclient -x eth0 - dhclient -x eth0
## 特殊说明
shell端暂不支持。
## 使用实例 ## 使用实例
**示例1:**启动网卡eth0的dhcp请求 **示例1** 启动网卡eth0的dhcp请求
``` ```
OHOS:/$ dhclient eth0 OHOS:/$ dhclient eth0
OHOS:/$ ifconfig OHOS:/$ ifconfig
...@@ -50,10 +53,9 @@ OHOS:/$ ...@@ -50,10 +53,9 @@ OHOS:/$
``` ```
**示例2:**关闭网卡eth0的dhcp请求 **示例2** 关闭网卡eth0的dhcp请求
``` ```
OHOS:/$ dhclient -x eth0 OHOS:/$ dhclient -x eth0
NetifStatusCallback(eth0): nsc event: 0xf0 NetifStatusCallback(eth0): nsc event: 0xf0
...@@ -63,4 +65,4 @@ lo ip:127.0.0.1 netmask:255.0.0.0 gateway:127.0.0.1 ...@@ -63,4 +65,4 @@ lo ip:127.0.0.1 netmask:255.0.0.0 gateway:127.0.0.1
HWaddr 00 MTU:0 Running Link UP HWaddr 00 MTU:0 Running Link UP
eth0 ip:0.0.0.0 netmask:0.0.0.0 gateway:0.0.0.0 eth0 ip:0.0.0.0 netmask:0.0.0.0 gateway:0.0.0.0
HWaddr 42:da:81:bc:58:94 MTU:1500 Running Default Link UP HWaddr 42:da:81:bc:58:94 MTU:1500 Running Default Link UP
``` ```
\ No newline at end of file
...@@ -27,7 +27,7 @@ option: ...@@ -27,7 +27,7 @@ option:
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -65,8 +65,8 @@ option: ...@@ -65,8 +65,8 @@ option:
## 输出说明 ## 输出说明
- **示例1:**设置网络参数 - **示例1** 设置网络参数
``` ```
OHOS:/$ ifconfig eth0 192.168.100.31 netmask 255.255.255.0 gateway 192.168.100.1 hw ether 00:49:cb:6c:a1:31 OHOS:/$ ifconfig eth0 192.168.100.31 netmask 255.255.255.0 gateway 192.168.100.1 hw ether 00:49:cb:6c:a1:31
OHOS:/$ ifconfig OHOS:/$ ifconfig
...@@ -79,7 +79,7 @@ option: ...@@ -79,7 +79,7 @@ option:
输出的各参数说明如下表所示: 输出的各参数说明如下表所示:
**表2** 参数说明 **表2** 参数说明
| 参数 | 说明 | | 参数 | 说明 |
| -------- | -------- | | -------- | -------- |
...@@ -92,8 +92,8 @@ option: ...@@ -92,8 +92,8 @@ option:
| Default | 有这项说明此网卡连接到默认网关。 | | Default | 有这项说明此网卡连接到默认网关。 |
| Link&nbsp;UP/Down | 网卡连接状态。 | | Link&nbsp;UP/Down | 网卡连接状态。 |
- **示例2:**获取协议栈统计信息 - **示例2** 获取协议栈统计信息
``` ```
OHOS # ifconfig -a OHOS # ifconfig -a
RX packets:6922 errors:0 ip dropped:4312 link dropped:67 overrun:0 bytes:0 (0.0 B) RX packets:6922 errors:0 ip dropped:4312 link dropped:67 overrun:0 bytes:0 (0.0 B)
...@@ -104,7 +104,7 @@ option: ...@@ -104,7 +104,7 @@ option:
输出的各参数说明如下表所示: 输出的各参数说明如下表所示:
**表3** ifconfig -a 参数说明 **表3** ifconfig -a 参数说明
| 参数 | 说明 | | 参数 | 说明 |
| -------- | -------- | | -------- | -------- |
...@@ -119,8 +119,8 @@ option: ...@@ -119,8 +119,8 @@ option:
| TX&nbsp;overrun | 暂未使用。 | | TX&nbsp;overrun | 暂未使用。 |
| TX&nbsp;bytes | IP层已正常发送或者转发的数据包的总长度。 | | TX&nbsp;bytes | IP层已正常发送或者转发的数据包的总长度。 |
- **示例3**设置IPv6的地址信息 - **示例3** 设置IPv6的地址信息
``` ```
OHOS:/$ ifconfig eth0 inet6 add 2001:a:b:c:d:e:f:d OHOS:/$ ifconfig eth0 inet6 add 2001:a:b:c:d:e:f:d
NetifStatusCallback(eth0): nsc event: 0x8 NetifStatusCallback(eth0): nsc event: 0x8
...@@ -139,8 +139,8 @@ option: ...@@ -139,8 +139,8 @@ option:
HWaddr 66:2f:e5:bd:24:e6 MTU:1500 Running Default Link UP HWaddr 66:2f:e5:bd:24:e6 MTU:1500 Running Default Link UP
``` ```
- **示例4**删除IPv6的地址信息 - **示例4** 删除IPv6的地址信息
``` ```
OHOS:/$ ifconfig eth0 inet6 del 2001:a:b:c:d:e:f:d OHOS:/$ ifconfig eth0 inet6 del 2001:a:b:c:d:e:f:d
NetifStatusCallback(eth0): nsc event: 0x200 NetifStatusCallback(eth0): nsc event: 0x200
......
...@@ -18,8 +18,8 @@ ipdebug ...@@ -18,8 +18,8 @@ ipdebug
## 输出说明 ## 输出说明
**示例:**ipdebug打印信息如下: **示例** ipdebug打印信息如下:
``` ```
OHOS # ipdebug OHOS # ipdebug
================= =================
......
...@@ -20,6 +20,9 @@ netstat ...@@ -20,6 +20,9 @@ netstat
netstat netstat
## 特殊说明
shell端暂不支持。
## 使用实例 ## 使用实例
...@@ -28,8 +31,8 @@ netstat ...@@ -28,8 +31,8 @@ netstat
## 输出说明 ## 输出说明
**示例:**netstat 打印信息 **示例** netstat 打印信息
``` ```
OHOS # netstat OHOS # netstat
========== total sockets 128 ====== unused sockets 119 ========== ========== total sockets 128 ====== unused sockets 119 ==========
...@@ -46,16 +49,16 @@ udp 0 0 127.0.0.1:62180 127.0.0.1:62179 ...@@ -46,16 +49,16 @@ udp 0 0 127.0.0.1:62180 127.0.0.1:62179
udp 0 0 127.0.0.1:62178 127.0.0.1:62177 udp 0 0 127.0.0.1:62178 127.0.0.1:62177
``` ```
**表1** 输出说明 **表1** 输出说明
| 输出 | 说明 | | 输出 | 说明 |
| -------- | -------- | | -------------------- | ------------------------------------------------------------ |
| Proto | 协议类型。 | | Proto | 协议类型。 |
| Recv-Q | 未被用户读取的数据量。<br/>对于Listen&nbsp;TCP,此值为已完成三次握手,但是未被用户accept的TCP连接的数量。 | | Recv-Q | 未被用户读取的数据量。<br/>对于Listen&nbsp;TCP,此值为已完成三次握手,但是未被用户accept的TCP连接的数量。 |
| Send-Q | 对TCP连接,已发送但未确认的数据量。<br/>对UDP连接,由于IP地址解析未完成而缓存的数据量。 | | Send-Q | 对TCP连接,已发送但未确认的数据量。<br/>对UDP连接,由于IP地址解析未完成而缓存的数据量。 |
| Local&nbsp;Address | 本地地址和端口。 | | Local&nbsp;Address | 本地地址和端口。 |
| Foreign&nbsp;Address | 远程地址和端口。 | | Foreign&nbsp;Address | 远程地址和端口。 |
| State | TCP连接状态,UDP此项无意义。 | | State | TCP连接状态,UDP此项无意义。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 形如“========== total sockets 32 ====== unused sockets 22 BootTime 27 s ========== ”,表示一共32个套接字,未使用套接字22个,距系统启动已经过27秒。 > 形如“========== total sockets 32 ====== unused sockets 22 BootTime 27 s ========== ”,表示一共32个套接字,未使用套接字22个,距系统启动已经过27秒。
\ No newline at end of file
...@@ -13,7 +13,7 @@ ntpdate [_SERVER_IP1_] [_SERVER_IP2_]... ...@@ -13,7 +13,7 @@ ntpdate [_SERVER_IP1_] [_SERVER_IP2_]...
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
......
...@@ -13,7 +13,7 @@ ping _[-4] [-c cnt] [-f] [-i interval] [-q] [-s size] &lt;IP&gt;_ ...@@ -13,7 +13,7 @@ ping _[-4] [-c cnt] [-f] [-i interval] [-q] [-s size] &lt;IP&gt;_
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -45,8 +45,8 @@ ping _[-4] [-c cnt] [-f] [-i interval] [-q] [-s size] &lt;IP&gt;_ ...@@ -45,8 +45,8 @@ ping _[-4] [-c cnt] [-f] [-i interval] [-q] [-s size] &lt;IP&gt;_
## 输出说明 ## 输出说明
**示例:**ping tftp 服务器地址 **示例** ping tftp 服务器地址
``` ```
OHOS:/$ ping 192.168.1.3 OHOS:/$ ping 192.168.1.3
Ping 192.168.1.3 (192.168.1.3): 56(84) bytes. Ping 192.168.1.3 (192.168.1.3): 56(84) bytes.
......
...@@ -13,14 +13,14 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_ ...@@ -13,14 +13,14 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | --------------------- | ----------------------------------- | -------- |
| -c&nbsp;count | 执行的次数,不带本参数则默认为4次。 | 1~65535 | | -c&nbsp;count | 执行的次数,不带本参数则默认为4次。 | [1, 65535] |
| -I&nbsp;interface | 指定网卡执行IPv6&nbsp;ping操作。 | N/A | | -I&nbsp;interface | 指定网卡执行IPv6&nbsp;ping操作。 | N/A |
| -I&nbsp;sourceAddress | 指定源IPv6地址执行ping操作。 | N/A | | -I&nbsp;sourceAddress | 指定源IPv6地址执行ping操作。 | N/A |
| destination | 目标主机地址。 | N/A | | destination | 目标主机地址。 | N/A |
## 使用指南 ## 使用指南
...@@ -31,6 +31,9 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_ ...@@ -31,6 +31,9 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_
- 命令需要启动TCP/IP协议栈后才能使用。 - 命令需要启动TCP/IP协议栈后才能使用。
## 特殊说明
shell端暂不支持。
## 使用实例 ## 使用实例
...@@ -45,8 +48,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_ ...@@ -45,8 +48,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_
## 输出说明 ## 输出说明
1. 输入ping6 2001:a:b:c:d:e:f:b 1. 输入`ping6 2001:a:b:c:d:e:f:b`
``` ```
OHOS # ping6 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data. OHOS # ping6 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data.
56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time<1 ms 56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time<1 ms
...@@ -58,8 +61,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_ ...@@ -58,8 +61,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_
rtt min/avg/max = 0/0.00/0 ms rtt min/avg/max = 0/0.00/0 ms
``` ```
2. 输入 ping6 -c 3 2001:a:b:c:d:e:f:b 指定3次进行网络测试 2. 输入 `ping6 -c 3 2001:a:b:c:d:e:f:b` 指定3次进行网络测试
``` ```
OHOS # ping6 -c 3 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data. OHOS # ping6 -c 3 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data.
56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time<1 ms 56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time<1 ms
...@@ -70,8 +73,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_ ...@@ -70,8 +73,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_
rtt min/avg/max = 0/0.00/0 ms rtt min/avg/max = 0/0.00/0 ms
``` ```
3. 输入 ping6 -I eth0 2001:a:b:c:d:e:f:b 使用指定网卡接口eth0测试IPv6。 3. 输入 `ping6 -I eth0 2001:a:b:c:d:e:f:b` 使用指定网卡接口eth0测试IPv6。
``` ```
OHOS # ping6 -I eth0 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data. OHOS # ping6 -I eth0 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data.
56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time=10 ms 56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time=10 ms
...@@ -82,8 +85,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_ ...@@ -82,8 +85,8 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_
4 packets transmitted, 4 received, 0.00% packet loss, time 30msrtt min/avg/max = 0/2.50/10 ms 4 packets transmitted, 4 received, 0.00% packet loss, time 30msrtt min/avg/max = 0/2.50/10 ms
``` ```
4. 输入 ping6 -I 2001:a:b:c:d:e:f:d 2001:a:b:c:d:e:f:b 使用指定的源IPv6地址2001:a:b:c:d:e:f:d进行测试。 4. 输入 `ping6 -I 2001:a:b:c:d:e:f:d 2001:a:b:c:d:e:f:b` 使用指定的源IPv6地址2001:a:b:c:d:e:f:d进行测试。
``` ```
OHOS # ping6 -I 2001:a:b:c:d:e:f:d 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data. OHOS # ping6 -I 2001:a:b:c:d:e:f:d 2001:a:b:c:d:e:f:b PING 2001:A:B:C:D:E:F:B with 56 bytes of data.
56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time<1 ms 56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=1 time<1 ms
...@@ -92,4 +95,4 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_ ...@@ -92,4 +95,4 @@ ping6 _[-c count] [-I interface / sourceAddress] destination_
56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=4 time<1 ms 56 bytes from 2001:A:B:C:D:E:F:B : icmp_seq=4 time<1 ms
--- 2001:a:b:c:d:e:f:b/64 ping statistics --- --- 2001:a:b:c:d:e:f:b/64 ping statistics ---
4 packets transmitted, 4 received, 0.00% packet loss, time 20msrtt min/avg/max = 0/0.00/0 ms 4 packets transmitted, 4 received, 0.00% packet loss, time 20msrtt min/avg/max = 0/0.00/0 ms
``` ```
\ No newline at end of file
...@@ -13,7 +13,7 @@ telnet [_on | off_] ...@@ -13,7 +13,7 @@ telnet [_on | off_]
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -37,9 +37,9 @@ telnet [_on | off_] ...@@ -37,9 +37,9 @@ telnet [_on | off_]
## 输出说明 ## 输出说明
**示例:**输入 telnet on **示例** 输入 telnet on
``` ```
OHOS # telnet on OHOS # telnet on
OHOS # start telnet server successfully, waiting for connection. OHOS # start telnet server successfully, waiting for connection.
......
...@@ -15,7 +15,7 @@ tftp命令可以从TFTP服务器上下载文件。 ...@@ -15,7 +15,7 @@ tftp命令可以从TFTP服务器上下载文件。
## 参数说明 ## 参数说明
**表1** 参数说明 **表1** 参数说明
| 参数 | 参数说明 | 取值范围 | | 参数 | 参数说明 | 取值范围 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
......
...@@ -45,7 +45,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -45,7 +45,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
- IDENTITY类型UINTPTR,表示事件操作的主体对象。 - IDENTITY类型UINTPTR,表示事件操作的主体对象。
- Params类型UINTPTR,表示事件的参数。 - Params类型UINTPTR,表示事件的参数。
示例: 示例:
``` ```
假设需要新增对文件(fd1、fd2)读写操作的简易插桩, 假设需要新增对文件(fd1、fd2)读写操作的简易插桩,
自定义读操作为type:1, 写操作为type:2,则 自定义读操作为type:1, 写操作为type:2,则
...@@ -63,7 +63,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -63,7 +63,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
- TYPE用于设置具体的事件类型,可以在头文件los_trace.h中的enum LOS_TRACE_TYPE中自定义事件类型。定义方法和规则可以参考其他事件类型。 - TYPE用于设置具体的事件类型,可以在头文件los_trace.h中的enum LOS_TRACE_TYPE中自定义事件类型。定义方法和规则可以参考其他事件类型。
- IDENTITY和Params的类型及含义同简易插桩。 - IDENTITY和Params的类型及含义同简易插桩。
示例: 示例:
``` ```
1.在enum LOS_TRACE_MASK中定义事件掩码,即模块级别的事件类型。 1.在enum LOS_TRACE_MASK中定义事件掩码,即模块级别的事件类型。
定义规范为TRACE_#MOD#_FLAG,#MOD#表示模块名。 定义规范为TRACE_#MOD#_FLAG,#MOD#表示模块名。
...@@ -86,9 +86,9 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -86,9 +86,9 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
LOS_TRACE(FS_READ, fp, fd, flag, size); // 读文件的代码桩, LOS_TRACE(FS_READ, fp, fd, flag, size); // 读文件的代码桩,
#TYPE#之后的入参就是上面3中的FS_READ_PARAMS函数的入参 #TYPE#之后的入参就是上面3中的FS_READ_PARAMS函数的入参
``` ```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 预置的Trace事件及参数均可以通过上述方式进行裁剪,参数详见kernel\include\los_trace.h > 预置的Trace事件及参数均可以通过上述方式进行裁剪,参数详见 [kernel\include\los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h)
- Trace Mask事件过滤接口LOS_TraceEventMaskSet(UINT32 mask),其入参mask仅高28位生效(对应LOS_TRACE_MASK中某模块的使能位),仅用于模块的过滤,暂不支持针对某个特定事件的细粒度过滤。例如:LOS_TraceEventMaskSet(0x202),则实际设置生效的mask为0x200(TRACE_QUE_FLAG),QUE模块的所有事件均会被采集。一般建议使用的方法为: LOS_TraceEventMaskSet(TRACE_EVENT_FLAG | TRACE_MUX_FLAG | TRACE_SEM_FLAG | TRACE_QUE_FLAG); - Trace Mask事件过滤接口LOS_TraceEventMaskSet(UINT32 mask),其入参mask仅高28位生效(对应LOS_TRACE_MASK中某模块的使能位),仅用于模块的过滤,暂不支持针对某个特定事件的细粒度过滤。例如:LOS_TraceEventMaskSet(0x202),则实际设置生效的mask为0x200(TRACE_QUE_FLAG),QUE模块的所有事件均会被采集。一般建议使用的方法为: LOS_TraceEventMaskSet(TRACE_EVENT_FLAG | TRACE_MUX_FLAG | TRACE_SEM_FLAG | TRACE_QUE_FLAG);
...@@ -100,8 +100,8 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -100,8 +100,8 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
- 针对中断事件的Trace, 提供中断号过滤,用于解决某些场景下特定中断号频繁触发导致其他事件被覆盖的情况,用户可自定义中断过滤的规则, - 针对中断事件的Trace, 提供中断号过滤,用于解决某些场景下特定中断号频繁触发导致其他事件被覆盖的情况,用户可自定义中断过滤的规则,
示例如下: 示例如下:
``` ```c
BOOL Example_HwiNumFilter(UINT32 hwiNum) BOOL Example_HwiNumFilter(UINT32 hwiNum)
{ {
if ((hwiNum == TIMER_INT) || (hwiNum == DMA_INT)) { if ((hwiNum == TIMER_INT) || (hwiNum == DMA_INT)) {
...@@ -117,7 +117,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -117,7 +117,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
### 用户态 ### 用户态
新增trace字符设备,位于"/dev/trace",通过对设备节点的read、write、ioctl,实现用户态trace的读写和控制: 新增trace字符设备,位于"/dev/trace"通过对设备节点的read、write、ioctl,实现用户态trace的读写和控制:
- read: 用户态读取Trace记录数据 - read: 用户态读取Trace记录数据
...@@ -125,8 +125,8 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -125,8 +125,8 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
- ioctl: 用户态Trace控制操作,包括 - ioctl: 用户态Trace控制操作,包括
``` ```c
#define TRACE_IOC_MAGIC 'T' #define TRACE_IOC_MAGIC 'T'
#define TRACE_START _IO(TRACE_IOC_MAGIC, 1) #define TRACE_START _IO(TRACE_IOC_MAGIC, 1)
#define TRACE_STOP _IO(TRACE_IOC_MAGIC, 2) #define TRACE_STOP _IO(TRACE_IOC_MAGIC, 2)
...@@ -148,7 +148,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -148,7 +148,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
开启Trace调测的典型流程如下: 开启Trace调测的典型流程如下:
1. 配置Trace模块相关宏。 1. 配置Trace模块相关宏。
配置Trace控制宏LOSCFG_KERNEL_TRACE,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel-&gt;Enable Hook Feature-&gt;Enable Trace Feature"中打开: 配置Trace控制宏LOSCFG_KERNEL_TRACE,默认关,在 kernel/liteos_a 目录下执行 make update_config 命令配置 "Kernel-&gt;Enable Hook Feature-&gt;Enable Trace Feature" 中打开:
| 配置项 | menuconfig选项 | 含义 | 设置值 | | 配置项 | menuconfig选项 | 含义 | 设置值 |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
...@@ -156,7 +156,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -156,7 +156,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
| LOSCFG_RECORDER_MODE_OFFLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Offline&nbsp;mode | Trace工作模式为离线模式 | YES/NO | | LOSCFG_RECORDER_MODE_OFFLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Offline&nbsp;mode | Trace工作模式为离线模式 | YES/NO |
| LOSCFG_RECORDER_MODE_ONLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Online&nbsp;mode | Trace工作模式为在线模式 | YES/NO | | LOSCFG_RECORDER_MODE_ONLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Online&nbsp;mode | Trace工作模式为在线模式 | YES/NO |
| LOSCFG_TRACE_CLIENT_INTERACT | Enable&nbsp;Trace&nbsp;Client&nbsp;Visualization&nbsp;and&nbsp;Control | 使能与Trace&nbsp;IDE&nbsp;(dev&nbsp;tools)的交互,包括数据可视化和流程控制 | YES/NO | | LOSCFG_TRACE_CLIENT_INTERACT | Enable&nbsp;Trace&nbsp;Client&nbsp;Visualization&nbsp;and&nbsp;Control | 使能与Trace&nbsp;IDE&nbsp;(dev&nbsp;tools)的交互,包括数据可视化和流程控制 | YES/NO |
| LOSCFG_TRACE_FRAME_CORE_MSG | Enable&nbsp;Record&nbsp;more&nbsp;extended&nbsp;content&nbsp;-<br>&gt;Record&nbsp;cpuid,&nbsp;hardware&nbsp;interrupt<br>&nbsp;status,&nbsp;task&nbsp;lock&nbsp;status | 记录CPUID、中断状态、锁任务状态 | YES/NO | | LOSCFG_TRACE_FRAME_CORE_MSG | Enable&nbsp;Record&nbsp;more&nbsp;extended content<br>->Record&nbsp;cpuid,&nbsp;hardware&nbsp;interrupt status,&nbsp;task&nbsp;lock&nbsp;status | 记录CPUID、中断状态、锁任务状态 | YES/NO |
| LOSCFG_TRACE_FRAME_EVENT_COUNT | Enable&nbsp;Record&nbsp;more&nbsp;extended&nbsp;content<br>&nbsp;-&gt;Record&nbsp;event&nbsp;count,<br>&nbsp;which&nbsp;indicate&nbsp;the&nbsp;sequence&nbsp;of&nbsp;happend&nbsp;events | 记录事件的次序编号 | YES/NO | | LOSCFG_TRACE_FRAME_EVENT_COUNT | Enable&nbsp;Record&nbsp;more&nbsp;extended&nbsp;content<br>&nbsp;-&gt;Record&nbsp;event&nbsp;count,<br>&nbsp;which&nbsp;indicate&nbsp;the&nbsp;sequence&nbsp;of&nbsp;happend&nbsp;events | 记录事件的次序编号 | YES/NO |
| LOSCFG_TRACE_FRAME_MAX_PARAMS | Record&nbsp;max&nbsp;params | 配置记录事件的最大参数个数 | INT | | LOSCFG_TRACE_FRAME_MAX_PARAMS | Record&nbsp;max&nbsp;params | 配置记录事件的最大参数个数 | INT |
| LOSCFG_TRACE_BUFFER_SIZE | Trace&nbsp;record&nbsp;buffer&nbsp;size | 配置Trace的缓冲区大小 | INT | | LOSCFG_TRACE_BUFFER_SIZE | Trace&nbsp;record&nbsp;buffer&nbsp;size | 配置Trace的缓冲区大小 | INT |
...@@ -165,7 +165,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -165,7 +165,7 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
3. (可选)调用LOS_TraceStop停止Trace后,清除缓冲区LOS_TraceReset(系统默认已启动trace)。 3. (可选)调用LOS_TraceStop停止Trace后,清除缓冲区LOS_TraceReset(系统默认已启动trace)。
4. (可选)调用LOS_TraceEventMaskSet设置需要追踪的事件掩码(系统默认的事件掩码仅使能中断与任务事件),事件掩码参见los_trace.h 中的LOS_TRACE_MASK定义。 4. (可选)调用LOS_TraceEventMaskSet设置需要追踪的事件掩码(系统默认的事件掩码仅使能中断与任务事件),事件掩码参见 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的LOS_TRACE_MASK定义。
5. 在需要记录事件的代码起始点调用LOS_TraceStart。 5. 在需要记录事件的代码起始点调用LOS_TraceStart。
...@@ -203,50 +203,52 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以 ...@@ -203,50 +203,52 @@ LiteOS-A内核的Trace模块提供下面几种功能,接口详细信息可以
### 内核态示例代码 ### 内核态示例代码
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。
实例代码如下: 实例代码如下:
``` ```c
#include "los_trace.h" #include "los_trace.h"
UINT32 g_traceTestTaskId; UINT32 g_traceTestTaskId;
VOID Example_Trace(VOID) VOID Example_Trace(VOID)
{ {
UINT32 ret; UINT32 ret;
LOS_TaskDelay(10); LOS_TaskDelay(10);
/* 开启trace */ /* 开启trace */
ret = LOS_TraceStart(); ret = LOS_TraceStart();
if (ret != LOS_OK) { if (ret != LOS_OK) {
dprintf("trace start error\n"); dprintf("trace start error\n");
return; return;
} }
/* 触发任务切换的事件 */ /* 触发任务切换的事件 */
LOS_TaskDelay(1); LOS_TaskDelay(1);
LOS_TaskDelay(1); LOS_TaskDelay(1);
LOS_TaskDelay(1); LOS_TaskDelay(1);
/* 停止trace */ /* 停止trace */
LOS_TraceStop(); LOS_TraceStop();
LOS_TraceRecordDump(FALSE); LOS_TraceRecordDump(FALSE);
} }
UINT32 Example_Trace_test(VOID){ UINT32 Example_Trace_test(VOID)
UINT32 ret; {
TSK_INIT_PARAM_S traceTestTask; UINT32 ret;
/* 创建用于trace测试的任务 */ TSK_INIT_PARAM_S traceTestTask;
memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S)); /* 创建用于trace测试的任务 */
traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace; memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S));
traceTestTask.pcName = "TestTraceTsk"; /* 测试任务名称 */ traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace;
traceTestTask.uwStackSize = 0x800; traceTestTask.pcName = "TestTraceTsk"; /* 测试任务名称 */
traceTestTask.usTaskPrio = 5; traceTestTask.uwStackSize = 0x800; // 0x800: trace test task stacksize
traceTestTask.uwResved = LOS_TASK_STATUS_DETACHED; traceTestTask.usTaskPrio = 5; // 5: trace test task priority
ret = LOS_TaskCreate(&g_traceTestTaskId, &traceTestTask); traceTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
if(ret != LOS_OK){ ret = LOS_TaskCreate(&g_traceTestTaskId, &traceTestTask);
dprintf("TraceTestTask create failed .\n"); if (ret != LOS_OK) {
return LOS_NOK; dprintf("TraceTestTask create failed .\n");
} return LOS_NOK;
/* 系统默认情况下已启动trace, 因此可先关闭trace后清除缓存区后,再重启trace */ }
LOS_TraceStop(); /* 系统默认情况下已启动trace, 因此可先关闭trace后清除缓存区后,再重启trace */
LOS_TraceReset(); LOS_TraceStop();
/* 开启任务模块事件记录 */ LOS_TraceReset();
LOS_TraceEventMaskSet(TRACE_TASK_FLAG); /* 开启任务模块事件记录 */
LOS_TraceEventMaskSet(TRACE_TASK_FLAG);
return LOS_OK; return LOS_OK;
} }
LOS_MODULE_INIT(Example_Trace_test, LOS_INIT_LEVEL_KMOD_EXTENDED); LOS_MODULE_INIT(Example_Trace_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
...@@ -262,7 +264,7 @@ LOS_MODULE_INIT(Example_Trace_test, LOS_INIT_LEVEL_KMOD_EXTENDED); ...@@ -262,7 +264,7 @@ LOS_MODULE_INIT(Example_Trace_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
***TraceInfo begin*** ***TraceInfo begin***
clockFreq = 50000000 clockFreq = 50000000
CurEvtIndex = 7 CurEvtIndex = 7
Index Time(cycles) EventType CurTask Identity params Index Time(cycles) EventType CurTask Identity params
0 0x366d5e88 0x45 0x1 0x0 0x1f 0x4 0x0 0 0x366d5e88 0x45 0x1 0x0 0x1f 0x4 0x0
1 0x366d74ae 0x45 0x0 0x1 0x0 0x8 0x1f 1 0x366d74ae 0x45 0x0 0x1 0x0 0x8 0x1f
2 0x36940da6 0x45 0x1 0xc 0x1f 0x4 0x9 2 0x36940da6 0x45 0x1 0xc 0x1f 0x4 0x9
...@@ -276,13 +278,13 @@ Index Time(cycles) EventType CurTask Identity params ...@@ -276,13 +278,13 @@ Index Time(cycles) EventType CurTask Identity params
输出的事件信息包括:发生时间、事件类型、事件发生在哪个任务中、事件操作的主体对象、事件的其他参数。 输出的事件信息包括:发生时间、事件类型、事件发生在哪个任务中、事件操作的主体对象、事件的其他参数。
- EventType:表示的具体事件可查阅头文件los_trace.h中的enum LOS_TRACE_TYPE。 - EventType:表示的具体事件可查阅头文件 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的enum LOS_TRACE_TYPE。
- CurrentTask:表示当前运行在哪个任务中,值为taskid。 - CurrentTask:表示当前运行在哪个任务中,值为taskid。
- Identity:表示事件操作的主体对象,可查阅头文件los_trace.h中的\#TYPE\#_PARAMS。 - Identity:表示事件操作的主体对象,可查阅头文件 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的\#TYPE\#_PARAMS。
- params:表示的事件参数可查阅头文件los_trace.h中的\#TYPE\#_PARAMS。 - params:表示的事件参数可查阅头文件 [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h) 中的\#TYPE\#_PARAMS。
下面以序号为0的输出项为例,进行说明。 下面以序号为0的输出项为例,进行说明。
...@@ -298,7 +300,7 @@ Index Time(cycles) EventType CurTask Identity params ...@@ -298,7 +300,7 @@ Index Time(cycles) EventType CurTask Identity params
- Identity和params的含义需要查看TASK_SWITCH_PARAMS宏定义: - Identity和params的含义需要查看TASK_SWITCH_PARAMS宏定义:
``` ```c
#define TASK_SWITCH_PARAMS(taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus) \ #define TASK_SWITCH_PARAMS(taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus) \
taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus
``` ```
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、踩内存分析以及backtrace功能等维测手段,可以提高用户态内存相关问题的定位效率。 Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、踩内存分析以及backtrace功能等维测手段,可以提高用户态内存相关问题的定位效率。
采用了对malloc/free接口进行插桩,保存关键节点信息,然后程序在申请和释放内存时进行内存节点完整性校验,最后在程序结束时通过统计节点信息得到内存统计信息并根据统计信息判断内存是否泄漏的设计思想 采用了对malloc/free接口进行插桩,保存关键节点信息,然后程序在申请和释放内存时进行内存节点完整性校验,最后在程序结束时通过统计节点信息得到内存统计信息并根据统计信息判断内存是否泄漏的设计思想
## 运行机制 ## 运行机制
...@@ -28,7 +28,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、 ...@@ -28,7 +28,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、
![zh-cn_image_0000001165890518](figures/zh-cn_image_0000001165890518.png) ![zh-cn_image_0000001165890518](figures/zh-cn_image_0000001165890518.png)
其中,TID表示线程ID;PID表示进程ID;ptr表示申请的内存地址;size表示申请的内存大小;lr[n]表示函数调用栈地址,变量n可以根据具体场景的需要进行配置。 其中,TID表示线程ID;PID表示进程ID;ptr表示申请的内存地址;size表示申请的内存大小;lr[n]表示函数调用栈地址,变量n的大小可以根据具体场景的需要进行配置。
释放内存时,将free等接口的入参指针与node的ptr字段进行匹配,如果相同则删除该内存节点控制块信息。 释放内存时,将free等接口的入参指针与node的ptr字段进行匹配,如果相同则删除该内存节点控制块信息。
...@@ -46,7 +46,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、 ...@@ -46,7 +46,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、
### 内存完整性检查 ### 内存完整性检查
- 使用malloc申请内存(小于等于0x1c000bytes时通过堆分配算法分配) - 使用malloc申请内存(小于等于0x1c000 bytes时通过堆分配算法分配)
用户程序申请堆内存时,在堆内存节点处添加校验值等信息,如果校验值异常,则很有可能是前一块堆内存使用越界导致的(目前无法识别校验值被野指针破坏的场景)。在内存申请、释放时校验内存节点校验值的正确性,若内存节点被破坏,校验失败时则输出tid、pid及当前被踩节点前一块堆内存申请时保存的调用栈信息,通过addr2line工具可获得具体的代码行信息,辅助用户解决问题。 用户程序申请堆内存时,在堆内存节点处添加校验值等信息,如果校验值异常,则很有可能是前一块堆内存使用越界导致的(目前无法识别校验值被野指针破坏的场景)。在内存申请、释放时校验内存节点校验值的正确性,若内存节点被破坏,校验失败时则输出tid、pid及当前被踩节点前一块堆内存申请时保存的调用栈信息,通过addr2line工具可获得具体的代码行信息,辅助用户解决问题。
**图4** node节点头信息添加校验值 **图4** node节点头信息添加校验值
...@@ -59,7 +59,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、 ...@@ -59,7 +59,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、
![zh-cn_image_0000001165890904](figures/zh-cn_image_0000001165890904.png) ![zh-cn_image_0000001165890904](figures/zh-cn_image_0000001165890904.png)
- 使用malloc申请内存(大于0x1c000bytes时通过mmap申请) - 使用malloc申请内存(大于0x1c000 bytes时通过mmap申请)
当malloc通过mmap申请大块内存时,在返回给用户使用的内存区间头和尾分别多申请一个页,一个页PAGE_SIZE当前为0x1000,这两个页分别通过mprotect接口设置权限为PROT_NONE(无可读可写权限),可以有效防止内存越界读写问题:越界读写数据时由于无读写权限而导致用户程序异常,根据异常调用栈信息可找到相应的代码逻辑。 当malloc通过mmap申请大块内存时,在返回给用户使用的内存区间头和尾分别多申请一个页,一个页PAGE_SIZE当前为0x1000,这两个页分别通过mprotect接口设置权限为PROT_NONE(无可读可写权限),可以有效防止内存越界读写问题:越界读写数据时由于无读写权限而导致用户程序异常,根据异常调用栈信息可找到相应的代码逻辑。
**图6** malloc通过mmap机制申请内存的内存布局 **图6** malloc通过mmap机制申请内存的内存布局
...@@ -119,7 +119,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、 ...@@ -119,7 +119,7 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、
代码功能:显式调用调测模块的相关接口对用户代码进行内存校验。 代码功能:显式调用调测模块的相关接口对用户代码进行内存校验。
``` ```c
#include <pthread.h> #include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
...@@ -127,7 +127,8 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、 ...@@ -127,7 +127,8 @@ Debug版本的musl-libc库为用户提供内存泄漏检测、堆内存统计、
#define MALLOC_LEAK_SIZE 0x300 #define MALLOC_LEAK_SIZE 0x300
void func(void) { void func(void)
{
char *ptr = malloc(MALLOC_LEAK_SIZE); char *ptr = malloc(MALLOC_LEAK_SIZE);
memset(ptr, '3', MALLOC_LEAK_SIZE); memset(ptr, '3', MALLOC_LEAK_SIZE);
} }
...@@ -158,15 +159,15 @@ $ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp ...@@ -158,15 +159,15 @@ $ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 本编译示例基于将编译器的路径写入环境变量中,即.bashrc文件中。 > - 本编译示例基于将编译器的路径写入环境变量中,即.bashrc文件中。
> >
> - 编译用户程序及所需的lib库时,需要添加编译选项-funwind-tables,-rdynamic,-g,用于栈回溯。 > - 编译用户程序及所需的lib库时,需要添加编译选项-funwind-tables,-rdynamic,-g,用于栈回溯。
> >
> - -mfloat-abi=softfp,-mcpu=cortex-a7,-mfpu=neon-vfpv4编译选项用于指定具体的芯片架构、浮点数计算优化、fpu,与具体的libc库使用的编译选项保持一致,否则链接时可能出现找不到libc库文件。 > - -mfloat-abi=softfp,-mcpu=cortex-a7,-mfpu=neon-vfpv4编译选项用于指定具体的芯片架构、浮点数计算优化、fpu,与具体的libc库使用的编译选项保持一致,否则链接时可能出现找不到libc库文件。
> >
> - -target arm-liteos用于指定编译器相关库文件路径。 > - -target arm-liteos用于指定编译器相关库文件路径。
> >
> - --sysroot=/home/&lt;user-name&gt;/directory/out/hispark_taurus/ipcamera_hispark_taurus/sysroot用于指定编译器库文件搜索根目录,假设OpenHarmony工程代码存放路径为/home/&lt;user-name&gt;/directory。其中out/hispark_taurus/ipcamera_hispark_taurus路径为在编译时,hb set命令指定的具体产品,本示例选择的是ipcamera_hispark_taurus产品。 > - --sysroot=/home/&lt;user-name&gt;/directory/out/hispark_taurus/ipcamera_hispark_taurus/sysroot用于指定编译器库文件搜索根目录,假设OpenHarmony工程代码存放路径为/home/&lt;user-name&gt;/directory。其中out/hispark_taurus/ipcamera_hispark_taurus路径为在编译时,hb set命令指定的具体产品,本示例选择的是ipcamera_hispark_taurus产品。
> >
> - $(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)用于指定相应的unwind库的路径。 > - $(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)用于指定相应的unwind库的路径。
...@@ -175,7 +176,7 @@ $ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp ...@@ -175,7 +176,7 @@ $ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp
``` ```
OHOS # ./mem_check OHOS # ./mem_check
OHOS # OHOS #
==PID:4== Heap memory statistics(bytes): // 堆内存统计信息 ==PID:4== Heap memory statistics(bytes): // 堆内存统计信息
[Check point]: // check点调用栈 [Check point]: // check点调用栈
#00: <main+0x38>[0x86c] -> mem_check #00: <main+0x38>[0x86c] -> mem_check
...@@ -293,14 +294,15 @@ kill -37 <pid> # 检查堆内存头节点是否完整 ...@@ -293,14 +294,15 @@ kill -37 <pid> # 检查堆内存头节点是否完整
代码功能:构造内存问题利用命令行方式进行内存调测。 代码功能:构造内存问题利用命令行方式进行内存调测。
``` ```c
#include <pthread.h> #include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#define MALLOC_LEAK_SIZE 0x300 #define MALLOC_LEAK_SIZE 0x300
void func(void) { void func(void)
{
char *ptr = malloc(MALLOC_LEAK_SIZE); char *ptr = malloc(MALLOC_LEAK_SIZE);
memset(ptr, '3', MALLOC_LEAK_SIZE); memset(ptr, '3', MALLOC_LEAK_SIZE);
} }
...@@ -325,9 +327,9 @@ int main() ...@@ -325,9 +327,9 @@ int main()
``` ```
OHOS # ./mem_check --mwatch // 利用task命令可以查到mem_check进程的pid为4 OHOS # ./mem_check --mwatch // 利用task命令可以查到mem_check进程的pid为4
OHOS # OHOS #
OHOS # kill -35 4 // 查看堆内存统计信息 OHOS # kill -35 4 // 查看堆内存统计信息
OHOS # OHOS #
==PID:4== Heap memory statistics(bytes): ==PID:4== Heap memory statistics(bytes):
[Check point]: [Check point]:
#00: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so #00: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so
...@@ -337,7 +339,7 @@ OHOS # ...@@ -337,7 +339,7 @@ OHOS #
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s) ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
OHOS # kill -36 4 // 检查是否存在堆内存泄漏 OHOS # kill -36 4 // 检查是否存在堆内存泄漏
OHOS # OHOS #
==PID:4== Detected memory leak(s): ==PID:4== Detected memory leak(s):
[Check point]: [Check point]:
#00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so #00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
...@@ -355,7 +357,7 @@ OHOS # ...@@ -355,7 +357,7 @@ OHOS #
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s). ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
OHOS # kill -37 4 // 检查堆内存头节点的完整性 OHOS # kill -37 4 // 检查堆内存头节点的完整性
OHOS # OHOS #
Check heap integrity ok! Check heap integrity ok!
``` ```
...@@ -391,109 +393,109 @@ Now using addr2line ... ...@@ -391,109 +393,109 @@ Now using addr2line ...
##### 使用mrecord参数命令 ##### 使用mrecord参数命令
1. 执行用户程序并指定记录内存调测信息的文件路径 1. 执行用户程序并指定记录内存调测信息的文件路径
``` ```
OHOS # ./mem_check --mrecord /storage/check.txt OHOS # ./mem_check --mrecord /storage/check.txt
``` ```
2. 利用kill -35 &lt;pid&gt;统计内存信息,该信息将会输出到文件中,使用cat命令查看 2. 利用kill -35 &lt;pid&gt;统计内存信息,该信息将会输出到文件中,使用cat命令查看
``` ```
OHOS # kill -35 4 OHOS # kill -35 4
OHOS # Memory statistics information saved in /storage/pid(4)_check.txt OHOS # Memory statistics information saved in /storage/pid(4)_check.txt
OHOS # cat /storage/pid(4)_check.txt OHOS # cat /storage/pid(4)_check.txt
==PID:4== Heap memory statistics(bytes): ==PID:4== Heap memory statistics(bytes):
[Check point]: [Check point]:
#00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID: 18, Used: 0x640] [TID: 18, Used: 0x640]
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s) ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
``` ```
3. 利用kill -36 &lt;pid&gt;校验内存完整性,该信息将会输出到文件中,使用cat命令查看 3. 利用kill -36 &lt;pid&gt;校验内存完整性,该信息将会输出到文件中,使用cat命令查看
``` ```
OHOS # kill -36 4 OHOS # kill -36 4
OHOS # Leak check information saved in /storage/pid(4)_check.txt OHOS # Leak check information saved in /storage/pid(4)_check.txt
OHOS # cat /storage/pid(4)_check.txt OHOS # cat /storage/pid(4)_check.txt
==PID:4== Heap memory statistics(bytes): ==PID:4== Heap memory statistics(bytes):
[Check point]: [Check point]:
#00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID: 18, Used: 0x640] [TID: 18, Used: 0x640]
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s) ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
==PID:4== Detected memory leak(s): ==PID:4== Detected memory leak(s):
[Check point]: [Check point]:
#00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
#01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so #01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from: [TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <main+0x14>[0x724] -> mem_check #00: <main+0x14>[0x724] -> mem_check
#01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from: [TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <func+0x14>[0x6ec] -> mem_check #00: <func+0x14>[0x6ec] -> mem_check
#01: <main+0x30>[0x740] -> mem_check #01: <main+0x30>[0x740] -> mem_check
#02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s). ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
``` ```
4. 利用kill -9 &lt;pid&gt;杀掉当前进程,进程退出后会默认校验内存完整性,该信息将会输出到文件中,使用cat命令查看 4. 利用kill -9 &lt;pid&gt;杀掉当前进程,进程退出后会默认校验内存完整性,该信息将会输出到文件中,使用cat命令查看
``` ```
OHOS # kill -9 4 OHOS # kill -9 4
OHOS # Leak check information saved in /storage/pid(4)_check.txt OHOS # Leak check information saved in /storage/pid(4)_check.txt
Check heap integrity ok! Check heap integrity ok!
OHOS # cat /storage/pid(4)_check.txt OHOS # cat /storage/pid(4)_check.txt
OHOS # OHOS #
==PID:4== Heap memory statistics(bytes): ==PID:4== Heap memory statistics(bytes):
[Check point]: [Check point]:
#00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so #00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID: 18, Used: 0x640] [TID: 18, Used: 0x640]
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s) ==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
==PID:4== Detected memory leak(s): ==PID:4== Detected memory leak(s):
[Check point]: [Check point]:
#00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
#01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so #01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from: [TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <main+0x14>[0x724] -> mem_check #00: <main+0x14>[0x724] -> mem_check
#01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from: [TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <func+0x14>[0x6ec] -> mem_check #00: <func+0x14>[0x6ec] -> mem_check
#01: <main+0x30>[0x740] -> mem_check #01: <main+0x30>[0x740] -> mem_check
#02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s). ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
==PID:4== Detected memory leak(s): ==PID:4== Detected memory leak(s):
[Check point]: [Check point]:
#00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so #00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
#01: <exit+0x28>[0x11b2c] -> /lib/libc.so #01: <exit+0x28>[0x11b2c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from: [TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <main+0x14>[0x724] -> mem_check #00: <main+0x14>[0x724] -> mem_check
#01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so #01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from: [TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <func+0x14>[0x6ec] -> mem_check #00: <func+0x14>[0x6ec] -> mem_check
#01: <main+0x30>[0x740] -> mem_check #01: <main+0x30>[0x740] -> mem_check
#02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so #02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s). ==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
``` ```
...@@ -504,7 +506,7 @@ Now using addr2line ... ...@@ -504,7 +506,7 @@ Now using addr2line ...
### UAF(Use after free) ### UAF(Use after free)
- 申请小块内存(不大于0x1c000字节 - 申请小块内存(不大于0x1c000 bytes
free之后: free之后:
读操作:读取free之后的内存大概率是魔术数字(0xFEFEFEFE) 读操作:读取free之后的内存大概率是魔术数字(0xFEFEFEFE)
...@@ -515,7 +517,7 @@ Now using addr2line ... ...@@ -515,7 +517,7 @@ Now using addr2line ...
写操作:无法校验。 写操作:无法校验。
- 申请大块内存(大于0x1c000) - 申请大块内存(大于0x1c000 bytes
堆内存由malloc通过调用mmap接口申请,free之后若仍访问该内存,则用户程序异常(该内存区间已被unmap)。 堆内存由malloc通过调用mmap接口申请,free之后若仍访问该内存,则用户程序异常(该内存区间已被unmap)。
...@@ -526,22 +528,23 @@ Double free时,用户程序将会异常退出。 ...@@ -526,22 +528,23 @@ Double free时,用户程序将会异常退出。
### 堆内存节点被踩 ### 堆内存节点被踩
- 申请小块内存(不大于0x1c000) - 申请小块内存(不大于0x1c000 bytes)
堆内存节点被踩时,用户程序将会异常退出,并输出破坏被踩节点的可能的堆内存申请调用栈,对于野指针踩内存情况无法校验出来。例如用户程序mem_check中存在堆内存越界踩的情况,利用命令行方式可以获得踩内存的可能的具体位置。 堆内存节点被踩时,用户程序将会异常退出,并输出破坏被踩节点的可能的堆内存申请调用栈,对于野指针踩内存情况无法校验出来。例如用户程序mem_check中存在堆内存越界踩的情况,利用命令行方式可以获得踩内存的可能的具体位置。
``` ```
OHOS # ./mem_check --mwatch OHOS # ./mem_check --mwatch
OHOS # OHOS #
==PID:6== Memory integrity information: ==PID:6== Memory integrity information:
[TID:28 allocated addr: 0x272e1ea0, size: 0x120] The possible attacker was allocated from: [TID:28 allocated addr: 0x272e1ea0, size: 0x120] The possible attacker was allocated from:
#00: <malloc+0x808>[0x640e8] -> /lib/libc.so #00: <malloc+0x808>[0x640e8] -> /lib/libc.so
#01: <threadFunc1+0x7c>[0x21d0] -> mem_check #01: <threadFunc1+0x7c>[0x21d0] -> mem_check
``` ```
可以通过调用栈解析脚本对调用栈信息进行解析。 可以通过调用栈解析脚本对调用栈信息进行解析。
- 申请大块内存(大于0x1c000) - 申请大块内存(大于0x1c000 bytes
堆内存由malloc通过mmap接口申请,申请得到的堆内存块前后各置一个size为PAGE_SIZE大小的区间,设置无读写权限,读写操作会触发用户程序异常。 堆内存由malloc通过mmap接口申请,申请得到的堆内存块前后各置一个size为PAGE_SIZE大小的区间,设置无读写权限,读写操作会触发用户程序异常。
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## 基本概念 ## 基本概念
LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double Free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。 LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能: OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能:
...@@ -20,7 +20,7 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能: ...@@ -20,7 +20,7 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能:
LMS使用影子内存映射标记系统内存的状态,一共可标记为三个状态:可读写,不可读写,已释放。影子内存存放在内存池的尾部。 LMS使用影子内存映射标记系统内存的状态,一共可标记为三个状态:可读写,不可读写,已释放。影子内存存放在内存池的尾部。
- 内存从堆上申请后,会将数据区的影子内存设置为“可读写”状态,并将头点区的影子内存设置为“不可读写”状态。 - 内存从堆上申请后,会将数据区的影子内存设置为“可读写”状态,并将头点区的影子内存设置为“不可读写”状态。
- 内存在堆上被释放时,会将被释放内存的影子内存设置为“已释放”状态。 - 内存在堆上被释放时,会将被释放内存的影子内存设置为“已释放”状态。
...@@ -38,12 +38,12 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信 ...@@ -38,12 +38,12 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信
**表1** LMS模块接口说明 **表1** LMS模块接口说明
| 功能分类 | 接口名 | 描述 | | 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| 添加指定内存池被检测 | LOS_LmsCheckPoolAdd | 将指定内存池的地址范围添加到LMS的内存检测链表上,当访问的地址在链表范围内时,LMS才进行合法性校验;且LOS_MemInit接口会调用该接口,默认将初始化的内存池挂入到检测链表中。 | | 添加指定内存池被检测 | LOS_LmsCheckPoolAdd | 将指定内存池的地址范围添加到LMS的内存检测链表上,当访问的地址在链表范围内时,LMS才进行合法性校验;且LOS_MemInit接口会调用该接口,默认将初始化的内存池挂入到检测链表中。 |
| 删除指定内存池不被检测 | LOS_LmsCheckPoolDel | 不检测指定内存池地址范围内的合法性校验。 | | 删除指定内存池不被检测 | LOS_LmsCheckPoolDel | 不检测指定内存池地址范围内的合法性校验。 |
| 使能指定内存段锁保护 | LOS_LmsAddrProtect | 为某段内存地址上锁,设置为不可读写,一旦访问则报错。 | | 使能指定内存段锁保护 | LOS_LmsAddrProtect | 为某段内存地址上锁,设置为不可读写,一旦访问则报错。 |
| 去能指定内存段锁保护 | LOS_LmsAddrDisableProtect | 为某段内存地址解锁,设置为可读写。 | | 去能指定内存段锁保护 | LOS_LmsAddrDisableProtect | 为某段内存地址解锁,设置为可读写。 |
### 用户态 ### 用户态
...@@ -61,19 +61,19 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信 ...@@ -61,19 +61,19 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信
1. 配置LMS模块相关宏。 1. 配置LMS模块相关宏。
配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel-&gt;Enable Lite Memory Sanitizer"中打开YES: 配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel-&gt;Enable Lite Memory Sanitizer"中打开YES:
| 宏 | menuconfig选项 | 含义 | 取值 | | 宏 | menuconfig选项 | 含义 | 取值 |
| -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_LMS | Enable&nbsp;Lms&nbsp;Feature | Lms模块的裁剪开关 | YES/NO | | LOSCFG_KERNEL_LMS | Enable&nbsp;Lms&nbsp;Feature | Lms模块的裁剪开关 | YES/NO |
| LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms&nbsp;check&nbsp;pool&nbsp;max&nbsp;num | LMS支持的检测内存池最大个数 | INT | | LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms&nbsp;check&nbsp;pool&nbsp;max&nbsp;num | LMS支持的检测内存池最大个数 | INT |
| LOSCFG_LMS_LOAD_CHECK | Enable&nbsp;lms&nbsp;read&nbsp;check | LMS内存读检测的裁剪开关 | YES/NO | | LOSCFG_LMS_LOAD_CHECK | Enable&nbsp;lms&nbsp;read&nbsp;check | LMS内存读检测的裁剪开关 | YES/NO |
| LOSCFG_LMS_STORE_CHECK | Enable&nbsp;lms&nbsp;write&nbsp;check | LMS内存写检测的裁剪开关 | YES/NO | | LOSCFG_LMS_STORE_CHECK | Enable&nbsp;lms&nbsp;write&nbsp;check | LMS内存写检测的裁剪开关 | YES/NO |
| LOSCFG_LMS_CHECK_STRICT | Enable&nbsp;lms&nbsp;strict&nbsp;check,&nbsp;byte-by-byte | LMS内存逐字节严格检测的裁剪开关 | YES/NO | | LOSCFG_LMS_CHECK_STRICT | Enable&nbsp;lms&nbsp;strict&nbsp;check,&nbsp;byte-by-byte | LMS内存逐字节严格检测的裁剪开关 | YES/NO |
2. 在被检测模块的编译脚本中,修改编译选项。 2. 在被检测模块的编译脚本中,修改编译选项。
增加LMS检测编译选项-fsanitize=kernel-address。为避免编译器优化,增加-O0编译选项。 增加LMS检测编译选项-fsanitize=kernel-address。为避免编译器优化,增加-O0编译选项。
gcc与clang编译选项存在差异,参照如下示例: gcc与clang编译选项存在差异,参照如下示例:
``` ```
if ("$ohos_build_compiler_specified" == "gcc") { if ("$ohos_build_compiler_specified" == "gcc") {
cflags_c = [ cflags_c = [
...@@ -105,14 +105,15 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信 ...@@ -105,14 +105,15 @@ OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信
2. 构造内存溢出错误和释放后使用错误。 2. 构造内存溢出错误和释放后使用错误。
3. 添加-fsanitize=kernel-address后编译执行,观察输出结果 3. 添加-fsanitize=kernel-address后编译执行,观察输出结果
#### 内核态示例代码 #### 内核态示例代码
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。
实例代码如下: 实例代码如下:
``` ```c
#define PAGE_SIZE (0x1000U) #define PAGE_SIZE (0x1000U)
#define INDEX_MAX 20 #define INDEX_MAX 20
UINT32 g_lmsTestTaskId; UINT32 g_lmsTestTaskId;
...@@ -138,31 +139,32 @@ static VOID LmsTestUseAfterFree(VOID) ...@@ -138,31 +139,32 @@ static VOID LmsTestUseAfterFree(VOID)
PRINTK("\n######%s start ######\n", __FUNCTION__); PRINTK("\n######%s start ######\n", __FUNCTION__);
UINT32 i; UINT32 i;
CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX); CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX);
LOS_MemFree(g_testLmsPool, str); (VOID)LOS_MemFree(g_testLmsPool, str);
PRINTK("str[%2d]=0x%2x ", 0, str[0]); /* trigger use after free at str[0] */ PRINTK("str[%2d]=0x%2x ", 0, str[0]); /* trigger use after free at str[0] */
PRINTK("\n######%s stop ######\n", __FUNCTION__); PRINTK("\n######%s stop ######\n", __FUNCTION__);
} }
VOID LmsTestCaseTask(VOID) VOID LmsTestCaseTask(VOID)
{ {
testPoolInit(); testPoolInit();
LmsTestOsmallocOverflow(); LmsTestOsmallocOverflow();
LmsTestUseAfterFree(); LmsTestUseAfterFree();
} }
UINT32 Example_Lms_test(VOID){ UINT32 Example_Lms_test(VOID)
UINT32 ret; {
TSK_INIT_PARAM_S lmsTestTask; UINT32 ret;
/* 创建用于lms测试的任务 */ TSK_INIT_PARAM_S lmsTestTask;
memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S)); /* 创建用于lms测试的任务 */
memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S));
lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask; lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask;
lmsTestTask.pcName = "TestLmsTsk"; /* 测试任务名称 */ lmsTestTask.pcName = "TestLmsTsk"; /* 测试任务名称 */
lmsTestTask.uwStackSize = 0x800; lmsTestTask.uwStackSize = 0x800; // 0x800: lms test task stack size
lmsTestTask.usTaskPrio = 5; lmsTestTask.usTaskPrio = 5; // 5: lms test task priority
lmsTestTask.uwResved = LOS_TASK_STATUS_DETACHED; lmsTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
ret = LOS_TaskCreate(&g_lmsTestTaskId, &lmsTestTask); ret = LOS_TaskCreate(&g_lmsTestTaskId, &lmsTestTask);
if(ret != LOS_OK){ if (ret != LOS_OK) {
PRINT_ERR("LmsTestTask create failed .\n"); PRINT_ERR("LmsTestTask create failed .\n");
return LOS_NOK; return LOS_NOK;
} }
return LOS_OK; return LOS_OK;
} }
LOS_MODULE_INIT(Example_Lms_test, LOS_INIT_LEVEL_KMOD_EXTENDED); LOS_MODULE_INIT(Example_Lms_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
...@@ -172,7 +174,7 @@ LOS_MODULE_INIT(Example_Lms_test, LOS_INIT_LEVEL_KMOD_EXTENDED); ...@@ -172,7 +174,7 @@ LOS_MODULE_INIT(Example_Lms_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
#### 内核态结果验证 #### 内核态结果验证
输出结果如下: 输出结果如下:
``` ```
######LmsTestOsmallocOverflow start ###### ######LmsTestOsmallocOverflow start ######
[ERR][KProcess:LmsTestCaseTask]* Kernel Address Sanitizer Error Detected Start * [ERR][KProcess:LmsTestCaseTask]* Kernel Address Sanitizer Error Detected Start *
...@@ -257,9 +259,9 @@ str[ 0]=0x 0 ...@@ -257,9 +259,9 @@ str[ 0]=0x 0
### 用户态开发流程 ### 用户态开发流程
在待检测的app编译脚本中,添加如下参数即可, 完整示例可参见/kernel/liteos_a/apps/lms/BUILD.gn。 在待检测的app编译脚本中,添加如下参数即可, 完整示例可参见 [/kernel/liteos_a/apps/lms/BUILD.gn](https://gitee.com/openharmony/kernel_liteos_a/blob/master/apps/lms/BUILD.gn)
``` ```
if ("$ohos_build_compiler_specified" == "gcc") { if ("$ohos_build_compiler_specified" == "gcc") {
cflags_c = [ cflags_c = [
...@@ -308,14 +310,14 @@ if ("$ohos_build_compiler_specified" == "gcc") { ...@@ -308,14 +310,14 @@ if ("$ohos_build_compiler_specified" == "gcc") {
1. 构造内存溢出错误和释放后使用错误。 1. 构造内存溢出错误和释放后使用错误。
2. 添加对应编译选项后,重新编译执行 2. 添加对应编译选项后,重新编译执行
#### 用户态示例代码 #### 用户态示例代码
实例代码如下: 实例代码如下:
``` ```c
static void BufWriteTest(void *buf, int start, int end) static void BufWriteTest(void *buf, int start, int end)
{ {
for (int i = start; i <= end; i++) { for (int i = start; i <= end; i++) {
...@@ -332,7 +334,7 @@ static void BufReadTest(void *buf, int start, int end) ...@@ -332,7 +334,7 @@ static void BufReadTest(void *buf, int start, int end)
static void LmsMallocTest(void) static void LmsMallocTest(void)
{ {
printf("\n-------- LmsMallocTest Start --------\n"); printf("\n-------- LmsMallocTest Start --------\n");
char *buf = (char *)malloc(16); char *buf = (char *)malloc(16); // 16: buffer size for test
BufReadTest(buf, -1, 16); BufReadTest(buf, -1, 16);
free(buf); free(buf);
printf("\n-------- LmsMallocTest End --------\n"); printf("\n-------- LmsMallocTest End --------\n");
...@@ -340,7 +342,7 @@ static void LmsMallocTest(void) ...@@ -340,7 +342,7 @@ static void LmsMallocTest(void)
static void LmsFreeTest(void) static void LmsFreeTest(void)
{ {
printf("\n-------- LmsFreeTest Start --------\n"); printf("\n-------- LmsFreeTest Start --------\n");
char *buf = (char *)malloc(16); char *buf = (char *)malloc(16); // 16: buffer size for test
free(buf); free(buf);
BufReadTest(buf, 1, 1); BufReadTest(buf, 1, 1);
free(buf); free(buf);
...@@ -349,7 +351,7 @@ static void LmsFreeTest(void) ...@@ -349,7 +351,7 @@ static void LmsFreeTest(void)
int main(int argc, char * const * argv) int main(int argc, char * const * argv)
{ {
printf("\n############### Lms Test start ###############\n"); printf("\n############### Lms Test start ###############\n");
char *tmp = (char *)malloc(5000); char *tmp = (char *)malloc(5000); // 5000: temp buffer size
LmsMallocTest(); LmsMallocTest();
LmsFreeTest(); LmsFreeTest();
printf("\n############### Lms Test End ###############\n"); printf("\n############### Lms Test End ###############\n");
...@@ -360,7 +362,7 @@ int main(int argc, char * const * argv) ...@@ -360,7 +362,7 @@ int main(int argc, char * const * argv)
#### 用户态结果验证 #### 用户态结果验证
输出结果如下: 输出结果如下:
``` ```
* Lite Memory Sanitizer Error Detected * * Lite Memory Sanitizer Error Detected *
Heap buffer overflow error detected! Heap buffer overflow error detected!
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## 内核启动流程 ## 内核启动流程
内核启动流程包含汇编启动阶段和C语言启动阶段2部分,如图1所示。汇编启动阶段完成CPU初始设置,关闭dcache/icache,使能FPU及neon,设置MMU建立虚实地址映射,设置系统栈,清理bss段,调用C语言main函数等。C语言启动阶段包含OsMain函数及开始调度等,其中如上图所示,OsMain函数用于内核基础初始化和架构、板级初始化等,其整体由内核启动框架主导初始化流程,图中右边区域为启动框架中可接受外部模块注册启动的阶段,各个阶段的说明如下表1所示。 内核启动流程包含汇编启动阶段和C语言启动阶段2部分,如图1所示。汇编启动阶段完成CPU初始设置,关闭dcache/icache,使能FPU及neon,设置MMU建立虚实地址映射,设置系统栈,清理bss段,调用C语言main函数等。C语言启动阶段包含OsMain函数及开始调度等,其中如图1所示,OsMain函数用于内核基础初始化和架构、板级初始化等,其整体由内核启动框架主导初始化流程,图中右边区域为启动框架中可接受外部模块注册启动的阶段,各个阶段的说明如下表1所示。
**图1** 内核启动流程图 **图1** 内核启动流程图
...@@ -12,59 +12,57 @@ ...@@ -12,59 +12,57 @@
**表1** 启动框架层级 **表1** 启动框架层级
| 层级 | 说明 | | 层级 | 说明 |
| -------- | -------- | | -------- | -------- |
| LOS_INIT_LEVEL_EARLIEST | 最早期初始化<br/>说明:不依赖架构,单板以及后续模块会对其有依赖的纯软件模块初始化<br/>例如:Trace模块 | | LOS_INIT_LEVEL_EARLIEST | 最早期初始化<br/>说明:不依赖架构,单板以及后续模块会对其有依赖的纯软件模块初始化<br/>例如:Trace模块 |
| LOS_INIT_LEVEL_ARCH_EARLY | 架构早期初始化<br/>说明:架构相关,后续模块会对其有依赖的模块初始化,如启动过程中非必需的功能,建议放到LOS_INIT_LEVEL_ARCH层 | | LOS_INIT_LEVEL_ARCH_EARLY | 架构早期初始化<br/>说明:架构相关,后续模块会对其有依赖的模块初始化,如启动过程中非必需的功能,建议放到LOS_INIT_LEVEL_ARCH层 |
| LOS_INIT_LEVEL_PLATFORM_EARLY | 平台早期初始化<br/>说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化,如启动过程中必需的功能,建议放到LOS_INIT_LEVEL_PLATFORM层<br/>例如:uart模块 | | LOS_INIT_LEVEL_PLATFORM_EARLY | 平台早期初始化<br/>说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化,如启动过程中必需的功能,建议放到LOS_INIT_LEVEL_PLATFORM层<br/>例如:uart模块 |
| LOS_INIT_LEVEL_KMOD_PREVM | 内存初始化前的内核模块初始化<br/>说明:在内存初始化之前需要使能的模块初始化 | | LOS_INIT_LEVEL_KMOD_PREVM | 内存初始化前的内核模块初始化<br/>说明:在内存初始化之前需要使能的模块初始化 |
| LOS_INIT_LEVEL_VM_COMPLETE | 基础内存就绪后的初始化<br/>说明:此时内存初始化完毕,需要进行使能且不依赖进程间通讯机制与系统进程的模块初始化<br/>例如:共享内存功能 | | LOS_INIT_LEVEL_VM_COMPLETE | 基础内存就绪后的初始化<br/>说明:此时内存初始化完毕,需要进行使能且不依赖进程间通讯机制与系统进程的模块初始化<br/>例如:共享内存功能 |
| LOS_INIT_LEVEL_ARCH | 架构后期初始化<br/>说明:架构拓展功能相关,后续模块会对其有依赖的模块初始化 | | LOS_INIT_LEVEL_ARCH | 架构后期初始化<br/>说明:架构拓展功能相关,后续模块会对其有依赖的模块初始化 |
| LOS_INIT_LEVEL_PLATFORM | 平台后期初始化<br/>说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化<br/>例如:驱动内核抽象层初始化(mmc、mtd) | | LOS_INIT_LEVEL_PLATFORM | 平台后期初始化<br/>说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化<br/>例如:驱动内核抽象层初始化(mmc、mtd) |
| LOS_INIT_LEVEL_KMOD_BASIC | 内核基础模块初始化<br/>说明:内核可拆卸的基础模块初始化<br/>例如:VFS初始化 | | LOS_INIT_LEVEL_KMOD_BASIC | 内核基础模块初始化<br/>说明:内核可拆卸的基础模块初始化<br/>例如:VFS初始化 |
| LOS_INIT_LEVEL_KMOD_EXTENDED | 内核扩展模块初始化<br/>说明:内核可拆卸的扩展模块初始化<br/>例如:系统调用初始化、ProcFS初始化、Futex初始化、HiLog初始化、HiEvent初始化、LiteIPC初始化 | | LOS_INIT_LEVEL_KMOD_EXTENDED | 内核扩展模块初始化<br/>说明:内核可拆卸的扩展模块初始化<br/>例如:系统调用初始化、ProcFS初始化、Futex初始化、HiLog初始化、HiEvent初始化、LiteIPC初始化 |
| LOS_INIT_LEVEL_KMOD_TASK | 内核任务创建<br/>说明:进行内核任务的创建(内核任务,软件定时器任务)<br/>例如:资源回收系统常驻任务的创建、SystemInit任务创建、CPU占用率统计任务创建 | | LOS_INIT_LEVEL_KMOD_TASK | 内核任务创建<br/>说明:进行内核任务的创建(内核任务,软件定时器任务)<br/>例如:资源回收系统常驻任务的创建、SystemInit任务创建、CPU占用率统计任务创建 |
| LOS_INIT_LEVEL_FINISH | 内核初始化完成 |
## 编程样例 ## 编程样例
**实例描述** **实例描述**
新增一个内核模块,需要在内核初始化时进行该模块的初始化,则通过内核启动框架将该模块的初始化函数注册进内核启动流程中。 新增一个内核模块,需要在内核初始化时进行该模块的初始化,则通过内核启动框架将该模块的初始化函数注册进内核启动流程中。
为方便学习,本演示代码直接在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证即可。
**示例代码** **示例代码**
```c
```
/* 内核启动框架头文件 */ /* 内核启动框架头文件 */
#include "los_init.h" #include "los_init.h"
......
/* 新增模块的初始化函数 */ /* 新增模块的初始化函数 */
unsigned int OsSampleModInit(void) unsigned int OsSampleModInit(void)
{ {
PRINTK("OsSampleModInit SUCCESS!\n"); PRINTK("OsSampleModInit SUCCESS!\n");
......
} }
......
/* 在启动框架的目标层级中注册新增模块 */ /* 在启动框架的目标层级中注册新增模块 */
LOS_MODULE_INIT(OsSampleModInit, LOS_INIT_LEVEL_KMOD_EXTENDED); LOS_MODULE_INIT(OsSampleModInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
``` ```
**结果验证** **结果验证**
``` ```
main core booting up... main core booting up...
/* 根据实际运行环境,过程打印会有差异 */
......
/* 打印测试代码新增模块初始化函数 */
OsSampleModInit SUCCESS! OsSampleModInit SUCCESS!
releasing 1 secondary cores
cpu 1 entering scheduler
cpu 0 entering scheduler
``` ```
...@@ -73,5 +71,5 @@ cpu 0 entering scheduler ...@@ -73,5 +71,5 @@ cpu 0 entering scheduler
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 启动框架中同一层级内的注册模块不能有依赖关系,建议新增模块按照上述启动阶段进行模块初始化的拆分,按需注册启动。 > 启动框架中同一层级内的注册模块不能有依赖关系,建议新增模块按照上述启动阶段进行模块初始化的拆分,按需注册启动。
> >
> 可通过查看系统编译生成文件OHOS_Image.map中.rodata.init.kernel.\*段内的符号表来了解当前已注册进内核启动框架中的各个模块初始化入口,以及检查新注册的模块初始化入口是否生效。 > 可通过查看系统编译生成文件OHOS_Image.map中.rodata.init.kernel.\*段内的符号表来了解当前已注册进内核启动框架中的各个模块初始化入口,以及检查新注册的模块初始化入口是否生效。
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
使用链接脚本将如下init启动代码放置到系统镜像指定位置。 使用链接脚本将如下init启动代码放置到系统镜像指定位置。
``` ```c
#define LITE_USER_SEC_ENTRY __attribute__((section(".user.entry"))) #define LITE_USER_SEC_ENTRY __attribute__((section(".user.entry")))
LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args) LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args)
{ {
...@@ -27,6 +27,8 @@ LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args) ...@@ -27,6 +27,8 @@ LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args)
} }
``` ```
> 上述启动代码已在 kernel/liteos_a/kernel/user/src/los_user_init.c 中,g_initPath 根据启动设置的不同,其值为 /dev/shm/init 或 /bin/init。
系统启动阶段,OsUserInitProcess启动init进程。具体过程如下: 系统启动阶段,OsUserInitProcess启动init进程。具体过程如下:
1. 由内核OsLoadUserInit加载上述代码。 1. 由内核OsLoadUserInit加载上述代码。
...@@ -48,7 +50,7 @@ LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args) ...@@ -48,7 +50,7 @@ LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args)
用户态程序启动有如下常见方式: 用户态程序启动有如下常见方式:
- shell命令启动进程。 - shell命令启动进程。
``` ```
OHOS $ exec helloworld OHOS $ exec helloworld
OHOS $ ./helloworld OHOS $ ./helloworld
......
...@@ -178,6 +178,7 @@ ...@@ -178,6 +178,7 @@
- [异常调测](kernel/kernel-mini-memory-exception.md) - [异常调测](kernel/kernel-mini-memory-exception.md)
- [Trace调测](kernel/kernel-mini-memory-trace.md) - [Trace调测](kernel/kernel-mini-memory-trace.md)
- [LMS调测](kernel/kernel-mini-memory-lms.md) - [LMS调测](kernel/kernel-mini-memory-lms.md)
- [SHELL](kernel/kernel-mini-debug-shell.md)
- 附录 - 附录
- [内核编码规范](kernel/kernel-mini-appx-code.md) - [内核编码规范](kernel/kernel-mini-appx-code.md)
- [标准库支持](kernel/kernel-mini-appx-lib.md) - [标准库支持](kernel/kernel-mini-appx-lib.md)
...@@ -217,6 +218,7 @@ ...@@ -217,6 +218,7 @@
- [虚拟文件系统](kernel/kernel-small-bundles-fs-virtual.md) - [虚拟文件系统](kernel/kernel-small-bundles-fs-virtual.md)
- [支持的文件系统](kernel/kernel-small-bundles-fs-support.md) - [支持的文件系统](kernel/kernel-small-bundles-fs-support.md)
- [适配新的文件系统](kernel/kernel-small-bundles-fs-new.md) - [适配新的文件系统](kernel/kernel-small-bundles-fs-new.md)
- [Plimitsfs文件系统](kernel/kernel-small-plimits.md)
- 调测与工具 - 调测与工具
- Shell - Shell
- [Shell介绍](kernel/kernel-small-debug-shell-overview.md) - [Shell介绍](kernel/kernel-small-debug-shell-overview.md)
...@@ -286,7 +288,7 @@ ...@@ -286,7 +288,7 @@
- [魔法键使用方法](kernel/kernel-small-debug-shell-magickey.md) - [魔法键使用方法](kernel/kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](kernel/kernel-small-debug-shell-error.md) - [用户态异常信息说明](kernel/kernel-small-debug-shell-error.md)
- [Trace调测](kernel/kernel-small-debug-trace.md) - [Trace调测](kernel/kernel-small-debug-trace.md)
- [Perf调测](kernel/kernel-mini-memory-perf.md) - [Perf调测](kernel/kernel-small-debug-perf.md)
- [LMS调测](kernel/kernel-small-memory-lms.md) - [LMS调测](kernel/kernel-small-memory-lms.md)
- [进程调测](kernel/kernel-small-debug-process-cpu.md) - [进程调测](kernel/kernel-small-debug-process-cpu.md)
- 内核态内存调测 - 内核态内存调测
...@@ -522,7 +524,7 @@ ...@@ -522,7 +524,7 @@
- [xdevice测试调度框架使用指导](device-test/xdevice.md) - [xdevice测试调度框架使用指导](device-test/xdevice.md)
- 调测工具 - 调测工具
- [bytrace使用指导](subsystems/subsys-toolchain-bytrace-guide.md) - [bytrace使用指导](subsystems/subsys-toolchain-bytrace-guide.md)
- [hdc 使用指导](subsystems/subsys-toolchain-hdc-guide.md) - [hdc\_std 使用指导](subsystems/subsys-toolchain-hdc-guide.md)
- [hiperf 使用指南](subsystems/subsys-toolchain-hiperf.md) - [hiperf 使用指南](subsystems/subsys-toolchain-hiperf.md)
- [XTS认证](device-test/xts.md) - [XTS认证](device-test/xts.md)
- 工具 - 工具
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册