提交 1589f82a 编写于 作者: D duangavin123

update 导入OpenHarmony工程

Signed-off-by: Nduangavin123 <duanxichao@huawei.com>
上级 abd8f3ad
# 组件开发指南 # 组件开发指南
- [组件开发规范](bundles-standard-rules.md) - [组件开发规范](oem_bundle_standard_des.md)
- [组件开发指南](bundles-guide.md) - [开发指南](bundles-guide.md)
- [组件开发指南](bundles-guide-overview.md) - [概述](bundles-guide-overview.md)
- [准备工作](bundles-guide-prepare.md) - [安装hpm命令行工具](bundles-guide-prepare.md)
- [组件开发](bundles-guide-develop.md) - [开发Bundle](bundles-guide-develop.md)
- [组件开发示例](bundles-demo.md) - [开发示例](bundles-demo.md)
- [HPM介绍](bundles-demo-hpmdescription.md) - [HPM介绍](bundles-demo-hpmdescription.md)
- [环境准备](bundles-demo-environment.md) - [编译环境准备](bundles-demo-environment.md)
- [操作实例](bundles-demo-devsample.md) - [操作实例](bundles-demo-devsample.md)
# 操作实例<a name="ZH-CN_TOPIC_0000001072143838"></a> # 操作实例<a name="ZH-CN_TOPIC_0000001072143838"></a>
环境准备好后,接下来本文以Hi3861平台为例,演示如何利用HPM进行组件的安装、编译和打包 环境准备好后,接下来本文以Hi3861平台为例,演示如何利用hpm进行发行版的安装、编译
1. 执行以下命令,初始化安装目录(目录名可自行设置): 1. 执行以下命令,创建目录,并根据模板dist创建一个默认工程(目录名可自行设置):
``` ```
mkdir test3861 mkdir test3861
cd test3861 cd test3861
hpm init -t dist hpm init -t dist myproduct
``` ```
初始化成功则显示: 创建成功则显示:
``` ```
Initialization finished. Initialization finished.
``` ```
2. 安装wifi\_iot发行版。 2. 安装hispark\_pegasus发行版。
``` ```
hpm install @ohos/wifi_iot hpm install @ohos/hispark_pegasus
``` ```
安装成功则显示: 安装成功则显示:
...@@ -31,11 +31,11 @@ ...@@ -31,11 +31,11 @@
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
>Hi3516平台采用下述命令: >Hi3516平台采用下述命令:
>``` >```
>hpm install @ohos/ip_camera_hi3516dv300 >hpm install @ohos/hispark_taurus
>``` >```
>Hi3518平台采用下述命令: >Hi3518平台采用下述命令:
>``` >```
>hpm install @ohos/ip_camera_hi3518ev300 >hpm install @ohos/hispark_aries
>``` >```
3. 编译打包 3. 编译打包
......
# 环境准备<a name="ZH-CN_TOPIC_0000001071315859"></a> # 编译环境准备<a name="ZH-CN_TOPIC_0000001071315859"></a>
- [linux服务器](#section20979554791) - [linux服务器](#section20979554791)
- [安装Node.js](#section9954105413153) - [安装Node.js](#section9954105413153)
- [安装HPM](#section15937194904819) - [安装HPM命令行工具](#section15937194904819)
- [安装python环境](#section1621819180417) - [安装python环境](#section1621819180417)
- [安装文件打包工具](#section77617165913) - [安装文件打包工具](#section77617165913)
- [安装SCons](#section20558439191516) - [安装SCons](#section873135716233)
![](figure/3516dv300.png)
## linux服务器<a name="section20979554791"></a> ## linux服务器<a name="section20979554791"></a>
准备一台装有Ubuntu 16.04 及以上 64 位系统的linux服务器(hpm是支持windows的,但是目前OpenHarmony开源的Hi3861、Hi3516、Hi3518三个解决方案都只支持Ubuntu)。 准备一台装有Ubuntu 16.04 及以上 64 位系统的linux服务器(当前未完全支持window环境下的编译)。
将linux shell改为bash: 将linux shell改为bash:
...@@ -25,12 +27,6 @@ ln -s bash /bin/sh ...@@ -25,12 +27,6 @@ ln -s bash /bin/sh
## 安装Node.js<a name="section9954105413153"></a> ## 安装Node.js<a name="section9954105413153"></a>
>![](../public_sys-resources/icon-note.gif) **说明:**
>如果配置的源的nodejs版本太低,可以执行以下语句后再执行apt-get install:
>```
>curl -L https://deb.nodesource.com/setup_12.x | bash
>```
推荐安装 Node.js 12.x (包含 npm 6.14.4)或更高版本(推荐 12.13.0+): 推荐安装 Node.js 12.x (包含 npm 6.14.4)或更高版本(推荐 12.13.0+):
``` ```
...@@ -45,7 +41,7 @@ node --version # 查看nodejs版本 ...@@ -45,7 +41,7 @@ node --version # 查看nodejs版本
npm --version # 查看npm版本 npm --version # 查看npm版本
``` ```
## 安装HPM<a name="section15937194904819"></a> ## 安装HPM命令行工具<a name="section15937194904819"></a>
通过 Node.js 自带的 npm(使用默认的源 https://registry.npmjs.org/ )安装 hpm-cli 命令行工具: 通过 Node.js 自带的 npm(使用默认的源 https://registry.npmjs.org/ )安装 hpm-cli 命令行工具:
...@@ -59,7 +55,7 @@ npm install -g @ohos/hpm-cli ...@@ -59,7 +55,7 @@ npm install -g @ohos/hpm-cli
hpm config hpm config
``` ```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置: 上述命令执行后将会显示hpm的默认配置,您可以根据实际情况对默认配置进行修改,以下是hpm的常用配置:
``` ```
registry = https://hpm.harmonyos.com # hpm注册中心地址,下载组件必须 registry = https://hpm.harmonyos.com # hpm注册中心地址,下载组件必须
...@@ -68,7 +64,7 @@ http_proxy = http://your-proxy-server:port # 配置HTTP代理 ...@@ -68,7 +64,7 @@ http_proxy = http://your-proxy-server:port # 配置HTTP代理
https_proxy = http://your-proxy-server:port # 配置HTTPS代理 https_proxy = http://your-proxy-server:port # 配置HTTPS代理
``` ```
hpm-cli的命令介绍可以参考:[hpm操作命令](bundles-standard-rules.md) hpm-cli的命令介绍可以参考:[hpm操作命令](oem_bundle_standard_des.md)
## 安装python环境<a name="section1621819180417"></a> ## 安装python环境<a name="section1621819180417"></a>
...@@ -115,7 +111,7 @@ sudo apt-get install mtools ...@@ -115,7 +111,7 @@ sudo apt-get install mtools
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
>Hi3518和Hi3516两种平台需要安装打包工具,Hi3861平台不需要。 >Hi3518和Hi3516两种平台需要安装打包工具,Hi3861平台不需要。
## 安装SCons<a name="section20558439191516"></a> ## 安装SCons<a name="section873135716233"></a>
1. 打开Linux编译服务器终端。 1. 打开Linux编译服务器终端。
2. 运行如下命令,安装SCons安装包。 2. 运行如下命令,安装SCons安装包。
...@@ -131,7 +127,7 @@ sudo apt-get install mtools ...@@ -131,7 +127,7 @@ sudo apt-get install mtools
``` ```
**图 1** SCons安装成功界面,版本要求3.0.4以上<a name="fig235815252492"></a> **图 1** SCons安装成功界面,版本要求3.0.4以上<a name="fig235815252492"></a>
![](figure/SCons安装成功界面-版本要求3-0-4以上-21.png "SCons安装成功界面-版本要求3-0-4以上-21") ![](figure/SCons安装成功界面-版本要求3-0-4以上-27.png "SCons安装成功界面-版本要求3-0-4以上-27")
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
......
# HPM介绍<a name="ZH-CN_TOPIC_0000001071487274"></a> # HPM介绍<a name="ZH-CN_TOPIC_0000001071487274"></a>
随着OpenHarmony正式开源,HPM包管理器也应运而生。HPM全称HarmonyOS Package Manager,是OpenHarmony组件包的管理和分发工具。HPM主要是面向设备开发者,用于获取/定制OpenHarmony源码,执行安装、编译、打包、升级等操作的工具集。本文档将向开发者介绍如何使用HPM工具进行OpenHarmony组件的安装、编译、打包等操作。 HPM全称HarmonyOS Package Manager,是OpenHarmonyBundle的管理和分发工具。HPM主要是面向HamronyOS开发者,用于获取/定制OpenHarmony源码,执行安装依赖、编译、打包、升级等操作的工具集。本文档将向开发者介绍如何使用HPM工具进行OpenHarmonyBundle的安装、编译、打包等操作。
# 组件开发示例<a name="ZH-CN_TOPIC_0000001157479397"></a> # 开发示例<a name="ZH-CN_TOPIC_0000001157479397"></a>
- **[HPM介绍](bundles-demo-hpmdescription.md)** - **[HPM介绍](bundles-demo-hpmdescription.md)**
- **[环境准备](bundles-demo-environment.md)** - **[编译环境准备](bundles-demo-environment.md)**
- **[操作实例](bundles-demo-devsample.md)** - **[操作实例](bundles-demo-devsample.md)**
......
# 组件开发<a name="ZH-CN_TOPIC_0000001051690861"></a> # 开发Bundle<a name="ZH-CN_TOPIC_0000001051690861"></a>
- [创建OpenHarmony组件](#section1976410130540) - [创建Bundle](#section717481119145)
- [新建组件](#section717481119145) - [将现有工程定义为Bundle](#section102861955201410)
- [改造组件](#section102861955201410) - [发布Bundle到HPM平台](#section1318574233211)
- [从模板创建组件](#section15882846181510) - [引用Bundle](#section57959284315)
- [编译组件](#section136732148541) - [全局安装Bundle](#section647375516313)
- [编译Bundle](#section7972161715325)
- [定义编译脚本](#section10274147111610) - [定义编译脚本](#section10274147111610)
- [执行编译](#section879301916172) - [执行编译](#section879301916172)
- [定义发行版](#section413216495619) - [定义发行版](#section127388393326)
- [定义脚本](#section11503171219190) - [定义脚本](#section11503171219190)
- [发行](#section4694125521912) - [编译发行版](#section4694125521912)
- [烧录](#section1746331545413) - [烧录](#section2061514431039)
- [运行调试](#section6742131615549)
## 创建OpenHarmony组件<a name="section1976410130540"></a>
创建OpenHarmony组件有如下几种方式: 创建OpenHarmonyBundle有如下几种方式:
- 从头开发一个全新的组件。 - 从头创建一个全新的Bundle。
- 将一个现有的非组件的代码改造成组件。 - 将一个现有的源码项目定义为Bundle。
- hpm提供了一些组件模板方便快速创建组件。
## 新建组件<a name="section717481119145"></a> ## 创建Bundle<a name="section717481119145"></a>
通常情况下,[HPM网站](https://hpm.harmonyOS.com)上能找到您开发常用的组件,如果现有的组件不能完全满足开发,这时可以自己动手开发一个组件 通常情况下,[HPM网站](https://hpm.harmonyOS.com)上能找到您开发常用的Bundle,如果现有的Bundle不能完全满足开发,这时可以自己动手开发一个Bundle
如果您愿意,可以将组件发布到HPM的仓库中供其他用户使用。假设要在D:/source目录下新建一个全新的组件my-bundle: 如果您愿意,可以将Bundle发布到HPM的仓库中供其他用户使用。
可以使用hpm init 创建该组件的脚手架代码,例如,进入D:/source目录,执行如下命令: 假设要在D:/source目录下新建一个全新的Bundle:my-bundle,可以使用hpm init 创建该Bundle的脚手架代码,例如,进入D:/source目录,执行如下命令:
``` ```
hpm init -t default -d demo my-bundle hpm init -t default -d demo mybundle
``` ```
会在 source 目录下生成如下文件 将使用'default' 模板 在当前目录下的demo路径下,创建一个名为mybundle的Bundle
``` ```
mybundle demo
├── bundle.json # 组件元数据描述文件 ├── headers # 头文件(样例)
├── example # 测试组件功能的示例 │ └── main.h
│ └── main.c └── src # 源代码(样例)
├── include # 组件的内部头文件 │ └─ main.c
│ └── mybundle.h ├── bundle.json # 元数据声明文件
├── README.md # 组件的简要说明 └── LICENSE # 许可协议文本
└── src # 组件的源代码 └── Makefile # 编译描述文件(样例)
└─ mybundle.c └── README.md # Bundle的自述文件
``` ```
接下来根据您的业务需要,实现组件内部的功能代码,完成代码开发后,通过git将代码(包括bundle.json文件)提交到组件代码托管仓库中(如gitee)。 接下来根据您的业务需要,实现Bundle内部的功能代码,以及编译脚本,完成代码开发后,通过git将代码(包括bundle.json文件)提交到组件代码托管仓库中(如gitee)。
>![](../public_sys-resources/icon-note.gif) **说明:**
>```
>hpm init -t {templatename} -d {dir} {name}
>```
>- -t \{templatename\} :指的是模板名称。
>- -d \{dir\}:是要创建的Bundle所存放的路径。
>- name:为要创建的Bundle名称。
hpm 除了提供了少量默认模板之外,其他模板均存储在服务器端,可以使用命令hpm search -t template 从服务器端搜索模板。
## 改造组件<a name="section102861955201410"></a> ![](figure/zh-cn_image_0000001141641532.png)
如果您已经有了代码,只是还不满足OpenHarmony的组件结构,需要改造成为hpm的组件包,只需要在当前要改造的代码目录下(例如mybundle2),执行如下命令,会提示您输入组件名称和版本。 ## 将现有工程定义为Bundle<a name="section102861955201410"></a>
如果您已经有了代码工程,需要分发的HPM平台,只需要在当前工程目录下(例如mybundle2),执行如下命令,会引导您输入组件名称和版本等信息。
``` ```
hpm init hpm init
``` ```
1. 输入名称后回车(如mybundle2)。 1. 输入名称后回车(如mybundle2)。
2. 输入版本后(如1.0.0)回车,在当前组件目录下会生成一个bundle.json文件。 2. 接下来依次输入版本、描述等信息后,会在当前目录下会生成一个bundle.json文件。
3. 打开bundle.json文件再添加其他的描述,这时候他已经是一个具备可发布的组件了 3. 也可以打开bundle.json文件
``` ```
$ hpm init $ hpm init
Your bundle will be created in dirname E:\demo\mybundle2 Your bundle will be created in directory ~\demo\mybundle2
? bundle name mybundel2 ? bundle name mybundel2
? version 1.0.0 ? version 1.0.0
Init finished! ...
Initialization finished.
``` ```
1. 打开bundle.json文件修改其他信息(如作者,代码仓库,代码目录,命令脚本,依赖组件等),如下 1. 打开bundle.json文件修改其他信息(如作者,代码仓库,代码目录,命令脚本,依赖组件等),如下(仅示意)
``` ```
{ {
"name": "mybundle2", "name": "mybundle2",
"version": "1.0.0", "version": "1.0.0",
"publishAs": "source", "publishAs": "code-segment",
"dirs":{ "dirs":{
".":[ ".":["README.md"],
"README.md" "src":["test.c"],
], "header":["header/test.h" ],
"src":[ "src/common":["src/common/foobar.txt"]
"test.c"
],
"header":[
"header/test.h"
],
"src/common":[
"src/common/foobar.txt"
]
}, },
"scripts": { "scripts": {
"build": "make -${args}" "build": "make -${args}"
}, },
"dependencies": { "dependencies": {
"@ohos/cjson": "^1.0.0", "@ohos/cjson": "^1.0.0",
"@ohos/": "^1.2.0" "@ohos/foobar": "^1.2.0"
} }
} }
``` ```
## 从模板创建组件<a name="section15882846181510"></a> ## 发布Bundle到HPM平台<a name="section1318574233211"></a>
要在发布Bundle到HPM,你需要先具备账号,并创建组织,创建组织的条件及详细步骤请参考hpm网站上的帮助说明。
完成账号申请和组织创建(或者加入一个现有的组织)后,您需要根据个人的邀请码(在HPM网站的个人中心页查看),在本机生成公钥,并在HPM网站的个人中心配置。
```
hpm config set loginUser {your-invitation-code}
hpm gen-keys
```
生成的文件将会存放在 \~\\Users\\yourname\\.hpm\\key 下,将公钥文件\(publicKey\_your-accout.pem\)中内容拷贝到 HPM 个人中心的 SSH 公钥中。
完成上述操作后,你就具备了在您的组织内发布Bundle的权限了。
在bundle所在目录,执行命令hpm publish,将会完成组件的打包发布操作。
```
hpm publish
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 为避免Bundle名称冲突,发布的Bundle的名称需限定在组织范围内,即命名为@org\_name/bundle\_name的格式。
>- 你的账号也必须是org\_name内的成员,才可以发布或更新组织内的Bundle。
>- 发布的组件,需要通过安全及内容审核,才能正式生效。
## 引用Bundle<a name="section57959284315"></a>
通常开发一个项目,需要引用其他的组件以加快特定功能的开发,可以采用安装依赖的方式。
首先去HPM网站,根据关键字去搜索满足您的需求的组件,找到合适的组件后,将其引入到您的工程。
在您的bundle工程中(工程目录中必须包含bundle.json文件)执行如下命令:
```
$ hpm install @scope/the_bundle
```
引用的bundle将会被安装到你的工程所在的目录的 ohos\_bundle下
```
project
├── ohos_bundle
│ └── scope
│ └─ the_bundle # <---引用的组件将会出现在这
└── src
│ └─ main.c
├── bundle.json # 元数据声明文件
└── LICENSE
└── Makefile
└── README.md
```
打开bundle.json文件,可以看到bundle已经被引入到您的工程的依赖中。
```
{
"dependencies": {
"@scope/the_bundle": "^1.0.0"
}
}
```
您也可以一次性在此文件中编辑多个Bundle的依赖
```
{
"dependencies": {
"@scope/the_bundle1": "^1.0.0",
"@scope/the_bundle2": "^2.0.0",
"@scope/the_bundle3": "^3.0.0",
"@scope/the_bundle4": "^1.1.0"
}
}
```
hpm 除了提供了默认模板 default和simple两个简单的模板之外,其他模板均存储在服务器端 再执行hpm install命令,将会一次性将所有未安装的Bundle一次性全部下载并安装完成
可以使用命令hpm search -t template 从服务器端搜索模板。 ## 全局安装Bundle<a name="section647375516313"></a>
![](figure/zh-cn_image_0000001051452177.png) 如果引用的Bundle是多个项目共用的组件(如编译工具链),你可以全局安装
根据description简要中的描述,找到适合的模板,基于模板可以快速创建一个组件的脚手架,执行如下初始化命令(指定-t -d 参数)。 在您的bundle工程中(工程目录中必须包含bundle.json文件)执行如下命令:
``` ```
hpm init -t {templatename} -d dir name $ hpm install -g @scope/the_tool
``` ```
- \{templatename\} :指的是模板名称。 引用的bundle将会被安装到你在hpm config中设置的globalRepo所指定的目录下:
- -d 后面的参数dir:是要创建的组件所存放的路径。
- name:为要创建的组件名称。
## 编译组件<a name="section136732148541"></a> ```
~\.hpm\global
│ └── scope
│ └─ the_tool # <---引用的组件将会出现在这
```
完成代码开发后,需要对组件进行编译。hpm提供了命令集成的能力,您可以选择任意的适合项目的编译工具(如make,gcc,gn等等)。只需在当前项目的bundle.json文件中定义scripts脚本中的build命令,就可以通过执行hpm build执行编译。 >![](../public_sys-resources/icon-note.gif) **说明:**
>- 在项目安装的Bundle,在执行hpm编译命令时可以通过引用环境变量 DEP\_SCOPE\_bundle\_name,例如:
>通过 hpm i @opensource/gn 安装后,可以编辑bundle.json中的编译脚本,如下:
>```
>"scripts": {
> "build": "${DEP_OPENSOURCE_gn}/gn --version"
> },
>```
>然后就可以通过执行hpm build将调用gn的功能。
>- 在全局安装的Bundle,可以通过设置系统环境变量,直接调用,或者hpm config set key value的方式,通过 $\{key\}/tool\_name 的方式 引用,例如:
>```
>hpm i -g @ohos/opensource/gn
>hpm config BUILD_SYS_GN ~/.hpm/global/ohos_bundles/opensource/gn
>```
>可以编辑bundle.json中的编译脚本,如下:
>```
>"scripts": {
> "build": "${BUILD_SYS_GN}/gn --version"
> },
>```
>然后就可以通过执行hpm build将调用gn的功能。
## 编译Bundle<a name="section7972161715325"></a>
完成代码开发后,如果Bundle的代码是可以独立编译的,可以配置编译工具和脚本以完成二进制的生成。
hpm具备命令集成的能力,您可以选择任意的适合项目所采用的语言编译工具(如make,gcc,gn等等)。只需在当前项目的bundle.json文件中定义scripts脚本中的build命令,就可以通过执行hpm build执行编译。
## 定义编译脚本<a name="section10274147111610"></a> ## 定义编译脚本<a name="section10274147111610"></a>
...@@ -172,37 +277,54 @@ hpm build ...@@ -172,37 +277,54 @@ hpm build
在完成一系列的编译动作后,显示build succeed。检查编译的输出结果: 在完成一系列的编译动作后,显示build succeed。检查编译的输出结果:
![](figure/zh-cn_image_0000001051770876.png) ![](figure/zh-cn_image_0000001188041297.png)
## 定义发行版<a name="section413216495619"></a> ## 定义发行版<a name="section127388393326"></a>
发行版是将一组组件组合起来的,编译生成可以运行的OpenHarmony解决方案,里面包含了较多依赖的组件,以及以脚本形式描述如何完整编译、链接这些组件。 发行版的元数据文件中定义了其依赖的Bundles,以及如何编译、链接这些bundles,生成镜像文件。
示例如下(以下示例的编译命令dist,采用hb编译框架描述)
## 定义脚本<a name="section11503171219190"></a> ## 定义脚本<a name="section11503171219190"></a>
bundle.json中定义 bundle.json中定义如下(示例)
``` ```
{ {
"name": "my_dist", "name": "@your/dist_name",
"version": "1.0.0", "version": "2.2.0",
"publishAs": "distribution", "publishAs": "distribution",
"description": "describe it",
"scripts": { "scripts": {
"dist": "make -${args}" "config_hb": "hb set -root $DEP_BUNDLE_BASE",
}, "dist": "PATH=/root/.local/bin:${DEP_OHOS_gn}:${DEP_OHOS_ninja}/ninja:${DEP_OHOS_llvm}/llvm/bin:${DEP_OHOS_hc_gen}/hc-gen:${PATH} && ./scripts/dist.sh"
"base": { },
"name": "dist-bundle",
"version": "1.0.0"
},
"envs": { "envs": {
"args": "x86" "debug": false
}, },
"dirs": {
"scripts": "scripts/*"
},
"dependencies": { "dependencies": {
} "@ohos/build_lite": "2.2.0",
"@ohos/gn": "1.1.1",
"@ohos/llvm": "1.1.1",
"@ohos/hc_gen": "1.1.0",
"@ohos/ninja": "1.1.0",
......
},
"ohos": {
"os": "2.2-Beta",
"board": "hi3516",
"kernel": "liteos-a"
},
"keywords": [ "hispark", "hi3516" ],
"repository": "https://gitee.com/openharmony/your-project",
"license": "Apache V2"
} }
``` ```
## 发行<a name="section4694125521912"></a> ## 编译发行版<a name="section4694125521912"></a>
在当前发行版根目录下,执行如下命令。 在当前发行版根目录下,执行如下命令。
...@@ -210,7 +332,7 @@ bundle.json中定义 ...@@ -210,7 +332,7 @@ bundle.json中定义
hpm dist hpm dist
``` ```
hpm-cli工具会自动执行编译,打包操作,将根据scripts定义的dist脚本生成镜像文件,如: hpm-cli工具会自动执行编译,生成镜像文件,如:
``` ```
out out
...@@ -218,23 +340,23 @@ out ...@@ -218,23 +340,23 @@ out
|-xx.file |-xx.file
``` ```
## 烧录<a name="section1746331545413"></a> ## 烧录<a name="section2061514431039"></a>
发行版的编译结果可以烧录到设备中运行,例如使用hiburn工具进行烧录。在发行版的bundle.json文件配置烧录参数。 发行版的编译结果可以烧录到设备中运行,例如使用hiburn工具进行烧录。在发行版的bundle.json文件配置烧录参数。
``` ```
"scripts": { "scripts": {
"flash": "{$DEP_HIBURN}/hiburn" "flash": "{$DEP_HIBURN}/hiburn"
}, },
``` ```
配置烧录相关的参数(参考烧录工具的说明进行配置)。 设置烧录命令行工具的所在路径,配置烧录相关的参数(参考烧录工具的说明进行配置)。
``` ```
hpm config set DEP_HIBURN {hiburn_path}
hpm run flash hpm run flash
``` ```
## 运行调试<a name="section6742131615549"></a> >![](../public_sys-resources/icon-note.gif) **说明:**
>上述仅描述如何定义bundle.json的样例,烧录工具取决于实际开发板所需的工具。
将发行版的镜像烧录到设备中后,就可以启动运行调试了,由于运行调试和具体的开发板和IDE调试工具相关,此处不再详细描述。
# 概述<a name="ZH-CN_TOPIC_0000001051452100"></a> # 概述<a name="ZH-CN_TOPIC_0000001051452100"></a>
本章节将简要介绍如何开发OpenHarmony组件和发行版,并通过命令行工具方式完成组件创建、开发、编译、烧录、调试等开发过程。 - [Bundle](#section196713235514)
- [Distribution](#section155387501033)
- 一个组件(bundle)通常和一个代码仓库对应,在代码的基础上增加bundle.json、README文件、LICENSE描述文件。
- 一个发行版(distribution)是由多个组件构成的。发行版中集合了一个完整系统的各种组件(如驱动、内核、框架、应用),可以用于设备的烧录。 本章节将介绍HarmonyOS中的Bundle相关概念以及如何定义Bundle,并以一个示例说明如何使用hpm命令行工具完成Bundle的创建、开发、编译、发布、安装使用的全过程。
**表 1** 组件和发行版的差异对比 ## Bundle<a name="section196713235514"></a>
<a name="table6287133615412"></a> Bundle是HarmonyOS中一个用来表示分发单元的术语,等同于包,一个Bundle中通常包含以下内容:
<table><thead align="left"><tr id="row17288183614415"><th class="cellrowborder" valign="top" width="16.24162416241624%" id="mcps1.2.4.1.1"><p id="p528818361545"><a name="p528818361545"></a><a name="p528818361545"></a>异同点</p>
</th> - 被分发的二进制文件(二进制类型)
<th class="cellrowborder" valign="top" width="33.31333133313331%" id="mcps1.2.4.1.2"><p id="p1288836247"><a name="p1288836247"></a><a name="p1288836247"></a>组件</p> - 被分发的源代码文件(源代码/代码片段类型)
</th> - 编译脚本(发行版类型需要)
<th class="cellrowborder" valign="top" width="50.44504450445044%" id="mcps1.2.4.1.3"><p id="p112885362418"><a name="p112885362418"></a><a name="p112885362418"></a>发行版</p> - 自身的说明文件
</th> - bundle.json:元数据声明(名称,版本,依赖等)
</tr> - LICENSE:许可协议文本
</thead> - README.md:自述文件
<tbody><tr id="row1728813361848"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p2010613564815"><a name="p2010613564815"></a><a name="p2010613564815"></a>应用场景</p> - CHANGELOG.md:变更日志(可选)
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1910555184818"><a name="p1910555184818"></a><a name="p1910555184818"></a>面向功能特性开发</p>
</td> >![](../public_sys-resources/icon-note.gif) **说明:**
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p13871955484"><a name="p13871955484"></a><a name="p13871955484"></a>面向系统开发</p> >Bundle的类型可以分为二进制,源代码,代码片段,模板,插件,发行版等。一个Bundle可以依赖其他的Bundles,依赖关系为有向无环图
</td>
</tr> 一个Bundle被发布到HPM服务器(https://hpm.harmonyos.com)后,另外一些开发者就可以通过hpm包管理器下载安装使用 。
<tr id="row676745614472"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p1028816365414"><a name="p1028816365414"></a><a name="p1028816365414"></a>内容</p>
</td> 一个Bundle在命名空间内拥有唯一的名称(命名格式为:@scope/name),可以进行独立的版本演进。
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p428812361042"><a name="p428812361042"></a><a name="p428812361042"></a>功能或特性的实现代码或二进制库</p>
</td> ## Distribution<a name="section155387501033"></a>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p328817366417"><a name="p328817366417"></a><a name="p328817366417"></a>依赖的组件清单及编译构建脚本</p>
</td> Distribution是HarmonyOS的发行版,是一个完整的操作系统版本,集合了各种Bundle(驱动,内核,框架,应用等),也通过Bundle在HPM平台分发。
</tr>
<tr id="row95114356"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p184894513517"><a name="p184894513517"></a><a name="p184894513517"></a>完整程度</p> >![](../public_sys-resources/icon-note.gif) **说明:**
</td> >发行版的元数据中仅描述了依赖的Bundles以及如何编译该发行版的编译脚本,并不包含发行版的二进制镜像。下载发行版后,需要在本地将依赖的Bundles下载下来,安装编译后才能得到可用于烧录的系统镜像文件。
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1951741155"><a name="p1951741155"></a><a name="p1951741155"></a>操作系统的一部分</p> >发行版可以继承,即在一个既有的发行版的基础上,通过增加/删除Bundle形成新的发行版,以实现发行版的定制。
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p20521542512"><a name="p20521542512"></a><a name="p20521542512"></a>一个完整操作系统版本</p> **图 1** 组Bundle和Distribution的关系<a name="fig85033524124"></a>
</td>
</tr>
<tr id="row13581419518"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p859171059"><a name="p859171059"></a><a name="p859171059"></a>编译后结果</p> ![](figure/组件和发行版的构成-英文.png)
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p259201355"><a name="p259201355"></a><a name="p259201355"></a>组件包</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p459414519"><a name="p459414519"></a><a name="p459414519"></a>系统镜像</p>
</td>
</tr>
</tbody>
</table>
**图 1** 组件和发行版的构成<a name="fig85033524124"></a>
![](figure/组件0924.png)
# 准备工作<a name="ZH-CN_TOPIC_0000001051770836"></a> # 安装hpm命令行工具<a name="ZH-CN_TOPIC_0000001051770836"></a>
- [硬件要求](#section98535485518) - [安装](#section14480912380)
- [安装Node.js和hpm命令行工具](#section106591616205311) - [配置hpm(可选)](#section138983413013)
- [更改hpm的配置(可选)](#section71821165412) - [下载OpenHarmony代码](#section669905815300)
- [下载OpenHarmony代码](#section102338221707)
- [安装开发依赖的组件](#section19233183315020)
## 硬件要求<a name="section98535485518"></a> 要进行Bundle的开发,需要安装包管理器hpm(HarmonyOS Package Manager),这是一个基于Node.js开发的跨平台的命令行工具,所以要运行hpm,需要先安装Node.js,然后可以npm 来安装hpm。
- 准备设备开发的开发板(如Hi3861、Hi3516DV300、Hi3518EV300) ## 安装<a name="section14480912380"></a>
- 主机电脑(Windows工作台)
- Linux服务器
**图 1** 硬件环境连接关系<a name="fig113816181847"></a>
![](figure/硬件环境连接关系.png "硬件环境连接关系")
## 安装Node.js和hpm命令行工具<a name="section106591616205311"></a>
1. 安装Node.js。 1. 安装Node.js。
...@@ -42,43 +33,41 @@ ...@@ -42,43 +33,41 @@
``` ```
## 更改hpm的配置(可选)<a name="section71821165412"></a> ## 配置hpm(可选)<a name="section138983413013"></a>
安装完hpm-cli命令行工具后,执行以下命令可以查看hpm配置: 安装完hpm-cli命令行工具后,如果需要更改配置信息(如代理,shell),执行以下命令可以查看hpm配置:
``` ```
hpm config hpm config
``` ```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置: 上述命令执行后将会显示hpm的默认配置,您可以根据自己需要对默认配置进行修改,以下是hpm的常用配置:
``` ```
registry = https://hpm.harmonyos.com/hpm/registry/api # hpm注册中心地址,下载组件必须 registry = https://hpm.harmonyos.com
login = https://hpm.harmonyos.com/hpm/auth/pk # hpm处理登录地址,发布组件必须 ### login Settings
loginUser = {your-account} # 配置hpm登录账号,发布组件必须 # loginUser = invitation_code
shellPath = C:\WINDOWS\System32\cmd.exe # hpm命令执行使用的shell
globalRepo = C:\Users\yourname\.global # 配置全局安装的组件存放路径 #### Path Settings
http_proxy = http://your-proxy-server:port # 配置HTTP代理 shellPath = C:\WINDOWS\System32\cmd.exe
https_proxy = http://your-proxy-server:port # 配置HTTPS代理 # shellPath = C:\Program Files\Git\bin\sh.exe
# globalRepo = C:\Users\username\.hpm\global
#### Network Settings
# no_proxy = *.server.com
# http_proxy = http://user:pwd@proxy_server:port
# https_proxy = http://user:pwd@proxy_server:port
# strictSsl = true
#### Other Settings
# privateSupport = true|false
# ignoreBundles = @ohos/llvm,@ohos/gn,
# OSPlatform = Auto|linux|darwin|win32
``` ```
hpm-cli的命令介绍可以参考:[hpm操作命令](bundles-guide-overview.md) hpm-cli的命令介绍可以参考:[hpm操作命令](bundles-guide-overview.md)
## 下载OpenHarmony代码<a name="section102338221707"></a> ## 下载OpenHarmony代码<a name="section669905815300"></a>
参考[《源码获取》](../get-code/sourcecode-acquire.md) 参考[《源码获取》](../get-code/sourcecode-acquire.md)
## 安装开发依赖的组件<a name="section19233183315020"></a>
hpm包管理器将常用开发开发工具(如烧录,编译,压缩等)也发布成了组件。可以通过如下命令方式进行安装,执行完该命令后,系统会自动将开发依赖的工具下载安装,且这些组件只需全局安装一次。
```
hpm i -g @ohos/llvm
hpm i -g @ohos/ninja
hpm i -g @ohos/gn
hpm i -g @ohos/hc_gen
hpm i -g @ohos/sysroot
```
这是一组开发工具的组件包(如包含gn,ninja等工具),有了这些开发态的组件,就可以进行常规的源码组件的开发了。
# 组件开发指南<a name="ZH-CN_TOPIC_0000001157319417"></a> # 开发指南<a name="ZH-CN_TOPIC_0000001157319417"></a>
- **[概述](bundles-guide-overview.md)** - **[概述](bundles-guide-overview.md)**
- **[准备工作](bundles-guide-prepare.md)** - **[安装hpm命令行工具](bundles-guide-prepare.md)**
- **[组件开发](bundles-guide-develop.md)** - **[开发Bundle](bundles-guide-develop.md)**
# 组件开发指南<a name="ZH-CN_TOPIC_0000001111039520"></a> # HPM bundle<a name="ZH-CN_TOPIC_0000001111039520"></a>
- **[组件开发规范](bundles-standard-rules.md)** - **[组件开发规范](oem_bundle_standard_des.md)**
- **[组件开发指南](bundles-guide.md)** - **[开发指南](bundles-guide.md)**
- **[组件开发示例](bundles-demo.md)** - **[开发示例](bundles-demo.md)**
# 组件开发规范<a name="ZH-CN_TOPIC_0000001051452141"></a> # 组件开发规范<a name="ZH-CN_TOPIC_0000001051452141"></a>
- [概述](#section1725818533344) - [概述](#section16820114352316)
- [定义](#section4821219183514) - [定义](#section123361236249)
- [组件划分原则](#section1089794263513) - [Bundle划分原则](#section1918162512419)
- [组件依赖](#section25701647163710) - [Bundle依赖](#section1687484311240)
- [组件构成](#section185538333914) - [Bundle构成](#section18351162611254)
- [代码文件](#section8431268393) - [代码文件](#section1575645102513)
- [说明文件](#section168121548173914) - [说明文件](#section15300198132611)
- [元数据描述文件](#section7107181819406) - [元数据描述文件](#section10956525102613)
- [组件管理](#section32061634104110) - [Bundle管理](#section32061634104110)
- [依赖关系](#section791115242423) - [依赖关系](#section37361058192610)
- [hpm操作命令参考](#section1183205411429) - [hpm操作命令参考](#section72383420271)
- [组件版本](#section12612142864316) - [Bundle版本](#section162921336288)
- [版本号命名规范](#section1487612416432) - [版本号命名规范](#section176561816172819)
- [版本发布](#section1548171014440) - [版本发布](#section8683417284)
- [发行版](#section1264139114413) - [发行版](#section243845052819)
- [环境变量说明](#section15352105174512) - [环境变量说明](#section19567181517299)
## 概述<a name="section1725818533344"></a> ## 概述<a name="section16820114352316"></a>
本文档将介绍组件的基本概念以及如何按照规范定义组件 本文档将介绍Bundle的基本概念以及如何按照规范定义Bundle
### 定义<a name="section4821219183514"></a> ### 定义<a name="section123361236249"></a>
OpenHarmony软件以组件\(bundle\)作为基本单元,从系统角度看,凡是运行在OpenHarmony上的软件都可以定义为组件;一般来讲,根据组件的应用范围,可以分为: OpenHarmony软件以bundle作为基本单元,从系统角度看,凡是运行在OpenHarmony上的软件都可以定义为Bundle;一般来讲,根据Bundle的应用范围,可以分为:
- 板级组件:如board、arch、mcu这些与设备硬件相关的组件 - 板级Bundle:如board、arch、mcu这些与设备硬件相关的Bundle
- 系统组件:一组独立功能的集合,如内核、文件系统、框架等。 - 系统Bundle:一组独立功能的集合,如内核、文件系统、框架等。
- 应用组件:直接面向用户提供服务的应用\(如wifi\_iot,ip\_camera\) - 应用Bundle:直接面向用户提供服务的应用\(如wifi\_iot,ip\_camera\)
从形式上看,组件是为复用而生,一切可以复用的模块都可以定义为组件,可以分为: 从形式上看,Bundle是为复用而生,一切可以复用的模块都可以定义为Bundle,可以分为:
- 源代码 - 源代码
- 二进制 - 二进制
- 代码片段 - 代码片段
- 发行版 - 发行版
### 组件划分原则<a name="section1089794263513"></a> ### Bundle划分原则<a name="section1918162512419"></a>
原则上应尽可能划分为细颗粒度的组件,以满足最大限度的复用。主要考虑以下几点: 原则上应尽可能划分为细颗粒度的Bundle,以满足最大限度的复用。主要考虑以下几点:
- 独立性:组件的功能应该相对独立,支持独立编译,可以单独对外提供接口和服务; - 独立性:Bundle的功能应该相对独立,支持独立编译,可以单独对外提供接口和服务;
- 耦合性:如果组件必须依赖其他的组件,才能对外提供服务,应考虑和被依赖的组件合并为一个组件 - 耦合性:如果Bundle必须依赖其他的Bundle,才能对外提供服务,应考虑和被依赖的Bundle合并为一个Bundle
- 相关性:如果一组组件共同完成一项功能,且没有被其他组件依赖,未来也没有被依赖的可能,则可以考虑合并为一个组件 - 相关性:如果一组Bundle共同完成一项功能,且没有被其他Bundle依赖,未来也没有被依赖的可能,则可以考虑合并为一个Bundle
### 组件依赖<a name="section25701647163710"></a> ### Bundle依赖<a name="section1687484311240"></a>
组件的依赖关系分为两种:必选依赖和可选依赖。 Bundle的依赖关系分为两种:必选依赖和可选依赖。
- 必选依赖:是指组件A在完成某个功能时,必须引入组件B,调用B的接口或服务配合才能完成。称B为A的必选依赖。 - 必选依赖:是指BundleA在完成某个功能时,必须引入BundleB,调用B的接口或服务配合才能完成。称B为A的必选依赖。
- 可选依赖:是在组件A在完成某个功能时,可以引入组件C,也可以引入组件D。C和D可以相互替换,称C和D为A的可选依赖。 - 可选依赖:是在BundleA在完成某个功能时,可以引入BundleC,也可以引入BundleD。C和D可以相互替换,称C和D为A的可选依赖。
## 组件构成<a name="section185538333914"></a> ## Bundle构成<a name="section18351162611254"></a>
一个组件包一般包含如下内容: 一个Bundle包一般包含如下内容:
- 组件包的代码或库(src目录下的代码文件) - Bundle包的代码或库(src目录下的代码文件)
- ohos\_bundles文件夹(存放依赖的组件,安装组件时自动生成,无需提交到代码库) - ohos\_bundles文件夹(存放依赖的Bundle,安装Bundle时自动生成,无需提交到代码库)
- 组件包的说明文件\(README.md\) - Bundle包的说明文件\(README.md\)
- 组件包元数据声明文件\(bundle.json\) - Bundle包元数据声明文件\(bundle.json\)
- 开源许可文件\(LICENSE\) - 开源许可文件\(LICENSE\)
``` ```
...@@ -75,23 +75,23 @@ OpenHarmony软件以组件\(bundle\)作为基本单元,从系统角度看, ...@@ -75,23 +75,23 @@ OpenHarmony软件以组件\(bundle\)作为基本单元,从系统角度看,
``` ```
### 代码文件<a name="section8431268393"></a> ### 代码文件<a name="section1575645102513"></a>
组件的代码文件和普通的代码目录没有差异。但要注意的是,组件中对外暴露的接口(头文件),会被其他组件所引用,需要单独在bundle.json的dirs中声明。 Bundle的代码文件和普通的代码目录没有差异。但要注意的是,Bundle中对外暴露的接口(头文件),会被其他Bundle所引用,需要单独在bundle.json的dirs中声明。
### 说明文件<a name="section168121548173914"></a> ### 说明文件<a name="section15300198132611"></a>
README.md,为markdown格式的描述关于组件自述说明文件。([语法参考](https://www.markdownguide.org/getting-started/)\) README.md,为markdown格式的描述关于Bundle自述说明文件。([语法参考](https://www.markdownguide.org/getting-started/)\)
为了帮助他人在hpm上找到该组件,并更方便的使用它,在组件的根目录中包含一个README文件。 为了帮助他人在hpm上找到该Bundle,并更方便的使用它,在Bundle的根目录中包含一个README文件。
README文件可能包括如何安装,配置和使用组件包中的实例代码说明,以及可能会对用户有所帮助的任何其他信息。 README文件可能包括如何安装,配置和使用Bundle包中的实例代码说明,以及可能会对用户有所帮助的任何其他信息。
每个组件的自述文件将显示在hpm系统的组件详情页面的描述中。 每个Bundle的自述文件将显示在hpm系统的Bundle详情页面的描述中。
### 元数据描述文件<a name="section7107181819406"></a> ### 元数据描述文件<a name="section10956525102613"></a>
bundle.json文件是对当前组件的元数据描述,每个组件中必须包含一个bundle.json文件。 bundle.json文件是对当前Bundle的元数据描述,每个Bundle中必须包含一个bundle.json文件。
``` ```
{ {
...@@ -133,20 +133,20 @@ bundle.json文件是对当前组件的元数据描述,每个组件中必须包 ...@@ -133,20 +133,20 @@ bundle.json文件是对当前组件的元数据描述,每个组件中必须包
bundle.json文件具有如下功能: bundle.json文件具有如下功能:
- name:定义组件的名称,放到组织下, 以@开头,/分割,如:@myorg/mybundle - name:定义Bundle的名称,放到组织下, 以@开头,/分割,如:@myorg/mybundle
- version:定义组件版本号,如1.0.0,需满足semver的标准。 - version:定义Bundle版本号,如1.0.0,需满足semver的标准。
- description:一句话对组件进行简要的描述。 - description:一句话对Bundle进行简要的描述。
- dependencies:定义组件的依赖组件 - dependencies:定义Bundle的依赖Bundle
- envs: 定义组件编译时所需要的参数,包括全局参数以及依赖所需的参数。 - envs: 定义Bundle编译时所需要的参数,包括全局参数以及依赖所需的参数。
- scripts:定义在当前组件下能够执行的命令(如编译,构建,测试,烧录等)。 - scripts:定义在当前Bundle下能够执行的命令(如编译,构建,测试,烧录等)。
- publishAs:定义组件的发布类型(source:源码,binary:二进制,distribution:发行版,code-segment:代码片段)。 - publishAs:定义Bundle的发布类型(source:源码,binary:二进制,distribution:发行版,code-segment:代码片段)。
- segment: 仅针对code-segment类型的组件,定义组件的目标路径(即安装后,组件包中包含的文件复制到的目标路径) - segment: 仅针对code-segment类型的Bundle,定义Bundle的目标路径(即安装后,Bundle包中包含的文件复制到的目标路径)
- dirs:定义发布时打包的目录结构(如头文件)。 - dirs:定义发布时打包的目录结构(如头文件)。
- ram&rom:统计相关信息:预计占用ROM和RAM信息。 - ram&rom:统计相关信息:预计占用ROM和RAM信息。
...@@ -154,11 +154,11 @@ bundle.json文件具有如下功能: ...@@ -154,11 +154,11 @@ bundle.json文件具有如下功能:
- 定义其他扩展信息:作者,主页,代码仓库,许可协议,标签,关键字。 - 定义其他扩展信息:作者,主页,代码仓库,许可协议,标签,关键字。
- 对于发行版类型,还有个base,可以定义继承自的发行版。 - 对于发行版类型,还有个base,可以定义继承自的发行版。
## 组件管理<a name="section32061634104110"></a> ## Bundle管理<a name="section32061634104110"></a>
### 依赖关系<a name="section791115242423"></a> ### 依赖关系<a name="section37361058192610"></a>
生成基础bundle.json以后,需要继续添加组件依赖来实现更复杂的功能。此时需要知道所依赖组件的名称和版本号,并且把它们定义在bundle.json里面的dependencies字段中。 生成基础bundle.json以后,需要继续添加Bundle依赖来实现更复杂的功能。此时需要知道所依赖Bundle的名称和版本号,并且把它们定义在bundle.json里面的dependencies字段中。
``` ```
{ {
...@@ -170,13 +170,13 @@ bundle.json文件具有如下功能: ...@@ -170,13 +170,13 @@ bundle.json文件具有如下功能:
} }
``` ```
上述示例中,my-bundle组件依赖于net 1.0.0组件。在全局安装了 hpm CLI 工具之后,执行如下命令可以从远端仓库获取到依赖: 上述示例中,my-bundleBundle依赖于net 1.0.0Bundle。在全局安装了 hpm CLI 工具之后,执行如下命令可以从远端仓库获取到依赖:
``` ```
hpm install hpm install
``` ```
依赖获取以后,会保存到当前组件根目录下到ohos\_bundles文件夹中。组件以及依赖之间会形成一个依赖关系的树状结构。全局安装了 hpm CLI 工具之后,在组件根目录下执行如下命令: 依赖获取以后,会保存到当前Bundle根目录下到ohos\_bundles文件夹中。Bundle以及依赖之间会形成一个依赖关系的树状结构。全局安装了 hpm CLI 工具之后,在Bundle根目录下执行如下命令:
``` ```
username@server MINGW64 /f/showcase/demo/demo username@server MINGW64 /f/showcase/demo/demo
...@@ -194,22 +194,22 @@ $ hpm list ...@@ -194,22 +194,22 @@ $ hpm list
| | +--@demo/dist_tools@4.0.0 | | +--@demo/dist_tools@4.0.0
``` ```
还可以使用可视化的形式,来查看当前组件的依赖关系,执行如下命令: 还可以使用可视化的形式,来查看当前Bundle的依赖关系,执行如下命令:
``` ```
hpm ui hpm ui
``` ```
会在本地启动一个web服务(默认会打开浏览器并进入项目页),点击侧边栏的项目依赖图标,打开页面,可以看到项目的依赖组件列表,点击右侧按钮切换到树状视图,就可以看到依赖关系的图形化展示\(如下图\) 会在本地启动一个web服务(默认会打开浏览器并进入项目页),点击侧边栏的项目依赖图标,打开页面,可以看到项目的依赖Bundle列表,点击右侧按钮切换到树状视图,就可以看到依赖关系的图形化展示\(如下图\)
**图 1** 组件包依赖关系图<a name="fig4306113315312"></a> **图 1** Bundle包依赖关系图<a name="fig4306113315312"></a>
![](figure/zh-cn_image_0000001173313501.png) ![](figure/zh-cn_image_0000001188040429.png)
### hpm操作命令参考<a name="section1183205411429"></a> ### hpm操作命令参考<a name="section72383420271"></a>
组件的全生命周期管理,可以通过hpm命令工具进行操作,hpm的操作命令如下(详细帮助可以执行 hpm -h学习): Bundle的全生命周期管理,可以通过hpm命令工具进行操作,hpm的操作命令如下(详细帮助可以执行 hpm -h学习):
**表 1** hpm操作命令 **表 1** hpm操作命令
...@@ -246,7 +246,7 @@ hpm ui ...@@ -246,7 +246,7 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p2046811558481"><a name="p2046811558481"></a><a name="p2046811558481"></a>hpm init bundle</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p2046811558481"><a name="p2046811558481"></a><a name="p2046811558481"></a>hpm init bundle</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1646818557481"><a name="p1646818557481"></a><a name="p1646818557481"></a>创建组件工程。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1646818557481"><a name="p1646818557481"></a><a name="p1646818557481"></a>创建Bundle工程。</p>
</td> </td>
</tr> </tr>
<tr id="row351184593713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18991313496"><a name="p18991313496"></a><a name="p18991313496"></a>hpm init -t template</p> <tr id="row351184593713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18991313496"><a name="p18991313496"></a><a name="p18991313496"></a>hpm init -t template</p>
...@@ -259,12 +259,12 @@ hpm ui ...@@ -259,12 +259,12 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p8896182914913"><a name="p8896182914913"></a><a name="p8896182914913"></a>hpm install 或hpm i</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p8896182914913"><a name="p8896182914913"></a><a name="p8896182914913"></a>hpm install 或hpm i</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1289692919493"><a name="p1289692919493"></a><a name="p1289692919493"></a>安装bundle.json中依赖的组件</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1289692919493"><a name="p1289692919493"></a><a name="p1289692919493"></a>安装bundle.json中依赖的Bundle</p>
</td> </td>
</tr> </tr>
<tr id="row15511194563712"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17917436134911"><a name="p17917436134911"></a><a name="p17917436134911"></a>hpm install bundle@version</p> <tr id="row15511194563712"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17917436134911"><a name="p17917436134911"></a><a name="p17917436134911"></a>hpm install bundle@version</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1891723611494"><a name="p1891723611494"></a><a name="p1891723611494"></a>安装指定组件版本。</p> <td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1891723611494"><a name="p1891723611494"></a><a name="p1891723611494"></a>安装指定Bundle版本。</p>
</td> </td>
</tr> </tr>
<tr id="row21051110155011"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1630384435010"><a name="p1630384435010"></a><a name="p1630384435010"></a>卸载</p> <tr id="row21051110155011"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1630384435010"><a name="p1630384435010"></a><a name="p1630384435010"></a>卸载</p>
...@@ -272,12 +272,12 @@ hpm ui ...@@ -272,12 +272,12 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p288195017502"><a name="p288195017502"></a><a name="p288195017502"></a>hpm uninstall bundle</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p288195017502"><a name="p288195017502"></a><a name="p288195017502"></a>hpm uninstall bundle</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p2088450165014"><a name="p2088450165014"></a><a name="p2088450165014"></a>删除depedencies依赖的组件</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p2088450165014"><a name="p2088450165014"></a><a name="p2088450165014"></a>删除depedencies依赖的Bundle</p>
</td> </td>
</tr> </tr>
<tr id="row73341617507"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p934161613508"><a name="p934161613508"></a><a name="p934161613508"></a>hpm remove 或hpm rm bundlename</p> <tr id="row73341617507"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p934161613508"><a name="p934161613508"></a><a name="p934161613508"></a>hpm remove 或hpm rm bundlename</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p234111685016"><a name="p234111685016"></a><a name="p234111685016"></a>删除depedencies依赖的组件</p> <td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p234111685016"><a name="p234111685016"></a><a name="p234111685016"></a>删除depedencies依赖的Bundle</p>
</td> </td>
</tr> </tr>
<tr id="row166449214501"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p8645421125016"><a name="p8645421125016"></a><a name="p8645421125016"></a>查看</p> <tr id="row166449214501"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p8645421125016"><a name="p8645421125016"></a><a name="p8645421125016"></a>查看</p>
...@@ -285,19 +285,19 @@ hpm ui ...@@ -285,19 +285,19 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p679412535211"><a name="p679412535211"></a><a name="p679412535211"></a>hpm list 或者 hpm ls</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p679412535211"><a name="p679412535211"></a><a name="p679412535211"></a>hpm list 或者 hpm ls</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p07941451526"><a name="p07941451526"></a><a name="p07941451526"></a>显示当前组件/发行版所有的组件树。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p07941451526"><a name="p07941451526"></a><a name="p07941451526"></a>显示当前Bundle/发行版所有的Bundle树。</p>
</td> </td>
</tr> </tr>
<tr id="row1764552105017"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p035818131525"><a name="p035818131525"></a><a name="p035818131525"></a>hpm dependencies</p> <tr id="row1764552105017"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p035818131525"><a name="p035818131525"></a><a name="p035818131525"></a>hpm dependencies</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p19358413135217"><a name="p19358413135217"></a><a name="p19358413135217"></a>生成当前组件/发行版依赖关系数据(在hpm ui也集成了该命令的调用,可以图形化的展示)</p> <td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p19358413135217"><a name="p19358413135217"></a><a name="p19358413135217"></a>生成当前Bundle/发行版依赖关系数据(在hpm ui也集成了该命令的调用,可以图形化的展示)</p>
</td> </td>
</tr> </tr>
<tr id="row1553428145020"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p353202845014"><a name="p353202845014"></a><a name="p353202845014"></a>搜索</p> <tr id="row1553428145020"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p353202845014"><a name="p353202845014"></a><a name="p353202845014"></a>搜索</p>
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1423903005211"><a name="p1423903005211"></a><a name="p1423903005211"></a>hpm search name</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1423903005211"><a name="p1423903005211"></a><a name="p1423903005211"></a>hpm search name</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p17239163018524"><a name="p17239163018524"></a><a name="p17239163018524"></a>搜索组件,--json,可以以json格式输出 -type 可以设置搜索组件的类型,包括bundle,distribution,code-segment三种。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p17239163018524"><a name="p17239163018524"></a><a name="p17239163018524"></a>搜索Bundle,--json,可以以json格式输出 -type 可以设置搜索Bundle的类型,包括bundle,distribution,code-segment三种。</p>
</td> </td>
</tr> </tr>
<tr id="row135482855018"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p38201311174016"><a name="p38201311174016"></a><a name="p38201311174016"></a>设置hpm配置项</p> <tr id="row135482855018"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p38201311174016"><a name="p38201311174016"></a><a name="p38201311174016"></a>设置hpm配置项</p>
...@@ -317,12 +317,12 @@ hpm ui ...@@ -317,12 +317,12 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1127981305516"><a name="p1127981305516"></a><a name="p1127981305516"></a>hpm update</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1127981305516"><a name="p1127981305516"></a><a name="p1127981305516"></a>hpm update</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p427971311555"><a name="p427971311555"></a><a name="p427971311555"></a>更新当前组件依赖的组件的版本。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p427971311555"><a name="p427971311555"></a><a name="p427971311555"></a>更新当前Bundle依赖的Bundle的版本。</p>
</td> </td>
</tr> </tr>
<tr id="row692503385015"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p627961317557"><a name="p627961317557"></a><a name="p627961317557"></a>hpm check-update</p> <tr id="row692503385015"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p627961317557"><a name="p627961317557"></a><a name="p627961317557"></a>hpm check-update</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p3279121315557"><a name="p3279121315557"></a><a name="p3279121315557"></a>检查依赖的组件版本是否有更新。</p> <td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p3279121315557"><a name="p3279121315557"></a><a name="p3279121315557"></a>检查依赖的Bundle版本是否有更新。</p>
</td> </td>
</tr> </tr>
<tr id="row1925173385019"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p2925133305014"><a name="p2925133305014"></a><a name="p2925133305014"></a>编译</p> <tr id="row1925173385019"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p2925133305014"><a name="p2925133305014"></a><a name="p2925133305014"></a>编译</p>
...@@ -330,7 +330,7 @@ hpm ui ...@@ -330,7 +330,7 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p2058919655611"><a name="p2058919655611"></a><a name="p2058919655611"></a>hpm build</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p2058919655611"><a name="p2058919655611"></a><a name="p2058919655611"></a>hpm build</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1958920625619"><a name="p1958920625619"></a><a name="p1958920625619"></a>编译组件/发行版。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1958920625619"><a name="p1958920625619"></a><a name="p1958920625619"></a>编译Bundle/发行版。</p>
</td> </td>
</tr> </tr>
<tr id="row18925233115016"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1958912618563"><a name="p1958912618563"></a><a name="p1958912618563"></a>hpm dist</p> <tr id="row18925233115016"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1958912618563"><a name="p1958912618563"></a><a name="p1958912618563"></a>hpm dist</p>
...@@ -342,7 +342,7 @@ hpm ui ...@@ -342,7 +342,7 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1785810219574"><a name="p1785810219574"></a><a name="p1785810219574"></a>hpm pack</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1785810219574"><a name="p1785810219574"></a><a name="p1785810219574"></a>hpm pack</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1485872165714"><a name="p1485872165714"></a><a name="p1485872165714"></a>本地组件打包依赖。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1485872165714"><a name="p1485872165714"></a><a name="p1485872165714"></a>本地Bundle打包依赖。</p>
</td> </td>
</tr> </tr>
<tr id="row1592653305016"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p84251810125716"><a name="p84251810125716"></a><a name="p84251810125716"></a>烧录</p> <tr id="row1592653305016"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p84251810125716"><a name="p84251810125716"></a><a name="p84251810125716"></a>烧录</p>
...@@ -356,7 +356,7 @@ hpm ui ...@@ -356,7 +356,7 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p198081455105712"><a name="p198081455105712"></a><a name="p198081455105712"></a>hpm publish</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p198081455105712"><a name="p198081455105712"></a><a name="p198081455105712"></a>hpm publish</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p880885516574"><a name="p880885516574"></a><a name="p880885516574"></a>发布组件,发布的组件在仓库中必须唯一,且版本唯一(需要账号登录)。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p880885516574"><a name="p880885516574"></a><a name="p880885516574"></a>发布Bundle,发布的Bundle在仓库中必须唯一,且版本唯一(需要账号登录)。</p>
</td> </td>
</tr> </tr>
<tr id="row5926333135014"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p39267336504"><a name="p39267336504"></a><a name="p39267336504"></a>执行扩展命令</p> <tr id="row5926333135014"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p39267336504"><a name="p39267336504"></a><a name="p39267336504"></a>执行扩展命令</p>
...@@ -398,49 +398,49 @@ hpm ui ...@@ -398,49 +398,49 @@ hpm ui
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p6778236153710"><a name="p6778236153710"></a><a name="p6778236153710"></a>hpm code clean|restore</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p6778236153710"><a name="p6778236153710"></a><a name="p6778236153710"></a>hpm code clean|restore</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1277843613376"><a name="p1277843613376"></a><a name="p1277843613376"></a>针对依赖的代码段(code-segment)组件,执行清理或还原操作(即根据segment.destPath执行拷贝/删除操作)</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1277843613376"><a name="p1277843613376"></a><a name="p1277843613376"></a>针对依赖的代码段(code-segment)Bundle,执行清理或还原操作(即根据segment.destPath执行拷贝/删除操作)</p>
</td> </td>
</tr> </tr>
<tr id="row122864915206"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1529124912207"><a name="p1529124912207"></a><a name="p1529124912207"></a>生成秘钥</p> <tr id="row122864915206"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1529124912207"><a name="p1529124912207"></a><a name="p1529124912207"></a>生成秘钥</p>
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p9291492204"><a name="p9291492204"></a><a name="p9291492204"></a>hpm gen-keys</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p9291492204"><a name="p9291492204"></a><a name="p9291492204"></a>hpm gen-keys</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p429249182012"><a name="p429249182012"></a><a name="p429249182012"></a>生成公钥/私钥对,将公钥配置到HPM服务端,可以实现hpm-cli 免密登录,发布组件</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p429249182012"><a name="p429249182012"></a><a name="p429249182012"></a>生成公钥/私钥对,将公钥配置到HPM服务端,可以实现hpm-cli 免密登录,发布Bundle</p>
</td> </td>
</tr> </tr>
<tr id="row3556450102011"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p35561850172015"><a name="p35561850172015"></a><a name="p35561850172015"></a>生成第三方开源说明</p> <tr id="row3556450102011"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p35561850172015"><a name="p35561850172015"></a><a name="p35561850172015"></a>生成第三方开源说明</p>
</td> </td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1155625018209"><a name="p1155625018209"></a><a name="p1155625018209"></a>hpm gen-notice</p> <td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1155625018209"><a name="p1155625018209"></a><a name="p1155625018209"></a>hpm gen-notice</p>
</td> </td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p11557175015205"><a name="p11557175015205"></a><a name="p11557175015205"></a>根据每个组件的说明,生成一份合并后的第三方开源说明的合并文件。</p> <td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p11557175015205"><a name="p11557175015205"></a><a name="p11557175015205"></a>根据每个Bundle的说明,生成一份合并后的第三方开源说明的合并文件。</p>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
## 组件版本<a name="section12612142864316"></a> ## Bundle版本<a name="section162921336288"></a>
### 版本号命名规范<a name="section1487612416432"></a> ### 版本号命名规范<a name="section176561816172819"></a>
名称需要为全小写字母,中间可以使用中划线或者下划线分隔。比如 "bundle", "my\_bundle"。 名称需要为全小写字母,中间可以使用中划线或者下划线分隔。比如 "bundle", "my\_bundle"。
版本号的格式为 "主版本号.次版本号.修订号" 或 "主版本号.次版本号.修订号-先行版本号",比如 "1.0.0", "1.0.0-beta",详细规格可以参考 [https://semver.org](https://semver.org/) 版本号的格式为 "主版本号.次版本号.修订号" 或 "主版本号.次版本号.修订号-先行版本号",比如 "1.0.0", "1.0.0-beta",详细规格可以参考 [https://semver.org](https://semver.org/)
### 版本发布<a name="section1548171014440"></a> ### 版本发布<a name="section8683417284"></a>
为了使组件能被其他开发者使用,组件需要上传到远端仓库。组件上传使用如下命令: 为了使Bundle能被其他开发者使用,Bundle需要上传到远端仓库。Bundle上传使用如下命令:
``` ```
hpm publish hpm publish
``` ```
命令执行以后,系统会对的整个依赖关系进行检查,下载缺失依赖组件。依赖检查完成后,如果发布类型为binary,系统会对整个组件进行编译,生成二进制文件,然后打包上传。如果使其他上传类型,则直接根据定义的打包规则进行打包,然后上传。 命令执行以后,系统会对的整个依赖关系进行检查,下载缺失依赖Bundle。依赖检查完成后,如果发布类型为binary,系统会对整个Bundle进行编译,生成二进制文件,然后打包上传。如果使其他上传类型,则直接根据定义的打包规则进行打包,然后上传。
注意:发布组件需要用户账号登录,需要先拥有hpm的系统账号后,并注册组织,申请组织认证通过后,才拥有发布的权限。 注意:发布Bundle需要用户账号登录,需要先拥有hpm的系统账号后,并注册组织,申请组织认证通过后,才拥有发布的权限。
## 发行版<a name="section1264139114413"></a> ## 发行版<a name="section243845052819"></a>
发行版通常是将一系列组件组合起来,成为编译可以运行的OpenHarmony解决方案镜像,里面包含了多个依赖的组件,以及脚本,用于描述如何完整编译、链接这些组件 发行版通常是将一系列Bundle组合起来,成为编译可以运行的OpenHarmony解决方案镜像,里面包含了多个依赖的Bundle,以及脚本,用于描述如何完整编译、链接这些Bundle
发行版本身通常不需要包含功能实现代码,仅包含bundle.json描述(设置publishAs为distribution)和一些编译脚本组成。 发行版本身通常不需要包含功能实现代码,仅包含bundle.json描述(设置publishAs为distribution)和一些编译脚本组成。
...@@ -472,9 +472,9 @@ hpm dist ...@@ -472,9 +472,9 @@ hpm dist
} }
``` ```
上述定义表明当前组件继承自发行版组件dist-wifi-iot 1.0.0。 上述定义表明当前Bundle继承自发行版Bundledist-wifi-iot 1.0.0。
发行版由很多的依赖组件组成,通过bundle.json中的dependencies段来描述,有些依赖是必须的,有些依赖则是根据可以需求增加或删除的。bundle.json中名称前带有?的依赖表示可选依赖,继承它的发行版,可以移除掉该可选组件,再增加别的组件进行替换。 发行版由很多的依赖Bundle组成,通过bundle.json中的dependencies段来描述,有些依赖是必须的,有些依赖则是根据可以需求增加或删除的。bundle.json中名称前带有?的依赖表示可选依赖,继承它的发行版,可以移除掉该可选Bundle,再增加别的Bundle进行替换。
``` ```
{ {
...@@ -492,13 +492,13 @@ hpm dist ...@@ -492,13 +492,13 @@ hpm dist
} }
``` ```
依赖被移除后,就不会参入组件的构建过程。只有标记为可选的依赖才能够被移除,强行移除未被标记的依赖会出现错误提示。 依赖被移除后,就不会参入Bundle的构建过程。只有标记为可选的依赖才能够被移除,强行移除未被标记的依赖会出现错误提示。
## 环境变量说明<a name="section15352105174512"></a> ## 环境变量说明<a name="section19567181517299"></a>
组件在编译的过程中需要依赖系统提供的环境变量来自定义输出,链接所需二进制文件等等。这里提出的环境变量均指根据需求把所需变量注入脚本执行的上下文中。所以在脚本中可以直接获取到变量的值。下面介绍当前系统存在的几种环境变量。 Bundle在编译的过程中需要依赖系统提供的环境变量来自定义输出,链接所需二进制文件等等。这里提出的环境变量均指根据需求把所需变量注入脚本执行的上下文中。所以在脚本中可以直接获取到变量的值。下面介绍当前系统存在的几种环境变量。
全局变量由bundle.json中的envs属性来定义。整个组件中的依赖都可以获取到全局变量定义的值。 全局变量由bundle.json中的envs属性来定义。整个Bundle中的依赖都可以获取到全局变量定义的值。
``` ```
{ {
...@@ -508,7 +508,7 @@ hpm dist ...@@ -508,7 +508,7 @@ hpm dist
} }
``` ```
不同组件在引入依赖的过程中可以传入不同的参数,从而使依赖的编译可以满足当前组件的需求。依赖中定义的参数可以在对应依赖脚本执行的上下文中获取到。 不同Bundle在引入依赖的过程中可以传入不同的参数,从而使依赖的编译可以满足当前Bundle的需求。依赖中定义的参数可以在对应依赖脚本执行的上下文中获取到。
``` ```
{ {
...@@ -521,7 +521,7 @@ hpm dist ...@@ -521,7 +521,7 @@ hpm dist
} }
``` ```
组件在链接二进制文件的时候,需要知道二进制文件在依赖中的路径,所以依赖的路径会作为环境变量传入编译组件中。 Bundle在链接二进制文件的时候,需要知道二进制文件在依赖中的路径,所以依赖的路径会作为环境变量传入编译Bundle中。
传入的环境变量的格式为DEP\_BundleName,BundleName为依赖的名称,例如 DEP\_first\_bundle。 传入的环境变量的格式为DEP\_BundleName,BundleName为依赖的名称,例如 DEP\_first\_bundle。
...@@ -545,5 +545,5 @@ hpm dist ...@@ -545,5 +545,5 @@ hpm dist
系统中存在两个固定环境变量: 系统中存在两个固定环境变量:
- DEP\_OHOS\_BUNDLES:表示ohos\_bundles文件夹所在的路径。 - DEP\_OHOS\_BUNDLES:表示ohos\_bundles文件夹所在的路径。
- DEP\_BUNDLE\_BASE:表示最外层组件的路径。 - DEP\_BUNDLE\_BASE:表示最外层Bundle的路径。
...@@ -26,7 +26,7 @@ OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及 ...@@ -26,7 +26,7 @@ OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及
## 源码获取概述<a name="section12763342204"></a> ## 源码获取概述<a name="section12763342204"></a>
本文档将介绍如何获取OpenHarmony源码并说明OpenHarmony的源码目录结构。OpenHarmony的代码以[组件](../bundles/bundles-standard-rules.md)的形式开放,开发者可以通过如下其中一种方式获取: 本文档将介绍如何获取OpenHarmony源码并说明OpenHarmony的源码目录结构。OpenHarmony的代码以[组件](../bundles/oem_bundle_standard_des.md)的形式开放,开发者可以通过如下其中一种方式获取:
- **获取方式1**:从代码仓库获取。通过repo或git工具从代码仓库中下载,此方式可获取最新代码。 - **获取方式1**:从代码仓库获取。通过repo或git工具从代码仓库中下载,此方式可获取最新代码。
- **获取方式2**:通过HPM包管理器获取。在[HPM](https://hpm.harmonyos.com)网站,查找满足需求的开源发行版,直接下载(或者定制后下载),再通过hpm-cli命令工具将所需的组件及工具链下载、安装到本地。 - **获取方式2**:通过HPM包管理器获取。在[HPM](https://hpm.harmonyos.com)网站,查找满足需求的开源发行版,直接下载(或者定制后下载),再通过hpm-cli命令工具将所需的组件及工具链下载、安装到本地。
......
# 内核使用指南 # 内核使用指南
- [轻量和小型系统内核](kernel-lite.md) - [轻量系统内核](kernel-mini.md)
- [内核概述](kernel-mini-overview.md)
- [轻量系统内核](kernel-lite-mini.md) - [基础内核](kernel-mini-basic.md)
- [内核概述](kernel-lite-mini-m.md) - [中断管理](kernel-mini-basic-interrupt.md)
- [基础内核](kernel-lite-mini-basic.md) - [基本概念](kernel-mini-basic-interrupt-concept.md)
- [中断管理](kernel-lite-mini-basic-interrupt.md) - [开发指导](kernel-mini-basic-interrupt-guide.md)
- [基本概念](kernel-lite-mini-basic-interrupt-concept.md) - [任务管理](kernel-mini-basic-task.md)
- [开发指导](kernel-lite-mini-basic-interrupt-guide.md) - [基本概念](kernel-mini-basic-task-basic.md)
- [任务管理](kernel-lite-mini-basic-task.md) - [开发指导](kernel-mini-basic-task-guide.md)
- [基本概念](kernel-lite-mini-basic-task-basic.md) - [内存管理](kernel-mini-basic-memory.md)
- [开发指导](kernel-lite-mini-basic-task-guide.md) - [基本概念](kernel-mini-basic-memory-basic.md)
- [内存管理](kernel-lite-mini-basic-memory.md) - [静态内存](kernel-mini-basic-memory-static.md)
- [基本概念](kernel-lite-mini-basic-memory-basic.md) - [动态内存](kernel-mini-basic-memory-dynamic.md)
- [静态内存](kernel-lite-mini-basic-memory-static.md) - [内核通信机制](kernel-mini-basic-ipc.md)
- [动态内存](kernel-lite-mini-basic-memory-dynamic.md) - [事件](kernel-mini-basic-ipc-event.md)
- [内核通信机制](kernel-lite-mini-basic-ipc.md) - [基本概念](kernel-mini-basic-ipc-event-basic.md)
- [事件](kernel-lite-mini-basic-ipc-event.md) - [开发指导](kernel-mini-basic-ipc-event-guide.md)
- [基本概念](kernel-lite-mini-basic-ipc-event-guide.md) - [互斥锁](kernel-mini-basic-ipc-mutex.md)
- [开发指导](kernel-lite-mini-basic-ipc-event-basic.md) - [基本概念](kernel-mini-basic-ipc-mutex-basic.md)
- [互斥锁](kernel-lite-mini-basic-ipc-mutex.md) - [开发指导](kernel-mini-basic-ipc-mutex-guide.md)
- [基本概念](kernel-lite-mini-basic-ipc-mutex-basic.md) - [消息队列](kernel-mini-basic-ipc-queue.md)
- [开发指导](kernel-lite-mini-basic-ipc-mutex-guide.md) - [基本概念](kernel-mini-basic-ipc-queue-basic.md)
- [消息队列](kernel-lite-mini-basic-ipc-queue.md) - [开发指导](kernel-mini-basic-ipc-queue-guide.md)
- [基本概念](kernel-lite-mini-basic-ipc-queue-basic.md) - [信号量](kernel-mini-basic-ipc-sem.md)
- [开发指导](kernel-lite-mini-basic-ipc-queue-guide.md) - [基本概念](kernel-mini-basic-ipc-sem-basic.md)
- [信号量](kernel-lite-mini-basic-ipc-sem.md) - [开发指导](kernel-mini-basic-ipc-sem-guide.md)
- [基本概念](kernel-lite-mini-basic-ipc-sem-basic.md) - [时间管理](kernel-basic-mini-time.md)
- [开发指导](kernel-lite-mini-basic-ipc-sem-guide.md) - [基本概念](kernel-mini-basic-time-basic.md)
- [时间管理](kernel-lite-basic-mini-time.md) - [开发指导](kernel-mini-basic-time-guide.md)
- [基本概念](kernel-lite-mini-basic-time-basic.md) - [软件定时器](kernel-mini-basic-soft.md)
- [开发指导](kernel-lite-mini-basic-time-guide.md) - [基本概念](kernel-mini-basic-soft-basic.md)
- [软件定时器](kernel-lite-mini-basic-soft.md) - [开发指导](kernel-mini-basic-soft-guide.md)
- [基本概念](kernel-lite-mini-basic-soft-basic.md) - [扩展组件](kernel-mini-extend.md)
- [开发指导](kernel-lite-mini-basic-soft-guide.md) - [C++支持](kernel-mini-extend-support.md)
- [扩展组件](kernel-lite-mini-extend.md) - [CPU占用率](kernel-mini-extend-cpup.md)
- [C++支持](kernel-lite-mini-extend-support.md) - [基本概念](kernel-mini-extend-cpup-basic.md)
- [CPU占用率](kernel-lite-mini-extend-cpup.md) - [开发指导](kernel-mini-extend-cpup-guide.md)
- [基本概念](kernel-lite-mini-extend-cpup-basic.md) - [动态加载](kernel-mini-extend-dynamic-loading.md)
- [开发指导](kernel-lite-mini-extend-cpup-guide.md) - [基本概念](kernel-mini-extend-dynamic-loading-basic.md)
- [文件系统](kernel-lite-mini-extend-file.md) - [开发指导](kernel-mini-extend-dynamic-loading-guide.md)
- [FAT](kernel-lite-mini-extend-file-fat.md) - [文件系统](kernel-mini-extend-file.md)
- [LittleFS](kernel-lite-mini-extend-file-lit.md) - [FAT](kernel-mini-extend-file-fat.md)
- [基本概念](kernel-lite-mini-extend-file-lit-basic.md) - [LittleFS](kernel-mini-extend-file-lit.md)
- [开发指导](kernel-lite-mini-extend-file-lit-guide.md) - [基本概念](kernel-mini-extend-file-littlefs-basic.md)
- [内核调测](kernel-lite-mini-inner.md) - [开发指导](kernel-mini-extend-file-littlefs-guide.md)
- [内存调测](kernel-lite-mini-inner-debug.md) - [内核调测](kernel-memory-inner.md)
- [内存信息统计](kernel-lite-mini-inner-debug-mes.md) - [内存调测](kernel-mini-memory-debug.md)
- [内存泄漏检测](kernel-lite-mini-inner-debug-det.md) - [内存信息统计](kernel-mini-memory-debug-mes.md)
- [踩内存检测](kernel-lite-mini-inner-debug-cet.md) - [内存泄漏检测](kernel-mini-imemory-debug-det.md)
- [异常调测](kernel-lite-mini-inner-exception.md) - [踩内存检测](kernel-mini-memory-debug-cet.md)
- [Trace调测](kernel-lite-mini-inner-trace.md) - [异常调测](kernel-mini-memory-exception.md)
- [附录](kernel-lite-mini-app.md) - [Trace调测](kernel-mini-memory-trace.md)
- [内核编码规范](kernel-lite-mini-app-code.md) - [附录](kernel-mini-app.md)
- [基本数据结构](kernel-lite-mini-app-data.md) - [内核编码规范](kernel-mini-appx-code.md)
- [双向链表](kernel-lite-mini-app-data-list.md) - [基本数据结构](kernel-mini-appx-data.md)
- [标准库支持](kernel-lite-mini-app-lib.md) - [双向链表](kernel-mini-appx-data-list.md)
- [CMSIS支持](kernel-lite-mini-app-lib-cmsis.md) - [标准库支持](kernel-mini-appx-lib.md)
- [POSIX支持](kernel-lite-mini-app-lib-posix.md) - [CMSIS支持](kernel-mini-appx-lib-cmsis.md)
- [POSIX支持](kernel-mini-appx-lib-posix.md)
- [小型系统内核](kernel-lite-small.md) - [小型系统内核](kernel-small.md)
- [基础内核](kernel-lite-small-basic.md) - [内核概述](kernel-small-overview.md)
- [进程](kernel-lite-small-process.md) - [内核启动](kernel-small-start.md)
- [线程](kernel-lite-small-thread.md) - [内核态启动](kernel-small-start-kernel.md)
- [内存](kernel-lite-small-memory.md) - [用户态启动](kernel-small-start-user.md)
- [网络](kernel-lite-small-net.md) - [基础内核](kernel-small-basics.md)
- [中断及异常处理](kernel-small-basic-interrupt.md)
- [文件系统](kernel-lite-small-file.md) - [进程管理](kernel-small-basic-process.md)
- [VFS](kernel-lite-small-file-vfs.md) - [进程](kernel-small-basic-process-process.md)
- [NFS](kernel-lite-small-file-nfs.md) - [线程](kernel-small-basic-process-thread.md)
- [RAMFS](kernel-lite-small-file-ramfs.md) - [调度器](kernel-small-basic-process-scheduler.md)
- [FAT](kernel-lite-small-file-fat.md) - [内存管理](kernel-small-basic-memory.md)
- [JFFS2](kernel-lite-small-file-jffs.md) - [堆内存管理](kernel-small-basic-memory-heap.md)
- [物理内存管理](kernel-small-basic-memory-physical.md)
- [标准库](kernel-lite-small-lib.md) - [虚拟内存管理](kernel-small-basic-memory-virtual.md)
- [标准库](kernel-lite-small-lib-standard.md) - [虚实映射](kernel-small-basic-inner-reflect.md)
- [与Linux标准库的差异](kernel-lite-small-lib-differ.md) - [内核通信机制](kernel-small-basic-trans.md)
- [事件](kernel-small-basic-trans-event.md)
- [调测](kernel-lite-small-shell.md) - [信号量](kernel-small-basic-trans-semaphore.md)
- [Shell介绍](kernel-lite-small-shell-des.md) - [互斥锁](kernel-small-basic-trans-mutex.md)
- [Shell命令开发指导](kernel-lite-small-shell-guide.md) - [消息队列](kernel-small-basic-trans-queue.md)
- [Shell命令编程实例](kernel-lite-small-shell-sample.md) - [读写锁](kernel-small-basic-trans-rwlock.md)
- [Shell命令使用详解](kernel-lite-small-shell-cmd.md) - [用户态快速互斥锁](kernel-small-basic-trans-user-mutex.md)
- [系统命令](kernel-lite-small-shell-cmd-sys.md) - [信号](kernel-small-basic-trans-user-signal.md)
- [cpup](kernel-lite-small-shell-cmd-sys-cpup.md) - [时间管理](kernel-small-basic-time.md)
- [date](kernel-lite-small-shell-cmd-sys-date.md) - [软件定时器](kernel-small-basic-softtimer.md)
- [dmesg](kernel-lite-small-shell-cmd-sys-demsg.md) - [原子操作](kernel-small-basic-atomic.md)
- [exec](kernel-lite-small-shell-cmd-sys-exec.md) - [扩展组件](kernel-small-bundles.md)
- [free](kernel-lite-small-shell-cmd-sys-free.md) - [系统调用](kernel-small-bundles-system.md)
- [help](kernel-lite-small-shell-cmd-sys-help.md) - [动态加载与链接](kernel-small-bundles-linking.md)
- [hwi](kernel-lite-small-shell-cmd-sys-hwi.md) - [虚拟动态共享库](kernel-small-bundles-share.md)
- [kill](kernel-lite-small-shell-cmd-sys-kill.md) - [轻量级进程间通信](kernel-small-bundles-ipc.md)
- [log](kernel-lite-small-shell-cmd-sys-log.md) - [文件系统](kernel-small-bundles-fs.md)
- [memcheck](kernel-lite-small-shell-cmd-sys-mem.md) - [虚拟文件系统](kernel-small-bundles-fs-virtual.md)
- [oom](kernel-lite-small-shell-cmd-sys-oom.md) - [支持的文件系统](kernel-small-bundles-fs-support.md)
- [pmm](kernel-lite-small-shell-cmd-sys-pmm.md) - [FAT](kernel-small-bundles-fs-support-fat.md)
- [reset](kernel-lite-small-shell-cmd-sys-reset.md) - [JFFS2](kernel-small-bundles-fs-support-jffs2.md)
- [sem](kernel-lite-small-shell-cmd-sys-sem.md) - [NFS](kernel-small-bundles-fs-support-nfs.md)
- [stack](kernel-lite-small-shell-cmd-sys-stack.md) - [Ramfs](kernel-small-bundles-fs-support-ramfs.md)
- [su](kernel-lite-small-shell-cmd-sys-su.md) - [Procfs](kernel-small-bundles-fs-support-procfs.md)
- [swtmr](kernel-lite-small-shell-cmd-sys-swymr.md) - [适配新的文件系统](kernel-small-bundles-fs-new.md)
- [systeminfo](kernel-lite-small-shell-cmd-sys-sys.md) - [调测与工具](kernel-small-debug.md)
- [task](kernel-lite-small-shell-cmd-sys-task.md) - [Shell](kernel-small-debug-shell.md)
- [uname](kernel-lite-small-shell-cmd-sys-uname.md) - [Shell介绍](kernel-small-debug-shell-overview.md)
- [vmm](kernel-lite-small-shell-cmd-sys-vmm.md) - [Shell命令开发指导](kernel-small-debug-shell-guide.md)
- [watch](kernel-lite-small-shell-cmd-sys-watch.md) - [Shell命令编程实例](kernel-small-debug-shell-build.md)
- [Shell命令使用详解](kernel-small-debug-shell-details.md)
- [文件命令](kernel-lite-small-shell-cmd-file.md) - [系统命令](kernel-small-debug-shell-cmd.md)
- [cat](kernel-lite-small-shell-cmd-file-cat.md) - [cpup](kernel-small-debug-shell-cmd-cpup.md)
- [cd](kernel-lite-small-shell-cmd-file-cd.md) - [date](kernel-small-debug-shell-cmd-date.md)
- [chgrp](kernel-lite-small-shell-cmd-file-chgrp.md) - [dmesg](kernel-small-debug-shell-cmd-dmesg.md)
- [chmod](kernel-lite-small-shell-cmd-file-chmod.md) - [exec](kernel-small-debug-shell-cmd-exec.md)
- [chown](kernel-lite-small-shell-cmd-file-chown.md) - [free](kernel-small-debug-shell-cmd-free.md)
- [cp](kernel-lite-small-shell-cmd-file-cp.md) - [help](kernel-small-debug-shell-cmd-help.md)
- [format](kernel-lite-small-shell-cmd-file-format.md) - [hwi](kernel-small-debug-shell-cmd-hwi.md)
- [ls](kernel-lite-small-shell-cmd-file-is.md) - [kill](kernel-small-debug-shell-cmd-kill.md)
- [lsfd](kernel-lite-small-shell-cmd-file-isfd.md) - [log](kernel-small-debug-shell-cmd-log.md)
- [mkdir](kernel-lite-small-shell-cmd-file-mkdir.md) - [memcheck](kernel-small-debug-shell-cmd-memcheck.md)
- [mount](kernel-lite-small-shell-cmd-file-mount.md) - [oom](kernel-small-debug-shell-cmd-oom.md)
- [partinfo](kernel-lite-small-shell-cmd-file-part.md) - [pmm](kernel-small-debug-shell-cmd-pmm.md)
- [partition](kernel-lite-small-shell-cmd-file-partion.md) - [reset](kernel-small-debug-shell-cmd-reset.md)
- [pwd](kernel-lite-small-shell-cmd-file-pwd.md) - [sem](kernel-small-debug-shell-cmd-sem.md)
- [rm](kernel-lite-small-shell-cmd-file-rm.md) - [stack](kernel-small-debug-shell-cmd-stack.md)
- [rmdir](kernel-lite-small-shell-cmd-file-rmdir.md) - [su](kernel-small-debug-shell-cmd-su.md)
- [statfs](kernel-lite-small-shell-cmd-file-sta.md) - [swtmr](kernel-small-debug-shell-cmd-swtmr.md)
- [sync](kernel-lite-small-shell-cmd-file-sync.md) - [systeminfo](kernel-small-debug-shell-cmd-sysinfo.md)
- [touch](kernel-lite-small-shell-cmd-file-touch.md) - [task](kernel-small-debug-shell-cmd-task.md)
- [writeproc](kernel-lite-small-shell-cmd-file-write.md) - [uname](kernel-small-debug-shell-cmd-uname.md)
- [umount](kernel-lite-small-shell-cmd-file-umount.md) - [vmm](kernel-small-debug-shell-cmd-vmm.md)
- [watch](kernel-small-debug-shell-cmd-watch.md)
- [网络命令](kernel-lite-small-shell-cmd-net.md) - [文件命令](kernel-small-debug-shell-file.md)
- [arp](kernel-lite-small-shell-cmd-net-arp.md) - [cat](kernel-small-debug-shell-file-cat.md)
- [dhclient](kernel-lite-small-shell-cmd-net-dh.md) - [cd](kernel-small-debug-shell-file-cd.md)
- [dns](kernel-lite-small-shell-cmd-net-dns.md) - [chgrp](kernel-small-debug-shell-file-chgrp.md)
- [ifconfig](kernel-lite-small-shell-cmd-net-ipc.md) - [chmod](kernel-small-debug-shell-file-chmod.md)
- [ipdebug](kernel-lite-small-shell-cmd-net-ipd.md) - [chown](kernel-small-debug-shell-file-chown.md)
- [netstat](kernel-lite-small-shell-cmd-net-net.md) - [cp](kernel-small-debug-shell-file-cp.md)
- [ntpdate](kernel-lite-small-shell-cmd-net-ntp.md) - [format](kernel-small-debug-shell-file-format.md)
- [ping](kernel-lite-small-shell-cmd-net-ping.md) - [ls](kernel-small-debug-shell-file-ls.md)
- [ping6](kernel-lite-small-shell-cmd-net-ping6.md) - [lsfd](kernel-small-debug-shell-file-lsfd.md)
- [telnet](kernel-lite-small-shell-cmd-net-tel.md) - [mkdir](kernel-small-debug-shell-file-mkdir.md)
- [tftp](kernel-lite-small-shell-cmd-net-tftp.md) - [mount](kernel-small-debug-shell-file-mount.md)
- [partinfo](kernel-small-debug-shell-file-partinfo.md)
- [魔法键使用方法](kernel-lite-small-shell-cmd-mag.md) - [partition](kernel-small-debug-shell-file-partition.md)
- [用户态异常信息说明](kernel-lite-small-shell-cmd-abn.md) - [pwd](kernel-small-debug-shell-file-pwd.md)
- [rm](kernel-small-debug-shell-file-rm.md)
- [rmdir](kernel-small-debug-shell-file-rmdir.md)
- [statfs](kernel-small-debug-shell-file-statfs.md)
- [sync](kernel-small-debug-shell-file-sync.md)
- [touch](kernel-small-debug-shell-file-touch.md)
- [writeproc](kernel-small-debug-shell-file-write.md)
- [umount](kernel-small-debug-shell-file-umount.md)
- [网络命令](kernel-small-debug-shell-net.md)
- [arp](kernel-small-debug-shell-net-arp.md)
- [dhclient](kernel-small-debug-shell-net-dhclient.md)
- [dns](kernel-small-debug-shell-net-dns.md)
- [ifconfig](kernel-small-debug-shell-net-ifconfig.md)
- [ipdebug](kernel-small-debug-shell-net-ipdebug.md)
- [netstat](kernel-small-debug-shell-net-netstat.md)
- [ntpdate](kernel-small-debug-shell-net-ntpdate.md)
- [ping](kernel-small-debug-shell-net-ping.md)
- [ping6](kernel-small-debug-shell-net-ping6.md)
- [telnet](kernel-small-debug-shell-net-telnet.md)
- [tftp](kernel-small-debug-shell-net-tftp.md)
- [魔法键使用方法](kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](kernel-small-debug-shell-error.md)
- [Trace](kernel-small-debug-trace.md)
- [进程调测](kernel-small-debug-process.md)
- [CPU占用率](kernel-small-debug-process-cpu.md)
- [内存调测](kernel-small-debug-memory.md)
- [内存信息统计](kernel-small-debug-memory-info.md)
- [内存泄漏检测](kernel-small-debug-memory-leak.md)
- [踩内存检测](kernel-small-debug-memory-corrupt.md)
- [其他内核调测手段](kernel-small-debug-other.md)
- [临终遗言](kernel-small-debug-trace-other-lastwords.md)
- [常见问题定位方法](kernel-small-debug-trace-other-faqs.md)
- [附录](kernel-small-apx.md)
- [基本数据结构](kernel-small-apx-structure.md)
- [双向链表](kernel-small-apx-dll.md)
- [位操作](kernel-small-apx-bitwise.md)
- [标准库](kernel-small-apx-library.md)
- [标准系统内核](kernel-standard.md) - [标准系统内核](kernel-standard.md)
- [Linux内核概述](kernel-standard-des.md) - [Linux内核概述](kernel-standard-overview.md)
- [OpenHarmony开发板Patch使用指导](kernel-standard-patch.md) - [OpenHarmony开发板Patch使用指导](kernel-standard-patch.md)
- [Linux内核编译与构建指导](kernel-standard-build.md) - [Linux内核编译与构建指导](kernel-standard-build.md)
\ No newline at end of file
# 时间管理<a name="ZH-CN_TOPIC_0000001078876462"></a> # 时间管理<a name="ZH-CN_TOPIC_0000001078876462"></a>
- **[基本概念](kernel-lite-mini-basic-time-basic.md)** - **[基本概念](kernel-mini-basic-time-basic.md)**
- **[开发指导](kernel-lite-mini-basic-time-guide.md)** - **[开发指导](kernel-mini-basic-time-guide.md)**
# 附录<a name="ZH-CN_TOPIC_0000001123948061"></a>
- **[内核编码规范](kernel-lite-mini-app-code.md)**
- **[基本数据结构](kernel-lite-mini-app-data.md)**
- **[标准库支持](kernel-lite-mini-app-lib.md)**
# 事件<a name="ZH-CN_TOPIC_0000001078716886"></a>
- **[基本概念](kernel-lite-mini-basic-ipc-event-guide.md)**
- **[开发指导](kernel-lite-mini-basic-ipc-event-basic.md)**
# 内核通信机制<a name="ZH-CN_TOPIC_0000001124573873"></a>
- **[事件](kernel-lite-mini-basic-ipc-event.md)**
- **[互斥锁](kernel-lite-mini-basic-ipc-mutex.md)**
- **[消息队列](kernel-lite-mini-basic-ipc-queue.md)**
- **[信号量](kernel-lite-mini-basic-ipc-sem.md)**
# 内存管理<a name="ZH-CN_TOPIC_0000001078876454"></a>
- **[基本概念](kernel-lite-mini-basic-memory-basic.md)**
- **[静态内存](kernel-lite-mini-basic-memory-static.md)**
- **[动态内存](kernel-lite-mini-basic-memory-dynamic.md)**
# 基础内核<a name="ZH-CN_TOPIC_0000001123863157"></a>
- **[中断管理](kernel-lite-mini-basic-interrupt.md)**
- **[任务管理](kernel-lite-mini-basic-task.md)**
- **[内存管理](kernel-lite-mini-basic-memory.md)**
- **[内核通信机制](kernel-lite-mini-basic-ipc.md)**
- **[时间管理](kernel-lite-basic-mini-time.md)**
- **[软件定时器](kernel-lite-mini-basic-soft.md)**
# 扩展组件<a name="ZH-CN_TOPIC_0000001123863139"></a>
- **[C++支持](kernel-lite-mini-extend-support.md)**
- **[CPU占用率](kernel-lite-mini-extend-cpup.md)**
- **[文件系统](kernel-lite-mini-extend-file.md)**
# 内核调测<a name="ZH-CN_TOPIC_0000001123763653"></a>
- **[内存调测](kernel-lite-mini-inner-debug.md)**
- **[异常调测](kernel-lite-mini-inner-exception.md)**
- **[Trace调测](kernel-lite-mini-inner-trace.md)**
# 快速入门<a name="ZH-CN_TOPIC_0000001124066549"></a>
- [搭建开发环境](#section157851447151716)
- [获取OpenHarmony源码](#section381985201816)
- [获取示例工程源码](#section204717216181)
- [编译运行](#section9772514181917)
OpenHarmony LiteOS-M内核的编译构建系统是一个基于gn和ninja的组件化构建系统,支持按组件配置、裁剪和拼装,按需构建出定制化的产品。编译构建系统的详细信息可以参考[考编译构建概](../subsystems/subsys-build-mini-lite.md#section10958256161119)。本文主要介绍如何基于gn和ninja编译LiteOS-M工程。
## 搭建开发环境<a name="section157851447151716"></a>
在搭建各个开发板环境前,需要完成OpenHarmony系统基础环境搭建。系统基础环境主要是指OpenHarmony的编译环境和开发环境,详细介绍请参考官方站点[搭建系统基础环境](../quick-start/quickstart-lite-env-setup-des.md)。开发者需要根据环境搭建文档,完成下述软件的安装:Python3.7+、gn、ninja、hb。对于LiteOS-M内核,还需要安装ARM GCC编译工具链。
## 获取OpenHarmony源码<a name="section381985201816"></a>
开发者需要在Linux服务器上通过Git克隆获取OpenHarmony最新源码,详细的源码获取方式,请见[源码获取](../get-code/sourcecode-acquire.md)。获取OpenHarmony完整仓代码后,假设克隆目录为\~/openHarmony。
## 获取示例工程源码<a name="section204717216181"></a>
以开发板Nucleo-F767Zi为例,演示如何编译运行OpenHarmony LiteOS-M内核工程。在本地目录,执行下述命令克隆示例代码。
```
git clone https://gitee.com/harylee/nucleo_f767zi.git
```
假设克隆到的代码目录为\~/nucleo\_f767zi。 执行如下命令把代码目录的device、vendor目录复制到openHarmony工程的相应目录。
```
cp -r ~/nucleo_f767zi/device/st ~/openHarmony/device/st
cp -r ~/nucleo_f767zi/vendor/st ~/openHarmony/vendor/st
```
关于示例代码目录的说明,可以参考资料站点[板级目录规范](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/porting/%E7%A7%BB%E6%A4%8D%E6%A6%82%E8%BF%B0-0.md#section6204129143013)。如果需要自行移植开发板,请参考[板级系统移植](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/porting/%E6%9D%BF%E7%BA%A7%E7%B3%BB%E7%BB%9F%E7%A7%BB%E6%A4%8D.md)
## 编译运行<a name="section9772514181917"></a>
编译运行前,把交叉编译工具链bin目录配置到PATH环境变量中或者在device/st/nucleo\_f767zi/liteos\_m/config.gni文件中把board\_toolchain\_path配置项设置为交叉编译工具链bin目录。 在OpenHarmony根目录,执行hb set设置产品路径,选择nucleo\_f767zi产品,然后执行hb build开启编译。如下:
```
user@dev:~/OpenHarmony$ hb set
[OHOS INFO] Input code path: # 直接按回车,然后选择nucleo_f767zi产品即可
OHOS Which product do you need? nucleo_f767zi@st
user@dev:~/OpenHarmony$ hb build
```
最终的镜像生成在\~/openHarmony/out/nucleo\_f767zi/目录中,通过STM32 ST-LINK Utility软件将镜像文件下载至单板查看运行效果。
# 轻量系统内核<a name="ZH-CN_TOPIC_0000001124663064"></a>
- **[内核概述](kernel-lite-mini-m.md)**
- **[基础内核](kernel-lite-mini-basic.md)**
- **[扩展组件](kernel-lite-mini-extend.md)**
- **[内核调测](kernel-lite-mini-inner.md)**
- **[附录](kernel-lite-mini-app.md)**
# 基础内核<a name="ZH-CN_TOPIC_0000001111199438"></a>
- **[进程](kernel-lite-small-process.md)**
- **[线程](kernel-lite-small-thread.md)**
- **[内存](kernel-lite-small-memory.md)**
- **[网络](kernel-lite-small-net.md)**
# FAT<a name="ZH-CN_TOPIC_0000001052170495"></a>
- [概述](#section17906101815113)
- [注意事项](#section781233610116)
- [开发指导](#section26081559713)
## 概述<a name="section17906101815113"></a>
FAT文件系统是File Allocation Table(文件配置表)的简称,FAT文件系统有FAT12、FAT16、FAT32。FAT文件系统将硬盘分为MBR区、DBR区、FAT区、DIR区、DATA区等5个区域。
FAT文件系统支持多种介质,特别在可移动存储介质(U盘、SD卡、移动硬盘等)上广泛使用。可以使嵌入式设备和Windows、Linux等桌面系统保持很好的兼容性,方便用户管理操作文件。
OpenHarmony内核的FAT文件系统具有代码量和资源占用小、可裁切、支持多种物理介质等特性,并且与Windows、Linux等系统保持兼容,支持多设备、多分区识别等功能。
OpenHarmony内核支持硬盘多分区,可以在主分区以及逻辑分区上创建FAT文件系统。同时OpenHarmony内核也可以识别出硬盘上其他类型的文件系统。
## 注意事项<a name="section781233610116"></a>
- 最多支持同时打开的fatfs文件(文件夹)数为512。
- 以可写方式打开一个文件后,未close前再次打开会失败。多次打开同一文件,必须全部使用只读方式。长时间打开一个文件,没有close时数据会丢失,必须close才能保存。
- FAT文件系统中,单个文件不能大于4G。
- 当有两个SD卡插槽时,卡0和卡1不固定,先插上的为卡0,后插上的为卡1。
- 当多分区功能打开,存在多分区的情况下,卡0注册的设备节点/dev/mmcblk0\(主设备\)和/dev/mmcblk0p0\(次设备\)是同一个设备,禁止对主设备进行操作。
- FAT文件系统的读写指针没有分离,所以以O\_APPEND(追加写)方式打开文件后,读指针也在文件尾,读文件前需要用户手动置位。
- FAT文件系统的stat及lstat函数获取出来的文件时间只是文件的修改时间。暂不支持创建时间和最后访问时间。微软FAT协议不支持1980年以前的时间。
- open打开一个文件,参数有O\_TRUNC时,会将文件中的内容清空。
- FAT文件系统支持的操作有:open, close, read, write, seek, sync, opendir, closedir, readdir, rewinddir, readdir\_r, statfs, remove, unlink, mkdir, rmdir, rename, stat, stat64, seek64, fallocate, fallocate64, truncate, truncate64,mount, umount。
- 为避免SD卡使用异常和内存泄漏,SD卡使用过程中拔卡,用户必须先关闭正处于打开状态的文件和目录,之后umount挂载节点。
- 在format操作之前,若fat文件系统已挂载,需确保所有目录及文件全部关闭,否则format会失败。
- FAT支持只读属性挂载:
- 当mount函数的入参为MS\_RDONLY时,FAT将开启只读属性,所有的带有写入的接口,如write、mkdir、unlink,以及通过非O\_RDONLY属性打开的文件,将均被拒绝,并传出EACCESS错误码(format接口除外)。
- 当mount函数的入参为MS\_NOSYNC时,FAT不会主动将cache的内容写回存储器件。FAT的如下接口(open、close、 unlink、rename、mkdir、rmdir、truncate)不会自动进行sync操作,速度可以提升,但是需要上层主动调用sync来进行数据同步,否则下电可能会数据丢失。
- FAT文件系统有定时刷cache功能。在menuconfig中开启LOSCFG\_FS\_FAT\_CACHE\_SYNC\_THREAD选项,打开后系统会创建一个任务刷cache,默认每隔5秒检查cache中脏数据块比例,超过80%时进行sync操作,将cache中的脏数据全部写回磁盘。任务优先级、刷新时间间隔以及脏数据块比例的阈值可分别通过接口LOS\_SetSyncThreadPrio、 LOS\_SetSyncThreadInterval和LOS\_SetDirtyRatioThreshold设置。
- 当前cache的默认大小为16个块,每个块256个扇区。
## 开发指导<a name="section26081559713"></a>
**设备识别**
- 在ffconf.h文件中配置FF\_MULTI\_PARTITION为1,可使用多分区功能。
- 在ffconf.h文件中配置FF\_VOLUMES大于2时,可使用多设备功能。
多设备、多分区功能开启后,系统对于插上的sd卡自动识别,自动注册设备节点如上图所示。mmcblk0和mmcblk1为卡0和卡1,是独立的主设备,mmcblk0p0、mmcblk0p1为卡0的两个分区,可作为分区设备使用。在有分区设备存在的情况下,禁止使用主设备。
可以使用 partinfo命令查看所识别的分区信息。
```
OHOS # partinfo /dev/mmcblk0p0
part info :
disk id : 0
part_id in system: 0
part no in disk : 0
part no in mbr : 1
part filesystem : 0C
part dev name : mmcblk0p0
part sec start : 8192
part sec count : 31108096
```
**FAT文件系统的挂载**
运行命令:
```
OHOS # mount /dev/mmcblk0p0 /vs/sd vfat
```
将从串口得到如下回应信息,表明挂载成功。
```
OHOS # mount /dev/mmcblk0p0 /vs/sd vfat
mount ok
```
**FAT文件系统的卸载**
运行命令:
```
OHOS # umount /vs/sd
```
将从串口得到如下回应信息,表明卸载成功。
```
OHOS # umount /vs/sd
umount ok
```
# NFS<a name="ZH-CN_TOPIC_0000001052170493"></a>
- [概述](#section18322139164413)
- [注意事项](#section532912331467)
- [开发指导](#section166873374711)
## 概述<a name="section18322139164413"></a>
NFS是Network File System(网络文件系统)的缩写。它最大的功能是可以通过网络,让不同的机器、不同的操作系统彼此分享其他用户的文件。因此,用户可以简单地将它看做是一个文件系统服务,在一定程度上相当于Windows环境下的共享文件夹。
NFS客户端用户,能够将网络远程的NFS服务端分享的目录挂载到本地端的机器中,运行程序和共享文件,但不占用当前的系统资源,所以,在本地端的机器看起来,远程服务端的目录就好像是自己的一个磁盘一样。
## 注意事项<a name="section532912331467"></a>
- 当前NFS文件不支持权限控制,请在创建NFS目录和文件时使用777权限。
- 当前NFS文件不支读阻塞和写阻塞。
- 当前NFS文件不支持信号功能。
- 当前NFS文件系统mount路径长度(不包含IP的长度)不超过255个字符,超过时返回ENAMETOOLONG错误。
- 当前NFS文件支持的操作有:open, close, read, write, seek, dup, dup2, sync, opendir, closedir, readdir, readdir\_r, rewinddir, scandir, statfs, remove, unlink, mkdir, rmdir, rename, stat, stat64, seek64, mmap, mount, umount。
- 当前NFS支持TCP和UDP两种传输层协议,默认使用TCP。
- open打开一个文件,参数有O\_TRUNC时,必须同时拥有写的权限,才会将文件中的内容清空。
- 在文件未关闭的情况下,rename\(\)函数重命名A为B之后,不会改变文件fd。
- NFS功能目前处于beta测试阶段,可能存在功能不稳定的情况,建议您不要用于正式商用产品当中。
## 开发指导<a name="section166873374711"></a>
1. **搭建NFS服务器**
这里以Ubuntu操作系统为例,说明服务器端设置步骤。
1. 安装NFS服务器软件。
设置好Ubuntu系统的下载源,保证网络连接好的情况下执行:
```
sudo apt-get install nfs-kernel-server
```
2. 创建用于挂载的目录并设置完全权限
```
mkdir /home/sqbin/nfs
sudo chmod 777 /home/sqbin/nfs
```
3. 设置和启动NFS server。
修改NFS配置文件/etc/exports,添加如下一行:
```
/home/sqbin/nfs *(rw,no_root_squash,async)
```
其中/home/sqbin/nfs是NFS共享的根目录。
执行以下命令启动NFS server:
```
sudo /etc/init.d/nfs-kernel-server start
```
执行以下命令重启NFS server:
```
sudo /etc/init.d/nfs-kernel-server restart
```
2. **设置单板为NFS客户端**
本指导中的NFS客户端指运行OpenHarmony内核的设备。
1. 硬件连接设置。
OpenHarmony内核设备连接到NFS服务器的网络。设置两者IP,使其处于同一网段。比如,设置NFS服务器的IP为10.67.212.178/24,设置OpenHarmony内核设备IP为10.67.212.3/24,注意:此IP为内网私有IP地址,用户使用时有差异,以用户实际IP为准。
OpenHarmony内核设备上的IP信息可通过ifconfig命令查看。
2. 启动网络,确保单板到NFS服务器之间的网络通畅。
启动以太网或者其他类型网络,使用ping命令检查到服务器的网络是否通畅。
```
OHOS # ping 10.67.212.178
[0]Reply from 10.67.212.178: time=1ms TTL=63
[1]Reply from 10.67.212.178: time=0ms TTL=63
[2]Reply from 10.67.212.178: time=1ms TTL=63
[3]Reply from 10.67.212.178: time=1ms TTL=63
--- 10.67.212.178 ping statistics ---
4 packets transmitted, 4 received, 0 loss
```
客户端NFS初始化,运行命令:
```
OHOS # mkdir /nfs
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
```
将从串口得到如下回应信息,表明初始化NFS客户端成功。
```
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
Mount nfs on 10.67.212.178:/home/sqbin/nfs, uid:1011, gid:1000
Mount nfs finished.
```
该命令将服务器10.67.212.178上的/home/sqbin/nfs目录mount在OpenHarmony内核设备上的/nfs上。
>![](../public_sys-resources/icon-note.gif) **说明:**
>本例默认nfs server已经配置可用,即示例中服务器10.67.212.178上的/home/sqbin/nfs已配置可访问。
mount命令的格式为:
```
mount <SERVER_IP:SERVER_PATH> <CLIENT_PATH> nfs
```
其中“SERVER\_IP“表示服务器的IP地址;“SERVER\_PATH“表示服务器端NFS共享目录路径;“CLIENT\_PATH“表示设备上的NFS路径。
如果不想有NFS访问权限限制,请在Linux命令行将NFS根目录权限设置成777:
```
chmod -R 777 /home/sqbin/nfs
```
至此,NFS客户端设置完毕。NFS文件系统已成功挂载。
3. **利用NFS共享文件**
在NFS服务器下新建目录dir,并保存。在OpenHarmony内核下运行ls命令:
```
OHOS # ls /nfs
```
则可从串口得到如下回应:
```
OHOS # ls /nfs
Directory /nfs:
drwxr-xr-x 0 u:0 g:0 dir
```
可见,刚刚在NFS服务器上新建的dir目录已同步到客户端\(OpenHarmony内核系统\)的/nfs目录,两者保持同步。
同样地,在客户端\(OpenHarmony内核系统\)上创建文件和目录,在NFS服务器上也可以访问,读者可自行体验。
**平台差异性:**
目前,NFS客户端仅支持NFS v3部分规范要求,因此对于规范支持不全的服务器,无法完全兼容。在开发测试过程中,建议使用Linux的NFS server,因为其对NFS支持很完善。
# RAMFS<a name="ZH-CN_TOPIC_0000001052810480"></a>
- [概述](#section7216205735619)
- [注意事项](#section970375615711)
- [开发指导](#section18433111125812)
## 概述<a name="section7216205735619"></a>
RAMFS是一个可动态调整大小的基于RAM的文件系统。RAMFS没有后备存储源。向RAMFS中进行的文件写操作也会分配目录项和页缓存,但是数据并不写回到任何其他存储介质上,掉电后数据丢失。
RAMFS文件系统把所有的文件都放在 RAM 中,所以读/写操作发生在RAM中,可以用RAMFS来存储一些临时性或经常要修改的数据,例如/tmp和/var目录,这样既避免了对存储器的读写损耗,也提高了数据读写速度。
OpenHarmony内核的RAMFS是一个简单的文件系统,它是基于RAM的动态文件系统的一种缓冲机制。
OpenHarmony内核的RAMFS基于虚拟文件系统层(VFS\),不能格式化。
## 注意事项<a name="section970375615711"></a>
- RAMFS文件系统的读写指针没有分离,所以以O\_APPEND(追加写)方式打开文件后,读指针也在文件尾,读文件前需要用户手动置位。
- RAMFS只能挂载一次,一次挂载成功后,后面不能继续挂载到其他目录。
- RAMFS文件数量受信号量资源限制,不能超过LOSCFG\_BASE\_IPC\_SEM\_LIMIT。
- open打开一个文件,参数有O\_TRUNC时,会将文件中的内容清空。
- RAMFS文件系统支持的操作有:open, close, read, write, seek, opendir, closedir, readdir, readdir\_r, rewinddir, sync, statfs, remove, unlink, mkdir, rmdir, rename, stat, stat64, seek64, mmap, mount, umount。
- RAMFS属于调测功能,默认配置为关闭,正式产品中禁止使用该功能。
## 开发指导<a name="section18433111125812"></a>
RAMFS的挂载和卸载可以在如下两种方式中任选其一:
- 使用代码挂载和卸载完成RAMFS文件系统的初始化和去初始化。
1. 调用mount函数完成RAMFS文件系统的初始化。
```
void ram_fs_init(void) {
int swRet;
swRet = mount(NULL, RAMFS_DIR, "ramfs", 0, NULL);
if (swRet != 0) {
dprintf("mount ramfs err %d\n", swRet);
return;
}
dprintf("Mount ramfs finished.\n");
}
```
调用初始化函数,随后在OpenHarmony内核系统启动时可以看到如下显示,表示RAMFS文件系统已初始化成功:
```
Mount ramfs finished
```
2. 卸载。调用去初始化函数,随后在OpenHarmony内核系统可以看到如下显示,表示RAMFS文件系统已卸载:
```
void ram_fs_uninit(void) {
int swRet;
swRet = umount(RAMFS_DIR);
if (swRet != 0) {
dprintf("Umount ramfs err %d\n", swRet);
return;
}
dprintf("Umount ramfs finished.\n");
}
```
- 使用命令行的方式完成RAMFS文件系统的挂载和卸载 。
1. 使用mount命令完成RAMFS文件系统的挂载,将从串口得到如下回应信息,表明挂载成功。
```
OHOS # mount 0 /ramfs ramfs
mount ok
```
2. 使用umount命令完成卸载,将从串口得到如下回应信息,表明卸载成功。
```
OHOS # umount /ramfs
umount ok
```
# VFS<a name="ZH-CN_TOPIC_0000001051451779"></a>
- [概述](#section132540468341)
- [基本概念](#section229417111227)
- [运作机制](#section18114182834215)
- [注意事项](#section18311145173712)
- [开发指导](#section422619258380)
- [编程实例](#section180311121420)
- [结果验证](#section16772334714)
## 概述<a name="section132540468341"></a>
## 基本概念<a name="section229417111227"></a>
VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。
由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用关心底层的存储介质和文件系统类型,提高开发效率。VFS和各个具体文件系统的关系如下:
**图 1** VFS和各个文件系统的关系<a name="fig633144419295"></a>
![](figure/VFS和各个文件系统的关系.png "VFS和各个文件系统的关系")
OpenHarmony内核中,VFS框架是通过在内存中的树结构来实现的,树的每个结点都是一个inode结构体。设备注册和文件系统挂载后会根据路径在树中生成相应的结点。VFS最主要是两个功能:
- 查找节点。
- 统一调用(标准)。
## 运作机制<a name="section18114182834215"></a>
通过VFS层,可以使用标准的Unix文件操作函数(如open、read、write等)来实现对不同介质上不同文件系统的访问。
VFS框架内存中的inode树结点有三种类型:
- 虚拟结点:作为VFS框架的虚拟文件,保持树的连续性,如/usr、/usr/bin。
- 设备结点:/dev目录下,对应一个设备,如/dev/mmcblk0。
- 挂载点:挂载具体文件系统,如/vs/sd、/mnt。
**图 2** 文件系统树形结构<a name="fig1648112392612"></a>
![](figure/文件系统树形结构.png "文件系统树形结构")
## 注意事项<a name="section18311145173712"></a>
- VFS下的所有文件系统,创建的目录名和文件名最多只可以有255个字节,能支持的全路径长度最长为259字节,超过这个路径长度的文件和目录无法创建。
- 目前仅有jffs2文件系统支持完整的权限控制。
- inode\_find\(\)函数调用后会使查找到的inode节点连接数+1,调用完成后需要调用inode\_release\(\)使连接数-1,所以一般inode\_find\(\)要和inode\_release\(\)配套使用。
- 设备分为字符设备和块设备,为了块设备上的文件系统系统数据安全,需挂载相应文件系统后通过文件系统接口操作数据。
- los\_vfs\_init\(\)只能调用一次,多次调用将会造成文件系统异常。
- 目前OpenHarmony内核所有的文件系统中的文件名和目录名中只可以出现“-” 与“\_”两种特殊字符,使用其他特殊字符可能造成的后果不可预知,请谨慎为之。
- OpenHarmony内核支持open\(\)+O\_DIRECTORY的方法获取目录数据信息。
- 挂载点必须为空目录,不能重复挂载至同一挂载点或挂载至其他挂载点下的目录或文件,错误挂载可能损坏设备及系统。
- open打开一个文件时,参数O\_RDWR、O\_WRONLY、O\_RDONLY互斥,只能出现一个,若出现2个或以上作为open的参数,文件读写操作会被拒绝,并返回EACCESS错误码,禁止使用。
- OpenHarmony内核文件系统在umount操作之前,需确保所有目录及文件全部关闭,否则umount会失败。如果强制umount,可能导致包括但不限于文件系统损坏、设备损坏等问题。
- SD卡移除前,需确保所有目录及文件全部关闭,并进行umount操作。如果强制拔卡,可能导致包括但不限于SD数据丢失、SD卡损坏等问题。
## 开发指导<a name="section422619258380"></a>
**开发流程**
推荐驱动开发人员使用VFS框架来注册/卸载设备,即调用register\_driver\(\)、register\_blockdriver\(\)接口生成设备结点,应用层使用open\(\)、read\(\)操作设备(字符设备)文件来调用驱动。
**文件描述符**
本系统中,进程的文件描述符最多有256个(File和Socket描述符合并统计),系统文件描述符共640个,系统文件描述符规格:
- File描述符,普通文件描述符,系统总规格为512。
- Socket描述符,系统总规格为128。
**VFS支持的操作**
open, close, read, write, seek, ioctl, fcntl, mmap, sync, dup, dup2, truncate, opendir, closedir, readdir, rewinddir, mount, umount, statfs, unlink, remove, mkdir, rmdir, rename, stat, utime, seek64, fallocate, fallocate64, truncate64, chmod, chown。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 当前只提供修改jffs2文件以及vfs设备节点属性的接口,各个系统对只读等属性有各自的处理方式。
>- 在OpenHarmony内核中属性并不冲突(可以任意修改)。
>- 在OpenHarmony内核中只读属性文件/目录不允许被删除。
>- 在OpenHarmony内核中只读属性文件/目录允许rename。
>- 只读文件不允许以O\_CREAT、O\_TRUNC,以及有含有写的权限的方式打开。
>- 在OpenHarmony内核中设置的系统文件加上隐藏属性,在Windows中只能通过命令行找到(在显示,不显示隐藏文件的属性情况下都不能看到)。
## 编程实例<a name="section180311121420"></a>
```
/* 说明:展示创建目录,和遍历目录的操作 */
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
int main()
{
int ret;
char *dirname = "/test";
char *pathname0 = "/test/test0";
char *pathname1 = "/test/test1";
char *pathname2 = "/test/test2";
struct dirent **namelist;
int num;
ret = mkdir(dirname, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", dirname, errno);
goto EXIT;
}
ret = mkdir(pathname0, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", pathname0, errno);
goto EXIT0;
}
ret = mkdir(pathname1, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", pathname1, errno);
goto EXIT1;
}
ret = mkdir(pathname2, 0777);
if ((ret < 0) && (errno != EEXIST)) {
printf("mkdir failed. path=%s, errno=%d\n", pathname2, errno);
goto EXIT2;
}
num = scandir(dirname, &namelist, NULL, alphasort);
if (num < 0) {
perror("scandir");
} else {
while (num--) {
printf("%s\n", namelist[num]->d_name);
free(namelist[num]);
}
free(namelist);
}
printf("fs_demo exit.\n");
return 0;
EXIT2:
remove(pathname2);
EXIT1:
remove(pathname1);
EXIT0:
remove(pathname0);
EXIT:
remove(dirname);
return 0;
}
```
## 结果验证<a name="section16772334714"></a>
```
OHOS # test2
test1
test0
fs_demo exit.
```
# 文件系统<a name="ZH-CN_TOPIC_0000001051611726"></a>
OpenHarmony轻内核支持的文件系统有:VFS(虚拟文件系统)、NFS、RAMFS、FAT、JFFS2。
**各个文件系统功能概述:**
**表 1** 文件系统功能概述
<a name="table6330194819415"></a>
<table><thead align="left"><tr id="row6331184864111"><th class="cellrowborder" valign="top" width="11.559999999999999%" id="mcps1.2.3.1.1"><p id="p17644161411438"><a name="p17644161411438"></a><a name="p17644161411438"></a>文件系统</p>
</th>
<th class="cellrowborder" valign="top" width="88.44%" id="mcps1.2.3.1.2"><p id="p116441414184312"><a name="p116441414184312"></a><a name="p116441414184312"></a>功能特点概述</p>
</th>
</tr>
</thead>
<tbody><tr id="row371213562318"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p37130569316"><a name="p37130569316"></a><a name="p37130569316"></a>VFS</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p1771335615316"><a name="p1771335615316"></a><a name="p1771335615316"></a>VFS是Virtual File System(虚拟文件系统)的缩写,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。</p>
</td>
</tr>
<tr id="row189255844219"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p1564481494319"><a name="p1564481494319"></a><a name="p1564481494319"></a>NFS</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p764561414434"><a name="p764561414434"></a><a name="p764561414434"></a>NFS是Network File System(网络文件系统)的缩写。它最大的功能是可以通过网络,让不同的机器、不同的操作系统彼此分享其他用户的文件。</p>
</td>
</tr>
<tr id="row17332194820411"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p2064561415435"><a name="p2064561415435"></a><a name="p2064561415435"></a>RAMFS</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p12646614204320"><a name="p12646614204320"></a><a name="p12646614204320"></a>RAMFS是一种基于RAM的文件系统。RAMFS文件系统把所有的文件都放在RAM中,所以读/写操作发生在RAM中,避免了对存储器的读写损耗,也提高了数据读写速度。RAMFS是基于RAM的动态文件系统的一种存储缓冲机制。</p>
</td>
</tr>
<tr id="row16332174894116"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p1864571410433"><a name="p1864571410433"></a><a name="p1864571410433"></a>FAT</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p364511141434"><a name="p364511141434"></a><a name="p364511141434"></a>FAT文件系统是File Allocation Table(文件配置表)的简称,有FAT12、FAT16、FAT32。在可移动存储介质(U盘、SD卡、移动硬盘等)上多使用FAT文件系统,使设备与Windows、Linux等桌面系统之间保持很好的兼容性。</p>
</td>
</tr>
<tr id="row1880218157414"><td class="cellrowborder" valign="top" width="11.559999999999999%" headers="mcps1.2.3.1.1 "><p id="p19645814144312"><a name="p19645814144312"></a><a name="p19645814144312"></a>JFFS2</p>
</td>
<td class="cellrowborder" valign="top" width="88.44%" headers="mcps1.2.3.1.2 "><p id="p8645161454314"><a name="p8645161454314"></a><a name="p8645161454314"></a>JFFS2是Journalling Flash File System Version 2(日志文件系统)的缩写,是MTD设备上的日志型文件系统。主要应用于对NOR_FLASH闪存的文件管理。<span id="text236315521580"><a name="text236315521580"></a><a name="text236315521580"></a>OpenHarmony</span>内核的JFFS2支持多分区。</p>
</td>
</tr>
</tbody>
</table>
- **[VFS](kernel-lite-small-file-vfs.md)**
- **[NFS](kernel-lite-small-file-nfs.md)**
- **[RAMFS](kernel-lite-small-file-ramfs.md)**
- **[FAT](kernel-lite-small-file-fat.md)**
- **[JFFS2](kernel-lite-small-file-jffs.md)**
# 与Linux标准库的差异<a name="ZH-CN_TOPIC_0000001053240737"></a>
- [进程](#section249218475301)
- [内存](#section55731513163117)
- [与Linux mmap的差异](#section1943551142314)
- [代码举例](#section16947155092514)
- [文件系统](#section1746965493115)
- [信号](#section1198254310333)
- [Time](#section0833419133414)
本章节描述了OpenHarmony内核承载的标准库与Linux标准库之间存在的关键差异。更多差异详见C库API文档说明。
## 进程<a name="section249218475301"></a>
1. OpenHarmony用户态**进程**优先级只支持静态优先级且用户态可配置的优先级范围为10\(最高优先级\)-31\(最低优先级)。
2. OpenHarmony用户态**线程**优先级只支持静态优先级且用户态可配置的优先级范围为0\(最高优先级\)-31\(最低优先级)。
3. OpenHarmony进程调度策略只支持SCHED\_RR, 线程调度策略支持SCHED\_RR和SCHED\_FIFO。
## 内存<a name="section55731513163117"></a>
## 与Linux mmap的差异<a name="section1943551142314"></a>
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进行回收。
## 代码举例<a name="section16947155092514"></a>
Linux目前支持的情况如下:
```
int main(int argc, char *argv[])
{
int fd;
void *addr = NULL;
...
fd = open(argv[1], O_RDONLY);
if (fd == -1){
perror("open");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
...
exit(EXIT_SUCCESS);
}
```
OpenHarmony支持的情况如下:
```
int main(int argc, char *argv[])
{
int fd;
void *addr = NULL;
...
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
...
munmap(addr, length);
close(fd); /* Close fd after the munmap is canceled. */
exit(EXIT_SUCCESS);
}
```
## 文件系统<a name="section1746965493115"></a>
**系统目录**:用户无权限修改系统目录和设备挂载目录。包含/dev,/proc,/app,/bin,/data,/etc,/lib,/system,/usr目录。
**用户目录**:用户可以在该目录下进行文件创建、读写,但**不能进行设备挂载**。用户目录指/storage目录。
**系统目录****用户目录**之外,用户可以自行创建文件夹进行设备的挂载。但是要注意,已挂载的文件夹及其子文件夹不允许重复或者嵌套挂载,非空文件夹不允许挂载。
## 信号<a name="section1198254310333"></a>
- 信号默认行为不支持STOP、CONTINUE、COREDUMP功能。
- 无法通过信号唤醒正在睡眠状态(举例:进程调用sleep函数进入睡眠)的进程。原因:信号机制无唤醒功能,当且仅当进程被CPU调度运行时才能处理信号内容。
- 进程退出后会发送SIGCHLD给父进程,发送动作无法取消。
- 信号仅支持1-30号信号,接收方收到多次同一信号,仅执行一次回调函数。
## Time<a name="section0833419133414"></a>
OpenHarmony当前时间精度以tick计算,系统默认10ms/tick。sleep、timeout系列函数时间误差<=20ms。
# 标准库<a name="ZH-CN_TOPIC_0000001111039548"></a>
- **[标准库](kernel-lite-small-lib-standard.md)**
- **[与Linux标准库的差异](kernel-lite-small-lib-differ.md)**
# 内存<a name="ZH-CN_TOPIC_0000001051452208"></a>
- [基本概念](#section1392116583424)
- [使用场景](#section159581619194319)
- [接口说明](#section114001032104317)
## 基本概念<a name="section1392116583424"></a>
内存管理是开发过程中必须要关注的重要过程,它包括内存的分配、使用和回收。
良好的内存管理对于提高软件性能和可靠性有着十分重要的意义。
## 使用场景<a name="section159581619194319"></a>
针对用户态开发,OpenHarmony内核提供了一套内存系统调用接口,支持内存的申请释放、重映射、内存属性的设置等,还有C库的标准内存操作函数。
## 接口说明<a name="section114001032104317"></a>
**表 1** 标准C库相关接口
<a name="table198502176175"></a>
<table><thead align="left"><tr id="row7850171781719"><th class="cellrowborder" valign="top" width="15.371537153715373%" id="mcps1.2.4.1.1"><p id="p23316052015"><a name="p23316052015"></a><a name="p23316052015"></a>头文件</p>
</th>
<th class="cellrowborder" valign="top" width="51.2951295129513%" id="mcps1.2.4.1.2"><p id="p03417010208"><a name="p03417010208"></a><a name="p03417010208"></a>接口</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p14347010207"><a name="p14347010207"></a><a name="p14347010207"></a>功能</p>
</th>
</tr>
</thead>
<tbody><tr id="row785091771710"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p73450202019"><a name="p73450202019"></a><a name="p73450202019"></a>strings.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p934008201"><a name="p934008201"></a><a name="p934008201"></a>int bcmp(const void *s1, const void *s2, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p93412018209"><a name="p93412018209"></a><a name="p93412018209"></a>比较字节序列。</p>
</td>
</tr>
<tr id="row14791155651713"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p934605204"><a name="p934605204"></a><a name="p934605204"></a>strings.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p113414018209"><a name="p113414018209"></a><a name="p113414018209"></a>void bcopy(const void *src, void *dest, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1134180102016"><a name="p1134180102016"></a><a name="p1134180102016"></a>拷贝字节序列。</p>
</td>
</tr>
<tr id="row1734319481817"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p1134900205"><a name="p1134900205"></a><a name="p1134900205"></a>strings.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p18344012207"><a name="p18344012207"></a><a name="p18344012207"></a>void bzero(void *s, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p23410042015"><a name="p23410042015"></a><a name="p23410042015"></a>写入零值字节。</p>
</td>
</tr>
<tr id="row79226010178"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p435705201"><a name="p435705201"></a><a name="p435705201"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p83520042019"><a name="p83520042019"></a><a name="p83520042019"></a>void *memccpy(void *dest, const void *src, int c, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1720911419407"><a name="p1720911419407"></a><a name="p1720911419407"></a>拷贝src 所指的内存内容前n 个字节到dest 所指的地址上。复制时检查参数c 是否出现,若是则返回dest 中值为c 的下一个字节地址。</p>
</td>
</tr>
<tr id="row1992212019173"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p8355012013"><a name="p8355012013"></a><a name="p8355012013"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p1635180162014"><a name="p1635180162014"></a><a name="p1635180162014"></a>void *memchr(const void *s, int c, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p235306203"><a name="p235306203"></a><a name="p235306203"></a>在s所指内存的前n个字节中查找c。</p>
</td>
</tr>
<tr id="row19231001174"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p23560172012"><a name="p23560172012"></a><a name="p23560172012"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p1335404201"><a name="p1335404201"></a><a name="p1335404201"></a>int memcmp(const void *s1, const void *s2, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p183518092016"><a name="p183518092016"></a><a name="p183518092016"></a>内存比较。</p>
</td>
</tr>
<tr id="row189641849111717"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p758113203203"><a name="p758113203203"></a><a name="p758113203203"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p17581112013208"><a name="p17581112013208"></a><a name="p17581112013208"></a>void *memcpy(void *dest, const void *src, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1958102014208"><a name="p1958102014208"></a><a name="p1958102014208"></a>内存拷贝。</p>
</td>
</tr>
<tr id="row2964114919178"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p85811620182012"><a name="p85811620182012"></a><a name="p85811620182012"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p3581112042013"><a name="p3581112042013"></a><a name="p3581112042013"></a>void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p4581102032018"><a name="p4581102032018"></a><a name="p4581102032018"></a>找到一个子串。</p>
</td>
</tr>
<tr id="row3965049101716"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p17581820192011"><a name="p17581820192011"></a><a name="p17581820192011"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p1058119209207"><a name="p1058119209207"></a><a name="p1058119209207"></a>void *memmove(void *dest, const void *src, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p55811020162015"><a name="p55811020162015"></a><a name="p55811020162015"></a>内存移动。</p>
</td>
</tr>
<tr id="row12421329179"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p358112042016"><a name="p358112042016"></a><a name="p358112042016"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p18581720102016"><a name="p18581720102016"></a><a name="p18581720102016"></a>void *mempcpy(void *dest, const void *src, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p25811520132017"><a name="p25811520132017"></a><a name="p25811520132017"></a>拷贝内存区域。</p>
</td>
</tr>
<tr id="row343932141715"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p358152062019"><a name="p358152062019"></a><a name="p358152062019"></a>string.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p20581720152017"><a name="p20581720152017"></a><a name="p20581720152017"></a>void *memset(void *s, int c, size_t n)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p258102052019"><a name="p258102052019"></a><a name="p258102052019"></a>内存初始化。</p>
</td>
</tr>
<tr id="row19344649182"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p93511010206"><a name="p93511010206"></a><a name="p93511010206"></a>stdlib.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p135180172016"><a name="p135180172016"></a><a name="p135180172016"></a>void *malloc(size_t size)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p193580102017"><a name="p193580102017"></a><a name="p193580102017"></a>申请内存。</p>
</td>
</tr>
<tr id="row923218311911"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p8347042018"><a name="p8347042018"></a><a name="p8347042018"></a>stdlib.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p133415072012"><a name="p133415072012"></a><a name="p133415072012"></a>void *calloc(size_t nmemb, size_t size)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p2342062011"><a name="p2342062011"></a><a name="p2342062011"></a>申请内存并清零。</p>
</td>
</tr>
<tr id="row612852462210"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p11582162062013"><a name="p11582162062013"></a><a name="p11582162062013"></a>stdlib.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p1558211209205"><a name="p1558211209205"></a><a name="p1558211209205"></a>void *realloc(void *ptr, size_t size)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p7582172082018"><a name="p7582172082018"></a><a name="p7582172082018"></a>重分配内存。</p>
</td>
</tr>
<tr id="row32325321910"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p15582192010204"><a name="p15582192010204"></a><a name="p15582192010204"></a>stdlib.h/malloc.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p458211205205"><a name="p458211205205"></a><a name="p458211205205"></a>void *valloc(size_t size)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p6582420192014"><a name="p6582420192014"></a><a name="p6582420192014"></a>分配以页对齐的内存。</p>
</td>
</tr>
<tr id="row450114218205"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p93419062018"><a name="p93419062018"></a><a name="p93419062018"></a>stdlib.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p1535303201"><a name="p1535303201"></a><a name="p1535303201"></a>void free(void *ptr)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p173511072015"><a name="p173511072015"></a><a name="p173511072015"></a>释放内存。</p>
</td>
</tr>
<tr id="row96751881817"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p14351408208"><a name="p14351408208"></a><a name="p14351408208"></a>malloc.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p1735120142011"><a name="p1735120142011"></a><a name="p1735120142011"></a>size_t malloc_usable_size(void *ptr)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p153513042014"><a name="p153513042014"></a><a name="p153513042014"></a>获取从堆分配的内存块的大小。</p>
</td>
</tr>
<tr id="row46759851816"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p1235140172015"><a name="p1235140172015"></a><a name="p1235140172015"></a>unistd.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p4351906203"><a name="p4351906203"></a><a name="p4351906203"></a>int getpagesize(void)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p103513010204"><a name="p103513010204"></a><a name="p103513010204"></a>获取页面大小。</p>
</td>
</tr>
<tr id="row20901907199"><td class="cellrowborder" valign="top" width="15.371537153715373%" headers="mcps1.2.4.1.1 "><p id="p1558232032010"><a name="p1558232032010"></a><a name="p1558232032010"></a>unistd.h</p>
</td>
<td class="cellrowborder" valign="top" width="51.2951295129513%" headers="mcps1.2.4.1.2 "><p id="p158232012203"><a name="p158232012203"></a><a name="p158232012203"></a>void *sbrk(intptr_t increment)</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1558212014202"><a name="p1558212014202"></a><a name="p1558212014202"></a>更改数据段大小。</p>
</td>
</tr>
</tbody>
</table>
差异接口详细说明:
- **mmap**
**函数原型:**
void \*mmap\(void \*addr, size\_t length, int prot, int flags, int fd, off\_t offset\);
**函数功能:**申请虚拟内存。
**参数说明:**
<a name="table104651722114218"></a>
<table><thead align="left"><tr id="row1346572219429"><th class="cellrowborder" valign="top" width="11.92%" id="mcps1.1.3.1.1"><p id="p146632215425"><a name="p146632215425"></a><a name="p146632215425"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="88.08%" id="mcps1.1.3.1.2"><p id="p1446620227424"><a name="p1446620227424"></a><a name="p1446620227424"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row1346652216429"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p19466122104213"><a name="p19466122104213"></a><a name="p19466122104213"></a>addr</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p1046692215426"><a name="p1046692215426"></a><a name="p1046692215426"></a>用来请求使用某个特定的虚拟内存地址。如果取NULL,结果地址就将自动分配(这是推荐的做法),否则会降低程序的可移植性,因为不同系统的可用地址范围不一样。</p>
</td>
</tr>
<tr id="row8466182274215"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p5466162284220"><a name="p5466162284220"></a><a name="p5466162284220"></a>length</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p17466152214420"><a name="p17466152214420"></a><a name="p17466152214420"></a>内存段的大小。</p>
</td>
</tr>
<tr id="row154671722134211"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p0467142204215"><a name="p0467142204215"></a><a name="p0467142204215"></a>prot</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p6467162234215"><a name="p6467162234215"></a><a name="p6467162234215"></a>用于设置内存段的访问权限,有如下权限:</p>
<a name="ul166872913431"></a><a name="ul166872913431"></a><ul id="ul166872913431"><li>PROT_READ:允许读该内存段。</li><li>PROT_WRITE:允许写该内存段。</li><li>PROT_EXEC:允许执行该内存段。</li><li>PROT_NONE:不能访问。</li></ul>
</td>
</tr>
<tr id="row173845488436"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p1538474818437"><a name="p1538474818437"></a><a name="p1538474818437"></a>flags</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p92503134411"><a name="p92503134411"></a><a name="p92503134411"></a>控制程序对内存段的改变所造成的影响,有如下属性:</p>
<a name="ul1971648144411"></a><a name="ul1971648144411"></a><ul id="ul1971648144411"><li>MAP_PRIVATE:内存段私有,对它的修改值仅对本进程有效。</li><li>MAP_SHARED:把对该内存段的修改保存到磁盘文件中。</li></ul>
</td>
</tr>
<tr id="row771075312437"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p187105538438"><a name="p187105538438"></a><a name="p187105538438"></a>fd</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p1871005374312"><a name="p1871005374312"></a><a name="p1871005374312"></a>打开的文件描述符。</p>
</td>
</tr>
<tr id="row1624023824419"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p62406387445"><a name="p62406387445"></a><a name="p62406387445"></a>offset</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p92401382448"><a name="p92401382448"></a><a name="p92401382448"></a>用以改变经共享内存段访问的文件中数据的起始偏移值。</p>
</td>
</tr>
</tbody>
</table>
>![](../public_sys-resources/icon-note.gif) **说明:**
>mmap与Linux实现差异详见[与Linux标准库的差异](kernel-lite-small-lib-differ.md)章节。
**返回值:**
- 成功返回:虚拟内存地址,这地址是页对齐。
- 失败返回:\(void \*\)-1。
- **munmap接口**
**函数原型:**
int munmap\(void \*addr, size\_t length\);
**函数功能:**释放虚拟内存。
**参数说明:**
<a name="table09071025134617"></a>
<table><thead align="left"><tr id="row11908192513464"><th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.1"><p id="p186351516144710"><a name="p186351516144710"></a><a name="p186351516144710"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.2"><p id="p1163581610472"><a name="p1163581610472"></a><a name="p1163581610472"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row6908112512469"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p10908325194614"><a name="p10908325194614"></a><a name="p10908325194614"></a>addr</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p209081825114610"><a name="p209081825114610"></a><a name="p209081825114610"></a>虚拟内存起始位置。</p>
</td>
</tr>
<tr id="row2908725174617"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p29084251467"><a name="p29084251467"></a><a name="p29084251467"></a>length</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p11908152510468"><a name="p11908152510468"></a><a name="p11908152510468"></a>内存段的大小。</p>
</td>
</tr>
</tbody>
</table>
**返回值:**
- 成功返回0。
- 失败返回-1。
- **mprotect接口**
**函数原型:**
int mprotect\(void \*addr, size\_t length, int prot\);
**函数功能:**修改内存段的访问权限。
**参数说明:**
<a name="table12636174834719"></a>
<table><thead align="left"><tr id="row19636124813475"><th class="cellrowborder" valign="top" width="16.42%" id="mcps1.1.3.1.1"><p id="p26364483473"><a name="p26364483473"></a><a name="p26364483473"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="83.58%" id="mcps1.1.3.1.2"><p id="p13636748124717"><a name="p13636748124717"></a><a name="p13636748124717"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row176369484473"><td class="cellrowborder" valign="top" width="16.42%" headers="mcps1.1.3.1.1 "><p id="p763615487477"><a name="p763615487477"></a><a name="p763615487477"></a>addr</p>
</td>
<td class="cellrowborder" valign="top" width="83.58%" headers="mcps1.1.3.1.2 "><p id="p1763654844715"><a name="p1763654844715"></a><a name="p1763654844715"></a>内存段起始地址,必须页对齐;访问权限异常,内核将直接抛异常并且kill该进程,而不会产生SIGSEGV信号给当前进程。</p>
</td>
</tr>
<tr id="row17636134824716"><td class="cellrowborder" valign="top" width="16.42%" headers="mcps1.1.3.1.1 "><p id="p1163694824714"><a name="p1163694824714"></a><a name="p1163694824714"></a>length</p>
</td>
<td class="cellrowborder" valign="top" width="83.58%" headers="mcps1.1.3.1.2 "><p id="p463613482472"><a name="p463613482472"></a><a name="p463613482472"></a>内存段的大小。</p>
</td>
</tr>
<tr id="row196361148184716"><td class="cellrowborder" valign="top" width="16.42%" headers="mcps1.1.3.1.1 "><p id="p8636184810477"><a name="p8636184810477"></a><a name="p8636184810477"></a>prot</p>
</td>
<td class="cellrowborder" valign="top" width="83.58%" headers="mcps1.1.3.1.2 "><p id="p474391424815"><a name="p474391424815"></a><a name="p474391424815"></a>内存段的访问权限,有如下定义:</p>
<a name="ul333217192481"></a><a name="ul333217192481"></a><ul id="ul333217192481"><li>PROT_READ:允许读该内存段。</li><li>PROT_WRITE:允许写该内存段。</li><li>PROT_EXEC:允许执行该内存段。</li><li>PROT_NONE:不能访问。</li></ul>
</td>
</tr>
</tbody>
</table>
**返回值:**
- 成功返回0。
- 失败返回-1。
- **mremap接口**
**函数原型:**
void \*mremap\(void \*old\_address, size\_t old\_size, size\_t new\_size, int flags, void new\_address\);
**函数功能:**重新映射虚拟内存地址。
**参数说明:**
<a name="table35441821104912"></a>
<table><thead align="left"><tr id="row19544132134919"><th class="cellrowborder" valign="top" width="19.35%" id="mcps1.1.3.1.1"><p id="p205459214499"><a name="p205459214499"></a><a name="p205459214499"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="80.65%" id="mcps1.1.3.1.2"><p id="p4545102104911"><a name="p4545102104911"></a><a name="p4545102104911"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row75451321164918"><td class="cellrowborder" valign="top" width="19.35%" headers="mcps1.1.3.1.1 "><p id="p125451321144916"><a name="p125451321144916"></a><a name="p125451321144916"></a>old_address</p>
</td>
<td class="cellrowborder" valign="top" width="80.65%" headers="mcps1.1.3.1.2 "><p id="p1554522104914"><a name="p1554522104914"></a><a name="p1554522104914"></a>需要扩大(或缩小)的内存段的原始地址。注意old_address必须是页对齐。</p>
</td>
</tr>
<tr id="row1545172118495"><td class="cellrowborder" valign="top" width="19.35%" headers="mcps1.1.3.1.1 "><p id="p205452215498"><a name="p205452215498"></a><a name="p205452215498"></a>old_size</p>
</td>
<td class="cellrowborder" valign="top" width="80.65%" headers="mcps1.1.3.1.2 "><p id="p954572164910"><a name="p954572164910"></a><a name="p954572164910"></a>内存段的原始大小。</p>
</td>
</tr>
<tr id="row1754512144913"><td class="cellrowborder" valign="top" width="19.35%" headers="mcps1.1.3.1.1 "><p id="p1854532184916"><a name="p1854532184916"></a><a name="p1854532184916"></a>new_size</p>
</td>
<td class="cellrowborder" valign="top" width="80.65%" headers="mcps1.1.3.1.2 "><p id="p85451021164911"><a name="p85451021164911"></a><a name="p85451021164911"></a>新内存段的大小。</p>
</td>
</tr>
<tr id="row1545152120497"><td class="cellrowborder" valign="top" width="19.35%" headers="mcps1.1.3.1.1 "><p id="p145451221204913"><a name="p145451221204913"></a><a name="p145451221204913"></a>flags</p>
</td>
<td class="cellrowborder" valign="top" width="80.65%" headers="mcps1.1.3.1.2 "><p id="p2692195864912"><a name="p2692195864912"></a><a name="p2692195864912"></a>如果没有足够的空间在当前位置展开映射,则返回失败</p>
<a name="ul14935819135019"></a><a name="ul14935819135019"></a><ul id="ul14935819135019"><li>MREMAP_MAYMOVE:允许内核将映射重定位到新的虚拟地址。</li><li>MREMAP_FIXED:mremap()接受第五个参数,void *new_address,该参数指定映射地址必须页对齐;在new_address和new_size指定的地址范围内的所有先前映射都被解除映射。如果指定了MREMAP_FIXED,还必须指定MREMAP_MAYMOVE。</li></ul>
</td>
</tr>
</tbody>
</table>
**返回值:**
- 成功返回:重新映射后的虚拟内存地址。
- 失败返回:\(\(void \*\)-1\)。
# 网络<a name="ZH-CN_TOPIC_0000001051770946"></a>
- [基本概念](#section9840143083510)
- [使用场景](#section1575885183516)
- [接口说明](#section16351198193614)
## 基本概念<a name="section9840143083510"></a>
网络模块实现了TCP/IP协议栈基本功能,提供标准的POSIX socket接口。
>![](../public_sys-resources/icon-note.gif) **说明:**
>当前系统使用**lwIP**提供网络能力。
## 使用场景<a name="section1575885183516"></a>
针对用户态开发,OpenHarmony内核提供了一套网络功能系统调用接口,支持socket的创建关闭、数据收发、网络属性的设置等,通过C库提供标准的POSIX socket函数供开发者使用。
## 接口说明<a name="section16351198193614"></a>
**表 1** 标准C库相关接口
<a name="table89488035718"></a>
<table><thead align="left"><tr id="row1494810045717"><th class="cellrowborder" valign="top" width="15.17%" id="mcps1.2.4.1.1"><p id="p294915015578"><a name="p294915015578"></a><a name="p294915015578"></a>头文件</p>
</th>
<th class="cellrowborder" valign="top" width="50.9%" id="mcps1.2.4.1.2"><p id="p17949190205711"><a name="p17949190205711"></a><a name="p17949190205711"></a>接口</p>
</th>
<th class="cellrowborder" valign="top" width="33.93%" id="mcps1.2.4.1.3"><p id="p894950175712"><a name="p894950175712"></a><a name="p894950175712"></a>功能</p>
</th>
</tr>
</thead>
<tbody><tr id="row19501105571"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p109504011576"><a name="p109504011576"></a><a name="p109504011576"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p99508013571"><a name="p99508013571"></a><a name="p99508013571"></a>int accept(int socket, struct sockaddr *address, socklen_t *address_len)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p2095015035719"><a name="p2095015035719"></a><a name="p2095015035719"></a>接受连接。</p>
</td>
</tr>
<tr id="row209508065717"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p136322417199"><a name="p136322417199"></a><a name="p136322417199"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p89509014573"><a name="p89509014573"></a><a name="p89509014573"></a>int bind(int s, const struct sockaddr *name, socklen_t namelen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p6950903575"><a name="p6950903575"></a><a name="p6950903575"></a>socket与IP地址绑定。</p>
</td>
</tr>
<tr id="row99511100571"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p23757247194"><a name="p23757247194"></a><a name="p23757247194"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p59529055717"><a name="p59529055717"></a><a name="p59529055717"></a>int shutdown(int socket, int how)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p129527012573"><a name="p129527012573"></a><a name="p129527012573"></a>关闭连接。</p>
</td>
</tr>
<tr id="row49527011574"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p0392172441910"><a name="p0392172441910"></a><a name="p0392172441910"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p29531909577"><a name="p29531909577"></a><a name="p29531909577"></a>int getpeername(int s, struct sockaddr *name, socklen_t *namelen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p119534011576"><a name="p119534011576"></a><a name="p119534011576"></a>获取对端地址。</p>
</td>
</tr>
<tr id="row139532014576"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p34091724181911"><a name="p34091724181911"></a><a name="p34091724181911"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p616711716015"><a name="p616711716015"></a><a name="p616711716015"></a>int getsockname(int s, struct sockaddr *name, socklen_t *namelen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p181651471103"><a name="p181651471103"></a><a name="p181651471103"></a>获取本地地址。</p>
</td>
</tr>
<tr id="row695520019572"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p1842812441920"><a name="p1842812441920"></a><a name="p1842812441920"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p2016357007"><a name="p2016357007"></a><a name="p2016357007"></a>int getsockopt(int s, struct sockaddr *name, socklen_t *namelen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p1716037404"><a name="p1716037404"></a><a name="p1716037404"></a>获取socket属性信息。</p>
</td>
</tr>
<tr id="row79551708579"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p2442224121911"><a name="p2442224121911"></a><a name="p2442224121911"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p6158671601"><a name="p6158671601"></a><a name="p6158671601"></a>int setsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p415510716015"><a name="p415510716015"></a><a name="p415510716015"></a>配置socket属性。</p>
</td>
</tr>
<tr id="row595550165713"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p1345422415197"><a name="p1345422415197"></a><a name="p1345422415197"></a>unistd.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p19153371020"><a name="p19153371020"></a><a name="p19153371020"></a>int close(int s)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p815119715017"><a name="p815119715017"></a><a name="p815119715017"></a>关闭socket。</p>
</td>
</tr>
<tr id="row139566085714"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p114692024121917"><a name="p114692024121917"></a><a name="p114692024121917"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p181481371010"><a name="p181481371010"></a><a name="p181481371010"></a>int connect(int s, const struct sockaddr *name, socklen_t namelen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p41455713010"><a name="p41455713010"></a><a name="p41455713010"></a>连接到指定的目的IP。</p>
</td>
</tr>
<tr id="row89575035714"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p184811924191919"><a name="p184811924191919"></a><a name="p184811924191919"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p21421376013"><a name="p21421376013"></a><a name="p21421376013"></a>int listen(int sockfd, int backlog)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p9139271308"><a name="p9139271308"></a><a name="p9139271308"></a>聆听连接本socket的请求。</p>
</td>
</tr>
<tr id="row69581108574"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p349182412196"><a name="p349182412196"></a><a name="p349182412196"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p1813627005"><a name="p1813627005"></a><a name="p1813627005"></a>ssize_t recv(int socket, void *buffer, size_t length, int flags)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p1113318713018"><a name="p1113318713018"></a><a name="p1113318713018"></a>接收socket上收到的数据。</p>
</td>
</tr>
<tr id="row89591609574"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p55011249191"><a name="p55011249191"></a><a name="p55011249191"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p10131976020"><a name="p10131976020"></a><a name="p10131976020"></a>ssize_t recvmsg(int s, struct msghdr *message, int flags)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p2010837004"><a name="p2010837004"></a><a name="p2010837004"></a>接收socket上收到的数据,可使用更丰富的参数。</p>
</td>
</tr>
<tr id="row8960903574"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p1351310242192"><a name="p1351310242192"></a><a name="p1351310242192"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p310519717015"><a name="p310519717015"></a><a name="p310519717015"></a>ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p11102471608"><a name="p11102471608"></a><a name="p11102471608"></a>接收socket上收到的数据,可同时获得数据来源IP地址。</p>
</td>
</tr>
<tr id="row16961120195719"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p3525112420198"><a name="p3525112420198"></a><a name="p3525112420198"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p101001872009"><a name="p101001872009"></a><a name="p101001872009"></a>ssize_t send(int s, const void *dataptr, size_t size, int flags)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p197171402"><a name="p197171402"></a><a name="p197171402"></a>通过socket发送数据。</p>
</td>
</tr>
<tr id="row59620075717"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p165381324121910"><a name="p165381324121910"></a><a name="p165381324121910"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p6941671602"><a name="p6941671602"></a><a name="p6941671602"></a>ssize_t sendmsg(int s, const struct msghdr *message, int flags)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p13912710013"><a name="p13912710013"></a><a name="p13912710013"></a>通过socket发送数据,可使用更丰富的参数。</p>
</td>
</tr>
<tr id="row296213055716"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p1055242414196"><a name="p1055242414196"></a><a name="p1055242414196"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p588573013"><a name="p588573013"></a><a name="p588573013"></a>ssize_t sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p108612713014"><a name="p108612713014"></a><a name="p108612713014"></a>通过socket发送数据,可指定发送的目的IP地址。</p>
</td>
</tr>
<tr id="row1896320155718"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p165642024191919"><a name="p165642024191919"></a><a name="p165642024191919"></a>sys/socket.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p168413711019"><a name="p168413711019"></a><a name="p168413711019"></a>int socket(int domain, int type, int protocol)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p1278772017"><a name="p1278772017"></a><a name="p1278772017"></a>创建socket。</p>
</td>
</tr>
<tr id="row49644012571"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p3574152491918"><a name="p3574152491918"></a><a name="p3574152491918"></a>sys/select.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p575471204"><a name="p575471204"></a><a name="p575471204"></a>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p6721171012"><a name="p6721171012"></a><a name="p6721171012"></a>多路复用。</p>
</td>
</tr>
<tr id="row1965904571"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p1958512413195"><a name="p1958512413195"></a><a name="p1958512413195"></a>sys/ioctl.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p27013715013"><a name="p27013715013"></a><a name="p27013715013"></a>int ioctl(int s, int request, ...)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p867471405"><a name="p867471405"></a><a name="p867471405"></a>socket属性获取、设置。</p>
</td>
</tr>
<tr id="row179471552191312"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p4595192471910"><a name="p4595192471910"></a><a name="p4595192471910"></a>arpa/inet.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p189481522130"><a name="p189481522130"></a><a name="p189481522130"></a>const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p494814527138"><a name="p494814527138"></a><a name="p494814527138"></a>网络地址格式转换:将二进制格式IP地址转换为字符串格式。</p>
</td>
</tr>
<tr id="row189663017574"><td class="cellrowborder" valign="top" width="15.17%" headers="mcps1.2.4.1.1 "><p id="p335556182016"><a name="p335556182016"></a><a name="p335556182016"></a>arpa/inet.h</p>
</td>
<td class="cellrowborder" valign="top" width="50.9%" headers="mcps1.2.4.1.2 "><p id="p46417716014"><a name="p46417716014"></a><a name="p46417716014"></a>int inet_pton(int af, const char *src, void *dst)</p>
</td>
<td class="cellrowborder" valign="top" width="33.93%" headers="mcps1.2.4.1.3 "><p id="p176112713010"><a name="p176112713010"></a><a name="p176112713010"></a>网络地址格式转换:将字符串格式IP地址转换为二进制格式。</p>
</td>
</tr>
</tbody>
</table>
与标准接口差异详细说明:
- **sendmsg**
**函数原型:**
ssize\_t sendmsg\(int s, const struct msghdr \*message, int flags\)
**函数功能:**发送消息。
**参数说明:**
<a name="table193101953145116"></a>
<table><thead align="left"><tr id="row13311125313516"><th class="cellrowborder" valign="top" width="19.43%" id="mcps1.1.3.1.1"><p id="p19311195312510"><a name="p19311195312510"></a><a name="p19311195312510"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="80.57%" id="mcps1.1.3.1.2"><p id="p19311205313512"><a name="p19311205313512"></a><a name="p19311205313512"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row1731175316511"><td class="cellrowborder" valign="top" width="19.43%" headers="mcps1.1.3.1.1 "><p id="p153111753125118"><a name="p153111753125118"></a><a name="p153111753125118"></a>s</p>
</td>
<td class="cellrowborder" valign="top" width="80.57%" headers="mcps1.1.3.1.2 "><p id="p031165311519"><a name="p031165311519"></a><a name="p031165311519"></a>套接字描述符。</p>
</td>
</tr>
<tr id="row15311185317518"><td class="cellrowborder" valign="top" width="19.43%" headers="mcps1.1.3.1.1 "><p id="p7311115319516"><a name="p7311115319516"></a><a name="p7311115319516"></a>message</p>
</td>
<td class="cellrowborder" valign="top" width="80.57%" headers="mcps1.1.3.1.2 "><p id="p331125385118"><a name="p331125385118"></a><a name="p331125385118"></a>待发送的消息,不支持发送ancillary消息。</p>
</td>
</tr>
<tr id="row63111753195116"><td class="cellrowborder" valign="top" width="19.43%" headers="mcps1.1.3.1.1 "><p id="p131175318519"><a name="p131175318519"></a><a name="p131175318519"></a>flags</p>
</td>
<td class="cellrowborder" valign="top" width="80.57%" headers="mcps1.1.3.1.2 "><p id="p11799112211525"><a name="p11799112211525"></a><a name="p11799112211525"></a>用于指定发送消息时行为特性,有如下行为特性:</p>
<a name="ul1179912222521"></a><a name="ul1179912222521"></a><ul id="ul1179912222521"><li>MSG_MORE:允许将多次发送的消息进行拼包发送。</li><li>MSG_DONTWAIT:非阻塞操作。</li></ul>
</td>
</tr>
</tbody>
</table>
**返回值:**
- 成功返回:已发送的消息长度(字节数)。
- 失败返回:-1,并设置errno。
- **recvmsg**
**函数原型:**
ssize\_t recvmsg\(int s, struct msghdr \*message, int flags\)
**函数功能:**接收消息。
**参数说明:**
<a name="table1847716407526"></a>
<table><thead align="left"><tr id="row15477840185218"><th class="cellrowborder" valign="top" width="21.42%" id="mcps1.1.3.1.1"><p id="p8477104015217"><a name="p8477104015217"></a><a name="p8477104015217"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="78.58000000000001%" id="mcps1.1.3.1.2"><p id="p1447717402527"><a name="p1447717402527"></a><a name="p1447717402527"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row3477340125210"><td class="cellrowborder" valign="top" width="21.42%" headers="mcps1.1.3.1.1 "><p id="p154771740155218"><a name="p154771740155218"></a><a name="p154771740155218"></a>s</p>
</td>
<td class="cellrowborder" valign="top" width="78.58000000000001%" headers="mcps1.1.3.1.2 "><p id="p1347718402522"><a name="p1347718402522"></a><a name="p1347718402522"></a>套接字描述符。</p>
</td>
</tr>
<tr id="row174771405527"><td class="cellrowborder" valign="top" width="21.42%" headers="mcps1.1.3.1.1 "><p id="p54771440185218"><a name="p54771440185218"></a><a name="p54771440185218"></a>message</p>
</td>
<td class="cellrowborder" valign="top" width="78.58000000000001%" headers="mcps1.1.3.1.2 "><p id="p5477164075215"><a name="p5477164075215"></a><a name="p5477164075215"></a>存放接收的消息,不支持接收ancillary消息。</p>
</td>
</tr>
<tr id="row9477174020529"><td class="cellrowborder" valign="top" width="21.42%" headers="mcps1.1.3.1.1 "><p id="p747715404521"><a name="p747715404521"></a><a name="p747715404521"></a>flags</p>
</td>
<td class="cellrowborder" valign="top" width="78.58000000000001%" headers="mcps1.1.3.1.2 "><p id="p99911829531"><a name="p99911829531"></a><a name="p99911829531"></a>用于指定接收消息时行为特性,有如下行为特性:</p>
<a name="ul1099113216538"></a><a name="ul1099113216538"></a><ul id="ul1099113216538"><li>MSG_PEEK:允许预读消息而不取走。</li><li>MSG_DONTWAIT:非阻塞操作。</li></ul>
</td>
</tr>
</tbody>
</table>
**返回值:**
- 成功返回:已接收的消息长度(字节数)。
- 失败返回:-1,并设置errno。
- **ioctl**
**函数原型:**
int ioctl\(int s, int request, ...\)
**函数功能:**获取或设置socket属性。
**参数说明:**
<a name="table1011381714533"></a>
<table><thead align="left"><tr id="row16113161795318"><th class="cellrowborder" valign="top" width="15.25%" id="mcps1.1.3.1.1"><p id="p1811381712530"><a name="p1811381712530"></a><a name="p1811381712530"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="84.75%" id="mcps1.1.3.1.2"><p id="p20113161712534"><a name="p20113161712534"></a><a name="p20113161712534"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row18113191735318"><td class="cellrowborder" valign="top" width="15.25%" headers="mcps1.1.3.1.1 "><p id="p9113617165312"><a name="p9113617165312"></a><a name="p9113617165312"></a>s</p>
</td>
<td class="cellrowborder" valign="top" width="84.75%" headers="mcps1.1.3.1.2 "><p id="p16114317145314"><a name="p16114317145314"></a><a name="p16114317145314"></a>套接字描述符。</p>
</td>
</tr>
<tr id="row5114121719536"><td class="cellrowborder" valign="top" width="15.25%" headers="mcps1.1.3.1.1 "><p id="p17114117185312"><a name="p17114117185312"></a><a name="p17114117185312"></a>request</p>
</td>
<td class="cellrowborder" valign="top" width="84.75%" headers="mcps1.1.3.1.2 "><p id="p137162040165319"><a name="p137162040165319"></a><a name="p137162040165319"></a>对socket属性要进行的操作,当前支持如下操作:</p>
<a name="ul1671694075316"></a><a name="ul1671694075316"></a><ul id="ul1671694075316"><li>FIONREAD:获取socket当前可读取的数据大小(字节数)。</li><li>FIONBIO:设置socket是否非阻塞。</li></ul>
</td>
</tr>
</tbody>
</table>
**返回值:**
- 成功返回:0。
- 失败返回:-1,并设置errno。
# 进程<a name="ZH-CN_TOPIC_0000001051612194"></a>
- [基本概念](#section29197338383)
- [使用场景](#section85513272398)
- [接口说明](#section4517119124015)
## 基本概念<a name="section29197338383"></a>
从系统的角度看,进程是资源管理单元。进程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它进程运行。
OpenHarmony内核的进程模块可以给用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。这样用户可以将更多的精力投入到业务功能的实现中。
OpenHarmony内核中的进程采用抢占式调度机制,支持时间片轮转调度方式。
OpenHarmony内核的进程一共有32个优先级\(0-31\),用户进程可配置的优先级有22个\(10-31\),最高优先级为10,最低优先级为31。
高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。
每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离。
用户态根进程init由内核态创建,其它用户态进程均由init进程fork而来。
**进程状态说明:**
- 初始化(Init):该进程正在被创建。
- 就绪(Ready):该进程在就绪列表中,等待CPU调度。
- 运行(Running):该进程正在运行。
- 阻塞(Pending):该进程被阻塞挂起。本进程内所有的线程均被阻塞时,进程被阻塞挂起。
- 僵尸态(Zombies):该进程运行结束,等待父进程回收其控制块资源。
**图 1** 进程状态迁移示意图<a name="fig1877059202911"></a>
![](figure/进程状态迁移示意图.png "进程状态迁移示意图")
**进程状态迁移说明:**
- Init→Ready:
进程创建或fork时,拿到该进程控制块后进入Init状态,处于进程初始化阶段,当进程初始化完成将进程插入调度队列,此时进程进入就绪状态。
- Ready→Running:
进程创建后进入就绪态,发生进程切换时,就绪列表中最高优先级的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则该进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存。
- Running→Pending:
进程内所有的线程均处于阻塞态时,进程在最后一个线程转为阻塞态时,同步进入阻塞态,然后发生进程切换。
- Pending→Ready:
阻塞进程内的任意线程恢复就绪态时,进程被加入到就绪队列,同步转为就绪态。
- Ready→Pending:
进程内的最后一个就绪态线程处于阻塞态时,进程从就绪列表中删除,进程由就绪态转为阻塞态。
- Running→Ready:
进程由运行态转为就绪态的情况有以下两种:
1. 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。
2. 若进程的调度策略为SCHED\_RR,且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。
- Running→Zombies:
当进程的主线程或所有线程运行结束后,进程由运行态转为僵尸态,等待父进程回收资源。
## 使用场景<a name="section85513272398"></a>
进程创建后,用户只能操作自己进程空间的资源,无法操作其它进程的资源(共享资源除外)。 用户态允许进程挂起,恢复,延时等操作,同时也可以设置用户态进程调度优先级和调度策略,获取进程调度优先级和调度策略。进程结束的时候,进程会主动释放持有的进程资源,但持有的进程pid资源需要父进程通过wait/waitpid或父进程退出时回收。
## 接口说明<a name="section4517119124015"></a>
OpenHarmony内核系统中的进程管理模块为用户提供下面几种功能:
**表 1** 进程管理模块功能
<a name="table12130144215441"></a>
<table><thead align="left"><tr id="row630210427446"><th class="cellrowborder" valign="top" width="13.08%" id="mcps1.2.5.1.1"><p id="p1430244284410"><a name="p1430244284410"></a><a name="p1430244284410"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="23.09%" id="mcps1.2.5.1.2"><p id="p9302164284416"><a name="p9302164284416"></a><a name="p9302164284416"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="28.82%" id="mcps1.2.5.1.3"><p id="p730211427445"><a name="p730211427445"></a><a name="p730211427445"></a>描述</p>
</th>
<th class="cellrowborder" valign="top" width="35.010000000000005%" id="mcps1.2.5.1.4"><p id="p1430214294419"><a name="p1430214294419"></a><a name="p1430214294419"></a>备注</p>
</th>
</tr>
</thead>
<tbody><tr id="row12302642134414"><td class="cellrowborder" rowspan="13" valign="top" width="13.08%" headers="mcps1.2.5.1.1 "><p id="p430213427443"><a name="p430213427443"></a><a name="p430213427443"></a>进程</p>
</td>
<td class="cellrowborder" valign="top" width="23.09%" headers="mcps1.2.5.1.2 "><p id="p10302154219449"><a name="p10302154219449"></a><a name="p10302154219449"></a>fork</p>
</td>
<td class="cellrowborder" valign="top" width="28.82%" headers="mcps1.2.5.1.3 "><p id="p930218420449"><a name="p930218420449"></a><a name="p930218420449"></a>创建一个新进程。</p>
</td>
<td class="cellrowborder" valign="top" width="35.010000000000005%" headers="mcps1.2.5.1.4 "><p id="p230224211440"><a name="p230224211440"></a><a name="p230224211440"></a>-</p>
</td>
</tr>
<tr id="row20302154218442"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p130314204419"><a name="p130314204419"></a><a name="p130314204419"></a>exit</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p53031426443"><a name="p53031426443"></a><a name="p53031426443"></a>终止进程。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p113034423445"><a name="p113034423445"></a><a name="p113034423445"></a>-</p>
</td>
</tr>
<tr id="row930314421443"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p13303124213442"><a name="p13303124213442"></a><a name="p13303124213442"></a>atexit</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p1330324210442"><a name="p1330324210442"></a><a name="p1330324210442"></a>注册正常进程终止的回调函数。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p3303144264414"><a name="p3303144264414"></a><a name="p3303144264414"></a>-</p>
</td>
</tr>
<tr id="row113039426449"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1630394220444"><a name="p1630394220444"></a><a name="p1630394220444"></a>abort</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p133037421441"><a name="p133037421441"></a><a name="p133037421441"></a>中止进程执行。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p1330334216449"><a name="p1330334216449"></a><a name="p1330334216449"></a>-</p>
</td>
</tr>
<tr id="row1330317422445"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p113036427441"><a name="p113036427441"></a><a name="p113036427441"></a>getpid</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p17303642194412"><a name="p17303642194412"></a><a name="p17303642194412"></a>获取进程ID。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p14304942104420"><a name="p14304942104420"></a><a name="p14304942104420"></a>-</p>
</td>
</tr>
<tr id="row3304204254412"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1430404218442"><a name="p1430404218442"></a><a name="p1430404218442"></a>getppid</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p9304134217443"><a name="p9304134217443"></a><a name="p9304134217443"></a>获取父进程ID。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p1530418423449"><a name="p1530418423449"></a><a name="p1530418423449"></a>-</p>
</td>
</tr>
<tr id="row610863618327"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p110811368324"><a name="p110811368324"></a><a name="p110811368324"></a>getpgrp</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p51091436133217"><a name="p51091436133217"></a><a name="p51091436133217"></a>获取调用进程的进程组ID。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p31094364326"><a name="p31094364326"></a><a name="p31094364326"></a>-</p>
</td>
</tr>
<tr id="row2379940183217"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1380184016329"><a name="p1380184016329"></a><a name="p1380184016329"></a>getpgid</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p8121101872215"><a name="p8121101872215"></a><a name="p8121101872215"></a>获取进程的进程组ID。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p63802401326"><a name="p63802401326"></a><a name="p63802401326"></a>-</p>
</td>
</tr>
<tr id="row1981395963412"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p4814559123412"><a name="p4814559123412"></a><a name="p4814559123412"></a>setpgrp</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p171226183225"><a name="p171226183225"></a><a name="p171226183225"></a>设置调用进程的进程组ID。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p8814959123416"><a name="p8814959123416"></a><a name="p8814959123416"></a>-</p>
</td>
</tr>
<tr id="row194862793516"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p5948162703511"><a name="p5948162703511"></a><a name="p5948162703511"></a>setpgid</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p7122131852218"><a name="p7122131852218"></a><a name="p7122131852218"></a>设置进程的进程组ID。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p1994915279352"><a name="p1994915279352"></a><a name="p1994915279352"></a>-</p>
</td>
</tr>
<tr id="row10304742114410"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p530474264418"><a name="p530474264418"></a><a name="p530474264418"></a>kill</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p2304174213441"><a name="p2304174213441"></a><a name="p2304174213441"></a>给进程发送信号。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><a name="ul949915272011"></a><a name="ul949915272011"></a><ul id="ul949915272011"><li>仅支持1-30号信号的发送。</li><li>信号的默认行为不支持STOP及CONTINUE,无COREDUMP功能。</li><li>不能屏蔽SIGSTOP、SIGKILL、SIGCONT。</li><li>异步信号,发送信号给某进程后,直到该进程被调度后才会执行信号回调(为安全起见,杀死进程的动作是进程自己执行的,内核不能通过信号强制杀死对方)。</li><li>进程消亡会发送SIGCHLD给父进程,发送动作无法取消。</li><li>无法通过信号唤醒正在睡眠的进程。</li></ul>
</td>
</tr>
<tr id="row1430454210446"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p830494212443"><a name="p830494212443"></a><a name="p830494212443"></a>wait</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p230464294410"><a name="p230464294410"></a><a name="p230464294410"></a>等待任意子进程结束并回收子进程资源。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p12512337347"><a name="p12512337347"></a><a name="p12512337347"></a>status的值可以由以下宏定义解析:</p>
<a name="ul13349201524417"></a><a name="ul13349201524417"></a><ul id="ul13349201524417"><li>WIFEXITED(status):如果子进程正常结束,它就返回真;否则返回假。</li><li>WEXITSTATUS(status):如果WIFEXITED(status)为真,则可以用该宏取得子进程exit()返回的退出码。</li><li>WTERMSIG(status) 仅支持以下情况:子进程触发异常结束后通过WTERMSIG获取的进程退出编号始终为SIGUSR2。</li><li>不支持的操作: WIFSTOPPED、WSTOPSIG、WCOREDUMP 、WIFCONTINUED。</li></ul>
</td>
</tr>
<tr id="row13041742134416"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1530434217444"><a name="p1530434217444"></a><a name="p1530434217444"></a>waitpid</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p130564294420"><a name="p130564294420"></a><a name="p130564294420"></a>等待子进程结束并回收子进程资源。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p969785263816"><a name="p969785263816"></a><a name="p969785263816"></a>options:不支持WUNTRACED,WCONTINUED;</p>
<p id="p8497151543715"><a name="p8497151543715"></a><a name="p8497151543715"></a>status的值可以由以下宏定义解析:</p>
<a name="ul7243133164416"></a><a name="ul7243133164416"></a><ul id="ul7243133164416"><li>WIFEXITED(status):如果子进程正常结束,它就返回真;否则返回假。</li><li>WEXITSTATUS(status):如果WIFEXITED(status)为真,则可以用该宏取得子进程exit()返回的退出码。</li><li>WTERMSIG(status)仅支持以下情况:子进程触发异常结束后通过WTERMSIG获取的进程退出编号始终为SIGUSR2。</li><li>不支持:WIFSTOPPED 、WSTOPSIG、WCOREDUMP 、WIFCONTINUED。</li></ul>
</td>
</tr>
<tr id="row4305194294417"><td class="cellrowborder" rowspan="10" valign="top" width="13.08%" headers="mcps1.2.5.1.1 "><p id="p5305194264419"><a name="p5305194264419"></a><a name="p5305194264419"></a>调度</p>
</td>
<td class="cellrowborder" valign="top" width="23.09%" headers="mcps1.2.5.1.2 "><p id="p630544224416"><a name="p630544224416"></a><a name="p630544224416"></a>getpriority</p>
</td>
<td class="cellrowborder" valign="top" width="28.82%" headers="mcps1.2.5.1.3 "><p id="p174915589591"><a name="p174915589591"></a><a name="p174915589591"></a>获取指定ID的静态优先级。</p>
</td>
<td class="cellrowborder" rowspan="2" valign="top" width="35.010000000000005%" headers="mcps1.2.5.1.4 "><a name="ul185518513478"></a><a name="ul185518513478"></a><ul id="ul185518513478"><li>不支持:PRIO_PGRP、PRIO_USER。</li></ul>
<a name="ul85091358174711"></a><a name="ul85091358174711"></a><ul id="ul85091358174711"><li>无动态优先级概念,用于设置静态优先级。</li></ul>
</td>
</tr>
<tr id="row930511425448"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1730524217448"><a name="p1730524217448"></a><a name="p1730524217448"></a>setpriority</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p17750205817594"><a name="p17750205817594"></a><a name="p17750205817594"></a>设置指定ID的静态优先级。</p>
</td>
</tr>
<tr id="row2305174216445"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p7305942104417"><a name="p7305942104417"></a><a name="p7305942104417"></a>sched_rr_get_interval</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p1362018100165"><a name="p1362018100165"></a><a name="p1362018100165"></a>获取执行时间限制。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p5306134212447"><a name="p5306134212447"></a><a name="p5306134212447"></a>-</p>
</td>
</tr>
<tr id="row33061042104416"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p143061642164412"><a name="p143061642164412"></a><a name="p143061642164412"></a>sched_yield</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p1262017102164"><a name="p1262017102164"></a><a name="p1262017102164"></a>系统调用运行进程主动让出执行权。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p14306134220441"><a name="p14306134220441"></a><a name="p14306134220441"></a>-</p>
</td>
</tr>
<tr id="row11306134234417"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p11306184264417"><a name="p11306184264417"></a><a name="p11306184264417"></a>sched_get_priority_max</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p123062423446"><a name="p123062423446"></a><a name="p123062423446"></a>获取进程静态优先级取值范围的最大值。</p>
</td>
<td class="cellrowborder" rowspan="4" valign="top" headers="mcps1.2.5.1.3 "><p id="p11306154210440"><a name="p11306154210440"></a><a name="p11306154210440"></a>调度策略只支持:SCHED_RR。</p>
</td>
</tr>
<tr id="row15306242124413"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p430612427448"><a name="p430612427448"></a><a name="p430612427448"></a>sched_get_priority_min</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p430618428442"><a name="p430618428442"></a><a name="p430618428442"></a>获取进程静态优先级取值范围的最小值。</p>
</td>
</tr>
<tr id="row730610428448"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p230684284419"><a name="p230684284419"></a><a name="p230684284419"></a>sched_getscheduler</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p20306184224417"><a name="p20306184224417"></a><a name="p20306184224417"></a>获取调度策略。</p>
</td>
</tr>
<tr id="row630764215441"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1530719424444"><a name="p1530719424444"></a><a name="p1530719424444"></a>sched_setscheduler</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p13072042104416"><a name="p13072042104416"></a><a name="p13072042104416"></a>设置调度策略。</p>
</td>
</tr>
<tr id="row3307184274411"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p12307114274419"><a name="p12307114274419"></a><a name="p12307114274419"></a>sched_getparam</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p9307104210441"><a name="p9307104210441"></a><a name="p9307104210441"></a>获取调度参数。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p163071842194417"><a name="p163071842194417"></a><a name="p163071842194417"></a>-</p>
</td>
</tr>
<tr id="row18307104210449"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1230784264419"><a name="p1230784264419"></a><a name="p1230784264419"></a>sched_setparam</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p1530784215445"><a name="p1530784215445"></a><a name="p1530784215445"></a>设置调度参数。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p730714264415"><a name="p730714264415"></a><a name="p730714264415"></a>-</p>
</td>
</tr>
<tr id="row17412918306"><td class="cellrowborder" rowspan="6" valign="top" width="13.08%" headers="mcps1.2.5.1.1 "><p id="p8528162314312"><a name="p8528162314312"></a><a name="p8528162314312"></a>exec</p>
</td>
<td class="cellrowborder" valign="top" width="23.09%" headers="mcps1.2.5.1.2 "><p id="p1951498305"><a name="p1951498305"></a><a name="p1951498305"></a>execl</p>
</td>
<td class="cellrowborder" valign="top" width="28.82%" headers="mcps1.2.5.1.3 "><p id="p1612191842215"><a name="p1612191842215"></a><a name="p1612191842215"></a>执行指定的elf格式的用户程序文件。</p>
</td>
<td class="cellrowborder" valign="top" width="35.010000000000005%" headers="mcps1.2.5.1.4 "><p id="p11679610113215"><a name="p11679610113215"></a><a name="p11679610113215"></a>-</p>
</td>
</tr>
<tr id="row16964151163015"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1996413117300"><a name="p1996413117300"></a><a name="p1996413117300"></a>execle</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p104059331261"><a name="p104059331261"></a><a name="p104059331261"></a>执行指定的elf格式的用户程序文件。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p3209101117329"><a name="p3209101117329"></a><a name="p3209101117329"></a>-</p>
</td>
</tr>
<tr id="row9418101418309"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p741881443010"><a name="p741881443010"></a><a name="p741881443010"></a>execlp</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p493315383264"><a name="p493315383264"></a><a name="p493315383264"></a>执行指定的elf格式的用户程序文件。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p8741121112325"><a name="p8741121112325"></a><a name="p8741121112325"></a>-</p>
</td>
</tr>
<tr id="row2058611176305"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p155869170309"><a name="p155869170309"></a><a name="p155869170309"></a>execv</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p1644334112613"><a name="p1644334112613"></a><a name="p1644334112613"></a>执行指定的elf格式的用户程序文件。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p423311211323"><a name="p423311211323"></a><a name="p423311211323"></a>-</p>
</td>
</tr>
<tr id="row182359476306"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p202351547163016"><a name="p202351547163016"></a><a name="p202351547163016"></a>execve</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p13152444192616"><a name="p13152444192616"></a><a name="p13152444192616"></a>执行指定的elf格式的用户程序文件。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p148072123324"><a name="p148072123324"></a><a name="p148072123324"></a>-</p>
</td>
</tr>
<tr id="row14242145013304"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p02437507305"><a name="p02437507305"></a><a name="p02437507305"></a>execvp</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p06334469262"><a name="p06334469262"></a><a name="p06334469262"></a>执行指定的elf格式的用户程序文件。</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p333161353217"><a name="p333161353217"></a><a name="p333161353217"></a>-</p>
</td>
</tr>
</tbody>
</table>
# 文件命令<a name="ZH-CN_TOPIC_0000001051930301"></a>
- **[cat](kernel-lite-small-shell-cmd-file-cat.md)**
- **[cd](kernel-lite-small-shell-cmd-file-cd.md)**
- **[chgrp](kernel-lite-small-shell-cmd-file-chgrp.md)**
- **[chmod](kernel-lite-small-shell-cmd-file-chmod.md)**
- **[chown](kernel-lite-small-shell-cmd-file-chown.md)**
- **[cp](kernel-lite-small-shell-cmd-file-cp.md)**
- **[format](kernel-lite-small-shell-cmd-file-format.md)**
- **[ls](kernel-lite-small-shell-cmd-file-is.md)**
- **[lsfd](kernel-lite-small-shell-cmd-file-isfd.md)**
- **[mkdir](kernel-lite-small-shell-cmd-file-mkdir.md)**
- **[mount](kernel-lite-small-shell-cmd-file-mount.md)**
- **[partinfo](kernel-lite-small-shell-cmd-file-part.md)**
- **[partition](kernel-lite-small-shell-cmd-file-partion.md)**
- **[pwd](kernel-lite-small-shell-cmd-file-pwd.md)**
- **[rm](kernel-lite-small-shell-cmd-file-rm.md)**
- **[rmdir](kernel-lite-small-shell-cmd-file-rmdir.md)**
- **[statfs](kernel-lite-small-shell-cmd-file-sta.md)**
- **[sync](kernel-lite-small-shell-cmd-file-sync.md)**
- **[touch](kernel-lite-small-shell-cmd-file-touch.md)**
- **[writeproc](kernel-lite-small-shell-cmd-file-write.md)**
- **[umount](kernel-lite-small-shell-cmd-file-umount.md)**
# 网络命令<a name="ZH-CN_TOPIC_0000001051770296"></a>
- **[arp](kernel-lite-small-shell-cmd-net-arp.md)**
- **[dhclient](kernel-lite-small-shell-cmd-net-dh.md)**
- **[dns](kernel-lite-small-shell-cmd-net-dns.md)**
- **[ifconfig](kernel-lite-small-shell-cmd-net-ipc.md)**
- **[ipdebug](kernel-lite-small-shell-cmd-net-ipd.md)**
- **[netstat](kernel-lite-small-shell-cmd-net-net.md)**
- **[ntpdate](kernel-lite-small-shell-cmd-net-ntp.md)**
- **[ping](kernel-lite-small-shell-cmd-net-ping.md)**
- **[ping6](kernel-lite-small-shell-cmd-net-ping6.md)**
- **[telnet](kernel-lite-small-shell-cmd-net-tel.md)**
- **[tftp](kernel-lite-small-shell-cmd-net-tftp.md)**
# 系统命令<a name="ZH-CN_TOPIC_0000001051451589"></a>
- **[cpup](kernel-lite-small-shell-cmd-sys-cpup.md)**
- **[date](kernel-lite-small-shell-cmd-sys-date.md)**
- **[dmesg](kernel-lite-small-shell-cmd-sys-demsg.md)**
- **[exec](kernel-lite-small-shell-cmd-sys-exec.md)**
- **[free](kernel-lite-small-shell-cmd-sys-free.md)**
- **[help](kernel-lite-small-shell-cmd-sys-help.md)**
- **[hwi](kernel-lite-small-shell-cmd-sys-hwi.md)**
- **[kill](kernel-lite-small-shell-cmd-sys-kill.md)**
- **[log](kernel-lite-small-shell-cmd-sys-log.md)**
- **[memcheck](kernel-lite-small-shell-cmd-sys-mem.md)**
- **[oom](kernel-lite-small-shell-cmd-sys-oom.md)**
- **[pmm](kernel-lite-small-shell-cmd-sys-pmm.md)**
- **[reset](kernel-lite-small-shell-cmd-sys-reset.md)**
- **[sem](kernel-lite-small-shell-cmd-sys-sem.md)**
- **[stack](kernel-lite-small-shell-cmd-sys-stack.md)**
- **[su](kernel-lite-small-shell-cmd-sys-su.md)**
- **[swtmr](kernel-lite-small-shell-cmd-sys-swymr.md)**
- **[systeminfo](kernel-lite-small-shell-cmd-sys-sys.md)**
- **[task](kernel-lite-small-shell-cmd-sys-task.md)**
- **[uname](kernel-lite-small-shell-cmd-sys-uname.md)**
- **[vmm](kernel-lite-small-shell-cmd-sys-vmm.md)**
- **[watch](kernel-lite-small-shell-cmd-sys-watch.md)**
# Shell命令使用详解<a name="ZH-CN_TOPIC_0000001051611536"></a>
本章节介绍了系统关键命令的功能、格式、参数范围、使用指南和使用实例。
不在本文档范围内的命令,详见[help](kernel-lite-small-shell-cmd-sys-help.md)命令的输出内容,也可以通过命令的“-h | --help”选项,查看该命令的使用帮助。
- **[系统命令](kernel-lite-small-shell-cmd-sys.md)**
- **[文件命令](kernel-lite-small-shell-cmd-file.md)**
- **[网络命令](kernel-lite-small-shell-cmd-net.md)**
# 调测<a name="ZH-CN_TOPIC_0000001157319409"></a>
- **[Shell介绍](kernel-lite-small-shell-des.md)**
- **[Shell命令开发指导](kernel-lite-small-shell-guide.md)**
- **[Shell命令编程实例](kernel-lite-small-shell-sample.md)**
- **[Shell命令使用详解](kernel-lite-small-shell-cmd.md)**
- **[魔法键使用方法](kernel-lite-small-shell-cmd-mag.md)**
- **[用户态异常信息说明](kernel-lite-small-shell-cmd-abn.md)**
# 线程<a name="ZH-CN_TOPIC_0000001051452247"></a>
- [基本概念](#section1179311337405)
- [使用场景](#section44877547404)
- [接口说明](#section2069477134115)
## 基本概念<a name="section1179311337405"></a>
从系统的角度看,线程是竞争系统资源的最小运行单元。线程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它线程运行。
OpenHarmony内核每个进程内的线程独立运行、独立调度,当前进程内线程的调度不受其它进程内线程的影响。
OpenHarmony内核中的线程采用抢占式调度机制,同时支持时间片轮转调度和FIFO调度方式。
OpenHarmony内核的线程一共有32个优先级\(0-31\),最高优先级为0,最低优先级为31。
当前进程内高优先级的线程可抢占当前进程内低优先级线程,当前进程内低优先级线程必须在当前进程内高优先级线程阻塞或结束后才能得到调度。
**线程状态说明:**
- 初始化(Init):该线程正在被创建。
- 就绪(Ready):该线程在就绪列表中,等待CPU调度。
- 运行(Running):该线程正在运行。
- 阻塞(Blocked):该线程被阻塞挂起。Blocked状态包括:pending\(因为锁、事件、信号量等阻塞\)、suspended(主动pend)、delay\(延时阻塞\)、pendtime\(因为锁、事件、信号量时间等超时等待\)
- 退出(Exit):该线程运行结束,等待父线程回收其控制块资源。
**图 1** 线程状态迁移示意图<a name="fig15746193414436"></a>
![](figure/线程状态迁移示意图.png "线程状态迁移示意图")
**线程状态迁移说明:**
- Init→Ready:
线程创建拿到控制块后为Init状态,处于线程初始化阶段,当线程初始化完成将线程插入调度队列,此时线程进入就绪状态。
- Ready→Running:
线程创建后进入就绪态,发生线程切换时,就绪列表中最高优先级的线程被执行,从而进入运行态,但此刻该线程会从就绪列表中删除。
- Running→Blocked:
正在运行的线程发生阻塞(挂起、延时、读信号量等)时,线程状态由运行态变成阻塞态,然后发生线程切换,运行就绪列表中剩余最高优先级线程。
- Blocked→Ready :
阻塞的线程被恢复后(线程恢复、延时时间超时、读信号量超时或读到信号量等),此时被恢复的线程会被加入就绪列表,从而由阻塞态变成就绪态。
- Ready→Blocked:
线程也有可能在就绪态时被阻塞(挂起),此时线程状态会由就绪态转变为阻塞态,该线程从就绪列表中删除,不会参与线程调度,直到该线程被恢复。
- Running→Ready:
有更高优先级线程创建或者恢复后,会发生线程调度,此刻就绪列表中最高优先级线程变为运行态,那么原先运行的线程由运行态变为就绪态,并加入就绪列表中。
- Running→Exit:
运行中的线程运行结束,线程状态由运行态变为退出态。若未设置分离属性(PTHREAD\_CREATE\_DETACHED)的线程,运行结束后对外呈现的是Exit状态,即退出态。
## 使用场景<a name="section44877547404"></a>
线程创建后,用户态可以执行线程调度、挂起、恢复、延时等操作,同时也可以设置线程优先级和调度策略,获取线程优先级和调度策略。
## 接口说明<a name="section2069477134115"></a>
OpenHarmony内核系统中的线程管理模块,线程间通信为用户提供下面几种功能:
**表 1** 线程管理模块功能
<a name="table134475244618"></a>
<table><thead align="left"><tr id="row16880122144619"><th class="cellrowborder" valign="top" width="14.299999999999999%" id="mcps1.2.5.1.1"><p id="p88808214619"><a name="p88808214619"></a><a name="p88808214619"></a>头文件</p>
</th>
<th class="cellrowborder" valign="top" width="28.599999999999998%" id="mcps1.2.5.1.2"><p id="p16880182174611"><a name="p16880182174611"></a><a name="p16880182174611"></a>名称</p>
</th>
<th class="cellrowborder" valign="top" width="22.38%" id="mcps1.2.5.1.3"><p id="p198806214469"><a name="p198806214469"></a><a name="p198806214469"></a>说明</p>
</th>
<th class="cellrowborder" valign="top" width="34.72%" id="mcps1.2.5.1.4"><p id="p1188013294618"><a name="p1188013294618"></a><a name="p1188013294618"></a>备注</p>
</th>
</tr>
</thead>
<tbody><tr id="row1188092104619"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p488052134616"><a name="p488052134616"></a><a name="p488052134616"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p108808218461"><a name="p108808218461"></a><a name="p108808218461"></a>pthread_attr_destroy</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p18809234612"><a name="p18809234612"></a><a name="p18809234612"></a>销毁线程属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1988012213468"><a name="p1988012213468"></a><a name="p1988012213468"></a>-</p>
</td>
</tr>
<tr id="row28802274616"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p148806212469"><a name="p148806212469"></a><a name="p148806212469"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p7880720461"><a name="p7880720461"></a><a name="p7880720461"></a><span>pthread_attr_getinheritsched</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p588012104619"><a name="p588012104619"></a><a name="p588012104619"></a>获取线程属性对象的调度属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p11880524466"><a name="p11880524466"></a><a name="p11880524466"></a>-</p>
</td>
</tr>
<tr id="row1888132164611"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p8881202114618"><a name="p8881202114618"></a><a name="p8881202114618"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p13881142154614"><a name="p13881142154614"></a><a name="p13881142154614"></a><span>pthread_attr_getschedparam</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p12881142144612"><a name="p12881142144612"></a><a name="p12881142144612"></a>获取线程属性对象的调度参数属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p988112204611"><a name="p988112204611"></a><a name="p988112204611"></a>-</p>
</td>
</tr>
<tr id="row788102134613"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p16881122114611"><a name="p16881122114611"></a><a name="p16881122114611"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p388111215466"><a name="p388111215466"></a><a name="p388111215466"></a><span>pthread_attr_getschedpolicy</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p19881152174612"><a name="p19881152174612"></a><a name="p19881152174612"></a>获取线程属性对象的调度策略属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p988112294619"><a name="p988112294619"></a><a name="p988112294619"></a><span id="text174691111144919"><a name="text174691111144919"></a><a name="text174691111144919"></a>OpenHarmony</span>:支持SCHED_FIFO 、SCHED_RR调度策略。</p>
</td>
</tr>
<tr id="row14881423468"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p588152114611"><a name="p588152114611"></a><a name="p588152114611"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p188811626465"><a name="p188811626465"></a><a name="p188811626465"></a><span>pthread_attr_getstacksize</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p08825214467"><a name="p08825214467"></a><a name="p08825214467"></a>获取线程属性对象的堆栈大小。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p8882827467"><a name="p8882827467"></a><a name="p8882827467"></a>-</p>
</td>
</tr>
<tr id="row088212144619"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p688215274612"><a name="p688215274612"></a><a name="p688215274612"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p88827218466"><a name="p88827218466"></a><a name="p88827218466"></a><span>pthread_attr_init</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p14447368158"><a name="p14447368158"></a><a name="p14447368158"></a>初始化线程属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p12882202134618"><a name="p12882202134618"></a><a name="p12882202134618"></a>-</p>
</td>
</tr>
<tr id="row1788214210462"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p3882525463"><a name="p3882525463"></a><a name="p3882525463"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1882528461"><a name="p1882528461"></a><a name="p1882528461"></a><span>pthread_attr_setdetachstate</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p11455363157"><a name="p11455363157"></a><a name="p11455363157"></a>设置线程属性对象的分离状态。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1788202174613"><a name="p1788202174613"></a><a name="p1788202174613"></a>-</p>
</td>
</tr>
<tr id="row188829211469"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1088222134619"><a name="p1088222134619"></a><a name="p1088222134619"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p588272204612"><a name="p588272204612"></a><a name="p588272204612"></a><span>pthread_attr_setinheritsched</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p14611364154"><a name="p14611364154"></a><a name="p14611364154"></a>设置线程属性对象的继承调度属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p3883102174611"><a name="p3883102174611"></a><a name="p3883102174611"></a>-</p>
</td>
</tr>
<tr id="row1588310244610"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p118831210461"><a name="p118831210461"></a><a name="p118831210461"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p188318214611"><a name="p188318214611"></a><a name="p188318214611"></a><span>pthread_attr_setschedparam</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1746636141515"><a name="p1746636141515"></a><a name="p1746636141515"></a>设置线程属性对象的调度参数属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p44251243115214"><a name="p44251243115214"></a><a name="p44251243115214"></a><span id="text1222517176498"><a name="text1222517176498"></a><a name="text1222517176498"></a>OpenHarmony</span>:设置线程优先级的参数值越小,线程在系统中的优先级越高;设置参数值越大,优先级越低。</p>
<p id="p142941635183917"><a name="p142941635183917"></a><a name="p142941635183917"></a>注意:需要将pthread_attr_t线程属性的inheritsched字段设置为PTHREAD_EXPLICIT_SCHED,否则设置的线程调度优先级将不会生效,系统默认设置为PTHREAD_INHERIT_SCHED。</p>
</td>
</tr>
<tr id="row118831264610"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1688315220469"><a name="p1688315220469"></a><a name="p1688315220469"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1488320217468"><a name="p1488320217468"></a><a name="p1488320217468"></a><span>pthread_attr_setschedpolicy</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p154615365156"><a name="p154615365156"></a><a name="p154615365156"></a>设置线程属性对象的调度策略属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p28831823468"><a name="p28831823468"></a><a name="p28831823468"></a><span id="text2826162394913"><a name="text2826162394913"></a><a name="text2826162394913"></a>OpenHarmony</span>:支持SCHED_FIFO 、SCHED_RR调度策略。</p>
</td>
</tr>
<tr id="row888320244618"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p88840216460"><a name="p88840216460"></a><a name="p88840216460"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p3884328461"><a name="p3884328461"></a><a name="p3884328461"></a><span>pthread_attr_setstacksize</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p158841329461"><a name="p158841329461"></a><a name="p158841329461"></a>设置线程属性对象的堆栈大小。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1488412244619"><a name="p1488412244619"></a><a name="p1488412244619"></a>-</p>
</td>
</tr>
<tr id="row168841629468"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p988452104612"><a name="p988452104612"></a><a name="p988452104612"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p19884162194610"><a name="p19884162194610"></a><a name="p19884162194610"></a>pthread_getattr_np</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p64812367153"><a name="p64812367153"></a><a name="p64812367153"></a>获取已创建线程的属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p108847254615"><a name="p108847254615"></a><a name="p108847254615"></a>-</p>
</td>
</tr>
<tr id="row28842029469"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1788412214613"><a name="p1788412214613"></a><a name="p1788412214613"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p188411220465"><a name="p188411220465"></a><a name="p188411220465"></a><span>pthread_cancel</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p08001317121519"><a name="p08001317121519"></a><a name="p08001317121519"></a>向线程发送取消请求。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1288416254611"><a name="p1288416254611"></a><a name="p1288416254611"></a>-</p>
</td>
</tr>
<tr id="row788418214464"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p128844204618"><a name="p128844204618"></a><a name="p128844204618"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p17885182194616"><a name="p17885182194616"></a><a name="p17885182194616"></a>pthread_testcancel</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1279931731513"><a name="p1279931731513"></a><a name="p1279931731513"></a>请求交付任何未决的取请求。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1588552204613"><a name="p1588552204613"></a><a name="p1588552204613"></a>-</p>
</td>
</tr>
<tr id="row98857211461"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p5885102174614"><a name="p5885102174614"></a><a name="p5885102174614"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1388582144612"><a name="p1388582144612"></a><a name="p1388582144612"></a>pthread_setcanceltype</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p2079991771517"><a name="p2079991771517"></a><a name="p2079991771517"></a>设置线程可取消类型。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p138854224619"><a name="p138854224619"></a><a name="p138854224619"></a>-</p>
</td>
</tr>
<tr id="row1988516211466"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p68851929468"><a name="p68851929468"></a><a name="p68851929468"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p288515234613"><a name="p288515234613"></a><a name="p288515234613"></a>pthread_setcancelstate</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p8799217101512"><a name="p8799217101512"></a><a name="p8799217101512"></a>设置线程可取消状态。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p488518224620"><a name="p488518224620"></a><a name="p488518224620"></a>-</p>
</td>
</tr>
<tr id="row1288520284619"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p158851125462"><a name="p158851125462"></a><a name="p158851125462"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p188511211463"><a name="p188511211463"></a><a name="p188511211463"></a><span>pthread_create</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p18798171712153"><a name="p18798171712153"></a><a name="p18798171712153"></a>创建一个新的线程。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p14886192124615"><a name="p14886192124615"></a><a name="p14886192124615"></a>-</p>
</td>
</tr>
<tr id="row1288614204611"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p388610218462"><a name="p388610218462"></a><a name="p388610218462"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p108861274620"><a name="p108861274620"></a><a name="p108861274620"></a><span>pthread_detach</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p379831718156"><a name="p379831718156"></a><a name="p379831718156"></a>分离一个线程。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p38861126461"><a name="p38861126461"></a><a name="p38861126461"></a>-</p>
</td>
</tr>
<tr id="row188614213467"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p14886826461"><a name="p14886826461"></a><a name="p14886826461"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p108861527469"><a name="p108861527469"></a><a name="p108861527469"></a><span>pthread_equal</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p18799817181516"><a name="p18799817181516"></a><a name="p18799817181516"></a>比较两个线程ID是否相等。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p588612219467"><a name="p588612219467"></a><a name="p588612219467"></a>-</p>
</td>
</tr>
<tr id="row1488619294613"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p108867214619"><a name="p108867214619"></a><a name="p108867214619"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p988752164613"><a name="p988752164613"></a><a name="p988752164613"></a><span>pthread_exit</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p979871741512"><a name="p979871741512"></a><a name="p979871741512"></a>终止正在调用的线程。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p28871522460"><a name="p28871522460"></a><a name="p28871522460"></a>-</p>
</td>
</tr>
<tr id="row88871220467"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p188877244617"><a name="p188877244617"></a><a name="p188877244617"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p188879212461"><a name="p188879212461"></a><a name="p188879212461"></a><span>pthread_getschedparam</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p158001717101517"><a name="p158001717101517"></a><a name="p158001717101517"></a>获取线程的调度策略和参数。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p198871128465"><a name="p198871128465"></a><a name="p198871128465"></a><span id="text138623004915"><a name="text138623004915"></a><a name="text138623004915"></a>OpenHarmony</span>:支持SCHED_FIFO 、SCHED_RR调度策略。</p>
</td>
</tr>
<tr id="row198871527462"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1188715284613"><a name="p1188715284613"></a><a name="p1188715284613"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p088715274620"><a name="p088715274620"></a><a name="p088715274620"></a><span>pthread_join</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p2079921719159"><a name="p2079921719159"></a><a name="p2079921719159"></a>等待指定的线程结束。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p2088815214462"><a name="p2088815214462"></a><a name="p2088815214462"></a>-</p>
</td>
</tr>
<tr id="row13888142184617"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p688802124614"><a name="p688802124614"></a><a name="p688802124614"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1088820215469"><a name="p1088820215469"></a><a name="p1088820215469"></a>pthread_self</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1179931761515"><a name="p1179931761515"></a><a name="p1179931761515"></a>获取当前线程的ID。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p588802164611"><a name="p588802164611"></a><a name="p588802164611"></a>-</p>
</td>
</tr>
<tr id="row15888132124614"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p8888627462"><a name="p8888627462"></a><a name="p8888627462"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1888811214620"><a name="p1888811214620"></a><a name="p1888811214620"></a>pthread_setschedprio</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1888816219469"><a name="p1888816219469"></a><a name="p1888816219469"></a>设置线程的调度静态优先级。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p48881822463"><a name="p48881822463"></a><a name="p48881822463"></a>-</p>
</td>
</tr>
<tr id="row12889142194616"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1988915284613"><a name="p1988915284613"></a><a name="p1988915284613"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p148891026466"><a name="p148891026466"></a><a name="p148891026466"></a>pthread_kill</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p128001017121510"><a name="p128001017121510"></a><a name="p128001017121510"></a>向线程发送信号。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p9889522466"><a name="p9889522466"></a><a name="p9889522466"></a>-</p>
</td>
</tr>
<tr id="row19889624465"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p0889620469"><a name="p0889620469"></a><a name="p0889620469"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p58894244612"><a name="p58894244612"></a><a name="p58894244612"></a>pthread_once</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p4801617171515"><a name="p4801617171515"></a><a name="p4801617171515"></a>使函数调用只能执行一次。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p16889122204617"><a name="p16889122204617"></a><a name="p16889122204617"></a>-</p>
</td>
</tr>
<tr id="row288917219462"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1688913294617"><a name="p1688913294617"></a><a name="p1688913294617"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p2889152174613"><a name="p2889152174613"></a><a name="p2889152174613"></a>pthread_atfork</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p198899219461"><a name="p198899219461"></a><a name="p198899219461"></a>注册fork的处理程序。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p2889520467"><a name="p2889520467"></a><a name="p2889520467"></a>-</p>
</td>
</tr>
<tr id="row988922114611"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p88897234618"><a name="p88897234618"></a><a name="p88897234618"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1588952114611"><a name="p1588952114611"></a><a name="p1588952114611"></a>pthread_cleanup_pop</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p2048113619157"><a name="p2048113619157"></a><a name="p2048113619157"></a>删除位于清理处理程序堆栈顶部的例程。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p178901424460"><a name="p178901424460"></a><a name="p178901424460"></a>-</p>
</td>
</tr>
<tr id="row188906284610"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p8890152134616"><a name="p8890152134616"></a><a name="p8890152134616"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p589017244615"><a name="p589017244615"></a><a name="p589017244615"></a>pthread_cleanup_push</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p114823610159"><a name="p114823610159"></a><a name="p114823610159"></a>将例程推送到清理处理程序堆栈的顶部。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1890828463"><a name="p1890828463"></a><a name="p1890828463"></a>-</p>
</td>
</tr>
<tr id="row189012284618"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p68908224615"><a name="p68908224615"></a><a name="p68908224615"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1589011234615"><a name="p1589011234615"></a><a name="p1589011234615"></a>pthread_barrier_destroy</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p188901723467"><a name="p188901723467"></a><a name="p188901723467"></a>销毁屏障对象(高级实时线程)</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p88902244620"><a name="p88902244620"></a><a name="p88902244620"></a>-</p>
</td>
</tr>
<tr id="row089015218467"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1689011254619"><a name="p1689011254619"></a><a name="p1689011254619"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p48908214468"><a name="p48908214468"></a><a name="p48908214468"></a>pthread_barrier_init</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p7890172124617"><a name="p7890172124617"></a><a name="p7890172124617"></a>初始化屏障对象(高级实时线程)</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1689015217461"><a name="p1689015217461"></a><a name="p1689015217461"></a>-</p>
</td>
</tr>
<tr id="row8890182114615"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p118907215468"><a name="p118907215468"></a><a name="p118907215468"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p128902215466"><a name="p128902215466"></a><a name="p128902215466"></a>pthread_barrier_wait</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1189112204618"><a name="p1189112204618"></a><a name="p1189112204618"></a>屏障同步(高级实时线程)</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p208911722464"><a name="p208911722464"></a><a name="p208911722464"></a>-</p>
</td>
</tr>
<tr id="row589110216461"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p08911826466"><a name="p08911826466"></a><a name="p08911826466"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p18891321469"><a name="p18891321469"></a><a name="p18891321469"></a>pthread_barrierattr_destroy</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1048203611514"><a name="p1048203611514"></a><a name="p1048203611514"></a>销毁屏障属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1989112124612"><a name="p1989112124612"></a><a name="p1989112124612"></a>-</p>
</td>
</tr>
<tr id="row9891624468"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p108914214465"><a name="p108914214465"></a><a name="p108914214465"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1289182104618"><a name="p1289182104618"></a><a name="p1289182104618"></a>pthread_barrierattr_init</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1848113618159"><a name="p1848113618159"></a><a name="p1848113618159"></a>初始化屏障属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p12891202104615"><a name="p12891202104615"></a><a name="p12891202104615"></a>-</p>
</td>
</tr>
<tr id="row118914214464"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1289116214465"><a name="p1289116214465"></a><a name="p1289116214465"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1989116254616"><a name="p1989116254616"></a><a name="p1989116254616"></a><span>pthread_mutex_destroy</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p3891927469"><a name="p3891927469"></a><a name="p3891927469"></a>销毁互斥锁。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1189111220464"><a name="p1189111220464"></a><a name="p1189111220464"></a>-</p>
</td>
</tr>
<tr id="row18891326468"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p68915219469"><a name="p68915219469"></a><a name="p68915219469"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p689212124610"><a name="p689212124610"></a><a name="p689212124610"></a><span>pthread_mutex_init</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p189262174615"><a name="p189262174615"></a><a name="p189262174615"></a>初始化互斥锁。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p089216210461"><a name="p089216210461"></a><a name="p089216210461"></a>-</p>
</td>
</tr>
<tr id="row1689213216461"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p38923244615"><a name="p38923244615"></a><a name="p38923244615"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p989216213462"><a name="p989216213462"></a><a name="p989216213462"></a><span>pthread_mutex_lock</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1089216218469"><a name="p1089216218469"></a><a name="p1089216218469"></a>互斥锁加锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p58921028469"><a name="p58921028469"></a><a name="p58921028469"></a>-</p>
</td>
</tr>
<tr id="row989214284614"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p168927213469"><a name="p168927213469"></a><a name="p168927213469"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1389262154612"><a name="p1389262154612"></a><a name="p1389262154612"></a><span>pthread_mutex_trylock</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p9892182114619"><a name="p9892182114619"></a><a name="p9892182114619"></a>互斥锁尝试加锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p28926213469"><a name="p28926213469"></a><a name="p28926213469"></a>-</p>
</td>
</tr>
<tr id="row1989218264610"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1892122164617"><a name="p1892122164617"></a><a name="p1892122164617"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p8893132114614"><a name="p8893132114614"></a><a name="p8893132114614"></a><span>pthread_mutex_unlock</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p7893182154611"><a name="p7893182154611"></a><a name="p7893182154611"></a>互斥锁解锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1689318210466"><a name="p1689318210466"></a><a name="p1689318210466"></a>-</p>
</td>
</tr>
<tr id="row10893192194614"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1789317254618"><a name="p1789317254618"></a><a name="p1789317254618"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1089320217465"><a name="p1089320217465"></a><a name="p1089320217465"></a><span>pthread_mutexattr_destroy</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p168933274614"><a name="p168933274614"></a><a name="p168933274614"></a>销毁互斥锁属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p11893326462"><a name="p11893326462"></a><a name="p11893326462"></a>-</p>
</td>
</tr>
<tr id="row7893523465"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p128937234619"><a name="p128937234619"></a><a name="p128937234619"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p38931922469"><a name="p38931922469"></a><a name="p38931922469"></a><span>pthread_mutexattr_gettype</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p547173614155"><a name="p547173614155"></a><a name="p547173614155"></a>获取互斥锁类型属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p118932211469"><a name="p118932211469"></a><a name="p118932211469"></a>-</p>
</td>
</tr>
<tr id="row15893526464"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1989416284611"><a name="p1989416284611"></a><a name="p1989416284611"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1389413212461"><a name="p1389413212461"></a><a name="p1389413212461"></a><span>pthread_mutexattr_init</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p447133671516"><a name="p447133671516"></a><a name="p447133671516"></a>初始化互斥锁属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1189415254616"><a name="p1189415254616"></a><a name="p1189415254616"></a>-</p>
</td>
</tr>
<tr id="row1894102194616"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1289432134614"><a name="p1289432134614"></a><a name="p1289432134614"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p18941928465"><a name="p18941928465"></a><a name="p18941928465"></a><span>pthread_mutexattr_settype</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1247203611159"><a name="p1247203611159"></a><a name="p1247203611159"></a>设置互斥锁类型属性。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p168941328465"><a name="p168941328465"></a><a name="p168941328465"></a>-</p>
</td>
</tr>
<tr id="row48942215466"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p108942217463"><a name="p108942217463"></a><a name="p108942217463"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1189418216468"><a name="p1189418216468"></a><a name="p1189418216468"></a>pthread_mutex_timedlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p580191751513"><a name="p580191751513"></a><a name="p580191751513"></a>使用超时锁定互斥锁。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p0894122134613"><a name="p0894122134613"></a><a name="p0894122134613"></a>-</p>
</td>
</tr>
<tr id="row1894122134612"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p689414212466"><a name="p689414212466"></a><a name="p689414212466"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1189517234613"><a name="p1189517234613"></a><a name="p1189517234613"></a>pthread_rwlock_destroy</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p7895429466"><a name="p7895429466"></a><a name="p7895429466"></a>销毁读写锁。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p10895122174617"><a name="p10895122174617"></a><a name="p10895122174617"></a>-</p>
</td>
</tr>
<tr id="row989562144613"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p389542184611"><a name="p389542184611"></a><a name="p389542184611"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p13895142104612"><a name="p13895142104612"></a><a name="p13895142104612"></a>pthread_rwlock_init</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p0895172114615"><a name="p0895172114615"></a><a name="p0895172114615"></a>初始化读写锁。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p78951827462"><a name="p78951827462"></a><a name="p78951827462"></a>-</p>
</td>
</tr>
<tr id="row118953217461"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p689516216461"><a name="p689516216461"></a><a name="p689516216461"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p58955244611"><a name="p58955244611"></a><a name="p58955244611"></a>pthread_rwlock_rdlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p15803181719154"><a name="p15803181719154"></a><a name="p15803181719154"></a>获取读写锁读锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p889502164620"><a name="p889502164620"></a><a name="p889502164620"></a>-</p>
</td>
</tr>
<tr id="row689515218467"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p178956218463"><a name="p178956218463"></a><a name="p178956218463"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p17895152134618"><a name="p17895152134618"></a><a name="p17895152134618"></a>pthread_rwlock_timedrdlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p5803181721513"><a name="p5803181721513"></a><a name="p5803181721513"></a>使用超时锁定读写锁读锁。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1589622114618"><a name="p1589622114618"></a><a name="p1589622114618"></a>-</p>
</td>
</tr>
<tr id="row789615254618"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p168961622467"><a name="p168961622467"></a><a name="p168961622467"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1889612124610"><a name="p1889612124610"></a><a name="p1889612124610"></a>pthread_rwlock_timedwrlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p11431336191520"><a name="p11431336191520"></a><a name="p11431336191520"></a>使用超时锁定读写锁写锁。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p188966244617"><a name="p188966244617"></a><a name="p188966244617"></a>-</p>
</td>
</tr>
<tr id="row38966284617"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1389620264616"><a name="p1389620264616"></a><a name="p1389620264616"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p138961222469"><a name="p138961222469"></a><a name="p138961222469"></a>pthread_rwlock_tryrdlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1780314172156"><a name="p1780314172156"></a><a name="p1780314172156"></a>尝试获取读写锁读锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p989642174614"><a name="p989642174614"></a><a name="p989642174614"></a>-</p>
</td>
</tr>
<tr id="row20896142154616"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1689622204620"><a name="p1689622204620"></a><a name="p1689622204620"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p38981620462"><a name="p38981620462"></a><a name="p38981620462"></a>pthread_rwlock_trywrlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1443936191520"><a name="p1443936191520"></a><a name="p1443936191520"></a>尝试获取读写锁写锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p128981725468"><a name="p128981725468"></a><a name="p128981725468"></a>-</p>
</td>
</tr>
<tr id="row489815210461"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p18899821465"><a name="p18899821465"></a><a name="p18899821465"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1789913217469"><a name="p1789913217469"></a><a name="p1789913217469"></a>pthread_rwlock_unlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p143193651512"><a name="p143193651512"></a><a name="p143193651512"></a>读写锁解锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p390010211465"><a name="p390010211465"></a><a name="p390010211465"></a>-</p>
</td>
</tr>
<tr id="row1890032124612"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p159009219466"><a name="p159009219466"></a><a name="p159009219466"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1190010214469"><a name="p1190010214469"></a><a name="p1190010214469"></a>pthread_rwlock_wrlock</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p14803517111519"><a name="p14803517111519"></a><a name="p14803517111519"></a>获取读写锁写锁操作。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1390011294618"><a name="p1390011294618"></a><a name="p1390011294618"></a>-</p>
</td>
</tr>
<tr id="row590032124613"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p890022144619"><a name="p890022144619"></a><a name="p890022144619"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1290010244614"><a name="p1290010244614"></a><a name="p1290010244614"></a>pthread_rwlockattr_destroy</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p154719365157"><a name="p154719365157"></a><a name="p154719365157"></a>销毁读写锁属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p19900428461"><a name="p19900428461"></a><a name="p19900428461"></a>-</p>
</td>
</tr>
<tr id="row190042174617"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1190010284610"><a name="p1190010284610"></a><a name="p1190010284610"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1890017217462"><a name="p1890017217462"></a><a name="p1890017217462"></a>pthread_rwlockattr_init</p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p247133661511"><a name="p247133661511"></a><a name="p247133661511"></a>初始化读写锁属性对象。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p17900192154611"><a name="p17900192154611"></a><a name="p17900192154611"></a>-</p>
</td>
</tr>
<tr id="row10900320461"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p5901229462"><a name="p5901229462"></a><a name="p5901229462"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p149018294618"><a name="p149018294618"></a><a name="p149018294618"></a><span>pthread_cond_broadcast</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p16802181771514"><a name="p16802181771514"></a><a name="p16802181771514"></a>解除若干已被等待条件阻塞的线程。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1290118264619"><a name="p1290118264619"></a><a name="p1290118264619"></a>-</p>
</td>
</tr>
<tr id="row590115234620"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p15901202194613"><a name="p15901202194613"></a><a name="p15901202194613"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1190119212466"><a name="p1190119212466"></a><a name="p1190119212466"></a><span>pthread_cond_destroy</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p19802017191512"><a name="p19802017191512"></a><a name="p19802017191512"></a>销毁条件变量。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p1390122114610"><a name="p1390122114610"></a><a name="p1390122114610"></a>-</p>
</td>
</tr>
<tr id="row1890192164611"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p3901112204616"><a name="p3901112204616"></a><a name="p3901112204616"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1890102184618"><a name="p1890102184618"></a><a name="p1890102184618"></a><span>pthread_cond_init</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p48025173153"><a name="p48025173153"></a><a name="p48025173153"></a>初始化条件变量。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p119011210466"><a name="p119011210466"></a><a name="p119011210466"></a>-</p>
</td>
</tr>
<tr id="row129011214615"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p9902523468"><a name="p9902523468"></a><a name="p9902523468"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p59021722460"><a name="p59021722460"></a><a name="p59021722460"></a><span>pthread_cond_signal</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p58024177158"><a name="p58024177158"></a><a name="p58024177158"></a>解除被阻塞的线程。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p179022244615"><a name="p179022244615"></a><a name="p179022244615"></a>-</p>
</td>
</tr>
<tr id="row13902423461"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p69022025464"><a name="p69022025464"></a><a name="p69022025464"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1190252134620"><a name="p1190252134620"></a><a name="p1190252134620"></a><span>pthread_cond_timedwait</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p158024175151"><a name="p158024175151"></a><a name="p158024175151"></a>定时等待条件。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p109020264613"><a name="p109020264613"></a><a name="p109020264613"></a>-</p>
</td>
</tr>
<tr id="row189022218464"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p09021228463"><a name="p09021228463"></a><a name="p09021228463"></a>pthread.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p3902324460"><a name="p3902324460"></a><a name="p3902324460"></a><span>pthread_cond_wait</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p1690262154612"><a name="p1690262154612"></a><a name="p1690262154612"></a>等待条件。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p19902122104611"><a name="p19902122104611"></a><a name="p19902122104611"></a>-</p>
</td>
</tr>
<tr id="row159027218467"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p990318212464"><a name="p990318212464"></a><a name="p990318212464"></a>semaphore.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p109039234617"><a name="p109039234617"></a><a name="p109039234617"></a><span>sem_destroy</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p195081328171710"><a name="p195081328171710"></a><a name="p195081328171710"></a>销毁指定的无名信号量。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p190318214460"><a name="p190318214460"></a><a name="p190318214460"></a>-</p>
</td>
</tr>
<tr id="row1690342194611"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1490318217469"><a name="p1490318217469"></a><a name="p1490318217469"></a>semaphore.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p0903162124610"><a name="p0903162124610"></a><a name="p0903162124610"></a><span>sem_getvalue</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p650892891712"><a name="p650892891712"></a><a name="p650892891712"></a>获得指定信号量计数值。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p69036234614"><a name="p69036234614"></a><a name="p69036234614"></a>-</p>
</td>
</tr>
<tr id="row1490312214464"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p159031284618"><a name="p159031284618"></a><a name="p159031284618"></a>semaphore.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1790315254617"><a name="p1790315254617"></a><a name="p1790315254617"></a><span>sem_init</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p2508328121711"><a name="p2508328121711"></a><a name="p2508328121711"></a>创建并初始化一个无名信号量。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p129038211463"><a name="p129038211463"></a><a name="p129038211463"></a>-</p>
</td>
</tr>
<tr id="row1490416211462"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p3904126469"><a name="p3904126469"></a><a name="p3904126469"></a>semaphore.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p090416220464"><a name="p090416220464"></a><a name="p090416220464"></a><span>sem_post</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p6508162813176"><a name="p6508162813176"></a><a name="p6508162813176"></a>增加信号量计数。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p090414218463"><a name="p090414218463"></a><a name="p090414218463"></a>-</p>
</td>
</tr>
<tr id="row14904162164618"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p1590432194620"><a name="p1590432194620"></a><a name="p1590432194620"></a>semaphore.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p29041822467"><a name="p29041822467"></a><a name="p29041822467"></a><span>sem_timedwait</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p139049213468"><a name="p139049213468"></a><a name="p139049213468"></a>获取信号量,且有超时返回功能。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p690452114613"><a name="p690452114613"></a><a name="p690452114613"></a>-</p>
</td>
</tr>
<tr id="row390411211468"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p199049214612"><a name="p199049214612"></a><a name="p199049214612"></a>semaphore.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p1190413217467"><a name="p1190413217467"></a><a name="p1190413217467"></a><span>sem_trywait</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p18509102891714"><a name="p18509102891714"></a><a name="p18509102891714"></a>尝试获取信号量。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p39048213469"><a name="p39048213469"></a><a name="p39048213469"></a>-</p>
</td>
</tr>
<tr id="row3905152174616"><td class="cellrowborder" valign="top" width="14.299999999999999%" headers="mcps1.2.5.1.1 "><p id="p690513215466"><a name="p690513215466"></a><a name="p690513215466"></a>semaphore.h</p>
</td>
<td class="cellrowborder" valign="top" width="28.599999999999998%" headers="mcps1.2.5.1.2 "><p id="p15905926462"><a name="p15905926462"></a><a name="p15905926462"></a><span>sem_wait</span></p>
</td>
<td class="cellrowborder" valign="top" width="22.38%" headers="mcps1.2.5.1.3 "><p id="p950912813172"><a name="p950912813172"></a><a name="p950912813172"></a>获取信号量。</p>
</td>
<td class="cellrowborder" valign="top" width="34.72%" headers="mcps1.2.5.1.4 "><p id="p109051725466"><a name="p109051725466"></a><a name="p109051725466"></a>-</p>
</td>
</tr>
</tbody>
</table>
# 小型系统内核<a name="ZH-CN_TOPIC_0000001171191693"></a>
- **[基础内核](kernel-lite-small-basic.md)**
- **[文件系统](kernel-lite-small-file.md)**
- **[标准库](kernel-lite-small-lib.md)**
- **[调测](kernel-lite-small-shell.md)**
# 轻量和小型系统内核<a name="ZH-CN_TOPIC_0000001157479401"></a>
- **[轻量系统内核](kernel-lite-mini.md)**
- **[小型系统内核](kernel-lite-small.md)**
# 内核调测<a name="ZH-CN_TOPIC_0000001123763653"></a>
- **[内存调测](kernel-mini-memory-debug.md)**
- **[异常调测](kernel-mini-memory-exception.md)**
- **[Trace调测](kernel-mini-memory-trace.md)**
# 附录<a name="ZH-CN_TOPIC_0000001123948061"></a>
- **[内核编码规范](kernel-mini-appx-code.md)**
- **[基本数据结构](kernel-mini-appx-data.md)**
- **[标准库支持](kernel-mini-appx-lib.md)**
# 基本数据结构<a name="ZH-CN_TOPIC_0000001123863115"></a> # 基本数据结构<a name="ZH-CN_TOPIC_0000001123863115"></a>
- **[双向链表](kernel-lite-mini-app-data-list.md)** - **[双向链表](kernel-mini-appx-data-list.md)**
...@@ -28,27 +28,20 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -28,27 +28,20 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody><tr id="row8954646388"><td class="cellrowborder" rowspan="28" valign="top" width="7.12%" headers="mcps1.2.5.1.1 "><p id="p109544461689"><a name="p109544461689"></a><a name="p109544461689"></a>process</p> <tbody><tr id="row8954646388"><td class="cellrowborder" rowspan="27" valign="top" width="7.12%" headers="mcps1.2.5.1.1 "><p id="p109544461689"><a name="p109544461689"></a><a name="p109544461689"></a>process</p>
</td> </td>
<td class="cellrowborder" valign="top" width="17.150000000000002%" headers="mcps1.2.5.1.2 "><p id="p12806628134615"><a name="p12806628134615"></a><a name="p12806628134615"></a>#include &lt;stdlib.h&gt;</p> <td class="cellrowborder" valign="top" width="17.150000000000002%" headers="mcps1.2.5.1.2 "><p id="p12806628134615"><a name="p12806628134615"></a><a name="p12806628134615"></a>#include &lt;stdlib.h&gt;</p>
</td> </td>
<td class="cellrowborder" valign="top" width="52.27%" headers="mcps1.2.5.1.3 "><p id="p39542461183"><a name="p39542461183"></a><a name="p39542461183"></a>void abort(void);</p> <td class="cellrowborder" valign="top" width="52.27%" headers="mcps1.2.5.1.3 "><p id="p39542461183"><a name="p39542461183"></a><a name="p39542461183"></a>void abort(void);</p>
</td> </td>
<td class="cellrowborder" valign="top" width="23.46%" headers="mcps1.2.5.1.4 "><p id="p1795410468811"><a name="p1795410468811"></a><a name="p1795410468811"></a>中止程执行</p> <td class="cellrowborder" valign="top" width="23.46%" headers="mcps1.2.5.1.4 "><p id="p1795410468811"><a name="p1795410468811"></a><a name="p1795410468811"></a>中止线程执行</p>
</td> </td>
</tr> </tr>
<tr id="row7559152918428"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p15806112816462"><a name="p15806112816462"></a><a name="p15806112816462"></a>#include &lt;assert.h&gt;</p> <tr id="row7559152918428"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p15806112816462"><a name="p15806112816462"></a><a name="p15806112816462"></a>#include &lt;assert.h&gt;</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p14560429154220"><a name="p14560429154220"></a><a name="p14560429154220"></a>void assert(scalar expression);</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p14560429154220"><a name="p14560429154220"></a><a name="p14560429154220"></a>void assert(scalar expression);</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p14560162914424"><a name="p14560162914424"></a><a name="p14560162914424"></a>断言为假终止进程</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p14560162914424"><a name="p14560162914424"></a><a name="p14560162914424"></a>断言为假终止线程</p>
</td>
</tr>
<tr id="row181411635144217"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p12806728164618"><a name="p12806728164618"></a><a name="p12806728164618"></a>#include &lt;stdlib.h&gt;</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p111421235154219"><a name="p111421235154219"></a><a name="p111421235154219"></a>void exit(int status);</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p1214243514429"><a name="p1214243514429"></a><a name="p1214243514429"></a>正常退出进程</p>
</td> </td>
</tr> </tr>
<tr id="row113215211438"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1980612289469"><a name="p1980612289469"></a><a name="p1980612289469"></a>#include &lt;pthread.h&gt;</p> <tr id="row113215211438"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p1980612289469"><a name="p1980612289469"></a><a name="p1980612289469"></a>#include &lt;pthread.h&gt;</p>
...@@ -226,7 +219,8 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -226,7 +219,8 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p15202412148"><a name="p15202412148"></a><a name="p15202412148"></a>等待条件</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p15202412148"><a name="p15202412148"></a><a name="p15202412148"></a>等待条件</p>
</td> </td>
</tr> </tr>
<tr id="row183901254784"><td class="cellrowborder" rowspan="16" valign="top" width="7.12%" headers="mcps1.2.5.1.1 "><p id="p8390105412815"><a name="p8390105412815"></a><a name="p8390105412815"></a>fs</p> <tr id="row183901254784"><td class="cellrowborder" rowspan="17" valign="top" width="7.12%" headers="mcps1.2.5.1.1 "><p id="p8390105412815"><a name="p8390105412815"></a><a name="p8390105412815"></a>fs</p>
<p id="p16899101444012"><a name="p16899101444012"></a><a name="p16899101444012"></a></p>
</td> </td>
<td class="cellrowborder" valign="top" width="17.150000000000002%" headers="mcps1.2.5.1.2 "><p id="p8807172824612"><a name="p8807172824612"></a><a name="p8807172824612"></a>#include &lt;libgen.h&gt;</p> <td class="cellrowborder" valign="top" width="17.150000000000002%" headers="mcps1.2.5.1.2 "><p id="p8807172824612"><a name="p8807172824612"></a><a name="p8807172824612"></a>#include &lt;libgen.h&gt;</p>
</td> </td>
...@@ -340,12 +334,11 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -340,12 +334,11 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p550222319127"><a name="p550222319127"></a><a name="p550222319127"></a>获取文件状态信息</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p550222319127"><a name="p550222319127"></a><a name="p550222319127"></a>获取文件状态信息</p>
</td> </td>
</tr> </tr>
<tr id="row789821444016"><td class="cellrowborder" valign="top" width="7.12%" headers="mcps1.2.5.1.1 ">&nbsp;&nbsp;</td> <tr id="row789821444016"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p10899514184010"><a name="p10899514184010"></a><a name="p10899514184010"></a>#include &lt;sys/statfs.h&gt;</p>
<td class="cellrowborder" valign="top" width="17.150000000000002%" headers="mcps1.2.5.1.2 "><p id="p10899514184010"><a name="p10899514184010"></a><a name="p10899514184010"></a>#include &lt;sys/statfs.h&gt;</p>
</td> </td>
<td class="cellrowborder" valign="top" width="52.27%" headers="mcps1.2.5.1.3 "><p id="p82761152115811"><a name="p82761152115811"></a><a name="p82761152115811"></a>int statfs(const char *path, struct statfs *buf);</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p82761152115811"><a name="p82761152115811"></a><a name="p82761152115811"></a>int statfs(const char *path, struct statfs *buf);</p>
</td> </td>
<td class="cellrowborder" valign="top" width="23.46%" headers="mcps1.2.5.1.4 "><p id="p1489913149409"><a name="p1489913149409"></a><a name="p1489913149409"></a>获取指定路径下文件的文件系统信息</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p1489913149409"><a name="p1489913149409"></a><a name="p1489913149409"></a>获取指定路径下文件的文件系统信息</p>
</td> </td>
</tr> </tr>
<tr id="row17474428506"><td class="cellrowborder" rowspan="16" valign="top" width="7.12%" headers="mcps1.2.5.1.1 "><p id="p186578497613"><a name="p186578497613"></a><a name="p186578497613"></a>time</p> <tr id="row17474428506"><td class="cellrowborder" rowspan="16" valign="top" width="7.12%" headers="mcps1.2.5.1.1 "><p id="p186578497613"><a name="p186578497613"></a><a name="p186578497613"></a>time</p>
...@@ -403,7 +396,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -403,7 +396,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p171271919878"><a name="p171271919878"></a><a name="p171271919878"></a>clock_t times(struct tms *buf);</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p171271919878"><a name="p171271919878"></a><a name="p171271919878"></a>clock_t times(struct tms *buf);</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p61272196713"><a name="p61272196713"></a><a name="p61272196713"></a>获取程时间</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p61272196713"><a name="p61272196713"></a><a name="p61272196713"></a>获取线程时间</p>
</td> </td>
</tr> </tr>
<tr id="row1512715191575"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p312714191673"><a name="p312714191673"></a><a name="p312714191673"></a>#include &lt;unistd.h&gt;</p> <tr id="row1512715191575"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p312714191673"><a name="p312714191673"></a><a name="p312714191673"></a>#include &lt;unistd.h&gt;</p>
...@@ -431,21 +424,21 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -431,21 +424,21 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p4262185092111"><a name="p4262185092111"></a><a name="p4262185092111"></a>int timer_create(clockid_t id, struct sigevent *__restrict evp, timer_t *__restrict t);</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p4262185092111"><a name="p4262185092111"></a><a name="p4262185092111"></a>int timer_create(clockid_t id, struct sigevent *__restrict evp, timer_t *__restrict t);</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p10400134620113"><a name="p10400134620113"></a><a name="p10400134620113"></a>程创建计时器</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p10400134620113"><a name="p10400134620113"></a><a name="p10400134620113"></a>线程创建计时器</p>
</td> </td>
</tr> </tr>
<tr id="row19400184614116"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p94001446121110"><a name="p94001446121110"></a><a name="p94001446121110"></a>#include &lt;time.h&gt;</p> <tr id="row19400184614116"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p94001446121110"><a name="p94001446121110"></a><a name="p94001446121110"></a>#include &lt;time.h&gt;</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p1626265012115"><a name="p1626265012115"></a><a name="p1626265012115"></a>int timer_delete(timer_t t);</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p1626265012115"><a name="p1626265012115"></a><a name="p1626265012115"></a>int timer_delete(timer_t t);</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p840054610114"><a name="p840054610114"></a><a name="p840054610114"></a>程删除计时器</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p840054610114"><a name="p840054610114"></a><a name="p840054610114"></a>线程删除计时器</p>
</td> </td>
</tr> </tr>
<tr id="row18400124618117"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p275111375343"><a name="p275111375343"></a><a name="p275111375343"></a>#include &lt;time.h&gt;</p> <tr id="row18400124618117"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p275111375343"><a name="p275111375343"></a><a name="p275111375343"></a>#include &lt;time.h&gt;</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p626315017218"><a name="p626315017218"></a><a name="p626315017218"></a>int timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old);</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.2 "><p id="p626315017218"><a name="p626315017218"></a><a name="p626315017218"></a>int timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old);</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p17400184616110"><a name="p17400184616110"></a><a name="p17400184616110"></a>程设置计时器</p> <td class="cellrowborder" valign="top" headers="mcps1.2.5.1.3 "><p id="p17400184616110"><a name="p17400184616110"></a><a name="p17400184616110"></a>线程设置计时器</p>
</td> </td>
</tr> </tr>
<tr id="row640094661119"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p4779162844815"><a name="p4779162844815"></a><a name="p4779162844815"></a>#include &lt;time.h&gt;</p> <tr id="row640094661119"><td class="cellrowborder" valign="top" headers="mcps1.2.5.1.1 "><p id="p4779162844815"><a name="p4779162844815"></a><a name="p4779162844815"></a>#include &lt;time.h&gt;</p>
...@@ -1145,7 +1138,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -1145,7 +1138,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody><tr id="row176151756201613"><td class="cellrowborder" valign="top" width="18.87811218878112%" headers="mcps1.1.5.1.1 "><p id="p17615125610163"><a name="p17615125610163"></a><a name="p17615125610163"></a>Success</p> <tbody><tr id="row176151756201613"><td class="cellrowborder" valign="top" width="18.87811218878112%" headers="mcps1.1.5.1.1 "><p id="p17615125610163"><a name="p17615125610163"></a><a name="p17615125610163"></a>ENOERR</p>
</td> </td>
<td class="cellrowborder" valign="top" width="8.389161083891612%" headers="mcps1.1.5.1.2 "><p id="p6615185613168"><a name="p6615185613168"></a><a name="p6615185613168"></a>0</p> <td class="cellrowborder" valign="top" width="8.389161083891612%" headers="mcps1.1.5.1.2 "><p id="p6615185613168"><a name="p6615185613168"></a><a name="p6615185613168"></a>0</p>
</td> </td>
...@@ -1178,7 +1171,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -1178,7 +1171,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
</td> </td>
<td class="cellrowborder" valign="top" width="39.156084391560846%" headers="mcps1.1.5.1.3 "><p id="p5616115614168"><a name="p5616115614168"></a><a name="p5616115614168"></a>No such process</p> <td class="cellrowborder" valign="top" width="39.156084391560846%" headers="mcps1.1.5.1.3 "><p id="p5616115614168"><a name="p5616115614168"></a><a name="p5616115614168"></a>No such process</p>
</td> </td>
<td class="cellrowborder" valign="top" width="33.57664233576642%" headers="mcps1.1.5.1.4 "><p id="p1018714272182"><a name="p1018714272182"></a><a name="p1018714272182"></a>没有这样的进程</p> <td class="cellrowborder" valign="top" width="33.57664233576642%" headers="mcps1.1.5.1.4 "><p id="p1018714272182"><a name="p1018714272182"></a><a name="p1018714272182"></a>没有这样的进程(暂不支持)</p>
</td> </td>
</tr> </tr>
<tr id="row1461635614168"><td class="cellrowborder" valign="top" width="18.87811218878112%" headers="mcps1.1.5.1.1 "><p id="p3616185610166"><a name="p3616185610166"></a><a name="p3616185610166"></a>EINTR</p> <tr id="row1461635614168"><td class="cellrowborder" valign="top" width="18.87811218878112%" headers="mcps1.1.5.1.1 "><p id="p3616185610166"><a name="p3616185610166"></a><a name="p3616185610166"></a>EINTR</p>
...@@ -1241,7 +1234,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO ...@@ -1241,7 +1234,7 @@ OpenHarmony内核使用**musl libc**库以及自研接口,支持部分标准PO
</td> </td>
<td class="cellrowborder" valign="top" width="39.156084391560846%" headers="mcps1.1.5.1.3 "><p id="p124061211192013"><a name="p124061211192013"></a><a name="p124061211192013"></a>No child processes</p> <td class="cellrowborder" valign="top" width="39.156084391560846%" headers="mcps1.1.5.1.3 "><p id="p124061211192013"><a name="p124061211192013"></a><a name="p124061211192013"></a>No child processes</p>
</td> </td>
<td class="cellrowborder" valign="top" width="33.57664233576642%" headers="mcps1.1.5.1.4 "><p id="p24067113203"><a name="p24067113203"></a><a name="p24067113203"></a>没有子进程</p> <td class="cellrowborder" valign="top" width="33.57664233576642%" headers="mcps1.1.5.1.4 "><p id="p24067113203"><a name="p24067113203"></a><a name="p24067113203"></a>没有子进程(暂不支持)</p>
</td> </td>
</tr> </tr>
<tr id="row17406611142014"><td class="cellrowborder" valign="top" width="18.87811218878112%" headers="mcps1.1.5.1.1 "><p id="p9406181112208"><a name="p9406181112208"></a><a name="p9406181112208"></a>EAGAIN</p> <tr id="row17406611142014"><td class="cellrowborder" valign="top" width="18.87811218878112%" headers="mcps1.1.5.1.1 "><p id="p9406181112208"><a name="p9406181112208"></a><a name="p9406181112208"></a>EAGAIN</p>
......
# 标准库支持<a name="ZH-CN_TOPIC_0000001078876478"></a> # 标准库支持<a name="ZH-CN_TOPIC_0000001078876478"></a>
- **[CMSIS支持](kernel-lite-mini-app-lib-cmsis.md)** - **[CMSIS支持](kernel-mini-appx-lib-cmsis.md)**
- **[POSIX支持](kernel-lite-mini-app-lib-posix.md)** - **[POSIX支持](kernel-mini-appx-lib-posix.md)**
# 中断管理<a name="ZH-CN_TOPIC_0000001123863135"></a> # 中断管理<a name="ZH-CN_TOPIC_0000001123863135"></a>
- **[基本概念](kernel-lite-mini-basic-interrupt-concept.md)** - **[基本概念](kernel-mini-basic-interrupt-concept.md)**
- **[开发指导](kernel-lite-mini-basic-interrupt-guide.md)** - **[开发指导](kernel-mini-basic-interrupt-guide.md)**
...@@ -35,13 +35,11 @@ typedef struct tagEvent { ...@@ -35,13 +35,11 @@ typedef struct tagEvent {
**读事件:**如果读取的事件已存在时,会直接同步返回。其他情况会根据超时时间以及事件触发情况,来决定返回时机:等待的事件条件在超时时间耗尽之前到达,阻塞任务会被直接唤醒,否则超时时间耗尽该任务才会被唤醒。 **读事件:**如果读取的事件已存在时,会直接同步返回。其他情况会根据超时时间以及事件触发情况,来决定返回时机:等待的事件条件在超时时间耗尽之前到达,阻塞任务会被直接唤醒,否则超时时间耗尽该任务才会被唤醒。
读事件条件满足与否取决于入参eventMask和mode,eventMask即需要关注的事件。mode是具体处理方式,分以下三种情况: 读事件条件满足与否取决于入参eventMask和mode,eventMask即需要关注的事件类型掩码。mode是具体处理方式,分以下三种情况:
LOS\_WAITMODE\_AND:表示eventMask中所有事件都发生时,才返回。 - LOS\_WAITMODE\_AND:逻辑与,基于接口传入的事件类型掩码eventMask,只有这些事件都已经发生才能读取成功,否则该任务将阻塞等待或者返回错误码。。
- LOS\_WAITMODE\_OR:逻辑或,基于接口传入的事件类型掩码eventMask,只要这些事件中有任一种事件发生就可以读取成功,否则该任务将阻塞等待或者返回错误码。
LOS\_WAITMODE\_OR:表示eventMask中任何事件发生时,就返回。 - LOS\_WAITMODE\_CLR:这是一种附加读取模式,需要与所有事件模式或任一事件模式结合使用(LOS\_WAITMODE\_AND | LOS\_WAITMODE\_CLR或 LOS\_WAITMODE\_OR | LOS\_WAITMODE\_CLR)。在这种模式下,当设置的所有事件模式或任一事件模式读取成功后,会自动清除事件控制块中对应的事件类型位。
LOS\_WAITMODE\_CLR:事件读取成功后,对应读取到的事件会被清零。需要配合LOS\_WAITMODE\_AND或者LOS\_WAITMODE\_OR来使用。
**事件清零:**根据指定掩码,去对事件控制块的事件集合进行清零操作。当掩码为0时,表示将事件集合全部清零。当掩码为0xffff时,表示不清除任何事件,保持事件集合原状。 **事件清零:**根据指定掩码,去对事件控制块的事件集合进行清零操作。当掩码为0时,表示将事件集合全部清零。当掩码为0xffff时,表示不清除任何事件,保持事件集合原状。
......
# 事件<a name="ZH-CN_TOPIC_0000001078716886"></a>
- **[基本概念](kernel-mini-basic-ipc-event-basic.md)**
- **[开发指导](kernel-mini-basic-ipc-event-guide.md)**
# 互斥锁<a name="ZH-CN_TOPIC_0000001123948099"></a> # 互斥锁<a name="ZH-CN_TOPIC_0000001123948099"></a>
- **[基本概念](kernel-lite-mini-basic-ipc-mutex-basic.md)** - **[基本概念](kernel-mini-basic-ipc-mutex-basic.md)**
- **[开发指导](kernel-lite-mini-basic-ipc-mutex-guide.md)** - **[开发指导](kernel-mini-basic-ipc-mutex-guide.md)**
# 消息队列<a name="ZH-CN_TOPIC_0000001123863117"></a> # 消息队列<a name="ZH-CN_TOPIC_0000001123863117"></a>
- **[基本概念](kernel-lite-mini-basic-ipc-queue-basic.md)** - **[基本概念](kernel-mini-basic-ipc-queue-basic.md)**
- **[开发指导](kernel-lite-mini-basic-ipc-queue-guide.md)** - **[开发指导](kernel-mini-basic-ipc-queue-guide.md)**
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
2. ExampleSemTask2得到信号量,被调度,然后任务休眠20Tick,ExampleSemTask2延迟,ExampleSemTask1被唤醒。 2. ExampleSemTask2得到信号量,被调度,然后任务休眠20Tick,ExampleSemTask2延迟,ExampleSemTask1被唤醒。
3. ExampleSemTask1定时阻塞模式申请信号量,等待时间为10Tick,因信号量仍被ExampleSemTask2持有,ExampleSemTask1挂起,10Tick后仍未得到信号量,ExampleSemTask1被唤醒,试图以永久阻塞模式申请信号量,ExampleSemTask1挂起。 3. ExampleSemTask1定时阻塞模式申请信号量,等待时间为10Tick,因信号量仍被ExampleSemTask2持有,ExampleSemTask1挂起,10Tick后仍未得到信号量,ExampleSemTask1被唤醒,试图以永久阻塞模式申请信号量,ExampleSemTask1挂起。
4. 20Tick后ExampleSemTask2唤醒, 释放信号量后,ExampleSemTask1得到信号量被调度运行,最后释放信号量。 4. 20Tick后ExampleSemTask2唤醒, 释放信号量后,ExampleSemTask1得到信号量被调度运行,最后释放信号量。
5. ExampleSemTask1执行完,40Tick后任务ExampleSem被唤醒,执行删除信号量。 5. ExampleSemTask1执行完,400Tick后任务ExampleSem被唤醒,执行删除信号量。
### 示例代码<a name="section1775922321416"></a> ### 示例代码<a name="section1775922321416"></a>
...@@ -160,7 +160,7 @@ UINT32 ExampleSem(VOID) ...@@ -160,7 +160,7 @@ UINT32 ExampleSem(VOID)
task1.usTaskPrio = TASK_PRIO_TEST; task1.usTaskPrio = TASK_PRIO_TEST;
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"); printf("task1 create failed.\n");
return LOS_NOK; return LOS_NOK;
} }
......
# 信号量<a name="ZH-CN_TOPIC_0000001123948077"></a> # 信号量<a name="ZH-CN_TOPIC_0000001123948077"></a>
- **[基本概念](kernel-lite-mini-basic-ipc-sem-basic.md)** - **[基本概念](kernel-mini-basic-ipc-sem-basic.md)**
- **[开发指导](kernel-lite-mini-basic-ipc-sem-guide.md)** - **[开发指导](kernel-mini-basic-ipc-sem-guide.md)**
# 内核通信机制<a name="ZH-CN_TOPIC_0000001124573873"></a>
- **[事件](kernel-mini-basic-ipc-event.md)**
- **[互斥锁](kernel-mini-basic-ipc-mutex.md)**
- **[消息队列](kernel-mini-basic-ipc-queue.md)**
- **[信号量](kernel-mini-basic-ipc-sem.md)**
...@@ -20,8 +20,8 @@ OpenHarmony LiteOS-M动态内存在TLSF算法的基础上,对区间的划分 ...@@ -20,8 +20,8 @@ OpenHarmony LiteOS-M动态内存在TLSF算法的基础上,对区间的划分
根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:\[4, 127\]\[2<sup>7</sup>, 2<sup>31</sup>\],如上图size class所示: 根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:\[4, 127\]\[2<sup>7</sup>, 2<sup>31</sup>\],如上图size class所示:
1.\[4,127\]区间的内存进行等分,如上图绿色部分所示,分为31个小区间,每个小区间对应内存块大小为4字节的倍数。每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位,值为1时,空闲链表非空。\[4,127\]区间的31个小区间内存对应31个比特位进行标记链表是否为空。 1.\[4,127\]区间的内存进行等分,如上图下半部分所示,分为31个小区间,每个小区间对应内存块大小为4字节的倍数。每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位,值为1时,空闲链表非空。\[4,127\]区间的31个小区间内存对应31个比特位进行标记链表是否为空。
2. 大于127字节的空闲内存块,按照2的次幂区间大小进行空闲链表管理。总共分为24个小区间,每个小区间又等分为8个二级小区间,见上图蓝色的Size Class和Size SubClass部分。每个二级小区间对应一个空闲链表和用于标记对应空闲内存链表是否为空的一个比特位。总共24\*8=192个二级小区间,对应192个空闲链表和192个比特位进行标记链表是否为空。 2. 大于127字节的空闲内存块,按照2的次幂区间大小进行空闲链表管理。总共分为24个小区间,每个小区间又等分为8个二级小区间,见上图上半部分的Size Class和Size SubClass部分。每个二级小区间对应一个空闲链表和用于标记对应空闲内存链表是否为空的一个比特位。总共24\*8=192个二级小区间,对应192个空闲链表和192个比特位进行标记链表是否为空。
例如,当有40字节的空闲内存需要插入空闲链表时,对应小区间\[40,43\],第10个空闲链表,位图标记的第10比特位。把40字节的空闲内存挂载第10个空闲链表上,并判断是否需要更新位图标记。当需要申请40字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。当有580字节的空闲内存需要插入空闲链表时,对应二级小区间\[2^9,2^9+2^6\],第31+2\*8=47个空闲链表,并使用位图的第47个比特位来标记链表是否为空。把580字节的空闲内存挂载第47个空闲链表上,并判断是否需要更新位图标记。当需要申请580字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。如果对应的空闲链表为空,则向更大的内存区间去查询是否有满足条件的空闲链表,实际计算时,会一次性查找到满足申请大小的空闲链表。 例如,当有40字节的空闲内存需要插入空闲链表时,对应小区间\[40,43\],第10个空闲链表,位图标记的第10比特位。把40字节的空闲内存挂载第10个空闲链表上,并判断是否需要更新位图标记。当需要申请40字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。当有580字节的空闲内存需要插入空闲链表时,对应二级小区间\[2^9,2^9+2^6\],第31+2\*8=47个空闲链表,并使用位图的第47个比特位来标记链表是否为空。把580字节的空闲内存挂载第47个空闲链表上,并判断是否需要更新位图标记。当需要申请580字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。如果对应的空闲链表为空,则向更大的内存区间去查询是否有满足条件的空闲链表,实际计算时,会一次性查找到满足申请大小的空闲链表。
......
# 内存管理<a name="ZH-CN_TOPIC_0000001078876454"></a>
- **[基本概念](kernel-mini-basic-memory-basic.md)**
- **[静态内存](kernel-mini-basic-memory-static.md)**
- **[动态内存](kernel-mini-basic-memory-dynamic.md)**
# 软件定时器<a name="ZH-CN_TOPIC_0000001123771893"></a> # 软件定时器<a name="ZH-CN_TOPIC_0000001123771893"></a>
- **[基本概念](kernel-lite-mini-basic-soft-basic.md)** - **[基本概念](kernel-mini-basic-soft-basic.md)**
- **[开发指导](kernel-lite-mini-basic-soft-guide.md)** - **[开发指导](kernel-mini-basic-soft-guide.md)**
...@@ -155,7 +155,7 @@ OpenHarmony LiteOS-M内核的任务管理模块提供下面几种功能,接口 ...@@ -155,7 +155,7 @@ OpenHarmony LiteOS-M内核的任务管理模块提供下面几种功能,接口
## 开发流程<a name="section783435801510"></a> ## 开发流程<a name="section783435801510"></a>
以创建任务为例,讲解开发流程。 本节介绍任务模块的典型场景开发流程:
1. 锁任务调度LOS\_TaskLock,防止高优先级任务调度。 1. 锁任务调度LOS\_TaskLock,防止高优先级任务调度。
2. 创建任务LOS\_TaskCreate。 2. 创建任务LOS\_TaskCreate。
......
# 任务管理<a name="ZH-CN_TOPIC_0000001124066565"></a> # 任务管理<a name="ZH-CN_TOPIC_0000001124066565"></a>
- **[基本概念](kernel-lite-mini-basic-task-basic.md)** - **[基本概念](kernel-mini-basic-task-basic.md)**
- **[开发指导](kernel-lite-mini-basic-task-guide.md)** - **[开发指导](kernel-mini-basic-task-guide.md)**
# 基本概念<a name="ZH-CN_TOPIC_0000001078876456"></a> # 基本概念<a name="ZH-CN_TOPIC_0000001078876456"></a>
- [时间单位:](#section97172532397)
时间管理以系统时钟为基础,给应用程序提供所有和时间有关的服务。 时间管理以系统时钟为基础,给应用程序提供所有和时间有关的服务。
系统时钟是由定时器/计数器产生的输出脉冲触发中断产生的,一般定义为整数或长整数。输出脉冲的周期叫做一个“时钟滴答”。系统时钟也称为时标或者Tick。 系统时钟是由定时器/计数器产生的输出脉冲触发中断产生的,一般定义为整数或长整数。输出脉冲的周期叫做一个“时钟滴答”。系统时钟也称为时标或者Tick。
...@@ -8,7 +10,7 @@ ...@@ -8,7 +10,7 @@
OpenHarmony LiteOS-M内核时间管理模块提供时间转换、统计功能。 OpenHarmony LiteOS-M内核时间管理模块提供时间转换、统计功能。
### 时间单位:<a name="section1368151114500"></a> ## 时间单位:<a name="section97172532397"></a>
- Cycle - Cycle
......
...@@ -39,14 +39,12 @@ OpenHarmony LiteOS-M内核的时间管理提供下面几种功能,接口详细 ...@@ -39,14 +39,12 @@ OpenHarmony LiteOS-M内核的时间管理提供下面几种功能,接口详细
</tr> </tr>
<tr id="row1736713145208"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p13367171492014"><a name="p13367171492014"></a><a name="p13367171492014"></a>OsCpuTick2MS</p> <tr id="row1736713145208"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p13367171492014"><a name="p13367171492014"></a><a name="p13367171492014"></a>OsCpuTick2MS</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p14367121422016"><a name="p14367121422016"></a><a name="p14367121422016"></a>Cycle数目转化为毫秒,使用2个</p> <td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p14367121422016"><a name="p14367121422016"></a><a name="p14367121422016"></a>Cycle数目转化为毫秒,使用2个UINT32类型的数值分别表示结果数值的高、低32位。</p>
<p id="p28931312219"><a name="p28931312219"></a><a name="p28931312219"></a>UINT32类型的数值分别表示结果数值的高、低32位。</p>
</td> </td>
</tr> </tr>
<tr id="row19475718122016"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14475121882012"><a name="p14475121882012"></a><a name="p14475121882012"></a>OsCpuTick2US</p> <tr id="row19475718122016"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14475121882012"><a name="p14475121882012"></a><a name="p14475121882012"></a>OsCpuTick2US</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p26621730152310"><a name="p26621730152310"></a><a name="p26621730152310"></a>Cycle数目转化为微秒,使用2个</p> <td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p26621730152310"><a name="p26621730152310"></a><a name="p26621730152310"></a>Cycle数目转化为微秒,使用2个UINT32类型的数值分别表示结果数值的高、低32位。</p>
<p id="p176621930152313"><a name="p176621930152313"></a><a name="p176621930152313"></a>UINT32类型的数值分别表示结果数值的高、低32位。</p>
</td> </td>
</tr> </tr>
<tr id="row327873511316"><td class="cellrowborder" rowspan="3" valign="top" width="17.77177717771777%" headers="mcps1.2.4.1.1 "><p id="p1743134312156"><a name="p1743134312156"></a><a name="p1743134312156"></a>时间统计</p> <tr id="row327873511316"><td class="cellrowborder" rowspan="3" valign="top" width="17.77177717771777%" headers="mcps1.2.4.1.1 "><p id="p1743134312156"><a name="p1743134312156"></a><a name="p1743134312156"></a>时间统计</p>
...@@ -63,7 +61,7 @@ OpenHarmony LiteOS-M内核的时间管理提供下面几种功能,接口详细 ...@@ -63,7 +61,7 @@ OpenHarmony LiteOS-M内核的时间管理提供下面几种功能,接口详细
</tr> </tr>
<tr id="row1027814354131"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1727843510137"><a name="p1727843510137"></a><a name="p1727843510137"></a>LOS_CyclePerTickGet</p> <tr id="row1027814354131"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1727843510137"><a name="p1727843510137"></a><a name="p1727843510137"></a>LOS_CyclePerTickGet</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p827819358134"><a name="p827819358134"></a><a name="p827819358134"></a>每个Tick多少Cycle数</p> <td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p827819358134"><a name="p827819358134"></a><a name="p827819358134"></a>获取每个Tick多少Cycle数</p>
</td> </td>
</tr> </tr>
</tbody> </tbody>
......
# 基础内核<a name="ZH-CN_TOPIC_0000001123863157"></a>
- **[中断管理](kernel-mini-basic-interrupt.md)**
- **[任务管理](kernel-mini-basic-task.md)**
- **[内存管理](kernel-mini-basic-memory.md)**
- **[内核通信机制](kernel-mini-basic-ipc.md)**
- **[时间管理](kernel-basic-mini-time.md)**
- **[软件定时器](kernel-mini-basic-soft.md)**
# CPU占用率<a name="ZH-CN_TOPIC_0000001123948073"></a> # CPU占用率<a name="ZH-CN_TOPIC_0000001123948073"></a>
- **[基本概念](kernel-lite-mini-extend-cpup-basic.md)** - **[基本概念](kernel-mini-extend-cpup-basic.md)**
- **[开发指导](kernel-lite-mini-extend-cpup-guide.md)** - **[开发指导](kernel-mini-extend-cpup-guide.md)**
# 基本概念<a name="ZH-CN_TOPIC_0000001136130422"></a>
- [运行机制](#section139861939219)
- [符号表导出](#section15414650102716)
- [ELF文件加载](#section5221181562810)
- [ELF文件链接](#section68441639182817)
- [ELF支持规格](#section187315541916)
- [ELF支持类型](#section1701552268)
- [ELF共享库编译链接选项](#section17292133274)
在硬件资源有限的小设备中,需要通过算法的动态部署能力来解决无法同时部署多种算法的问题。以开发者易用为主要考虑因素,同时考虑到多平台的通用性,LiteOS-M选择业界标准的ELF方案,方便拓展算法生态。LiteOS-M提供类似于dlopen、dlsym等接口,APP通过动态加载模块提供的接口可以加载、卸载相应算法库。如图1所示,APP需要通过三方算法库所需接口获取对应信息输出,三方算法库又依赖内核提供的基本接口,如malloc等。APP加载所需接口,并对相关的未定义符号完成重定位后,APP即可调用该接口完成功能调用。目前动态加载组件只支持arm架构。
**图 1** LiteOS-M内核动态加载架构图<a name="fig3662173651419"></a>
![](figure/LiteOS-M内核动态加载架构图.png "LiteOS-M内核动态加载架构图")
## 运行机制<a name="section139861939219"></a>
### 符号表导出<a name="section15414650102716"></a>
共享库调用内核接口需要内核主动暴露动态库所需的接口,如图2所示,该机制将符号信息编译到指定段中,调用SYM\_EXPORT宏即可完成对指定符号的信息导出。符号信息通过结构体SymInfo描述,成员包括符号名和符号地址信息,宏SYM\_EXPORT通过\_\_attribute\_\_编译属性将符号信息导入.sym.\*段中。
```
typedef struct {
CHAR *name;
UINTPTR addr;
} SymInfo;
#define SYM_EXPORT(func) \
const SymInfo sym_##func __attribute__((section(".sym."#func))) = { \
.name = #func, \
.addr = (UINTPTR)func \
};
```
**图 2** 导出的符号表信息<a name="fig1024363510159"></a>
![](figure/导出的符号表信息.png "导出的符号表信息")
### ELF文件加载<a name="section5221181562810"></a>
加载过程中,根据ELF文件的句柄以及程序头表的段偏移可以得到需要加载到内存的LOAD段,一般有两个段,只读段及读写段,如下所示,可以用readelf -l查看ELF文件的LOAD段信息。如图3所示,根据相应的对齐属性申请物理内存,通过每个段的加载基址及偏移将代码段或数据段写入内存中。
```
$ readelf -l lib.so
Elf file type is DYN (Shared object file)
Entry point 0x5b4
There are 4 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x000760 0x00000760 0x00000760 0x00008 0x00008 R 0x4
LOAD 0x000000 0x00000000 0x00000000 0x0076c 0x0076c R E 0x10000
LOAD 0x00076c 0x0001076c 0x0001076c 0x0010c 0x00128 RW 0x10000
DYNAMIC 0x000774 0x00010774 0x00010774 0x000c8 0x000c8 RW 0x4
Section to Segment mapping:
Segment Sections...
00 .ARM.exidx
01 .hash .dynsym .dynstr .rel.dyn .rel.plt .init .plt .text .fini .ARM.exidx .eh_frame
02 .init_array .fini_array .dynamic .got .data .bss
03 .dynamic
```
**图 3** ELF文件的加载过程<a name="fig15547494157"></a>
![](figure/ELF文件的加载过程.png "ELF文件的加载过程")
### ELF文件链接<a name="section68441639182817"></a>
如图4所示,通过ELF文件的.dynamic段获取重定位表,遍历表中每一个需要重定位的条目,再根据需要重定位的符号名在共享库和内核提供的导出符号表中查找相应符号并更新相应的重定位信息。
**图 4** ELF文件的链接过程<a name="fig968155141613"></a>
![](figure/ELF文件的链接过程.png "ELF文件的链接过程")
## ELF支持规格<a name="section187315541916"></a>
### ELF支持类型<a name="section1701552268"></a>
编译共享库时,添加-fPIC可以编译出位置无关代码(-fPIC为编译选项),此时共享库文件类型为ET\_DYN,其可以加载至任意有效的地址区间。
例:arm-none-eabi-gcc -fPIC –shared –o lib.so lib.c
### ELF共享库编译链接选项<a name="section17292133274"></a>
1. “-nostdlib”编译链接选项:不依赖编译器中lib库。
2. “-nostartfiles”编译链接选项:不依赖编译器中启动相关的文件。
3. “-fPIC”编译选项:可编译位置无关的共享库。
4. “-z max-page-size=4”链接选项:二进制文件中可加载段的对齐字节数为4,可节约内存,可用于动态库。
5. “-mcpu=”需要指定对应的cpu架构。
# 开发指导<a name="ZH-CN_TOPIC_0000001182409801"></a>
- [接口说明](#section158501652121514)
- [开发流程](#section5241132917523)
- [编程实例](#section8708112313531)
## 接口说明<a name="section158501652121514"></a>
**表 1** 功能列表
<a name="table18293928155615"></a>
<table><thead align="left"><tr id="row129362875613"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p19444103765618"><a name="p19444103765618"></a><a name="p19444103765618"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p944473716569"><a name="p944473716569"></a><a name="p944473716569"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p144445378565"><a name="p144445378565"></a><a name="p144445378565"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row16964173231"><td class="cellrowborder" rowspan="4" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p106040172412"><a name="p106040172412"></a><a name="p106040172412"></a>动态加载功能接口</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p136961178237"><a name="p136961178237"></a><a name="p136961178237"></a>LOS_DynlinkInit</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p3697131710237"><a name="p3697131710237"></a><a name="p3697131710237"></a>初始化动态链接器链表以及互斥锁</p>
</td>
</tr>
<tr id="row18697201714231"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p66971817102319"><a name="p66971817102319"></a><a name="p66971817102319"></a>LOS_SoLoad</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1569711715233"><a name="p1569711715233"></a><a name="p1569711715233"></a>加载指定路径的共享库</p>
</td>
</tr>
<tr id="row18697117132313"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1697161732312"><a name="p1697161732312"></a><a name="p1697161732312"></a>LOS_FindSym</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p5697917132313"><a name="p5697917132313"></a><a name="p5697917132313"></a>根据共享库句柄查找指定符号</p>
</td>
</tr>
<tr id="row1925202662319"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p7925526112315"><a name="p7925526112315"></a><a name="p7925526112315"></a>LOS_SoUnload</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p492520269233"><a name="p492520269233"></a><a name="p492520269233"></a>卸载共享库句柄</p>
</td>
</tr>
</tbody>
</table>
## 开发流程<a name="section5241132917523"></a>
1. 利用arm-none-eabi-gcc交叉编译器编译共享库并制作FAT或LittleFS文件系统格式镜像烧写至flash中;
2. 在target\_config.h文件中定义宏LOSCFG\_DYNLINK为1使能动态加载模块;
3. 调用LOS\_SoLoad接口加载指定路径下的共享库;
4. 调用LOS\_FindSym接口查找指定符号,获取符号地址;
5. 调用LOS\_SoUnload卸载指定共享库句柄。
>![](../public_sys-resources/icon-note.gif) **说明:**
>1. 利用交叉编译器编译共享库所需要的编译选项参考ELF支持规格一节。
>2. 制作文件系统镜像之前需要对特定单板适配FAT或LittleFS文件系统。
>3. 共享库不依赖编译器中的libc库,不支持c++。
>4. 共享库只能依赖内核提供的接口,不能依赖其他共享库。
## 编程实例<a name="section8708112313531"></a>
实例以cortex-m4单板为例。
1. 共享库示例代码及编译
示例代码主要测试全局符号间的调用功能以及对内核接口maloc、free、memset接口的调用功能。
```
#include <stdlib.h>
#include <string.h>
int g_param = 10;
int callee(int a, int b)
{
char *addr = malloc(g_param);
if (addr == NULL) {
return 0;
}
memset(addr, '1', g_param);
free(addr);
return a + b + g_param;
}
int caller(int a, int b)
{
return callee(a, b);
}
```
```
$ arm-none-eabi-gcc -fPIC -shared -mcpu=cortex-m4 -nostdlib -nostartfiles -z max-page-size=4 -o test.so test.c
```
2. 导出共享库中使用到的malloc、free、memset符号,下述代码单独编写成一个.c文件,参与OS编译即可。
```
#include "stdlib.h"
#include "string.h"
SYM_EXPORT(malloc);
SYM_EXPORT(free);
SYM_EXPORT(memset);
```
3. 确定内核的编译环境,在对应编译器的编译链接脚本中添加如下语句,保证符号表信息在编译链接的时候输出到指定的段。
在IAR编译器.icf链接脚本中添加如下语句:
```
keep {section .TABLE.START};
keep {section .sym.*};
keep {section .table.end};
define block SYMBOL_TABLE with fixed order
{
section .TABLE.START,
section .sym.*,
section .table.end
};
place in ROM_region {readonly, block SYMBOL_TABLE};
```
在gcc编译器的.ld链接脚本中添加如下语句:
```
__sym_table_start = .;
KEEP(*( SORT (.sym.*)));
__sym_table_end = .;
```
4. 共享库加载链接、执行与卸载
示例代码主要测试LOS\_SoLoad、LOS\_FindSym、LOS\_SoUnload接口的功能是否正常以及通过LOS\_FindSym查找到的符号的调用是否正常。
```
#include "los_dynlink.h"
VOID DynlinkTest(VOID)
{
VOID *handle = NULL;
INT32 (*func)(INT32, INT32) = NULL;
CHAR *symbolName = "caller";
CHAR *dsoName = "/lib/test.so";
INT32 ret;
handle = (VOID *)LOS_SoLoad(dsoName, NULL);
if (handle == NULL) {
printf("Failed to load so\n");
return;
}
func = (INT32 (*)(INT32, INT32))LOS_FindSym(handle, symbolName);
if (func == NULL) {
printf("Failed to find symbol\n");
LOS_SoUnload(handle);
return;
}
ret = func(1, 1);
if (ret != 12) {
printf("Failed to execute function\n");
LOS_SoUnload(handle);
return;
}
ret = LOS_SoUnload(handle);
if (ret != 0) {
printf("Failed to unload so\n");
}
printf("Success!\n");
}
```
5. 结果验证
```
Success!
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>用例中文件系统路径为/lib/test.so;
>可以创建一个任务,在任务中调用DynlinkTest接口进行测试;
# 动态加载<a name="ZH-CN_TOPIC_0000001136290130"></a>
- **[基本概念](kernel-mini-extend-dynamic-loading-basic.md)**
- **[开发指导](kernel-mini-extend-dynamic-loading-guide.md)**
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
- [开发指导](#section1149072811148) - [开发指导](#section1149072811148)
- [驱动适配](#section19174939191414) - [驱动适配](#section19174939191414)
- [开发流程](#section131211626151513) - [开发流程](#section131211626151513)
- [编程实例](#section206071303163)
- [编程实例](#section1133718619459)
- [实例描述](#section45337345313) - [实例描述](#section45337345313)
- [示例代码](#section119813171539) - [示例代码](#section119813171539)
- [结果验证](#section7987101232311) - [结果验证](#section7987101232311)
...@@ -53,7 +54,7 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC ...@@ -53,7 +54,7 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
> - 在fatfs\_fdisk操作前,需要该设备中的所有分区均已umount。 > - 在fatfs\_fdisk操作前,需要该设备中的所有分区均已umount。
> - fatfs\_fdisk与fatfs\_format会造成设备数据丢失,请谨慎使用。 > - fatfs\_fdisk与fatfs\_format会造成设备数据丢失,请谨慎使用。
### 编程实例<a name="section206071303163"></a> ## 编程实例<a name="section1133718619459"></a>
### 实例描述<a name="section45337345313"></a> ### 实例描述<a name="section45337345313"></a>
......
# LittleFS<a name="ZH-CN_TOPIC_0000001106260762"></a> # LittleFS<a name="ZH-CN_TOPIC_0000001106260762"></a>
- **[基本概念](kernel-lite-mini-extend-file-lit-basic.md)** - **[基本概念](kernel-mini-extend-file-littlefs-basic.md)**
- **[开发指导](kernel-lite-mini-extend-file-lit-guide.md)** - **[开发指导](kernel-mini-extend-file-littlefs-guide.md)**
# 基本概念<a name="ZH-CN_TOPIC_0000001153060453"></a> # 基本概念<a name="ZH-CN_TOPIC_0000001153060453"></a>
LittleFS是一个小型的的Flash文件系统,它结合日志结构(log-structured)文件系统和COW(copy-on-write)文件系统的思想,以日志结构存储元数据,以COW结构存储数据。这种特殊的存储方式,使LittleFS具有强大的掉电恢复能力(power-loss resilience)。分配COW数据块时LittleFS采用了名为统计损耗均衡的动态损耗均衡算法,使Flash设备的寿命得到有效保障。同时LittleFS针对资源紧缺的小型设备进行设计,具有极其有限的ROM和RAM占用,并且所有RAM的使用都通过一个可配置的固定大小缓冲区进行分配,不会随文件系统的扩大占据更多的系统资源。
LittleFS是一个小型的的Flash文件系统,它结合日志结构(log-structured)文件系统和COW(copy-on-write)文件系统的思想,以日志结构存储元数据,以COW结构存储数据。这种特殊的存储方式,使LittleFS具有强大的掉电恢复能力(power-loss resilience\)。分配COW数据块时LittleFS采用了名为统计损耗均衡的动态损耗均衡算法,使Flash设备的寿命得到有效保障。同时LittleFS针对资源紧缺的小型设备进行设计,具有极其有限的ROM和RAM占用,并且所有RAM的使用都通过一个可配置的固定大小缓冲区进行分配,不会随文件系统的扩大占据更多的系统资源。
当在一个资源非常紧缺的小型设备上,寻找一个具有掉电恢复能力并支持损耗均衡的Flash文件系统时,LittleFS是一个比较好的选择。 当在一个资源非常紧缺的小型设备上,寻找一个具有掉电恢复能力并支持损耗均衡的Flash文件系统时,LittleFS是一个比较好的选择。
# 开发指导<a name="ZH-CN_TOPIC_0000001152860497"></a> # 开发指导<a name="ZH-CN_TOPIC_0000001152860497"></a>
- [示例代码](#section1034515054620)
移植LittleFS到新硬件设备上,需要申明lfs\_config: 移植LittleFS到新硬件设备上,需要申明lfs\_config:
``` ```
...@@ -31,7 +33,7 @@ block\_size 每个擦除块的字节数,可以比物理擦除单元大,但 ...@@ -31,7 +33,7 @@ block\_size 每个擦除块的字节数,可以比物理擦除单元大,但
block\_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。 block\_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。
### 示例代码<a name="section4670115211265"></a> ## 示例代码<a name="section1034515054620"></a>
代码实现如下: 代码实现如下:
......
...@@ -197,8 +197,8 @@ ...@@ -197,8 +197,8 @@
</tbody> </tbody>
</table> </table>
- **[FAT](kernel-lite-mini-extend-file-fat.md)** - **[FAT](kernel-mini-extend-file-fat.md)**
- **[LittleFS](kernel-lite-mini-extend-file-lit.md)** - **[LittleFS](kernel-mini-extend-file-lit.md)**
# C++支持<a name="ZH-CN_TOPIC_0000001079036442"></a> # C++支持<a name="ZH-CN_TOPIC_0000001079036442"></a>
- [基本概念](#section11374125415814) - [基本概念](#section11374125415814)
- [运行机制](#section125251720195) - [运行机制](#section189351319134418)
- [开发指导](#section166302407911) - [开发指导](#section166302407911)
- [接口说明](#section1881825119919) - [接口说明](#section1881825119919)
- [开发流程](#section76371145108) - [开发流程](#section76371145108)
...@@ -13,7 +12,7 @@ ...@@ -13,7 +12,7 @@
C++作为目前使用最广泛的编程语言之一,支持类、封装、重载等特性,是在C语言基础上开发的一种面向对象的编程语言。 C++作为目前使用最广泛的编程语言之一,支持类、封装、重载等特性,是在C语言基础上开发的一种面向对象的编程语言。
### 运行机制<a name="section125251720195"></a> ## 运行机制<a name="section189351319134418"></a>
C++代码的识别主要由编译器支持,系统主要对全局对象进行构造函数调用,进行初始化操作。 C++代码的识别主要由编译器支持,系统主要对全局对象进行构造函数调用,进行初始化操作。
......
# 扩展组件<a name="ZH-CN_TOPIC_0000001123863139"></a>
- **[C++支持](kernel-mini-extend-support.md)**
- **[CPU占用率](kernel-mini-extend-cpup.md)**
- **[动态加载](kernel-mini-extend-dynamic-loading.md)**
- **[文件系统](kernel-mini-extend-file.md)**
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
- 内存水线:即内存池的最大使用量,每次申请和释放时,都会更新水线值,实际业务可根据该值,优化内存池大小; - 内存水线:即内存池的最大使用量,每次申请和释放时,都会更新水线值,实际业务可根据该值,优化内存池大小;
- 碎片率:衡量内存池的碎片化程度,碎片率高表现为内存池剩余内存很多,但是最大空闲内存块很小,可以用公式(fragment=100-最大空闲内存块大小/剩余内存大小)来度量; - 碎片率:衡量内存池的碎片化程度,碎片率高表现为内存池剩余内存很多,但是最大空闲内存块很小,可以用公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)来度量;
- 其他参数:通过调用接口(详见[内存管理](kernel-lite-mini-basic-memory.md)章节接口说明),扫描内存池的节点信息,统计出相关信息。 - 其他参数:通过调用接口(详见[内存管理](kernel-mini-basic-memory-basic.md)章节接口说明),扫描内存池的节点信息,统计出相关信息。
## 功能配置<a name="section470611682411"></a> ## 功能配置<a name="section470611682411"></a>
...@@ -44,7 +44,7 @@ typedef struct { ...@@ -44,7 +44,7 @@ typedef struct {
- 内存水线获取:调用LOS\_MemInfoGet接口,第1个参数是内存池首地址,第2个参数是LOS\_MEM\_POOL\_STATUS类型的句柄,其中字段usageWaterLine即水线值。 - 内存水线获取:调用LOS\_MemInfoGet接口,第1个参数是内存池首地址,第2个参数是LOS\_MEM\_POOL\_STATUS类型的句柄,其中字段usageWaterLine即水线值。
- 内存碎片率计算:同样调用LOS\_MemInfoGet接口,可以获取内存池的剩余内存大小和最大空闲内存块大小,然后根据公式(fragment=100-最大空闲内存块大小/剩余内存大小)得出此时的动态内存池碎片率。 - 内存碎片率计算:同样调用LOS\_MemInfoGet接口,可以获取内存池的剩余内存大小和最大空闲内存块大小,然后根据公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)得出此时的动态内存池碎片率。
### 编程实例<a name="section1025453412611"></a> ### 编程实例<a name="section1025453412611"></a>
...@@ -70,6 +70,9 @@ typedef struct { ...@@ -70,6 +70,9 @@ typedef struct {
void MemInfoTaskFunc(void) void MemInfoTaskFunc(void)
{ {
LOS_MEM_POOL_STATUS poolStatus = {0}; LOS_MEM_POOL_STATUS poolStatus = {0};
/* 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;
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
内存调测方法旨在辅助定位动态内存相关问题,提供了基础的动态内存池信息统计手段,向用户呈现内存池水线、碎片率等信息;提供了内存泄漏检测手段,方便用户准确定位存在内存泄漏的代码行,也可以辅助分析系统各个模块内存的使用情况;提供了踩内存检测手段,可以辅助定位越界踩内存的场景。 内存调测方法旨在辅助定位动态内存相关问题,提供了基础的动态内存池信息统计手段,向用户呈现内存池水线、碎片率等信息;提供了内存泄漏检测手段,方便用户准确定位存在内存泄漏的代码行,也可以辅助分析系统各个模块内存的使用情况;提供了踩内存检测手段,可以辅助定位越界踩内存的场景。
- **[内存信息统计](kernel-lite-mini-inner-debug-mes.md)** - **[内存信息统计](kernel-mini-memory-debug-mes.md)**
- **[内存泄漏检测](kernel-lite-mini-inner-debug-det.md)** - **[内存泄漏检测](kernel-mini-imemory-debug-det.md)**
- **[踩内存检测](kernel-lite-mini-inner-debug-cet.md)** - **[踩内存检测](kernel-mini-memory-debug-cet.md)**
...@@ -51,7 +51,7 @@ CPU体系架构分为通用架构定义和特定架构定义两层,通用架 ...@@ -51,7 +51,7 @@ CPU体系架构分为通用架构定义和特定架构定义两层,通用架
</tbody> </tbody>
</table> </table>
LiteOS-M已经支持ARM Cortex-M3、ARM Cortex-M4、ARM Cortex-M7、ARM Cortex-M33、RISC-V等主流架构,如果需要扩展CPU体系架构,请参考[芯片架构适配点](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/porting/%E7%A7%BB%E6%A4%8D%E6%A6%82%E8%BF%B0.md#%E8%8A%AF%E7%89%87%E6%9E%B6%E6%9E%84%E9%80%82%E9%85%8D%E7%82%B9) LiteOS-M已经支持ARM Cortex-M3、ARM Cortex-M4、ARM Cortex-M7、ARM Cortex-M33、RISC-V等主流架构,如果需要扩展CPU体系架构,请参考[芯片架构适配点](../porting/porting-chip-kernel-overview.md#section137431650339)
### 运行机制<a name="section4599142312817"></a> ### 运行机制<a name="section4599142312817"></a>
......
# 轻量系统内核<a name="ZH-CN_TOPIC_0000001124663064"></a>
- **[内核概述](kernel-mini-overview.md)**
- **[基础内核](kernel-mini-basic.md)**
- **[扩展组件](kernel-mini-extend.md)**
- **[内核调测](kernel-memory-inner.md)**
- **[附录](kernel-mini-app.md)**
# 位操作<a name="ZH-CN_TOPIC_0000001078588212"></a>
- [基本概念](#section1990715203418)
- [功能说明](#section848334511411)
- [编程实例](#section67569495514)
- [实例描述](#section33551554391)
- [结果验证](#section8931859194)
## 基本概念<a name="section1990715203418"></a>
位操作是指对二进制数的bit位进行操作。程序可以设置某一变量为状态字,状态字中的每一bit位(标志位)可以具有自定义的含义。
## 功能说明<a name="section848334511411"></a>
系统提供标志位的置1和清0操作,可以改变标志位的内容,同时还提供获取状态字中标志位为1的最高位和最低位的功能。用户也可以对系统的寄存器进行位操作。位操作模块为用户提供下面几种功能,接口详细信息可以查看API参考。
**表 1** 位操作模块接口
<a name="table148791521769"></a>
<table><thead align="left"><tr id="row13880624615"><th class="cellrowborder" valign="top" width="16.89168916891689%" id="mcps1.2.4.1.1"><p id="p1587119571763"><a name="p1587119571763"></a><a name="p1587119571763"></a><strong id="b128711357261"><a name="b128711357261"></a><a name="b128711357261"></a><span>功能分类</span></strong></p>
</th>
<th class="cellrowborder" valign="top" width="35.54355435543554%" id="mcps1.2.4.1.2"><p id="p38714577610"><a name="p38714577610"></a><a name="p38714577610"></a><strong id="b2871195711612"><a name="b2871195711612"></a><a name="b2871195711612"></a><span>接口名称</span></strong></p>
</th>
<th class="cellrowborder" valign="top" width="47.56475647564757%" id="mcps1.2.4.1.3"><p id="p108711657563"><a name="p108711657563"></a><a name="p108711657563"></a><strong id="b10871105714617"><a name="b10871105714617"></a><a name="b10871105714617"></a><span>描述</span></strong></p>
</th>
</tr>
</thead>
<tbody><tr id="row18801722069"><td class="cellrowborder" rowspan="2" valign="top" width="16.89168916891689%" headers="mcps1.2.4.1.1 "><p id="p108717579612"><a name="p108717579612"></a><a name="p108717579612"></a>置1/清0标志位</p>
</td>
<td class="cellrowborder" valign="top" width="35.54355435543554%" headers="mcps1.2.4.1.2 "><p id="p88717574616"><a name="p88717574616"></a><a name="p88717574616"></a>LOS_BitmapSet</p>
</td>
<td class="cellrowborder" valign="top" width="47.56475647564757%" headers="mcps1.2.4.1.3 "><p id="p16871957668"><a name="p16871957668"></a><a name="p16871957668"></a>对状态字的某一标志位进行置1操作</p>
</td>
</tr>
<tr id="row38805219612"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p68713574610"><a name="p68713574610"></a><a name="p68713574610"></a>LOS_BitmapClr</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p14871155718618"><a name="p14871155718618"></a><a name="p14871155718618"></a>对状态字的某一标志位进行清0操作</p>
</td>
</tr>
<tr id="row16880112663"><td class="cellrowborder" rowspan="2" valign="top" width="16.89168916891689%" headers="mcps1.2.4.1.1 "><p id="p158710579615"><a name="p158710579615"></a><a name="p158710579615"></a>获取标志位为1的bit位</p>
</td>
<td class="cellrowborder" valign="top" width="35.54355435543554%" headers="mcps1.2.4.1.2 "><p id="p1787145718612"><a name="p1787145718612"></a><a name="p1787145718612"></a>LOS_HighBitGet</p>
</td>
<td class="cellrowborder" valign="top" width="47.56475647564757%" headers="mcps1.2.4.1.3 "><p id="p168713571468"><a name="p168713571468"></a><a name="p168713571468"></a>获取状态字中为1的最高位</p>
</td>
</tr>
<tr id="row138803219613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p15871957467"><a name="p15871957467"></a><a name="p15871957467"></a>LOS_LowBitGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p148719571569"><a name="p148719571569"></a><a name="p148719571569"></a>获取状态字中为1的最低位</p>
</td>
</tr>
<tr id="row0880182168"><td class="cellrowborder" rowspan="3" valign="top" width="16.89168916891689%" headers="mcps1.2.4.1.1 "><p id="p10871957265"><a name="p10871957265"></a><a name="p10871957265"></a>连续bit位操作</p>
</td>
<td class="cellrowborder" valign="top" width="35.54355435543554%" headers="mcps1.2.4.1.2 "><p id="p787185717616"><a name="p787185717616"></a><a name="p787185717616"></a>LOS_BitmapSetNBits</p>
</td>
<td class="cellrowborder" valign="top" width="47.56475647564757%" headers="mcps1.2.4.1.3 "><p id="p10871135714613"><a name="p10871135714613"></a><a name="p10871135714613"></a>对状态字的连续标志位进行置1操作</p>
</td>
</tr>
<tr id="row12881728619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18710575615"><a name="p18710575615"></a><a name="p18710575615"></a>LOS_BitmapClrNBits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1387145711610"><a name="p1387145711610"></a><a name="p1387145711610"></a>对状态字的连续标志位进行清0操作</p>
</td>
</tr>
<tr id="row4881192262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1987155714611"><a name="p1987155714611"></a><a name="p1987155714611"></a>LOS_BitmapFfz</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p187115571369"><a name="p187115571369"></a><a name="p187115571369"></a>获取从最低有效位开始的第一个0的bit位</p>
</td>
</tr>
</tbody>
</table>
## 编程实例<a name="section67569495514"></a>
### 实例描述<a name="section33551554391"></a>
对数据实现位操作,本实例实现如下功能:
1. 某一标志位置1。
2. 获取标志位为1的最高bit位。
3. 某一标志位清0。
4. 获取标志位为1的最低bit位。
```
#include "los_bitmap.h"
#include "los_printf.h"
static UINT32 BitSample(VOID)
{
UINT32 flag = 0x10101010;
UINT16 pos;
PRINTK("\nBitmap Sample!\n");
PRINTK("The flag is 0x%8x\n", flag);
pos = 8;
LOS_BitmapSet(&flag, pos);
PRINTK("LOS_BitmapSet:\t pos : %d, the flag is 0x%0+8x\n", pos, flag);
pos = LOS_HighBitGet(flag);
PRINTK("LOS_HighBitGet:\t The highest one bit is %d, the flag is 0x%0+8x\n", pos, flag);
LOS_BitmapClr(&flag, pos);
PRINTK("LOS_BitmapClr:\t pos : %d, the flag is 0x%0+8x\n", pos, flag);
pos = LOS_LowBitGet(flag);
PRINTK("LOS_LowBitGet:\t The lowest one bit is %d, the flag is 0x%0+8x\n\n", pos, flag);
return LOS_OK;
}
```
### 结果验证<a name="section8931859194"></a>
编译运行得到的结果为:
```
Bitmap Sample!
The flag is 0x10101010
LOS_BitmapSet: pos : 8, the flag is 0x10101110
LOS_HighBitGet:The highest one bit is 28, the flag is 0x10101110
LOS_BitmapClr: pos : 28, the flag is 0x00101110
LOS_LowBitGet: The lowest one bit is 4, the flag is 0x00101110
```
# 双向链表<a name="ZH-CN_TOPIC_0000001123753381"></a>
- [基本概念](#section1990715203418)
- [功能说明](#section848334511411)
- [开发流程](#section01781261552)
- [编程实例](#section8354175218128)
## 基本概念<a name="section1990715203418"></a>
双向链表是指含有往前和往后两个方向的链表,即每个结点中除存放下一个节点指针外,还增加一个指向前一个节点的指针。其头指针head是唯一确定的。从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点,这种数据结构形式使得双向链表在查找时更加方便,特别是大量数据的遍历。由于双向链表具有对称性,能方便地完成各种插入、删除等操作,但需要注意前后方向的操作。
## 功能说明<a name="section848334511411"></a>
双向链表模块为用户提供下面几种功能,接口详细信息可以查看API参考。
<a name="table9827162254713"></a>
<table><tbody><tr id="row2089515228470"><td class="cellrowborder" valign="top" width="8.14%"><p id="p4895182214473"><a name="p4895182214473"></a><a name="p4895182214473"></a><strong id="b17895022154712"><a name="b17895022154712"></a><a name="b17895022154712"></a><span>功能分类</span></strong></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p58951922124713"><a name="p58951922124713"></a><a name="p58951922124713"></a><strong id="b15895132214476"><a name="b15895132214476"></a><a name="b15895132214476"></a><span>接口名</span></strong></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p5895122134719"><a name="p5895122134719"></a><a name="p5895122134719"></a><strong id="b5895132214471"><a name="b5895132214471"></a><a name="b5895132214471"></a><span>描述</span></strong></p>
</td>
</tr>
<tr id="row20895152284710"><td class="cellrowborder" rowspan="2" valign="top" width="8.14%"><p id="p18951922144714"><a name="p18951922144714"></a><a name="p18951922144714"></a><span>初始化链表</span></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p789516220474"><a name="p789516220474"></a><a name="p789516220474"></a><span>LOS_ListInit</span></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p38951422144710"><a name="p38951422144710"></a><a name="p38951422144710"></a><span>将指定节点初始化为双向链表节点</span></p>
</td>
</tr>
<tr id="row289552216475"><td class="cellrowborder" valign="top"><p id="p11895222194718"><a name="p11895222194718"></a><a name="p11895222194718"></a><span>LOS_DL_LIST_HEAD</span></p>
</td>
<td class="cellrowborder" valign="top"><p id="p3895222184710"><a name="p3895222184710"></a><a name="p3895222184710"></a><span>定义一个节点并初始化为双向链表节点</span></p>
</td>
</tr>
<tr id="row1689522210476"><td class="cellrowborder" rowspan="3" valign="top" width="8.14%"><p id="p12896132294720"><a name="p12896132294720"></a><a name="p12896132294720"></a><span>增加节点</span></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p789611221477"><a name="p789611221477"></a><a name="p789611221477"></a><span>LOS_ListAdd</span></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p9896122134715"><a name="p9896122134715"></a><a name="p9896122134715"></a><span>将指定节点插入到双向链表头端</span></p>
</td>
</tr>
<tr id="row191212010315"><td class="cellrowborder" valign="top"><p id="p14135012318"><a name="p14135012318"></a><a name="p14135012318"></a>LOS_ListHeadInsert</p>
</td>
<td class="cellrowborder" valign="top"><p id="p4138202417318"><a name="p4138202417318"></a><a name="p4138202417318"></a><span>将指定节点插入到双向链表头端,</span><span>LOS_ListAdd</span></p>
</td>
</tr>
<tr id="row188961225475"><td class="cellrowborder" valign="top"><p id="p18961122154718"><a name="p18961122154718"></a><a name="p18961122154718"></a><span>LOS_ListTailInsert</span></p>
</td>
<td class="cellrowborder" valign="top"><p id="p188961322144712"><a name="p188961322144712"></a><a name="p188961322144712"></a><span>将指定节点插入到双向链表尾端</span></p>
</td>
</tr>
<tr id="row15357444193310"><td class="cellrowborder" rowspan="3" valign="top" width="8.14%"><p id="p1692010363413"><a name="p1692010363413"></a><a name="p1692010363413"></a>增加链表</p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p1735715449336"><a name="p1735715449336"></a><a name="p1735715449336"></a>LOS_ListAddList</p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p6622934203610"><a name="p6622934203610"></a><a name="p6622934203610"></a><span>将指定链表的头端插入到双向链表头端</span></p>
</td>
</tr>
<tr id="row15195047123311"><td class="cellrowborder" valign="top"><p id="p17195124711336"><a name="p17195124711336"></a><a name="p17195124711336"></a>LOS_ListHeadInsertList</p>
</td>
<td class="cellrowborder" valign="top"><p id="p185641532153916"><a name="p185641532153916"></a><a name="p185641532153916"></a><span>将指定链表的头端插入到双向链表头端,同</span>LOS_ListAddList</p>
</td>
</tr>
<tr id="row144801751153310"><td class="cellrowborder" valign="top"><p id="p1048055153313"><a name="p1048055153313"></a><a name="p1048055153313"></a>LOS_ListTailInsertList</p>
</td>
<td class="cellrowborder" valign="top"><p id="p13855544153914"><a name="p13855544153914"></a><a name="p13855544153914"></a><span>将指定链表的尾端插入到双向链表头端</span></p>
</td>
</tr>
<tr id="row5896112264710"><td class="cellrowborder" rowspan="2" valign="top" width="8.14%"><p id="p28961122174717"><a name="p28961122174717"></a><a name="p28961122174717"></a><span>删除节点</span></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p28961422154710"><a name="p28961422154710"></a><a name="p28961422154710"></a><span>LOS_ListDelete</span></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p289610224473"><a name="p289610224473"></a><a name="p289610224473"></a><span>将指定节点从链表中删除</span></p>
</td>
</tr>
<tr id="row3896522124711"><td class="cellrowborder" valign="top"><p id="p0896152213471"><a name="p0896152213471"></a><a name="p0896152213471"></a><span>LOS_ListDelInit</span></p>
</td>
<td class="cellrowborder" valign="top"><p id="p48965226475"><a name="p48965226475"></a><a name="p48965226475"></a><span>将指定节点从链表中删除,并使用该节点初始化链表</span></p>
</td>
</tr>
<tr id="row1689602294714"><td class="cellrowborder" rowspan="3" valign="top" width="8.14%"><p id="p18961222164716"><a name="p18961222164716"></a><a name="p18961222164716"></a><span>判断双向链表</span></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p78961522184715"><a name="p78961522184715"></a><a name="p78961522184715"></a><span>LOS_ListEmpty</span></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p16896172254720"><a name="p16896172254720"></a><a name="p16896172254720"></a><span>判断链表是否为空</span></p>
</td>
</tr>
<tr id="row18516729174116"><td class="cellrowborder" valign="top"><p id="p17517829184112"><a name="p17517829184112"></a><a name="p17517829184112"></a>LOS_DL_LIST_IS_END</p>
</td>
<td class="cellrowborder" valign="top"><p id="p6517142944113"><a name="p6517142944113"></a><a name="p6517142944113"></a>判断指定链表节点是否为链表尾端</p>
</td>
</tr>
<tr id="row893214104211"><td class="cellrowborder" valign="top"><p id="p149321243429"><a name="p149321243429"></a><a name="p149321243429"></a>LOS_DL_LIST_IS_ON_QUEUE</p>
</td>
<td class="cellrowborder" valign="top"><p id="p393211444212"><a name="p393211444212"></a><a name="p393211444212"></a>判断链表节点是否在双向链表里</p>
</td>
</tr>
<tr id="row128977221474"><td class="cellrowborder" rowspan="5" valign="top" width="8.14%"><p id="p138971322174717"><a name="p138971322174717"></a><a name="p138971322174717"></a><span>获取结构体信息</span></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p138971922194712"><a name="p138971922194712"></a><a name="p138971922194712"></a><span>LOS_OFF_SET_OF</span></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p08971022144720"><a name="p08971022144720"></a><a name="p08971022144720"></a><span>获取指定结构体内的成员相对于结构体起始地址的偏移量</span></p>
</td>
</tr>
<tr id="row17897102264718"><td class="cellrowborder" valign="top"><p id="p222185817011"><a name="p222185817011"></a><a name="p222185817011"></a><span>LOS_DL_LIST_ENTRY</span></p>
</td>
<td class="cellrowborder" valign="top"><p id="p165524542002"><a name="p165524542002"></a><a name="p165524542002"></a><span>获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称</span></p>
</td>
</tr>
<tr id="row15461471406"><td class="cellrowborder" valign="top"><p id="p1889792218473"><a name="p1889792218473"></a><a name="p1889792218473"></a>LOS_ListPeekHeadType</p>
</td>
<td class="cellrowborder" valign="top"><p id="p111876351019"><a name="p111876351019"></a><a name="p111876351019"></a><span>获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称</span>。如果链表为空,返回NULL。</p>
</td>
</tr>
<tr id="row203104014114"><td class="cellrowborder" valign="top"><p id="p18321540016"><a name="p18321540016"></a><a name="p18321540016"></a>LOS_ListRemoveHeadType</p>
</td>
<td class="cellrowborder" valign="top"><p id="p913828651"><a name="p913828651"></a><a name="p913828651"></a><span>获取双向链表中第一个链表节点所在的结构体地址,并把第一个链表节点从链表中删除。接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称</span>。如果链表为空,返回NULL。</p>
</td>
</tr>
<tr id="row745116416618"><td class="cellrowborder" valign="top"><p id="p1645217411963"><a name="p1645217411963"></a><a name="p1645217411963"></a>LOS_ListNextType</p>
</td>
<td class="cellrowborder" valign="top"><p id="p972412565619"><a name="p972412565619"></a><a name="p972412565619"></a><span>获取双向链表中指定链表节点的下一个节点所在的结构体地址。接口的第一个入参表示的是链表中的头节点,第二个入参是指定的链表节点,第三个入参是要获取的结构体名称,第四个入参是链表在该结构体中的名称</span>。如果链表节点下一个为链表头结点为空,返回NULL。</p>
</td>
</tr>
<tr id="row4897192254715"><td class="cellrowborder" rowspan="2" valign="top" width="8.14%"><p id="p3897922164714"><a name="p3897922164714"></a><a name="p3897922164714"></a><span>遍历双向链表</span></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p58971222194713"><a name="p58971222194713"></a><a name="p58971222194713"></a><span>LOS_DL_LIST_FOR_EACH</span></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p28971222194714"><a name="p28971222194714"></a><a name="p28971222194714"></a><span>遍历双向链表</span></p>
</td>
</tr>
<tr id="row589792254710"><td class="cellrowborder" valign="top"><p id="p689792264718"><a name="p689792264718"></a><a name="p689792264718"></a><span>LOS_DL_LIST_FOR_EACH_SAFE</span></p>
</td>
<td class="cellrowborder" valign="top"><p id="p148975222479"><a name="p148975222479"></a><a name="p148975222479"></a><span>遍历双向链表,并存储当前节点的后继节点用于安全校验</span></p>
</td>
</tr>
<tr id="row208971622174718"><td class="cellrowborder" rowspan="2" valign="top" width="8.14%"><p id="p168977224474"><a name="p168977224474"></a><a name="p168977224474"></a><span>遍历包含双向链表的结构体</span></p>
</td>
<td class="cellrowborder" valign="top" width="32.09%"><p id="p1489752216479"><a name="p1489752216479"></a><a name="p1489752216479"></a><span>LOS_DL_LIST_FOR_EACH_ENTRY</span></p>
</td>
<td class="cellrowborder" valign="top" width="59.77%"><p id="p10897522194717"><a name="p10897522194717"></a><a name="p10897522194717"></a><span>遍历指定双向链表,获取包含该链表节点的结构体地址</span></p>
</td>
</tr>
<tr id="row10897622104713"><td class="cellrowborder" valign="top"><p id="p2897112215478"><a name="p2897112215478"></a><a name="p2897112215478"></a><span>LOS_DL_LIST_FOR_EACH_ENTRY_SAFE</span></p>
</td>
<td class="cellrowborder" valign="top"><p id="p13898102220475"><a name="p13898102220475"></a><a name="p13898102220475"></a><span>遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址</span></p>
</td>
</tr>
</tbody>
</table>
## 开发流程<a name="section01781261552"></a>
双向链表的典型开发流程:
1. 调用LOS\_ListInit/LOS\_DL\_LIST\_HEAD初始双向链表。
2. 调用LOS\_ListAdd向链表插入节点。
3. 调用LOS\_ListTailInsert向链表尾部插入节点。
4. 调用LOS\_ListDelete删除指定节点。
5. 调用LOS\_ListEmpty判断链表是否为空。
6. 调用LOS\_ListDelInit删除指定节点并以此节点初始化链表。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 需要注意节点指针前后方向的操作。
>- 链表操作接口,为底层接口,不对入参进行判空,需要使用者确保传参合法。
>- 如果链表节点的内存是动态申请的,删除节点时,要注意释放内存。
### 编程实例<a name="section8354175218128"></a>
**实例描述**
本实例实现如下功能:
1. 初始化双向链表。
2. 增加节点。
3. 删除节点。
4. 测试操作是否成功。
```
#include "stdio.h"
#include "los_list.h"
static UINT32 ListSample(VOID)
{
LOS_DL_LIST listHead = {NULL,NULL};
LOS_DL_LIST listNode1 = {NULL,NULL};
LOS_DL_LIST listNode2 = {NULL,NULL};
//首先初始化链表
PRINTK("Initial head\n");
LOS_ListInit(&listHead);
//添加节点1和节点2,并校验他们的相互关系
LOS_ListAdd(&listHead, &listNode1);
if (listNode1.pstNext == &listHead && listNode1.pstPrev == &listHead) {
PRINTK("Add listNode1 success\n");
}
LOS_ListTailInsert(&listHead, &listNode2);
if (listNode2.pstNext == &listHead && listNode2.pstPrev == &listNode1) {
PRINTK("Tail insert listNode2 success\n");
}
//删除两个节点
LOS_ListDelete(&listNode1);
LOS_ListDelete(&listNode2);
//确认链表为空
if (LOS_ListEmpty(&listHead)) {
PRINTK("Delete success\n");
}
return LOS_OK;
}
```
**结果验证**
编译运行得到的结果为:
```
Initial head
Add listNode1 success
Tail insert listNode2 success
Delete success
```
# 标准库<a name="ZH-CN_TOPIC_0000001051690267"></a> # 标准库<a name="ZH-CN_TOPIC_0000001126847658"></a>
- [框架流程](#section1247343413257) - [标准库接口框架](#section149319478561)
- [操作实例](#section4807125622614) - [操作实例](#section20874620185915)
- [常见问题](#section1219455217277) - [与Linux标准库差异](#section6555642165713)
- [进程](#section11299104511409)
- [内存](#section175754484116)
- [文件系统](#section118191113134220)
- [信号](#section195939264421)
- [Time](#section20825124304213)
OpenHarmony内核使用**musl libc**库,支持标准POSIX接口,开发者可基于POSIX标准接口开发内核之上的组件及应用。
## 框架流程<a name="section1247343413257"></a> OpenHarmony内核使用musl libc库,支持标准POSIX接口,开发者可基于POSIX标准接口开发内核之上的组件及应用。
**图 1** POSIX接口框架<a name="fig279734632911"></a> ## 标准库接口框架<a name="section149319478561"></a>
**图 1** POSIX接口框架<a name="fig153258541429"></a>
![](figure/POSIX接口框架.png "POSIX接口框架") ![](figure/POSIX接口框架.png "POSIX接口框架")
**musl libc**库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony内核适配支持 ,以满足接口对外描述的功能要求。 musl libc库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony内核适配支持 ,以满足接口对外描述的功能要求。
标准库支持接口的详细情况请参考C库的API文档,其中也涵盖了与POSIX标准之间的差异说明。 标准库支持接口的详细情况请参考C库的API文档,其中也涵盖了与POSIX标准之间的差异说明。
## 操作实例<a name="section4807125622614"></a> ## 操作实例<a name="section20874620185915"></a>
在本示例中,主线程创建了THREAD\_NUM个子线程,每个子线程启动后等待被主线程唤醒,主线程成功唤醒所有子线程后,子线程继续执行直至生命周期结束,同时主线程通过pthread\_join方法等待所有线程执行结束。 在本示例中,主线程创建了THREAD\_NUM个子线程,每个子线程启动后等待被主线程唤醒,主线程成功唤醒所有子线程后,子线程继续执行直至生命周期结束,同时主线程通过pthread\_join方法等待所有线程执行结束。
...@@ -191,7 +197,91 @@ int main(int argc, char *argv[]) ...@@ -191,7 +197,91 @@ int main(int argc, char *argv[])
#endif /* __cplusplus */ #endif /* __cplusplus */
``` ```
## 常见问题<a name="section1219455217277"></a> ## 与Linux标准库差异<a name="section6555642165713"></a>
本节描述了OpenHarmony内核承载的标准库与Linux标准库之间存在的关键差异。更多差异详见C库API文档说明。
### 进程<a name="section11299104511409"></a>
1. OpenHarmony用户态**进程**优先级只支持静态优先级且用户态可配置的优先级范围为10\(最高优先级\)-31\(最低优先级)。
2. OpenHarmony用户态**线程**优先级只支持静态优先级且用户态可配置的优先级范围为0\(最高优先级\)-31\(最低优先级)。
3. OpenHarmony进程调度策略只支持SCHED\_RR, 线程调度策略支持SCHED\_RR和SCHED\_FIFO。
### 内存<a name="section175754484116"></a>
**h2****与Linux mmap的差异**
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进行回收。
**h2****代码举例**
Linux目前支持的情况如下:
```
int main(int argc, char *argv[])
{
int fd;
void *addr = NULL;
...
fd = open(argv[1], O_RDONLY);
if (fd == -1){
perror("open");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
...
exit(EXIT_SUCCESS);
}
```
OpenHarmony支持的情况如下:
```
int main(int argc, char *argv[])
{
int fd;
void *addr = NULL;
...
fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
...
munmap(addr, length);
close(fd); /* Close fd after the munmap is canceled. */
exit(EXIT_SUCCESS);
}
```
### 文件系统<a name="section118191113134220"></a>
**系统目录**:用户无权限修改系统目录和设备挂载目录。包含/dev,/proc,/app,/bin,/data,/etc,/lib,/system,/usr目录。
**用户目录**:用户可以在该目录下进行文件创建、读写,但**不能进行设备挂载**。用户目录指/storage目录。
**系统目录****用户目录**之外,用户可以自行创建文件夹进行设备的挂载。但是要注意,已挂载的文件夹及其子文件夹不允许重复或者嵌套挂载,非空文件夹不允许挂载。
### 信号<a name="section195939264421"></a>
- 信号默认行为不支持STOP、CONTINUE、COREDUMP功能。
- 无法通过信号唤醒正在睡眠状态(举例:进程调用sleep函数进入睡眠)的进程。原因:信号机制无唤醒功能,当且仅当进程被CPU调度运行时才能处理信号内容。
- 进程退出后会发送SIGCHLD给父进程,发送动作无法取消。
- 信号仅支持1-30号信号,接收方收到多次同一信号,仅执行一次回调函数。
### Time<a name="section20825124304213"></a>
OpenHarmony当前时间精度以tick计算,系统默认10ms/tick。sleep、timeout系列函数时间误差<=20ms
# 基本数据结构<a name="ZH-CN_TOPIC_0000001078876282"></a>
- **[双向链表](kernel-small-apx-dll.md)**
- **[位操作](kernel-small-apx-bitwise.md)**
# 附录<a name="ZH-CN_TOPIC_0000001123841647"></a>
- **[基本数据结构](kernel-small-apx-structure.md)**
- **[标准库](kernel-small-apx-library.md)**
# 原子操作<a name="ZH-CN_TOPIC_0000001078876272"></a>
- [基本概念](#section1792118384594)
- [运行机制](#section1786635117596)
- [开发指导](#section2911115308)
- [接口说明](#section335914201010)
- [开发流程](#section12207371304)
- [编程实例](#section8538651511)
## 基本概念<a name="section1792118384594"></a>
在支持多任务的操作系统中,修改一块内存区域的数据需要“读取-修改-写入”三个步骤。然而同一内存区域的数据可能同时被多个任务访问,如果在修改数据的过程中被其他任务打断,就会造成该操作的执行结果无法预知。
使用开关中断的方法固然可以保证多任务执行结果符合预期,但是显然这种方法会影响系统性能。
ARMv6架构引入了LDREX和STREX指令,以支持对共享存储器更缜密的非阻塞同步。由此实现的原子操作能确保对同一数据的“读取-修改-写入”操作在它的执行期间不会被打断,即操作的原子性。
## 运行机制<a name="section1786635117596"></a>
OpenHarmony系统通过对ARMv6架构中的LDREX和STREX进行封装,向用户提供了一套原子性的操作接口。
- LDREX Rx, \[Ry\]
读取内存中的值,并标记对该段内存的独占访问:
- 读取寄存器Ry指向的4字节内存数据,保存到Rx寄存器中。
- 对Ry指向的内存区域添加独占访问标记。
- STREX Rf, Rx, \[Ry\]
检查内存是否有独占访问标记,如果有则更新内存值并清空标记,否则不更新内存:
- 有独占访问标记
- 将寄存器Rx中的值更新到寄存器Ry指向的内存。
- 标志寄存器Rf置为0。
- 没有独占访问标记
- 不更新内存。
- 标志寄存器Rf置为1。
- 判断标志寄存器
- 标志寄存器为0时,退出循环,原子操作结束。
- 标志寄存器为1时,继续循环,重新进行原子操作。
## 开发指导<a name="section2911115308"></a>
### 接口说明<a name="section335914201010"></a>
OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口详细信息可以查看API参考。
**表 1** 原子操作接口说明
<a name="table29217519171"></a>
<table><thead align="left"><tr id="row79375119172"><th class="cellrowborder" valign="top" width="21.21212121212121%" id="mcps1.2.4.1.1"><p id="p159375113174"><a name="p159375113174"></a><a name="p159375113174"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.39333933393339%" id="mcps1.2.4.1.2"><p id="p199385118173"><a name="p199385118173"></a><a name="p199385118173"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="45.3945394539454%" id="mcps1.2.4.1.3"><p id="p18937511175"><a name="p18937511175"></a><a name="p18937511175"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row159315151712"><td class="cellrowborder" rowspan="2" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p593135115176"><a name="p593135115176"></a><a name="p593135115176"></a></p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p1193651181714"><a name="p1193651181714"></a><a name="p1193651181714"></a>LOS_AtomicRead</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p09316512178"><a name="p09316512178"></a><a name="p09316512178"></a>读取32bit原子数据</p>
</td>
</tr>
<tr id="row1493151161719"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p119395111718"><a name="p119395111718"></a><a name="p119395111718"></a>LOS_Atomic64Read</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p49311514178"><a name="p49311514178"></a><a name="p49311514178"></a>读取64bit原子数据</p>
</td>
</tr>
<tr id="row69365111712"><td class="cellrowborder" rowspan="2" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p199355111175"><a name="p199355111175"></a><a name="p199355111175"></a></p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p1693175191714"><a name="p1693175191714"></a><a name="p1693175191714"></a>LOS_AtomicSet</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p129320516173"><a name="p129320516173"></a><a name="p129320516173"></a>设置32bit原子数据</p>
</td>
</tr>
<tr id="row1593651111718"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p7944510176"><a name="p7944510176"></a><a name="p7944510176"></a>LOS_Atomic64Set</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p294115191713"><a name="p294115191713"></a><a name="p294115191713"></a>设置64bit原子数据</p>
</td>
</tr>
<tr id="row149495114177"><td class="cellrowborder" rowspan="6" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p1394165151718"><a name="p1394165151718"></a><a name="p1394165151718"></a></p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p494115112179"><a name="p494115112179"></a><a name="p494115112179"></a>LOS_AtomicAdd</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p1694155120174"><a name="p1694155120174"></a><a name="p1694155120174"></a>对32bit原子数据做加法</p>
</td>
</tr>
<tr id="row394651101719"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p179435113171"><a name="p179435113171"></a><a name="p179435113171"></a>LOS_Atomic64Add</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p594851181718"><a name="p594851181718"></a><a name="p594851181718"></a>对64bit原子数据做加法</p>
</td>
</tr>
<tr id="row294185110171"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1834102212615"><a name="p1834102212615"></a><a name="p1834102212615"></a>LOS_AtomicInc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p129413519173"><a name="p129413519173"></a><a name="p129413519173"></a>对32bit原子数据做加1</p>
</td>
</tr>
<tr id="row1894175101713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1981302213264"><a name="p1981302213264"></a><a name="p1981302213264"></a>LOS_Atomic64Inc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p167671640113316"><a name="p167671640113316"></a><a name="p167671640113316"></a>对64bit原子数据做加1</p>
</td>
</tr>
<tr id="row12946512178"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1994051181716"><a name="p1994051181716"></a><a name="p1994051181716"></a>LOS_AtomicIncRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p59414511172"><a name="p59414511172"></a><a name="p59414511172"></a>对32bit原子数据做加1并返回</p>
</td>
</tr>
<tr id="row1994551101712"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p129414519173"><a name="p129414519173"></a><a name="p129414519173"></a>LOS_Atomic64IncRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1194951111713"><a name="p1194951111713"></a><a name="p1194951111713"></a>对64bit原子数据做加1并返回</p>
</td>
</tr>
<tr id="row1794451121719"><td class="cellrowborder" rowspan="6" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p179412517173"><a name="p179412517173"></a><a name="p179412517173"></a></p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p89495115176"><a name="p89495115176"></a><a name="p89495115176"></a>LOS_AtomicSub</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p18220416345"><a name="p18220416345"></a><a name="p18220416345"></a>对32bit原子数据做减法</p>
</td>
</tr>
<tr id="row139485131718"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1894195116176"><a name="p1894195116176"></a><a name="p1894195116176"></a>LOS_Atomic64Sub</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p20822124173415"><a name="p20822124173415"></a><a name="p20822124173415"></a>对64bit原子数据做减法</p>
</td>
</tr>
<tr id="row209505110175"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p7951051141713"><a name="p7951051141713"></a><a name="p7951051141713"></a>LOS_AtomicDec</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p382234117340"><a name="p382234117340"></a><a name="p382234117340"></a>对32bit原子数据做减1</p>
</td>
</tr>
<tr id="row995151171711"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p395151131715"><a name="p395151131715"></a><a name="p395151131715"></a>LOS_Atomic64Dec</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1982244117340"><a name="p1982244117340"></a><a name="p1982244117340"></a>对64bit原子数据做减1</p>
</td>
</tr>
<tr id="row895155117179"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p395155151719"><a name="p395155151719"></a><a name="p395155151719"></a>LOS_AtomicDecRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p198222414349"><a name="p198222414349"></a><a name="p198222414349"></a>对32bit原子数据做减1并返回</p>
</td>
</tr>
<tr id="row59511518170"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1495125119175"><a name="p1495125119175"></a><a name="p1495125119175"></a>LOS_Atomic64DecRet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p198221841103419"><a name="p198221841103419"></a><a name="p198221841103419"></a>对64bit原子数据做减1并返回</p>
</td>
</tr>
<tr id="row159575131714"><td class="cellrowborder" rowspan="4" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p159585110177"><a name="p159585110177"></a><a name="p159585110177"></a>交换</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p29515114174"><a name="p29515114174"></a><a name="p29515114174"></a>LOS_AtomicXchgByte</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p6956510177"><a name="p6956510177"></a><a name="p6956510177"></a>交换8bit内存数据</p>
</td>
</tr>
<tr id="row14951451111710"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p8952514173"><a name="p8952514173"></a><a name="p8952514173"></a>LOS_AtomicXchg16bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p12334173143919"><a name="p12334173143919"></a><a name="p12334173143919"></a>交换16bit内存数据</p>
</td>
</tr>
<tr id="row595251131716"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1495145117171"><a name="p1495145117171"></a><a name="p1495145117171"></a>LOS_AtomicXchg32bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p9951513173"><a name="p9951513173"></a><a name="p9951513173"></a>交换32bit内存数据</p>
</td>
</tr>
<tr id="row195165131718"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18951151141717"><a name="p18951151141717"></a><a name="p18951151141717"></a>LOS_AtomicXchg64bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p169685115172"><a name="p169685115172"></a><a name="p169685115172"></a>交换64bit内存数据</p>
</td>
</tr>
<tr id="row149616511175"><td class="cellrowborder" rowspan="4" valign="top" width="21.21212121212121%" headers="mcps1.2.4.1.1 "><p id="p49615120172"><a name="p49615120172"></a><a name="p49615120172"></a>先比较后交换</p>
</td>
<td class="cellrowborder" valign="top" width="33.39333933393339%" headers="mcps1.2.4.1.2 "><p id="p129605112171"><a name="p129605112171"></a><a name="p129605112171"></a>LOS_AtomicCmpXchgByte</p>
</td>
<td class="cellrowborder" valign="top" width="45.3945394539454%" headers="mcps1.2.4.1.3 "><p id="p6965510178"><a name="p6965510178"></a><a name="p6965510178"></a>比较相同后交换8bit内存数据</p>
</td>
</tr>
<tr id="row99605171713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p109675131711"><a name="p109675131711"></a><a name="p109675131711"></a>LOS_AtomicCmpXchg16bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p17961951191719"><a name="p17961951191719"></a><a name="p17961951191719"></a>比较相同后交换16bit内存数据</p>
</td>
</tr>
<tr id="row169614513177"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p49645115172"><a name="p49645115172"></a><a name="p49645115172"></a>LOS_AtomicCmpXchg32bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p129611512175"><a name="p129611512175"></a><a name="p129611512175"></a>比较相同后交换32bit内存数据</p>
</td>
</tr>
<tr id="row696175110179"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p16961051161715"><a name="p16961051161715"></a><a name="p16961051161715"></a>LOS_AtomicCmpXchg64bits</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1296205118179"><a name="p1296205118179"></a><a name="p1296205118179"></a>比较相同后交换64bit内存数据</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section12207371304"></a>
有多个任务对同一个内存数据进行加减或交换等操作时,使用原子操作保证结果的可预知性。
>![](../public_sys-resources/icon-note.gif) **说明:**
>原子操作接口仅支持整型数据。
### 编程实例<a name="section8538651511"></a>
**实例描述**
调用原子操作相关接口,观察结果:
1. 创建两个任务
- 任务一用LOS\_AtomicInc对全局变量加100次。
- 任务二用LOS\_AtomicDec对全局变量减100次。
2. 子任务结束后在主任务中打印全局变量的值。
**示例代码**
示例代码如下:
```
#include "los_hwi.h"
#include "los_atomic.h"
#include "los_task.h"
UINT32 g_testTaskId01;
UINT32 g_testTaskId02;
Atomic g_sum;
Atomic g_count;
UINT32 Example_Atomic01(VOID)
{
int i = 0;
for(i = 0; i < 100; ++i) {
LOS_AtomicInc(&g_sum);
}
LOS_AtomicInc(&g_count);
return LOS_OK;
}
UINT32 Example_Atomic02(VOID)
{
int i = 0;
for(i = 0; i < 100; ++i) {
LOS_AtomicDec(&g_sum);
}
LOS_AtomicInc(&g_count);
return LOS_OK;
}
UINT32 Example_AtomicTaskEntry(VOID)
{
TSK_INIT_PARAM_S stTask1={0};
stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Atomic01;
stTask1.pcName = "TestAtomicTsk1";
stTask1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
stTask1.usTaskPrio = 4;
stTask1.uwResved = LOS_TASK_STATUS_DETACHED;
TSK_INIT_PARAM_S stTask2={0};
stTask2.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Atomic02;
stTask2.pcName = "TestAtomicTsk2";
stTask2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
stTask2.usTaskPrio = 4;
stTask2.uwResved = LOS_TASK_STATUS_DETACHED;
LOS_TaskLock();
LOS_TaskCreate(&g_testTaskId01, &stTask1);
LOS_TaskCreate(&g_testTaskId02, &stTask2);
LOS_TaskUnlock();
while(LOS_AtomicRead(&g_count) != 2);
PRINTK("g_sum = %d\n", g_sum);
return LOS_OK;
}
```
**结果验证**
```
g_sum = 0
```
# 虚实映射<a name="ZH-CN_TOPIC_0000001079036248"></a>
- [基本概念](#section9108144913615)
- [运行机制](#section12392621871)
- [开发指导](#section10264102013713)
- [接口说明](#section195320251578)
- [开发流程](#section152774210712)
## 基本概念<a name="section9108144913615"></a>
虚实映射是指系统通过内存管理单元(MMU,Memory Management Unit)将进程空间的虚拟地址与实际的物理地址做映射,并指定相应的访问权限、缓存属性等。程序执行时,CPU访问的是虚拟内存,通过MMU页表条目找到对应的物理内存,并做相应的代码执行或数据读写操作。MMU的映射由页表(Page Table)来描述,其中保存虚拟地址和物理地址的映射关系以及访问权限等。每个进程在创建的时候都会创建一个页表,页表由一个个页表条目(Page Table Entry, PTE)构成,每个页表条目描述虚拟地址区间与物理地址区间的映射关系。MMU中有一块页表缓存,称为快表(TLB, Translation Lookaside Buffers),做地址转换时,MMU首先在TLB中查找,如果找到对应的页表条目可直接进行转换,提高了查询效率。CPU访问内存或外设的示意图如下:
**图 1** CPU访问内存或外设的示意图<a name="fig209379387574"></a>
![](figure/CPU访问内存或外设的示意图.png "CPU访问内存或外设的示意图")
## 运行机制<a name="section12392621871"></a>
虚实映射其实就是一个建立页表的过程。MMU有多级页表,LiteOS-A内核采用二级页表描述进程空间。每个一级页表条目描述符占用4个字节,可表示1MiB的内存空间的映射关系,即1GiB用户空间(LiteOS-A内核中用户空间占用1GiB)的虚拟内存空间需要1024个。系统创建用户进程时,在内存中申请一块4KiB大小的内存块作为一级页表的存储区域,二级页表根据当前进程的需要做动态的内存申请。
- 用户程序加载启动时,会将代码段、数据段映射进虚拟内存空间(详细可参考动态加载与链接一节),此时并没有物理页做实际的映射;
- 程序执行时,如下图粗箭头所示,CPU访问虚拟地址,通过MMU查找是否有对应的物理内存,若该虚拟地址无对应的物理地址则触发缺页异常,内核申请物理内存并将虚实映射关系及对应的属性配置信息写进页表,并把页表条目缓存至TLB,接着CPU可直接通过转换关系访问实际的物理内存;
- 若CPU访问已缓存至TLB的页表条目,无需再访问保存在内存中的页表,可加快查找速度。
**图 2** CPU访问内存示意图<a name="fig95557155719"></a>
![](figure/CPU访问内存示意图.png "CPU访问内存示意图")
## 开发指导<a name="section10264102013713"></a>
### 接口说明<a name="section195320251578"></a>
**表 1** 虚实映射模块接口
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.821282128212822%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.832983298329836%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row12171174434013"><td class="cellrowborder" rowspan="5" valign="top" width="12.821282128212822%" headers="mcps1.2.4.1.1 "><p id="p48244461959"><a name="p48244461959"></a><a name="p48244461959"></a>MMU相关操作</p>
</td>
<td class="cellrowborder" valign="top" width="29.832983298329836%" headers="mcps1.2.4.1.2 "><p id="p15630114884017"><a name="p15630114884017"></a><a name="p15630114884017"></a>LOS_ArchMmuQuery</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p4171244164013"><a name="p4171244164013"></a><a name="p4171244164013"></a>获取进程空间虚拟地址对应的物理地址以及映射属性。</p>
</td>
</tr>
<tr id="row17223043124018"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1730695210400"><a name="p1730695210400"></a><a name="p1730695210400"></a>LOS_ArchMmuMap</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p202242431404"><a name="p202242431404"></a><a name="p202242431404"></a>映射进程空间虚拟地址区间与物理地址区间。</p>
</td>
</tr>
<tr id="row536885134010"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p236819594010"><a name="p236819594010"></a><a name="p236819594010"></a>LOS_ArchMmuUnmap</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p736918564019"><a name="p736918564019"></a><a name="p736918564019"></a>解除进程空间虚拟地址区间与物理地址区间的映射关系。</p>
</td>
</tr>
<tr id="row11567448194112"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0568204814115"><a name="p0568204814115"></a><a name="p0568204814115"></a>LOS_ArchMmuChangeProt</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p05681348204114"><a name="p05681348204114"></a><a name="p05681348204114"></a>修改进程空间虚拟地址区间的映射属性。</p>
</td>
</tr>
<tr id="row1141513373562"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17765212416"><a name="p17765212416"></a><a name="p17765212416"></a>LOS_ArchMmuMove</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1972971913115"><a name="p1972971913115"></a><a name="p1972971913115"></a>将进程空间一个虚拟地址区间的映射关系转移至另一块未使用的虚拟地址区间重新做映射。</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section152774210712"></a>
虚实映射相关接口的使用:
1. 通过LOS\_ArchMmuMap映射一块物理内存。
2. 对映射的地址区间做相关操作:
- 通过LOS\_ArchMmuQuery可以查询相应虚拟地址区间映射的物理地址区间及映射属性;
- 通过LOS\_ArchMmuChangeProt修改映射属性;
- 通过LOS\_ArchMmuMove做虚拟地址区间的重映射。
3. 通过LOS\_ArchMmuUnmap解除映射关系。
>![](../public_sys-resources/icon-note.gif) **说明:**
>上述接口的使用都是基于MMU初始化完成以及相关进程页表的建立,MMU在系统启动阶段已完成初始化,进程创建的时候会建立页表,开发者无需介入操作。
# 中断及异常处理<a name="ZH-CN_TOPIC_0000001123638623"></a>
- [基本概念](#section439816296117)
- [运行机制](#section2792838318)
- [开发指导](#section15415165510110)
- [接口说明](#section57441612024)
- [开发流程](#section64332181221)
- [编程实例](#section204698276478)
- [结果验证](#section1466144215476)
## 基本概念<a name="section439816296117"></a>
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,这个过程就叫做中断。通过中断机制,可以使CPU避免把大量时间耗费在等待、查询外设状态的操作上,大大提高系统实时性以及执行效率。
异常处理是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作,例如虚拟内存缺页异常、打印异常发生时函数的调用栈信息、CPU现场信息、任务的堆栈情况等。
## 运行机制<a name="section2792838318"></a>
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,产生一个中断信号,该信号连接至中断控制器。中断控制器是一方面接收其它外设中断引脚的输入,另一方面它会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和GIC(General Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。CPU收到中断控制器发送的中断信号后,中断当前任务来响应中断请求。
异常处理就是可以打断CPU正常运行流程的一些事情,如未定义指令异常、试图修改只读的数据异常、不对齐的地址访问异常等。当异常发生时,CPU暂停当前的程序,先处理异常事件,然后再继续执行被异常打断的程序。
以ARMv7-a架构为例,中断和异常处理的入口为中断向量表,中断向量表包含各个中断和异常处理的入口函数。
**图 1** 中断向量表<a name="fig105771014134715"></a>
![](figure/zh-cn_image_0000001173449871.png)
## 开发指导<a name="section15415165510110"></a>
### 接口说明<a name="section57441612024"></a>
异常处理为内部机制,不对外提供接口,中断模块提供对外接口如下:
<a name="table11657113333110"></a>
<table><thead align="left"><tr id="row1170612337312"><th class="cellrowborder" valign="top" width="19.900000000000002%" id="mcps1.1.4.1.1"><p id="p4706133373112"><a name="p4706133373112"></a><a name="p4706133373112"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="18.43%" id="mcps1.1.4.1.2"><p id="p1070653343117"><a name="p1070653343117"></a><a name="p1070653343117"></a><strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>接口名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="61.67%" id="mcps1.1.4.1.3"><p id="p370613330311"><a name="p370613330311"></a><a name="p370613330311"></a><strong id="b57068335318"><a name="b57068335318"></a><a name="b57068335318"></a>描述</strong></p>
</th>
</tr>
</thead>
<tbody><tr id="row8706123317311"><td class="cellrowborder" rowspan="2" valign="top" width="19.900000000000002%" headers="mcps1.1.4.1.1 "><p id="p4706193319318"><a name="p4706193319318"></a><a name="p4706193319318"></a>创建和删除中断</p>
</td>
<td class="cellrowborder" valign="top" width="18.43%" headers="mcps1.1.4.1.2 "><p id="p170683310317"><a name="p170683310317"></a><a name="p170683310317"></a>LOS_HwiCreate</p>
</td>
<td class="cellrowborder" valign="top" width="61.67%" headers="mcps1.1.4.1.3 "><p id="p15706833163110"><a name="p15706833163110"></a><a name="p15706833163110"></a>中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,会调用该中断处理程序</p>
</td>
</tr>
<tr id="row18706153318316"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p1870615332312"><a name="p1870615332312"></a><a name="p1870615332312"></a>LOS_HwiDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p770616333313"><a name="p770616333313"></a><a name="p770616333313"></a>删除中断</p>
</td>
</tr>
<tr id="row1370633316316"><td class="cellrowborder" rowspan="3" valign="top" width="19.900000000000002%" headers="mcps1.1.4.1.1 "><p id="p970611333318"><a name="p970611333318"></a><a name="p970611333318"></a>打开和关闭所有中断</p>
</td>
<td class="cellrowborder" valign="top" width="18.43%" headers="mcps1.1.4.1.2 "><p id="p147061033103117"><a name="p147061033103117"></a><a name="p147061033103117"></a>LOS_IntUnLock</p>
</td>
<td class="cellrowborder" valign="top" width="61.67%" headers="mcps1.1.4.1.3 "><p id="p167061333193114"><a name="p167061333193114"></a><a name="p167061333193114"></a>打开<span>当前处理器所有中断响应</span></p>
</td>
</tr>
<tr id="row1270603314312"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p1970623343114"><a name="p1970623343114"></a><a name="p1970623343114"></a>LOS_IntLock</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1370623373115"><a name="p1370623373115"></a><a name="p1370623373115"></a>关闭<span>当前处理器所有中断响应</span></p>
</td>
</tr>
<tr id="row8706233173113"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p1770620337313"><a name="p1770620337313"></a><a name="p1770620337313"></a>LOS_IntRestore</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1470643323112"><a name="p1470643323112"></a><a name="p1470643323112"></a>恢复到使用LOS_IntLock关闭所有中断之前的状态</p>
</td>
</tr>
<tr id="row870793320317"><td class="cellrowborder" valign="top" width="19.900000000000002%" headers="mcps1.1.4.1.1 "><p id="p1970763318316"><a name="p1970763318316"></a><a name="p1970763318316"></a>获取系统支持的最大中断数</p>
</td>
<td class="cellrowborder" valign="top" width="18.43%" headers="mcps1.1.4.1.2 "><p id="p1707333123115"><a name="p1707333123115"></a><a name="p1707333123115"></a>LOS_GetSystemHwiMaximum</p>
</td>
<td class="cellrowborder" valign="top" width="61.67%" headers="mcps1.1.4.1.3 "><p id="p4707173323111"><a name="p4707173323111"></a><a name="p4707173323111"></a>获取系统支持的最大中断数</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section64332181221"></a>
1. 调用中断创建接口LOS\_HwiCreate创建中断。
2. 调用LOS\_HwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。
### 编程实例<a name="section204698276478"></a>
本实例实现如下功能:
1. 创建中断。
2. 删除中断。
代码实现如下,演示如何创建中断和删除中断,当指定的中断号HWI\_NUM\_TEST产生中断时,会调用中断处理函数:
```
#include "los_hwi.h"
/*中断处理函数*/
STATIC VOID HwiUsrIrq(VOID)
{
printf("in the func HwiUsrIrq \n");
}
static UINT32 Example_Interrupt(VOID)
{
UINT32 ret;
HWI_HANDLE_T hwiNum = 7;
HWI_PRIOR_T hwiPrio = 3;
HWI_MODE_T mode = 0;
HWI_ARG_T arg = 0;
/*创建中断*/
ret = LOS_HwiCreate(hwiNum, hwiPrio, mode, (HWI_PROC_FUNC)HwiUsrIrq, (HwiIrqParam *)arg);
if(ret == LOS_OK){
printf("Hwi create success!\n");
} else {
printf("Hwi create failed!\n");
return LOS_NOK;
}
/* 延时50个Ticks, 当有硬件中断发生时,会调用函数HwiUsrIrq*/
LOS_TaskDelay(50);
/*删除中断*/
ret = LOS_HwiDelete(hwiNum, (HwiIrqParam *)arg);
if(ret == LOS_OK){
printf("Hwi delete success!\n");
} else {
printf("Hwi delete failed!\n");
return LOS_NOK;
}
return LOS_OK;
}
```
### 结果验证<a name="section1466144215476"></a>
编译运行得到的结果为:
```
Hwi create success!
Hwi delete success!
```
# 堆内存管理<a name="ZH-CN_TOPIC_0000001123795191"></a>
- [基本概念](#section449414395916)
- [运行机制](#section465085575911)
- [开发指导](#section577019272015)
- [使用场景](#section326917198583)
- [接口说明](#section1032331584)
- [开发流程](#section07271773592)
- [编程实例](#section84931234145913)
- [结果验证](#section165233233917)
## 基本概念<a name="section449414395916"></a>
内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。OpenHarmony LiteOS-A的堆内存管理提供内存初始化、分配、释放等功能。在系统运行过程中,堆内存管理模块通过对内存的申请/释放来管理用户和OS对内存的使用,使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。
## 运行机制<a name="section465085575911"></a>
堆内存管理,即在内存资源充足的情况下,根据用户需求,从系统配置的一块比较大的连续内存(内存池,也是堆内存)中分配任意大小的内存块。当用户不需要该内存块时,又可以释放回系统供下一次使用。与静态内存相比,动态内存管理的优点是按需分配,缺点是内存池中容易出现碎片。OpenHarmony LiteOS-A堆内存在TLSF算法的基础上,对区间的划分进行了优化,获得更优的性能,降低了碎片率。动态内存核心算法框图如下:
**图 1** 动态内存核心算法<a name="fig14558185217397"></a>
![](figure/动态内存核心算法-19.png "动态内存核心算法-19")
根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:\[4, 127\]\[2<sup>7</sup>, 2<sup>31</sup>\],如上图size class所示:
1.\[4,127\]区间的内存进行等分,如上图下半部分所示,分为31个小区间,每个小区间对应内存块大小为4字节的倍数。每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位,值为1时,空闲链表非空。\[4,127\]区间的31个小区间内存对应31个比特位进行标记链表是否为空。
2. 大于127字节的空闲内存块,按照2的次幂区间大小进行空闲链表管理。总共分为24个小区间,每个小区间又等分为8个二级小区间,见上图上半部分的Size Class和Size SubClass部分。每个二级小区间对应一个空闲链表和用于标记对应空闲内存链表是否为空的一个比特位。总共24\*8=192个二级小区间,对应192个空闲链表和192个比特位进行标记链表是否为空。
例如,当有40字节的空闲内存需要插入空闲链表时,对应小区间\[40,43\],第10个空闲链表,位图标记的第10比特位。把40字节的空闲内存挂载第10个空闲链表上,并判断是否需要更新位图标记。当需要申请40字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。当有580字节的空闲内存需要插入空闲链表时,对应二级小区间\[2^9,2^9+2^6\],第31+2\*8=47个空闲链表,并使用位图的第47个比特位来标记链表是否为空。把580字节的空闲内存挂载第47个空闲链表上,并判断是否需要更新位图标记。当需要申请580字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。如果对应的空闲链表为空,则向更大的内存区间去查询是否有满足条件的空闲链表,实际计算时,会一次性查找到满足申请大小的空闲链表。
内存管理结构如下图所示:
**图 2** 动态内存管理结构图<a name="fig5395115964114"></a>
![](figure/动态内存管理结构图-20.png "动态内存管理结构图-20")
- 内存池池头部分
内存池池头部分包含内存池信息、位图标记数组和空闲链表数组。内存池信息包含内存池起始地址及堆区域总大小,内存池属性。位图标记数组有7个32位无符号整数组成,每个比特位标记对应的空闲链表是否挂载空闲内存块节点。空闲内存链表包含223个空闲内存头节点信息,每个空闲内存头节点信息维护内存节点头和空闲链表中的前驱、后继空闲内存节点。
- 内存池节点部分
包含3种类型节点:未使用空闲内存节点,已使用内存节点和尾节点。每个内存节点维护一个前序指针,指向内存池中上一个内存节点,还维护内存节点的大小和使用标记。空闲内存节点和已使用内存节点后面的内存区域是数据域,尾节点没有数据域。
## 开发指导<a name="section577019272015"></a>
### 使用场景<a name="section326917198583"></a>
堆内存管理的主要工作是动态分配并管理用户申请到的内存区间,主要用于用户需要使用大小不等的内存块的场景,当用户需要使用内存时,可以通过操作系统的动态内存申请函数索取指定大小的内存块。一旦使用完毕,通过内存释放函数释放所占用内存,使之可以重复使用。
### 接口说明<a name="section1032331584"></a>
OpenHarmony LiteOS-A的堆内存管理主要为用户提供以下功能,接口详细信息可以查看API参考。
**表 1** 堆内存管理接口
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row0415737175610"><td class="cellrowborder" rowspan="2" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p6485848217"><a name="p6485848217"></a><a name="p6485848217"></a>初始化和删除内存池</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p1448511481314"><a name="p1448511481314"></a><a name="p1448511481314"></a>LOS_MemInit</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p94857483110"><a name="p94857483110"></a><a name="p94857483110"></a>初始化一块指定的动态内存池,大小为size</p>
</td>
</tr>
<tr id="row1841519376561"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20485134810119"><a name="p20485134810119"></a><a name="p20485134810119"></a>LOS_MemDeInit</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p154851348113"><a name="p154851348113"></a><a name="p154851348113"></a>删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效</p>
</td>
</tr>
<tr id="row1187514443616"><td class="cellrowborder" rowspan="4" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p19661710214"><a name="p19661710214"></a><a name="p19661710214"></a>申请、释放动态内存</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p66111714213"><a name="p66111714213"></a><a name="p66111714213"></a>LOS_MemAlloc</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p4661715214"><a name="p4661715214"></a><a name="p4661715214"></a>从指定动态内存池中申请size长度的内存</p>
</td>
</tr>
<tr id="row1745415527441"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p116111718218"><a name="p116111718218"></a><a name="p116111718218"></a>LOS_MemFree</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1569175218"><a name="p1569175218"></a><a name="p1569175218"></a>释放从指定动态内存中申请的内存</p>
</td>
</tr>
<tr id="row19101718144518"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p161417225"><a name="p161417225"></a><a name="p161417225"></a>LOS_MemRealloc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p56181718219"><a name="p56181718219"></a><a name="p56181718219"></a>按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块</p>
</td>
</tr>
<tr id="row1346314166464"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10610171528"><a name="p10610171528"></a><a name="p10610171528"></a>LOS_MemAllocAlign</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p26171714214"><a name="p26171714214"></a><a name="p26171714214"></a>从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存</p>
</td>
</tr>
<tr id="row28531740101112"><td class="cellrowborder" rowspan="4" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p39818810129"><a name="p39818810129"></a><a name="p39818810129"></a>获取内存池信息</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p16981986123"><a name="p16981986123"></a><a name="p16981986123"></a>LOS_MemPoolSizeGet</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p129820881212"><a name="p129820881212"></a><a name="p129820881212"></a>获取指定动态内存池的总大小</p>
</td>
</tr>
<tr id="row34281341171114"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0987831214"><a name="p0987831214"></a><a name="p0987831214"></a>LOS_MemTotalUsedGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1598889124"><a name="p1598889124"></a><a name="p1598889124"></a>获取指定动态内存池的总使用量大小</p>
</td>
</tr>
<tr id="row112644551119"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p398208201215"><a name="p398208201215"></a><a name="p398208201215"></a>LOS_MemInfoGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p139815820126"><a name="p139815820126"></a><a name="p139815820126"></a>获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小</p>
</td>
</tr>
<tr id="row1357684518110"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3981383125"><a name="p3981383125"></a><a name="p3981383125"></a>LOS_MemPoolList</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p998148101218"><a name="p998148101218"></a><a name="p998148101218"></a>打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效</p>
</td>
</tr>
<tr id="row14824879135"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p1058973361319"><a name="p1058973361319"></a><a name="p1058973361319"></a>获取内存块信息</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p989115206287"><a name="p989115206287"></a><a name="p989115206287"></a>LOS_MemFreeNodeShow</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p437618158141"><a name="p437618158141"></a><a name="p437618158141"></a>打印指定内存池的空闲内存块的大小及数量</p>
</td>
</tr>
<tr id="row0715201211155"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p13599202711513"><a name="p13599202711513"></a><a name="p13599202711513"></a>检查指定内存池的完整性</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p5784183891513"><a name="p5784183891513"></a><a name="p5784183891513"></a>LOS_MemIntegrityCheck</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p15644611153"><a name="p15644611153"></a><a name="p15644611153"></a>对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效</p>
</td>
</tr>
</tbody>
</table>
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 由于动态内存管理需要管理控制块数据结构来管理内存,这些数据结构会额外消耗内存,故实际用户可使用内存总量小于配置项OS\_SYS\_MEM\_SIZE的大小。
>- 对齐分配内存接口LOS\_MemAllocAlign/LOS\_MemMallocAlign因为要进行地址对齐,可能会额外消耗部分内存,故存在一些遗失内存,当系统释放该对齐内存时,同时回收由于对齐导致的遗失内存。
### 开发流程<a name="section07271773592"></a>
本节介绍使用动态内存的典型场景开发流程。
1. 初始化LOS\_MemInit。
初始一个内存池后生成一个内存池控制头、尾节点EndNode,剩余的内存被标记为FreeNode内存节点。注:EndNode作为内存池末尾的节点,size为0。
1. 申请任意大小的动态内存LOS\_MemAlloc。
判断动态内存池中是否存在大于申请量大小的空闲内存块空间,若存在,则划出一块内存块,以指针形式返回,若不存在,返回NULL。如果空闲内存块大于申请量,需要对内存块进行分割,剩余的部分作为空闲内存块挂载到空闲内存链表上。
1. 释放动态内存LOS\_MemFree。
回收内存块,供下一次使用。调用LOS\_MemFree释放内存块,则会回收内存块,并且将其标记为FreeNode。在回收内存块时,相邻的FreeNode会自动合并。
### 编程实例<a name="section84931234145913"></a>
本实例执行以下步骤:
1. 初始化一个动态内存池。
2. 从动态内存池中申请一个内存块。
3. 在内存块中存放一个数据。
4. 打印出内存块中的数据。
5. 释放该内存块。
示例代码如下:
```
#include "los_memory.h"
#define TEST_POOL_SIZE (2*1024*1024)
__attribute__((aligned(4))) UINT8 g_testPool[TEST_POOL_SIZE];
VOID Example_DynMem(VOID)
{
UINT32 *mem = NULL;
UINT32 ret;
/*初始化内存池*/
ret = LOS_MemInit(g_testPool, TEST_POOL_SIZE);
if (LOS_OK == ret) {
printf("Mem init success!\n");
} else {
printf("Mem init failed!\n");
return;
}
/*分配内存*/
mem = (UINT32 *)LOS_MemAlloc(g_testPool, 4);
if (NULL == mem) {
printf("Mem alloc failed!\n");
return;
}
printf("Mem alloc success!\n");
/*赋值*/
*mem = 828;
printf("*mem = %d\n", *mem);
/*释放内存*/
ret = LOS_MemFree(g_testPool, mem);
if (LOS_OK == ret) {
printf("Mem free success!\n");
} else {
printf("Mem free failed!\n");
}
return;
}
UINT32 ExampleDynMemEntry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S initParam = {0};
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_DynMem;
initParam.usTaskPrio = 10;
initParam.pcName = "Example_DynMem";
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
initParam.uwResved = LOS_TASK_STATUS_DETACHED;
/* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */
ret = LOS_TaskCreate(&g_taskHiID, &initParam);
if (ret != LOS_OK) {
LOS_TaskUnlock();
PRINTK("Example_DynMem create Failed! ret=%d\n", ret);
return LOS_NOK;
}
PRINTK("Example_DynMem create Success!\n");
while(1){};
return LOS_OK;
}
```
### 结果验证<a name="section165233233917"></a>
输出结果如下:
```
Mem init success!
Mem alloc success!
*mem = 828
Mem free success!
```
# 物理内存管理<a name="ZH-CN_TOPIC_0000001078575732"></a>
- [基本概念](#section210891719217)
- [运行机制](#section111355315213)
- [开发指导](#section393116496217)
- [接口说明](#section13210155619214)
- [开发流程](#section178441091231)
- [编程实例](#section1258174015319)
- [结果验证](#section515091342819)
## 基本概念<a name="section210891719217"></a>
物理内存是计算机上最重要的资源之一,指的是实际的内存设备提供的、可以通过CPU总线直接进行寻址的内存空间,其主要作用是为操作系统及程序提供临时存储空间。LiteOS-A内核管理物理内存是通过分页实现的,除了内核堆占用的一部分内存外,其余可用内存均以4k为单位划分成页帧,内存分配和内存回收便是以页帧为单位进行操作。内核采用伙伴算法管理空闲页面,可以降低一定的内存碎片率,提高内存分配和释放的效率,但是一个很小的块往往也会阻塞一个大块的合并,导致不能分配较大的内存块。
## 运行机制<a name="section111355315213"></a>
如下图所示,LiteOS-A内核的物理内存使用分布视图,主要由内核镜像、内核堆及物理页组成。内核堆部分见堆内存管理一节。
**图 1** 物理内存使用分布图<a name="fig3648124205514"></a>
![](figure/物理内存使用分布图.png "物理内存使用分布图")
伙伴算法把所有空闲页帧分成9个内存块组,每组中内存块包含2的幂次方个页帧,例如:第0组的内存块包含2的0次方个页帧,即1个页帧;第8组的内存块包含2的8次方个页帧,即256个页帧。相同大小的内存块挂在同一个链表上进行管理。
- 申请内存
系统申请12k内存,即3个页帧时,9个内存块组中索引为3的链表挂着一块大小为8个页帧的内存块满足要求,分配出12k内存后还剩余20k内存,即5个页帧,将5个页帧分成2的幂次方之和,即4跟1,尝试查找伙伴进行合并。4个页帧的内存块没有伙伴则直接插到索引为2的链表上,继续查找1个页帧的内存块是否有伙伴,索引为0的链表上此时有1个,如果两个内存块地址连续则进行合并,并将内存块挂到索引为1的链表上,否则不做处理。
**图 2** 内存申请示意图<a name="fig1319620135615"></a>
![](figure/内存申请示意图.png "内存申请示意图")
- 释放内存
系统释放12k内存,即3个页帧,将3个页帧分成2的幂次方之和,即2跟1,尝试查找伙伴进行合并,索引为1的链表上有1个内存块,若地址连续则合并,并将合并后的内存块挂到索引为2的链表上,索引为0的链表上此时也有1个,如果地址连续则进行合并,并将合并后的内存块挂到索引为1的链表上,此时继续判断是否有伙伴,重复上述操作。
**图 3** 内存释放示意图<a name="fig44001027165614"></a>
![](figure/内存释放示意图.png "内存释放示意图")
## 开发指导<a name="section393116496217"></a>
### 接口说明<a name="section13210155619214"></a>
**表 1** 物理内存管理模块接口
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.821282128212822%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.832983298329836%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row11567448194112"><td class="cellrowborder" rowspan="3" valign="top" width="12.821282128212822%" headers="mcps1.2.4.1.1 "><p id="p1377313451287"><a name="p1377313451287"></a><a name="p1377313451287"></a>申请物理内存</p>
</td>
<td class="cellrowborder" valign="top" width="29.832983298329836%" headers="mcps1.2.4.1.2 "><p id="p69501257634"><a name="p69501257634"></a><a name="p69501257634"></a>LOS_PhysPageAlloc</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p17950155714310"><a name="p17950155714310"></a><a name="p17950155714310"></a>申请一个物理页</p>
</td>
</tr>
<tr id="row1877155711548"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p687795718546"><a name="p687795718546"></a><a name="p687795718546"></a>LOS_PhysPagesAlloc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p11877957115413"><a name="p11877957115413"></a><a name="p11877957115413"></a>申请物理页并挂在对应的链表上</p>
</td>
</tr>
<tr id="row1141513373562"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1525917111411"><a name="p1525917111411"></a><a name="p1525917111411"></a>LOS_PhysPagesAllocContiguous</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p72594111245"><a name="p72594111245"></a><a name="p72594111245"></a>申请多页地址连续的物理内存</p>
</td>
</tr>
<tr id="row11129518231"><td class="cellrowborder" rowspan="3" valign="top" width="12.821282128212822%" headers="mcps1.2.4.1.1 "><p id="p329691015710"><a name="p329691015710"></a><a name="p329691015710"></a>释放物理内存</p>
</td>
<td class="cellrowborder" valign="top" width="29.832983298329836%" headers="mcps1.2.4.1.2 "><p id="p836211258313"><a name="p836211258313"></a><a name="p836211258313"></a>LOS_PhysPageFree</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p183626251933"><a name="p183626251933"></a><a name="p183626251933"></a>释放一个物理页</p>
</td>
</tr>
<tr id="row171671014107"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p368411237415"><a name="p368411237415"></a><a name="p368411237415"></a>LOS_PhysPagesFree</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p12684112320411"><a name="p12684112320411"></a><a name="p12684112320411"></a>释放挂在链表上的物理页</p>
</td>
</tr>
<tr id="row13796135518114"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p379616558114"><a name="p379616558114"></a><a name="p379616558114"></a>LOS_PhysPagesFreeContiguous</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1879675510114"><a name="p1879675510114"></a><a name="p1879675510114"></a>释放多页地址连续的物理内存</p>
</td>
</tr>
<tr id="row757517464414"><td class="cellrowborder" rowspan="2" valign="top" width="12.821282128212822%" headers="mcps1.2.4.1.1 "><p id="p128501418185714"><a name="p128501418185714"></a><a name="p128501418185714"></a>查询地址</p>
</td>
<td class="cellrowborder" valign="top" width="29.832983298329836%" headers="mcps1.2.4.1.2 "><p id="p147379529411"><a name="p147379529411"></a><a name="p147379529411"></a>LOS_VmPageGet</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p1573711521144"><a name="p1573711521144"></a><a name="p1573711521144"></a>根据物理地址获取其对应的物理页结构体指针</p>
</td>
</tr>
<tr id="row20508104412412"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1124573417"><a name="p1124573417"></a><a name="p1124573417"></a>LOS_PaddrToKVaddr</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p71217579414"><a name="p71217579414"></a><a name="p71217579414"></a>根据物理地址获取其对应的内核虚拟地址</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section178441091231"></a>
内存申请时根据需要调用相关接口,小内存申请建议使用堆内存申请相关接口,4k及以上内存申请可以使用上述物理内存相关接口。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 物理内存申请相关接口需要在OsSysMemInit接口完成初始化之后再使用;
>- 内存申请的基本单位是页帧,即4k;
>- 物理内存申请时,有地址连续要求的使用LOS\_PhysPagesAllocContiguous接口,无地址连续的要求尽量使用LOS\_PhysPagesAlloc接口,将连续的大块内存留给有需要的模块使用。
### 编程实例<a name="section1258174015319"></a>
编程示例主要是调用申请、释放接口对内存进行操作,包括申请一个页以及多个页的示例。
```
#include "los_vm_phys.h"
#define PHYS_PAGE_SIZE 0x4000
// 申请一个页
VOID OsPhysPagesAllocTest3(VOID)
{
PADDR_T newPaddr;
VOID *kvaddr = NULL;
LosVmPage *newPage = NULL;
newPage = LOS_PhysPageAlloc();
if (newPage == NULL) {
printf("LOS_PhysPageAlloc fail\n");
return;
}
printf("LOS_PhysPageAlloc success\n");
newPaddr = VM_PAGE_TO_PHYS(newPage);
kvaddr = OsVmPageToVaddr(newPage);
// Handle the physical memory
// Free the physical memory
LOS_PhysPageFree(newPage);
}
// 申请多个页,不要求连续
VOID OsPhysPagesAllocTest2(VOID)
{
UINT32 sizeCount;
UINT32 count;
UINT32 size = PHYS_PAGE_SIZE;
LosVmPage *vmPageArray[PHYS_PAGE_SIZE >> PAGE_SHIFT] = { NULL };
UINT32 i = 0;
LosVmPage *vmPage = NULL;
PADDR_T pa;
size = LOS_Align(size, PAGE_SIZE);
if (size == 0) {
return;
}
sizeCount = size >> PAGE_SHIFT;
LOS_DL_LIST_HEAD(pageList);
count = LOS_PhysPagesAlloc(sizeCount, &pageList);
if (count < sizeCount) {
printf("failed to allocate enough pages (ask %zu, got %zu)\n", sizeCount, count);
goto ERROR;
}
printf("LOS_PhysPagesAlloc success\n");
while ((vmPage = LOS_ListRemoveHeadType(&pageList, LosVmPage, node))) {
pa = vmPage->physAddr;
vmPageArray[i++] = vmPage;
// Handle the physical memory
}
// Free the physical memory
for (i = 0; i < sizeCount; ++i) {
LOS_PhysPageFree(vmPageArray[i]);
}
return;
ERROR:
(VOID)LOS_PhysPagesFree(&pageList);
}
// 申请多个连续页
VOID OsPhysPagesAllocTest1(VOID)
{
VOID *ptr = NULL;
LosVmPage *page = NULL;
UINT32 size = PHYS_PAGE_SIZE;
ptr = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT);
if (ptr == NULL) {
printf("LOS_PhysPagesAllocContiguous fail\n");
return;
}
printf("LOS_PhysPagesAllocContiguous success\n");
// Handle the physical memory
// Free the physical memory
page = OsVmVaddrToPage((VOID *)ptr);
LOS_PhysPagesFreeContiguous((VOID *)ptr, size >> PAGE_SHIFT);
}
UINT32 ExamplePhyMemCaseEntry(VOID)
{
OsPhysPagesAllocTest1();
OsPhysPagesAllocTest2();
OsPhysPagesAllocTest3();
return LOS_OK;
}
```
### 结果验证<a name="section515091342819"></a>
编译运行得到的结果为:
```
LOS_PhysPagesAllocContiguous success
LOS_PhysPagesAlloc success
LOS_PhysPageAlloc success
```
# 虚拟内存管理<a name="ZH-CN_TOPIC_0000001123800847"></a>
- [基本概念](#section650193717411)
- [运行机制](#section072885512412)
- [开发指导](#section20956116050)
- [接口说明](#section166137221657)
- [开发流程](#section8752103914513)
## 基本概念<a name="section650193717411"></a>
虚拟内存管理是计算机系统管理内存的一种技术。每个进程都有连续的虚拟地址空间,虚拟地址空间的大小由CPU的位数决定,32位的硬件平台可以提供的最大的寻址空间为0-4G。整个4G空间分成两部分,LiteOS-A内核占据3G的高地址空间,1G的低地址空间留给进程使用。各个进程空间的虚拟地址空间是独立的,代码、数据互不影响。
系统将虚拟内存分割为称为虚拟页的内存块,大小一般为4k或64k,LiteOS-A内核默认的页的大小是4k,根据需要可以对MMU(Memory Management Units)进行配置。虚拟内存管理操作的最小单位就是一个页,LiteOS-A内核中一个虚拟地址区间region包含地址连续的多个虚拟页,也可只有一个页。同样,物理内存也会按照页大小进行分割,分割后的每个内存块称为页帧。虚拟地址空间划分:内核态占高地址3G\(0x40000000 \~ 0xFFFFFFFF\),用户态占低地址1G\(0x01000000 \~ 0x3F000000\),具体见下表,详细可以查看或配置los\_vm\_zone.h。
**表 1** 内核态地址规划:
<a name="table9988174163613"></a>
<table><thead align="left"><tr id="row164675173616"><th class="cellrowborder" valign="top" width="11.761176117611761%" id="mcps1.2.6.1.1"><p id="p046752361"><a name="p046752361"></a><a name="p046752361"></a>Zone名称</p>
</th>
<th class="cellrowborder" valign="top" width="22.792279227922794%" id="mcps1.2.6.1.2"><p id="p746165113619"><a name="p746165113619"></a><a name="p746165113619"></a>起始地址</p>
</th>
<th class="cellrowborder" valign="top" width="18.381838183818385%" id="mcps1.2.6.1.3"><p id="p6461957362"><a name="p6461957362"></a><a name="p6461957362"></a>结束地址</p>
</th>
<th class="cellrowborder" valign="top" width="25.372537253725376%" id="mcps1.2.6.1.4"><p id="p0461651361"><a name="p0461651361"></a><a name="p0461651361"></a>用途</p>
</th>
<th class="cellrowborder" valign="top" width="21.692169216921695%" id="mcps1.2.6.1.5"><p id="p446195183611"><a name="p446195183611"></a><a name="p446195183611"></a>属性</p>
</th>
</tr>
</thead>
<tbody><tr id="row94619516367"><td class="cellrowborder" valign="top" width="11.761176117611761%" headers="mcps1.2.6.1.1 "><p id="p1846553363"><a name="p1846553363"></a><a name="p1846553363"></a>DMA zone</p>
</td>
<td class="cellrowborder" valign="top" width="22.792279227922794%" headers="mcps1.2.6.1.2 "><p id="p2463543619"><a name="p2463543619"></a><a name="p2463543619"></a>0x40000000</p>
</td>
<td class="cellrowborder" valign="top" width="18.381838183818385%" headers="mcps1.2.6.1.3 "><p id="p13461954361"><a name="p13461954361"></a><a name="p13461954361"></a>0x43FFFFFF</p>
</td>
<td class="cellrowborder" valign="top" width="25.372537253725376%" headers="mcps1.2.6.1.4 "><p id="p3461158364"><a name="p3461158364"></a><a name="p3461158364"></a>USB、网络等dma内存访问</p>
</td>
<td class="cellrowborder" valign="top" width="21.692169216921695%" headers="mcps1.2.6.1.5 "><p id="p10461152363"><a name="p10461152363"></a><a name="p10461152363"></a>Uncache</p>
</td>
</tr>
<tr id="row246551361"><td class="cellrowborder" valign="top" width="11.761176117611761%" headers="mcps1.2.6.1.1 "><p id="p3461259362"><a name="p3461259362"></a><a name="p3461259362"></a>Normal zone</p>
</td>
<td class="cellrowborder" valign="top" width="22.792279227922794%" headers="mcps1.2.6.1.2 "><p id="p746059367"><a name="p746059367"></a><a name="p746059367"></a>0x80000000</p>
</td>
<td class="cellrowborder" valign="top" width="18.381838183818385%" headers="mcps1.2.6.1.3 "><p id="p74615519368"><a name="p74615519368"></a><a name="p74615519368"></a>0x83FFFFFF</p>
</td>
<td class="cellrowborder" valign="top" width="25.372537253725376%" headers="mcps1.2.6.1.4 "><p id="p1546056362"><a name="p1546056362"></a><a name="p1546056362"></a>内核代码、数据段和堆内存和栈</p>
</td>
<td class="cellrowborder" valign="top" width="21.692169216921695%" headers="mcps1.2.6.1.5 "><p id="p646125143613"><a name="p646125143613"></a><a name="p646125143613"></a>Cache</p>
</td>
</tr>
<tr id="row646165133613"><td class="cellrowborder" valign="top" width="11.761176117611761%" headers="mcps1.2.6.1.1 "><p id="p114675183615"><a name="p114675183615"></a><a name="p114675183615"></a>high mem zone</p>
</td>
<td class="cellrowborder" valign="top" width="22.792279227922794%" headers="mcps1.2.6.1.2 "><p id="p13462058362"><a name="p13462058362"></a><a name="p13462058362"></a>0x84000000</p>
</td>
<td class="cellrowborder" valign="top" width="18.381838183818385%" headers="mcps1.2.6.1.3 "><p id="p64655183614"><a name="p64655183614"></a><a name="p64655183614"></a>0x8BFFFFFF</p>
</td>
<td class="cellrowborder" valign="top" width="25.372537253725376%" headers="mcps1.2.6.1.4 "><p id="p194611583613"><a name="p194611583613"></a><a name="p194611583613"></a>连续虚拟内存分配,物理内存不连续</p>
</td>
<td class="cellrowborder" valign="top" width="21.692169216921695%" headers="mcps1.2.6.1.5 "><p id="p8461153369"><a name="p8461153369"></a><a name="p8461153369"></a>Cache</p>
</td>
</tr>
</tbody>
</table>
**表 2** 用户态虚地址规划:
<a name="table19965411366"></a>
<table><thead align="left"><tr id="row646185183618"><th class="cellrowborder" valign="top" width="11.721172117211722%" id="mcps1.2.6.1.1"><p id="p3466593612"><a name="p3466593612"></a><a name="p3466593612"></a>Zone名称</p>
</th>
<th class="cellrowborder" valign="top" width="22.712271227122713%" id="mcps1.2.6.1.2"><p id="p164605153615"><a name="p164605153615"></a><a name="p164605153615"></a>起始地址</p>
</th>
<th class="cellrowborder" valign="top" width="18.681868186818683%" id="mcps1.2.6.1.3"><p id="p4464512361"><a name="p4464512361"></a><a name="p4464512361"></a>结束地址</p>
</th>
<th class="cellrowborder" valign="top" width="25.27252725272527%" id="mcps1.2.6.1.4"><p id="p84645143613"><a name="p84645143613"></a><a name="p84645143613"></a>用途</p>
</th>
<th class="cellrowborder" valign="top" width="21.61216121612161%" id="mcps1.2.6.1.5"><p id="p1146115203615"><a name="p1146115203615"></a><a name="p1146115203615"></a>属性</p>
</th>
</tr>
</thead>
<tbody><tr id="row7462511363"><td class="cellrowborder" valign="top" width="11.721172117211722%" headers="mcps1.2.6.1.1 "><p id="p2467516363"><a name="p2467516363"></a><a name="p2467516363"></a>代码段</p>
</td>
<td class="cellrowborder" valign="top" width="22.712271227122713%" headers="mcps1.2.6.1.2 "><p id="p747135163620"><a name="p747135163620"></a><a name="p747135163620"></a>0x0200000</p>
</td>
<td class="cellrowborder" valign="top" width="18.681868186818683%" headers="mcps1.2.6.1.3 "><p id="p647651366"><a name="p647651366"></a><a name="p647651366"></a>0x09FFFFFF</p>
</td>
<td class="cellrowborder" valign="top" width="25.27252725272527%" headers="mcps1.2.6.1.4 "><p id="p7472523618"><a name="p7472523618"></a><a name="p7472523618"></a>用户态代码段地址空间</p>
</td>
<td class="cellrowborder" valign="top" width="21.61216121612161%" headers="mcps1.2.6.1.5 "><p id="p14476563611"><a name="p14476563611"></a><a name="p14476563611"></a>Cache</p>
</td>
</tr>
<tr id="row34755153614"><td class="cellrowborder" valign="top" width="11.721172117211722%" headers="mcps1.2.6.1.1 "><p id="p194735173612"><a name="p194735173612"></a><a name="p194735173612"></a></p>
</td>
<td class="cellrowborder" valign="top" width="22.712271227122713%" headers="mcps1.2.6.1.2 "><p id="p7474533616"><a name="p7474533616"></a><a name="p7474533616"></a>0x0FC00000(起始地址随机)</p>
</td>
<td class="cellrowborder" valign="top" width="18.681868186818683%" headers="mcps1.2.6.1.3 "><p id="p194717573615"><a name="p194717573615"></a><a name="p194717573615"></a>0x17BFFFFF</p>
</td>
<td class="cellrowborder" valign="top" width="25.27252725272527%" headers="mcps1.2.6.1.4 "><p id="p114720518362"><a name="p114720518362"></a><a name="p114720518362"></a>用户态堆地址空间</p>
</td>
<td class="cellrowborder" valign="top" width="21.61216121612161%" headers="mcps1.2.6.1.5 "><p id="p9474515364"><a name="p9474515364"></a><a name="p9474515364"></a>Cache</p>
</td>
</tr>
<tr id="row9476518368"><td class="cellrowborder" valign="top" width="11.721172117211722%" headers="mcps1.2.6.1.1 "><p id="p34714516369"><a name="p34714516369"></a><a name="p34714516369"></a></p>
</td>
<td class="cellrowborder" valign="top" width="22.712271227122713%" headers="mcps1.2.6.1.2 "><p id="p134785173617"><a name="p134785173617"></a><a name="p134785173617"></a>0x37000000</p>
</td>
<td class="cellrowborder" valign="top" width="18.681868186818683%" headers="mcps1.2.6.1.3 "><p id="p20474510368"><a name="p20474510368"></a><a name="p20474510368"></a>0x3EFFFFFF(起始地址随机)</p>
</td>
<td class="cellrowborder" valign="top" width="25.27252725272527%" headers="mcps1.2.6.1.4 "><p id="p74705163612"><a name="p74705163612"></a><a name="p74705163612"></a>用户态栈空间地址</p>
</td>
<td class="cellrowborder" valign="top" width="21.61216121612161%" headers="mcps1.2.6.1.5 "><p id="p144775143613"><a name="p144775143613"></a><a name="p144775143613"></a>Cache</p>
</td>
</tr>
<tr id="row1047353364"><td class="cellrowborder" valign="top" width="11.721172117211722%" headers="mcps1.2.6.1.1 "><p id="p1947145163615"><a name="p1947145163615"></a><a name="p1947145163615"></a>共享库</p>
</td>
<td class="cellrowborder" valign="top" width="22.712271227122713%" headers="mcps1.2.6.1.2 "><p id="p147053364"><a name="p147053364"></a><a name="p147053364"></a>0x1F800000(起始地址随机)</p>
</td>
<td class="cellrowborder" valign="top" width="18.681868186818683%" headers="mcps1.2.6.1.3 "><p id="p2476517362"><a name="p2476517362"></a><a name="p2476517362"></a>0x277FFFFF</p>
</td>
<td class="cellrowborder" valign="top" width="25.27252725272527%" headers="mcps1.2.6.1.4 "><p id="p24745193617"><a name="p24745193617"></a><a name="p24745193617"></a>用户态共享库加载地址空间,包括mmap</p>
</td>
<td class="cellrowborder" valign="top" width="21.61216121612161%" headers="mcps1.2.6.1.5 "><p id="p11472510363"><a name="p11472510363"></a><a name="p11472510363"></a>Cache</p>
</td>
</tr>
</tbody>
</table>
## 运行机制<a name="section072885512412"></a>
虚拟内存管理中,虚拟地址空间是连续的,但是其映射的物理内存并不一定是连续的,如下图所示。可执行程序加载运行,CPU访问虚拟地址空间的代码或数据时存在两种情况:
- CPU访问的虚拟地址所在的页,如V0,已经与具体的物理页P0做映射,CPU通过找到进程对应的页表条目(详见虚实映射一节),根据页表条目中的物理地址信息访问物理内存中的内容并返回。
- CPU访问的虚拟地址所在的页,如V2,没有与具体的物理页做映射,系统会触发缺页异常,系统申请一个物理页,并把相应的信息拷贝到物理页中,并且把物理页的起始地址更新到页表条目中。此时CPU重新执行访问虚拟内存的指令便能够访问到具体的代码或数据。
**图 1** 内存映射示意图<a name="fig144371159135620"></a>
![](figure/内存映射示意图.png "内存映射示意图")
## 开发指导<a name="section20956116050"></a>
### 接口说明<a name="section166137221657"></a>
**表 3** 虚拟内存管理模块接口
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.811281128112812%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.84298429842984%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row0415737175610"><td class="cellrowborder" rowspan="5" valign="top" width="12.811281128112812%" headers="mcps1.2.4.1.1 "><p id="p4917132105710"><a name="p4917132105710"></a><a name="p4917132105710"></a>获取进程空间系列接口</p>
</td>
<td class="cellrowborder" valign="top" width="29.84298429842984%" headers="mcps1.2.4.1.2 "><p id="p341513372561"><a name="p341513372561"></a><a name="p341513372561"></a>LOS_CurrSpaceGet</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p74151037185617"><a name="p74151037185617"></a><a name="p74151037185617"></a>获取当前进程空间结构体指针</p>
</td>
</tr>
<tr id="row1841519376561"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p64151837155618"><a name="p64151837155618"></a><a name="p64151837155618"></a>LOS_SpaceGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p441516379562"><a name="p441516379562"></a><a name="p441516379562"></a>获取虚拟地址对应的进程空间结构体指针</p>
</td>
</tr>
<tr id="row536885134010"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p236819594010"><a name="p236819594010"></a><a name="p236819594010"></a>LOS_GetKVmSpace</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p736918564019"><a name="p736918564019"></a><a name="p736918564019"></a>获取内核进程空间结构体指针</p>
</td>
</tr>
<tr id="row11567448194112"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0568204814115"><a name="p0568204814115"></a><a name="p0568204814115"></a>LOS_GetVmallocSpace</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p05681348204114"><a name="p05681348204114"></a><a name="p05681348204114"></a>获取vmalloc空间结构体指针</p>
</td>
</tr>
<tr id="row1141513373562"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17765212416"><a name="p17765212416"></a><a name="p17765212416"></a>LOS_GetVmSpaceList</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1972971913115"><a name="p1972971913115"></a><a name="p1972971913115"></a>获取进程空间链表指针</p>
</td>
</tr>
<tr id="row137812054195014"><td class="cellrowborder" rowspan="15" valign="top" width="12.811281128112812%" headers="mcps1.2.4.1.1 "><p id="p15344719152113"><a name="p15344719152113"></a><a name="p15344719152113"></a>虚拟地址区间region相关的操作</p>
</td>
<td class="cellrowborder" valign="top" width="29.84298429842984%" headers="mcps1.2.4.1.2 "><p id="p97821654195014"><a name="p97821654195014"></a><a name="p97821654195014"></a>LOS_RegionFind</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p137821854205011"><a name="p137821854205011"></a><a name="p137821854205011"></a>根据起始地址在进程空间内查找是否存在虚拟地址区间</p>
</td>
</tr>
<tr id="row254713575505"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p954785720501"><a name="p954785720501"></a><a name="p954785720501"></a>LOS_RegionRangeFind</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p20547557175013"><a name="p20547557175013"></a><a name="p20547557175013"></a>根据地址区间在进程空间内查找是否存在虚拟地址区间</p>
</td>
</tr>
<tr id="row1692045119"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1510110115114"><a name="p1510110115114"></a><a name="p1510110115114"></a>LOS_IsRegionFileValid</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p61011045112"><a name="p61011045112"></a><a name="p61011045112"></a>判断虚拟地址区间region是否与文件关联映射</p>
</td>
</tr>
<tr id="row186701424548"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1967018210546"><a name="p1967018210546"></a><a name="p1967018210546"></a>LOS_RegionAlloc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p196701221548"><a name="p196701221548"></a><a name="p196701221548"></a>申请空闲的虚拟地址区间</p>
</td>
</tr>
<tr id="row1955586175412"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p555626195420"><a name="p555626195420"></a><a name="p555626195420"></a>LOS_RegionFree</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p85568612547"><a name="p85568612547"></a><a name="p85568612547"></a>释放进程空间内特定的region</p>
</td>
</tr>
<tr id="row259111510282"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3591135110288"><a name="p3591135110288"></a><a name="p3591135110288"></a>LOS_RegionEndAddr</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p4675183817474"><a name="p4675183817474"></a><a name="p4675183817474"></a>获取指定地址区间region的结束地址</p>
</td>
</tr>
<tr id="row12894115716285"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p889418577280"><a name="p889418577280"></a><a name="p889418577280"></a>LOS_RegionSize</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p68941757112813"><a name="p68941757112813"></a><a name="p68941757112813"></a>获取region的大小</p>
</td>
</tr>
<tr id="row14931456182812"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1293135611287"><a name="p1293135611287"></a><a name="p1293135611287"></a>LOS_IsRegionTypeFile</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1393185613288"><a name="p1393185613288"></a><a name="p1393185613288"></a>判断是否为文件内存映射</p>
</td>
</tr>
<tr id="row12153854132814"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p115335452819"><a name="p115335452819"></a><a name="p115335452819"></a>LOS_IsRegionPermUserReadOnly</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1415314545285"><a name="p1415314545285"></a><a name="p1415314545285"></a>判断地址区间是否是用户空间只读属性</p>
</td>
</tr>
<tr id="row29249497282"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1492415495284"><a name="p1492415495284"></a><a name="p1492415495284"></a>LOS_IsRegionFlagPrivateOnly</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1392434982817"><a name="p1392434982817"></a><a name="p1392434982817"></a>判断地址区间是否是具有私有属性</p>
</td>
</tr>
<tr id="row1233194042814"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3339401289"><a name="p3339401289"></a><a name="p3339401289"></a>LOS_SetRegionTypeFile</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p193317409285"><a name="p193317409285"></a><a name="p193317409285"></a>设置文件内存映射属性</p>
</td>
</tr>
<tr id="row178971473283"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p4898184782815"><a name="p4898184782815"></a><a name="p4898184782815"></a>LOS_IsRegionTypeDev</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p11898144722818"><a name="p11898144722818"></a><a name="p11898144722818"></a>判断是否为设备内存映射</p>
</td>
</tr>
<tr id="row11137546152811"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20137194672812"><a name="p20137194672812"></a><a name="p20137194672812"></a>LOS_SetRegionTypeDev</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p81384462287"><a name="p81384462287"></a><a name="p81384462287"></a>设置设备内存映射属性</p>
</td>
</tr>
<tr id="row1023564216285"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p92351842162819"><a name="p92351842162819"></a><a name="p92351842162819"></a>LOS_IsRegionTypeAnon</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p6235842132818"><a name="p6235842132818"></a><a name="p6235842132818"></a>判断是否为匿名映射</p>
</td>
</tr>
<tr id="row1646364402813"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p44631644152814"><a name="p44631644152814"></a><a name="p44631644152814"></a>LOS_SetRegionTypeAnon</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p174631844182818"><a name="p174631844182818"></a><a name="p174631844182818"></a>设置匿名映射属性</p>
</td>
</tr>
<tr id="row038233717288"><td class="cellrowborder" rowspan="5" valign="top" width="12.811281128112812%" headers="mcps1.2.4.1.1 "><p id="p6820331185317"><a name="p6820331185317"></a><a name="p6820331185317"></a>地址校验</p>
</td>
<td class="cellrowborder" valign="top" width="29.84298429842984%" headers="mcps1.2.4.1.2 "><p id="p838383720282"><a name="p838383720282"></a><a name="p838383720282"></a>LOS_IsUserAddress</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p12383837102818"><a name="p12383837102818"></a><a name="p12383837102818"></a>判断地址是否在用户态空间</p>
</td>
</tr>
<tr id="row61506354284"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2151113517288"><a name="p2151113517288"></a><a name="p2151113517288"></a>LOS_IsUserAddressRange</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p615123552814"><a name="p615123552814"></a><a name="p615123552814"></a>判断地址区间是否在用户态空间</p>
</td>
</tr>
<tr id="row18301515194210"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p19301141519421"><a name="p19301141519421"></a><a name="p19301141519421"></a>LOS_IsKernelAddress</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p730110154427"><a name="p730110154427"></a><a name="p730110154427"></a>判断地址是否在内核空间</p>
</td>
</tr>
<tr id="row191211718204213"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1112121812423"><a name="p1112121812423"></a><a name="p1112121812423"></a>LOS_IsKernelAddressRange</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p6122101814219"><a name="p6122101814219"></a><a name="p6122101814219"></a>判断地址区间是否在内核空间</p>
</td>
</tr>
<tr id="row774964092115"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17152102415416"><a name="p17152102415416"></a><a name="p17152102415416"></a>LOS_IsRangeInSpace</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p115218248547"><a name="p115218248547"></a><a name="p115218248547"></a>判断地址区间是否在进程空间内</p>
</td>
</tr>
<tr id="row179196525521"><td class="cellrowborder" rowspan="3" valign="top" width="12.811281128112812%" headers="mcps1.2.4.1.1 "><p id="p153501191535"><a name="p153501191535"></a><a name="p153501191535"></a>vmalloc操作</p>
</td>
<td class="cellrowborder" valign="top" width="29.84298429842984%" headers="mcps1.2.4.1.2 "><p id="p152945155531"><a name="p152945155531"></a><a name="p152945155531"></a>LOS_VMalloc</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p1229461512535"><a name="p1229461512535"></a><a name="p1229461512535"></a>vmalloc申请内存</p>
</td>
</tr>
<tr id="row1934135935211"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p162941115155315"><a name="p162941115155315"></a><a name="p162941115155315"></a>LOS_VFree</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p12294171516536"><a name="p12294171516536"></a><a name="p12294171516536"></a>vmalloc释放内存</p>
</td>
</tr>
<tr id="row944214919304"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p644229163016"><a name="p644229163016"></a><a name="p644229163016"></a>LOS_IsVmallocAddress</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1344220993011"><a name="p1344220993011"></a><a name="p1344220993011"></a>判断地址是否是通过vmalloc申请的</p>
</td>
</tr>
<tr id="row72131845145315"><td class="cellrowborder" rowspan="4" valign="top" width="12.811281128112812%" headers="mcps1.2.4.1.1 "><p id="p84847816543"><a name="p84847816543"></a><a name="p84847816543"></a>内存申请系列接口</p>
</td>
<td class="cellrowborder" valign="top" width="29.84298429842984%" headers="mcps1.2.4.1.2 "><p id="p8787345546"><a name="p8787345546"></a><a name="p8787345546"></a>LOS_KernelMalloc</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p17787444543"><a name="p17787444543"></a><a name="p17787444543"></a>申请小于16k的内存则通过堆内存池获取,否则申请多个连续物理页</p>
</td>
</tr>
<tr id="row48491549145311"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14787149541"><a name="p14787149541"></a><a name="p14787149541"></a>LOS_KernelMallocAlign</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p478719411543"><a name="p478719411543"></a><a name="p478719411543"></a>申请具有对齐属性的内存,申请规则:申请小于16k的内存则通过堆内存池获取,否则申请多个连续物理页</p>
</td>
</tr>
<tr id="row151093538536"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p15787134185412"><a name="p15787134185412"></a><a name="p15787134185412"></a>LOS_KernelFree</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p878712410546"><a name="p878712410546"></a><a name="p878712410546"></a>释放内核堆内存</p>
</td>
</tr>
<tr id="row5126856205319"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p197871646545"><a name="p197871646545"></a><a name="p197871646545"></a>LOS_KernelRealloc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p378813416547"><a name="p378813416547"></a><a name="p378813416547"></a>重新分配内核内存空间</p>
</td>
</tr>
<tr id="row12397132718549"><td class="cellrowborder" rowspan="5" valign="top" width="12.811281128112812%" headers="mcps1.2.4.1.1 "><p id="p112971954115419"><a name="p112971954115419"></a><a name="p112971954115419"></a>其他</p>
</td>
<td class="cellrowborder" valign="top" width="29.84298429842984%" headers="mcps1.2.4.1.2 "><p id="p2777034145414"><a name="p2777034145414"></a><a name="p2777034145414"></a>LOS_PaddrQuery</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p13777834115413"><a name="p13777834115413"></a><a name="p13777834115413"></a>根据虚拟地址获取对应的物理地址</p>
</td>
</tr>
<tr id="row5558122119542"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p9558421155418"><a name="p9558421155418"></a><a name="p9558421155418"></a>LOS_VmSpaceFree</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p755852119545"><a name="p755852119545"></a><a name="p755852119545"></a>释放进程空间,包括虚拟内存区间、页表等信息</p>
</td>
</tr>
<tr id="row15860142919544"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p168603298547"><a name="p168603298547"></a><a name="p168603298547"></a>LOS_VmSpaceReserve</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p12860429185410"><a name="p12860429185410"></a><a name="p12860429185410"></a>在进程空间中预留一块内存空间</p>
</td>
</tr>
<tr id="row394217543569"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p11943125419566"><a name="p11943125419566"></a><a name="p11943125419566"></a>LOS_VaddrToPaddrMmap</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p16943954105613"><a name="p16943954105613"></a><a name="p16943954105613"></a>将指定长度的物理地址区间与虚拟地址区间做映射,需提前申请物理地址区间</p>
</td>
</tr>
<tr id="row18527155718"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p118526110579"><a name="p118526110579"></a><a name="p118526110579"></a>LOS_UserSpaceVmAlloc</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1485214117575"><a name="p1485214117575"></a><a name="p1485214117575"></a>根据地址、大小、权限等信息在用户进程空间内申请地址区间region</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section8752103914513"></a>
虚拟内存相关接口的使用:
1. 根据进程空间获取的系列接口可以得到进程空间结构体,进而可以读取结构体相应信息。
2. 对虚拟地址区间做相关操作:
- 通过LOS\_RegionAlloc申请虚拟地址区间;
- 通过LOS\_RegionFind、LOS\_RegionRangeFind可以查询是否存在相应的地址区间;
- 通过LOS\_RegionFree释放虚拟地址区间。
3. vmalloc接口及内存申请系列接口可以在内核中根据需要申请内存。
>![](../public_sys-resources/icon-note.gif) **说明:**
>内存申请系列接口申请的内存要求物理内存是连续的,当系统内存无法满足大块连续内存的申请条件时会申请失败,一般适用于小块内存的申请;vmalloc相关接口申请的内存可以获得不连续的物理内存,但其是以页(当前系统一个页为4096字节)为单位的,当需要申请以页为整数倍的内存时可以通过vmalloc申请,例如文件系统中文件读取需要较大的缓存,便可以通过vmalloc相关接口申请内存。
# 内存管理<a name="ZH-CN_TOPIC_0000001123695259"></a>
- **[堆内存管理](kernel-small-basic-memory-heap.md)**
- **[物理内存管理](kernel-small-basic-memory-physical.md)**
- **[虚拟内存管理](kernel-small-basic-memory-virtual.md)**
- **[虚实映射](kernel-small-basic-inner-reflect.md)**
# 进程<a name="ZH-CN_TOPIC_0000001078704186"></a>
- [基本概念](#section89346055119)
- [运行机制](#section174514474512)
- [开发指导](#section159637182521)
- [接口说明](#section1153124135212)
- [开发流程](#section1533674618526)
## 基本概念<a name="section89346055119"></a>
进程是系统资源管理的最小单元。OpenHarmony LiteOS-A内核提供的进程模块主要用于实现用户态进程的隔离,内核态被视为一个进程空间,不存在其它进程\(KIdle除外,KIdle进程是系统提供的空闲进程,和KProcess共享一个进程空间)。
- OpenHarmony 的进程模块主要为用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。
- OpenHarmony 的进程采用抢占式调度机制,采用高优先级优先+同优先级时间片轮转的调度算法。
- OpenHarmony 的进程一共有32个优先级\(0-31\),用户进程可配置的优先级有22个\(10-31\),最高优先级为10,最低优先级为31。
- 高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。
- 每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离。
- 用户态根进程init由内核态创建,其它用户态子进程均由init进程fork而来。
**进程状态说明:**
- 初始化(Init):进程正在被创建。
- 就绪(Ready):进程在就绪列表中,等待CPU调度。
- 运行(Running):进程正在运行。
- 阻塞(Pending):进程被阻塞挂起。本进程内所有的线程均被阻塞时,进程被阻塞挂起。
- 僵尸态(Zombies):进程运行结束,等待父进程回收其控制块资源。
**图 1** 进程状态迁移示意图<a name="fig13604525122919"></a>
![](figure/进程状态迁移示意图.png "进程状态迁移示意图")
**进程状态迁移说明:**
- Init→Ready:
进程创建或fork时,拿到该进程控制块后进入Init状态,处于进程初始化阶段,当进程初始化完成将进程插入调度队列,此时进程进入就绪状态。
- Ready→Running:
进程创建后进入就绪态,发生进程切换时,就绪列表中最高优先级的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存,但对外呈现的进程状态为运行态。
- Running→Pending:
进程在最后一个线程转为阻塞态时, 进程内所有的线程均处于阻塞态,此时进程同步进入阻塞态,然后发生进程切换。
- Pending→Ready:
阻塞进程内的任意线程恢复就绪态时,进程被加入到就绪队列,同步转为就绪态。
- Ready→Pending:
进程内的最后一个就绪态线程转为阻塞态时,进程从就绪列表中删除,进程由就绪态转为阻塞态。
- Running→Ready:
进程由运行态转为就绪态的情况有以下两种:
1. 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。
2. 若进程的调度策略为LOS\_SCHED\_RR,且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。
- Running→Zombies:
当进程的主线程或所有线程运行结束后,进程由运行态转为僵尸态,等待父进程回收资源。
## 运行机制<a name="section174514474512"></a>
OpenHarmony 提供的进程模块主要用于实现用户态进程的隔离,支持用户态进程的创建、退出、资源回收、设置/获取调度参数、获取进程ID、设置/获取进程组ID等功能。
用户态进程通过fork父进程而来,fork进程时会将父进程的进程虚拟内存空间clone到子进程,子进程实际运行时通过写时复制机制将父进程的内容按需复制到子进程的虚拟内存空间。
进程只是资源管理单元,实际运行是由进程内的各个线程完成的,不同进程内的线程相互切换时会进行进程空间的切换。
**图 2** 进程管理示意图<a name="fig5251243193113"></a>
![](figure/zh-cn_image_0000001127519136.png)
## 开发指导<a name="section159637182521"></a>
### 接口说明<a name="section1153124135212"></a>
**表 1** 进程管理模块接口
<a name="table359914125718"></a>
<table><thead align="left"><tr id="row85991712770"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p13162121815218"><a name="p13162121815218"></a><a name="p13162121815218"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p12162618623"><a name="p12162618623"></a><a name="p12162618623"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p16162118427"><a name="p16162118427"></a><a name="p16162118427"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row66002121074"><td class="cellrowborder" rowspan="4" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p13571544484"><a name="p13571544484"></a><a name="p13571544484"></a>进程调度参数控制</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p7571644283"><a name="p7571644283"></a><a name="p7571644283"></a>LOS_GetProcessScheduler</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p205724410813"><a name="p205724410813"></a><a name="p205724410813"></a>获取指定进程的调度策略</p>
</td>
</tr>
<tr id="row166001712574"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p6571144286"><a name="p6571144286"></a><a name="p6571144286"></a>LOS_SetProcessScheduler</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p18572443819"><a name="p18572443819"></a><a name="p18572443819"></a>设置指定进程的调度参数,包括优先级和调度策略</p>
</td>
</tr>
<tr id="row1560071212719"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3571144885"><a name="p3571144885"></a><a name="p3571144885"></a>LOS_GetProcessPriority</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p95710448818"><a name="p95710448818"></a><a name="p95710448818"></a>获取指定进程的优先级</p>
</td>
</tr>
<tr id="row1274011131587"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17572443812"><a name="p17572443812"></a><a name="p17572443812"></a>LOS_SetProcessPriority</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p16573445819"><a name="p16573445819"></a><a name="p16573445819"></a>设置指定进程的优先级</p>
</td>
</tr>
<tr id="row162882182816"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p175734417814"><a name="p175734417814"></a><a name="p175734417814"></a>等待回收子进程</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p165754410812"><a name="p165754410812"></a><a name="p165754410812"></a>LOS_Wait</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p5578441687"><a name="p5578441687"></a><a name="p5578441687"></a>等待子进程结束并回收子进程</p>
</td>
</tr>
<tr id="row81051920589"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p4571844289"><a name="p4571844289"></a><a name="p4571844289"></a>进程组</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p20578442083"><a name="p20578442083"></a><a name="p20578442083"></a>LOS_GetProcessGroupID</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p145704416818"><a name="p145704416818"></a><a name="p145704416818"></a>获取指定进程的进程组ID</p>
</td>
</tr>
<tr id="row13410161611819"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p657944289"><a name="p657944289"></a><a name="p657944289"></a>LOS_GetCurrProcessGroupID</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p165816445819"><a name="p165816445819"></a><a name="p165816445819"></a>获取当前进程的进程组ID</p>
</td>
</tr>
<tr id="row1260011213718"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p125818441781"><a name="p125818441781"></a><a name="p125818441781"></a>获取进程ID</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p25814445819"><a name="p25814445819"></a><a name="p25814445819"></a>LOS_GetCurrProcessID</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1058644687"><a name="p1058644687"></a><a name="p1058644687"></a>获取当前进程的进程ID</p>
</td>
</tr>
<tr id="row060019121871"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p145810441285"><a name="p145810441285"></a><a name="p145810441285"></a>用户及用户组</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p10581744783"><a name="p10581744783"></a><a name="p10581744783"></a>LOS_GetUserID</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p7581944287"><a name="p7581944287"></a><a name="p7581944287"></a>获取当前进程的用户ID</p>
</td>
</tr>
<tr id="row1160021211713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18582447814"><a name="p18582447814"></a><a name="p18582447814"></a>LOS_GetGroupID</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p3581444382"><a name="p3581444382"></a><a name="p3581444382"></a>获取当前进程的用户组ID</p>
</td>
</tr>
<tr id="row1160018123717"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p19589442084"><a name="p19589442084"></a><a name="p19589442084"></a>LOS_CheckInGroups</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p5581144689"><a name="p5581144689"></a><a name="p5581144689"></a>检查指定用户组ID是否在当前进程的用户组内</p>
</td>
</tr>
<tr id="row317461111812"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p105814419818"><a name="p105814419818"></a><a name="p105814419818"></a>系统支持的最大进程数</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p3583441888"><a name="p3583441888"></a><a name="p3583441888"></a>LOS_GetSystemProcessMaximum</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p115818441187"><a name="p115818441187"></a><a name="p115818441187"></a>获取系统支持的最大进程数目</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section1533674618526"></a>
不支持内核态进程创建,内核态不涉及进程相关开发。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- idle线程的数量跟随CPU核心数,每个CPU均有一个相应的idle线程。
>- 不支持创建除KProcess和KIdle进程之外的其它内核态进程。
>- 用户态进程通过系统调用进入内核态后创建的线程属于KProcess, 不属于当前用户态进程。
# 调度器<a name="ZH-CN_TOPIC_0000001078863798"></a>
- [基本概念](#section123882355719)
- [运行机制](#section143015396572)
- [开发指导](#section10604192145816)
- [接口说明](#section207985910582)
- [开发流程](#section1015110331584)
## 基本概念<a name="section123882355719"></a>
OpenHarmony LiteOS-A内核 了高优先级优先+同优先级时间片轮转的抢占式调度机制,系统从启动开始基于real time的时间轴向前运行,使得该调度算法具有很好的实时性。
OpenHarmony 的调度算法将tickless机制天然嵌入到调度算法中,一方面使得系统具有更低的功耗,另一方面也使得tick中断按需响应,减少无用的tick中断响应,进一步提高系统的实时性。
OpenHarmony 的进程调度策略支持SCHED\_RR,线程调度策略支持SCHED\_RR和SCHED\_FIFO。
OpenHarmony 调度的最小单元为线程。
## 运行机制<a name="section143015396572"></a>
OpenHarmony 采用进程优先级队列+线程优先级队列的方式,进程优先级范围为0-31,共有32个进程优先级桶队列,每个桶队列对应一个线程优先级桶队列;线程优先级范围也为0-31,一个线程优先级桶队列也有32个优先级队列。
**图 1** 调度优先级桶队列示意图<a name="fig623133213389"></a>
![](figure/zh-cn_image_0000001127520662.png)
OpenHarmony 在系统启动内核初始化之后开始调度,运行过程中创建的进程或线程会被加入到调度队列,系统根据进程和线程的优先级及线程的时间片消耗情况选择最优的线程进行调度运行,线程一旦调度到就会从调度队列上删除,线程在运行过程中发生阻塞,会被加入到对应的阻塞队列中并触发一次调度,调度其它线程运行。如果调度队列上没有可以调度的线程,则系统就会选择KIdle进程的线程进行调度运行。
**图 2** 调度流程示意图<a name="fig5251243193113"></a>
![](figure/zh-cn_image_0000001176974089.png)
## 开发指导<a name="section10604192145816"></a>
### 接口说明<a name="section207985910582"></a>
<a name="table687929113814"></a>
<table><thead align="left"><tr id="row513082983812"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.1"><p id="p121309298384"><a name="p121309298384"></a><a name="p121309298384"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.2"><p id="p713082933817"><a name="p713082933817"></a><a name="p713082933817"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.3"><p id="p20130829123810"><a name="p20130829123810"></a><a name="p20130829123810"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row713032973813"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p0130429133818"><a name="p0130429133818"></a><a name="p0130429133818"></a>触发系统调度</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p71581556124414"><a name="p71581556124414"></a><a name="p71581556124414"></a>LOS_Schedule</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p181303297387"><a name="p181303297387"></a><a name="p181303297387"></a>触发系统调度</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section1015110331584"></a>
>![](../public_sys-resources/icon-note.gif) **说明:**
>系统启动初始化阶段,不允许触发调度。
# 线程<a name="ZH-CN_TOPIC_0000001078641280"></a>
- [基本概念](#section138411646175417)
- [运行机制](#section1381918945512)
- [开发指导](#section10649727135519)
- [接口说明](#section78333315555)
- [开发流程](#section16229657115514)
- [编程实例](#section2809723165612)
## 基本概念<a name="section138411646175417"></a>
从系统的角度看,线程是竞争系统资源的最小运行单元。线程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它线程运行。
OpenHarmony 内核中同优先级进程内的线程统一调度、运行。
OpenHarmony 内核中的线程采用抢占式调度机制,同时支持时间片轮转调度和FIFO调度方式。
OpenHarmony 内核的线程一共有32个优先级\(0-31\),最高优先级为0,最低优先级为31。
当前进程内, 高优先级的线程可抢占低优先级线程,低优先级线程必须在高优先级线程阻塞或结束后才能得到调度。
**线程状态说明**
- 初始化(Init):线程正在被创建。
- 就绪(Ready):线程在就绪列表中,等待CPU调度。
- 运行(Running):线程正在运行。
- 阻塞(Blocked):线程被阻塞挂起。Blocked状态包括:pending\(因为锁、事件、信号量等阻塞\)、suspended(主动pend)、delay\(延时阻塞\)、pendtime\(因为锁、事件、信号量时间等超时等待\)
- 退出(Exit):线程运行结束,等待父线程回收其控制块资源。
**图 1** 线程状态迁移示意图<a name="fig5251243193113"></a>
![](figure/线程状态迁移示意图.png "线程状态迁移示意图")
**线程状态迁移说明:**
- Init→Ready:
线程创建拿到控制块后为初始化阶段\(Init状态\),当线程初始化完成将线程插入调度队列,此时线程进入就绪状态。
- Ready→Running:
线程创建后进入就绪态,发生线程切换时,就绪列表中最高优先级的线程被执行,从而进入运行态,此刻该线程从就绪列表中删除。
- Running→Blocked:
正在运行的线程发生阻塞(挂起、延时、读信号量等)时,线程状态由运行态变成阻塞态,然后发生线程切换,运行就绪列表中剩余最高优先级线程。
- Blocked→Ready :
阻塞的线程被恢复后(线程恢复、延时时间超时、读信号量超时或读到信号量等),此时被恢复的线程会被加入就绪列表,从而由阻塞态变成就绪态。
- Ready→Blocked:
线程也有可能在就绪态时被阻塞(挂起),此时线程状态会由就绪态转变为阻塞态,该线程从就绪列表中删除,不会参与线程调度,直到该线程被恢复。
- Running→Ready:
有更高优先级线程创建或者恢复后,会发生线程调度,此刻就绪列表中最高优先级线程变为运行态,那么原先运行的线程由运行态变为就绪态,并加入就绪列表中。
- Running→Exit:
运行中的线程运行结束,线程状态由运行态变为退出态。若为设置了分离属性(LOS\_TASK\_STATUS\_DETACHED)的线程,运行结束后将直接销毁。
## 运行机制<a name="section1381918945512"></a>
OpenHarmony 线程管理模块提供线程创建、线程延时、线程挂起和线程恢复、锁线程调度和解锁线程调度、根据ID查询线程控制块信息功能。
用户创建线程时,系统会将线程栈进行初始化,预置上下文。此外,系统还会将“线程入口函数”地址放在相应位置。这样在线程第一次启动进入运行态时,将会执行线程入口函数。
## 开发指导<a name="section10649727135519"></a>
### 接口说明<a name="section78333315555"></a>
<a name="table687929113814"></a>
<table><thead align="left"><tr id="row513082983812"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.1"><p id="p121309298384"><a name="p121309298384"></a><a name="p121309298384"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.2"><p id="p713082933817"><a name="p713082933817"></a><a name="p713082933817"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.3"><p id="p20130829123810"><a name="p20130829123810"></a><a name="p20130829123810"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row713032973813"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p0130429133818"><a name="p0130429133818"></a><a name="p0130429133818"></a>线程的创建和删除</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p6130102911384"><a name="p6130102911384"></a><a name="p6130102911384"></a>LOS_TaskCreateOnly</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p181303297387"><a name="p181303297387"></a><a name="p181303297387"></a>创建线程,并使该线程进入Init状态,不执行线程调度</p>
</td>
</tr>
<tr id="row51301329123813"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p41301293386"><a name="p41301293386"></a><a name="p41301293386"></a>LOS_TaskCreate</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p513092983812"><a name="p513092983812"></a><a name="p513092983812"></a>创建线程,并使该线程进入Ready状态,并调度</p>
</td>
</tr>
<tr id="row14130729193816"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p7130152993810"><a name="p7130152993810"></a><a name="p7130152993810"></a>LOS_TaskDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p11130122910387"><a name="p11130122910387"></a><a name="p11130122910387"></a>删除指定的线程</p>
</td>
</tr>
<tr id="row1513118292383"><td class="cellrowborder" rowspan="4" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1813114299384"><a name="p1813114299384"></a><a name="p1813114299384"></a>线程状态控制</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p1713113291382"><a name="p1713113291382"></a><a name="p1713113291382"></a>LOS_TaskResume</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p16131229173819"><a name="p16131229173819"></a><a name="p16131229173819"></a>恢复挂起的线程</p>
</td>
</tr>
<tr id="row9131729173817"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p131311929123810"><a name="p131311929123810"></a><a name="p131311929123810"></a>LOS_TaskSuspend</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1813192919384"><a name="p1813192919384"></a><a name="p1813192919384"></a>挂起指定的线程</p>
</td>
</tr>
<tr id="row151311929193818"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p213114299387"><a name="p213114299387"></a><a name="p213114299387"></a>LOS_TaskDelay</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p141311729183817"><a name="p141311729183817"></a><a name="p141311729183817"></a>线程延时等待</p>
</td>
</tr>
<tr id="row18131182910384"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p15131122923810"><a name="p15131122923810"></a><a name="p15131122923810"></a>LOS_TaskYield</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1713122953816"><a name="p1713122953816"></a><a name="p1713122953816"></a>显式放权,调整调用线程优先级的线程调度顺序</p>
</td>
</tr>
<tr id="row9131829123812"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1313115299387"><a name="p1313115299387"></a><a name="p1313115299387"></a>线程调度的控制</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p101312029113815"><a name="p101312029113815"></a><a name="p101312029113815"></a>LOS_TaskLock</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p0131629183812"><a name="p0131629183812"></a><a name="p0131629183812"></a>锁线程调度</p>
</td>
</tr>
<tr id="row5131829193813"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p1313182910388"><a name="p1313182910388"></a><a name="p1313182910388"></a>LOS_TaskUnlock</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1131122913812"><a name="p1131122913812"></a><a name="p1131122913812"></a>解锁线程调度</p>
</td>
</tr>
<tr id="row213115292389"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p41312295381"><a name="p41312295381"></a><a name="p41312295381"></a>线程优先级的控制</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p1131829103815"><a name="p1131829103815"></a><a name="p1131829103815"></a>LOS_CurTaskPriSet</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p6131729163810"><a name="p6131729163810"></a><a name="p6131729163810"></a>设置当前线程的优先级</p>
</td>
</tr>
<tr id="row913142917389"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p10131172913819"><a name="p10131172913819"></a><a name="p10131172913819"></a>LOS_TaskPriSet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p113162912387"><a name="p113162912387"></a><a name="p113162912387"></a>设置指定线程的优先级</p>
</td>
</tr>
<tr id="row7131192913812"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p713142923817"><a name="p713142923817"></a><a name="p713142923817"></a>LOS_TaskPriGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p14131162923818"><a name="p14131162923818"></a><a name="p14131162923818"></a>获取指定线程的优先级</p>
</td>
</tr>
<tr id="row14132329133817"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p81323295380"><a name="p81323295380"></a><a name="p81323295380"></a>线程信息获取</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p31324294389"><a name="p31324294389"></a><a name="p31324294389"></a>LOS_CurTaskIDGet</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p14132929193814"><a name="p14132929193814"></a><a name="p14132929193814"></a>获取当前线程的ID</p>
</td>
</tr>
<tr id="row4132182920383"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p15133172923815"><a name="p15133172923815"></a><a name="p15133172923815"></a>LOS_TaskInfoGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p5133329123814"><a name="p5133329123814"></a><a name="p5133329123814"></a>获取指定线程的信息</p>
</td>
</tr>
<tr id="row855810357401"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p9682331164117"><a name="p9682331164117"></a><a name="p9682331164117"></a>线程绑核操作</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p205581835144010"><a name="p205581835144010"></a><a name="p205581835144010"></a>LOS_TaskCpuAffiSet</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p115582035154014"><a name="p115582035154014"></a><a name="p115582035154014"></a>绑定指定线程到指定cpu上运行,仅在多核下使用</p>
</td>
</tr>
<tr id="row5866193714018"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p8867133744011"><a name="p8867133744011"></a><a name="p8867133744011"></a>LOS_TaskCpuAffiGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p10867173718404"><a name="p10867173718404"></a><a name="p10867173718404"></a>获取指定线程的绑核信息,仅在多核下使用</p>
</td>
</tr>
<tr id="row197312218434"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p20362114474318"><a name="p20362114474318"></a><a name="p20362114474318"></a>线程调度参数的控制</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p5974192215434"><a name="p5974192215434"></a><a name="p5974192215434"></a>LOS_GetTaskScheduler</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p2974922164317"><a name="p2974922164317"></a><a name="p2974922164317"></a>获取指定线程的调度策略</p>
</td>
</tr>
<tr id="row141414214436"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p9141202144319"><a name="p9141202144319"></a><a name="p9141202144319"></a>LOS_SetTaskScheduler</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p3141221154319"><a name="p3141221154319"></a><a name="p3141221154319"></a>设置指定线程的调度参数,包括优先级和调度策略</p>
</td>
</tr>
<tr id="row617914918441"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p17180184911445"><a name="p17180184911445"></a><a name="p17180184911445"></a>系统支持的最大线程数</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p151807498449"><a name="p151807498449"></a><a name="p151807498449"></a>LOS_GetSystemTaskMaximum</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p81801249124417"><a name="p81801249124417"></a><a name="p81801249124417"></a>获取系统支持的最大线程数目</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section16229657115514"></a>
线程的典型开发流程:
1. 通过LOS\_TaskCreate创建一个线程。
- 指定线程的执行入口函数
- 指定线程名
- 指定线程的栈大小
- 指定线程的优先级
- 指定线程的属性,是否支持LOS\_TASK\_STATUS\_DETACHED属性
- 多核运行时,可以选择设置线程的绑核属性
2. 线程参与调度运行,执行用户指定的业务代码。
3. 线程执行结束,如果线程设置了LOS\_TASK\_STATUS\_DETACHED属性,则线程运行结束后自动回收线程资源,如果未设置LOS\_TASK\_STATUS\_DETACHED属性,则需要调用LOS\_TaskDelete接口回收线程资源。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 内核态具有最高权限,可以操作任意进程内的线程。
>- 用户态进程通过系统调用进入内核态后创建的线程属于KProcess, 不属于当前用户态进程。
### 编程实例<a name="section2809723165612"></a>
代码实现如下:
```
UINT32 g_taskLoID;
UINT32 g_taskHiID;
#define TSK_PRIOR_HI 4
#define TSK_PRIOR_LO 5
UINT32 ExampleTaskHi(VOID)
{
UINT32 ret;
PRINTK("Enter TaskHi Handler.\n");
/* 延时2个Tick,延时后该任务会挂起,执行剩余任务中最高优先级的任务(g_taskLoID任务) */
ret = LOS_TaskDelay(2);
if (ret != LOS_OK) {
PRINTK("Delay Task Failed.\n");
return LOS_NOK;
}
/* 2个Tick时间到了后,该任务恢复,继续执行 */
PRINTK("TaskHi LOS_TaskDelay Done.\n");
/* 挂起自身任务 */
ret = LOS_TaskSuspend(g_taskHiID);
if (ret != LOS_OK) {
PRINTK("Suspend TaskHi Failed.\n");
return LOS_NOK;
}
PRINTK("TaskHi LOS_TaskResume Success.\n");
return LOS_OK;
}
/* 低优先级任务入口函数 */
UINT32 ExampleTaskLo(VOID)
{
UINT32 ret;
PRINTK("Enter TaskLo Handler.\n");
/* 延时2个Tick,延时后该任务会挂起,执行剩余任务中就高优先级的任务(背景任务) */
ret = LOS_TaskDelay(2);
if (ret != LOS_OK) {
PRINTK("Delay TaskLo Failed.\n");
return LOS_NOK;
}
PRINTK("TaskHi LOS_TaskSuspend Success.\n");
/* 恢复被挂起的任务g_taskHiID */
ret = LOS_TaskResume(g_taskHiID);
if (ret != LOS_OK) {
PRINTK("Resume TaskHi Failed.\n");
return LOS_NOK;
}
PRINTK("TaskHi LOS_TaskDelete Success.\n");
return LOS_OK;
}
/* 任务测试入口函数,在里面创建优先级不一样的两个任务 */
UINT32 ExampleTaskCaseEntry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S initParam = {0};
/* 锁任务调度 */
LOS_TaskLock();
PRINTK("LOS_TaskLock() Success!\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskHi;
initParam.usTaskPrio = TSK_PRIOR_HI;
initParam.pcName = "HIGH_NAME";
initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE;
initParam.uwResved = LOS_TASK_STATUS_DETACHED;
/* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */
ret = LOS_TaskCreate(&g_taskHiID, &initParam);
if (ret != LOS_OK) {
LOS_TaskUnlock();
PRINTK("ExampleTaskHi create Failed! ret=%d\n", ret);
return LOS_NOK;
}
PRINTK("ExampleTaskHi create Success!\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleTaskLo;
initParam.usTaskPrio = TSK_PRIOR_LO;
initParam.pcName = "LOW_NAME";
initParam.uwStackSize = LOS_TASK_MIN_STACK_SIZE;
initParam.uwResved = LOS_TASK_STATUS_DETACHED;
/* 创建低优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */
ret = LOS_TaskCreate(&g_taskLoID, &initParam);
if (ret!= LOS_OK) {
LOS_TaskUnlock();
PRINTK("ExampleTaskLo create Failed!\n");
return LOS_NOK;
}
PRINTK("ExampleTaskLo create Success!\n");
/* 解锁任务调度,此时会发生任务调度,执行就绪列表中最高优先级任务 */
LOS_TaskUnlock();
while(1){};
return LOS_OK;
}
```
编译运行得到的结果为:
```
LOS_TaskLock() Success!
ExampleTaskHi create Success!
ExampleTaskLo create Success!
Enter TaskHi Handler.
Enter TaskLo Handler.
TaskHi LOS_TaskDelay Done.
TaskHi LOS_TaskSuspend Success.
TaskHi LOS_TaskResume Success.
TaskHi LOS_TaskDelete Success.
```
# 进程管理<a name="ZH-CN_TOPIC_0000001173298177"></a>
- **[进程](kernel-small-basic-process-process.md)**
- **[线程](kernel-small-basic-process-thread.md)**
- **[调度器](kernel-small-basic-process-scheduler.md)**
# 软件定时器<a name="ZH-CN_TOPIC_0000001078575728"></a>
- [基本概念](#section4118241563)
- [运行机制](#section31079397569)
- [开发指导](#section18576131520577)
- [接口说明](#section3138019145719)
- [开发流程](#section1344817403575)
- [编程实例](#section114416313585)
## 基本概念<a name="section4118241563"></a>
软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数值后会触发用户定义的回调函数。定时精度与系统Tick时钟的周期有关。硬件定时器受硬件的限制,数量上不足以满足用户的实际需求,因此为了满足用户需求,提供更多的定时器,Huawei LiteOS操作系统提供软件定时器功能。软件定时器扩展了定时器的数量,允许创建更多的定时业务。
软件定时器功能上支持:
- 静态裁剪:能通过宏关闭软件定时器功能。
- 软件定时器创建。
- 软件定时器启动。
- 软件定时器停止。
- 软件定时器删除。
- 软件定时器剩余Tick数获取。
## 运行机制<a name="section31079397569"></a>
软件定时器是系统资源,在模块初始化的时候已经分配了一块连续的内存,系统支持的最大定时器个数由los\_config.h中的LOSCFG\_BASE\_CORE\_SWTMR\_LIMIT宏配置。软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,先进先出。同一时刻设置的定时时间短的定时器总是比定时时间长的靠近队列头,满足优先被触发的准则。软件定时器以Tick为基本计时单位,当用户创建并启动一个软件定时器时,OpenHarmony系统会根据当前系统Tick时间及用户设置的定时间隔确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。
当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,看是否有定时器超时,若有则将超时的定时器记录下来。
Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用之前记录下来的定时器的超时回调函数。
定时器状态
- OS\_SWTMR\_STATUS\_UNUSED(未使用)
系统在定时器模块初始化的时候将系统中所有定时器资源初始化成该状态。
- OS\_SWTMR\_STATUS\_CREATED(创建未启动/停止)
在未使用状态下调用LOS\_SwtmrCreate接口或者启动后调用LOS\_SwtmrStop接口后,定时器将变成该状态。
- OS\_SWTMR\_STATUS\_TICKING(计数)
在定时器创建后调用LOS\_SwtmrStart接口,定时器将变成该状态,表示定时器运行时的状态。
定时器模式
OpenHarmony系统的软件定时器提供三类定时器机制:
- 第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。
- 第二类是周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动停止定时器,否则将永远持续执行下去。
- 第三类也是单次触发定时器,但与第一类不同之处在于这类定时器超时后不会自动删除,需要调用定时器删除接口删除定时器。
## 开发指导<a name="section18576131520577"></a>
### 接口说明<a name="section3138019145719"></a>
OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接口详细信息可以查看API参考。
**表 1** 软件定时器接口说明
<a name="table107038227425"></a>
<table><thead align="left"><tr id="row2704122217420"><th class="cellrowborder" valign="top" width="20.6020602060206%" id="mcps1.2.4.1.1"><p id="p57041622144212"><a name="p57041622144212"></a><a name="p57041622144212"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.542954295429542%" id="mcps1.2.4.1.2"><p id="p19704142216424"><a name="p19704142216424"></a><a name="p19704142216424"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="49.85498549854985%" id="mcps1.2.4.1.3"><p id="p670412224217"><a name="p670412224217"></a><a name="p670412224217"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row1470413222429"><td class="cellrowborder" rowspan="2" valign="top" width="20.6020602060206%" headers="mcps1.2.4.1.1 "><p id="p8284115918428"><a name="p8284115918428"></a><a name="p8284115918428"></a>创建、删除定时器</p>
</td>
<td class="cellrowborder" valign="top" width="29.542954295429542%" headers="mcps1.2.4.1.2 "><p id="p117045225428"><a name="p117045225428"></a><a name="p117045225428"></a>LOS_SwtmrCreate</p>
</td>
<td class="cellrowborder" valign="top" width="49.85498549854985%" headers="mcps1.2.4.1.3 "><p id="p170422234213"><a name="p170422234213"></a><a name="p170422234213"></a>创建软件定时器</p>
</td>
</tr>
<tr id="row11704102217425"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1970492213426"><a name="p1970492213426"></a><a name="p1970492213426"></a>LOS_SwtmrDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p870442211421"><a name="p870442211421"></a><a name="p870442211421"></a>删除软件定时器</p>
</td>
</tr>
<tr id="row57041422184215"><td class="cellrowborder" rowspan="2" valign="top" width="20.6020602060206%" headers="mcps1.2.4.1.1 "><p id="p1476172124318"><a name="p1476172124318"></a><a name="p1476172124318"></a>启动、停止定时器</p>
</td>
<td class="cellrowborder" valign="top" width="29.542954295429542%" headers="mcps1.2.4.1.2 "><p id="p167040225423"><a name="p167040225423"></a><a name="p167040225423"></a>LOS_SwtmrStart</p>
</td>
<td class="cellrowborder" valign="top" width="49.85498549854985%" headers="mcps1.2.4.1.3 "><p id="p1570412229421"><a name="p1570412229421"></a><a name="p1570412229421"></a>启动软件定时器</p>
</td>
</tr>
<tr id="row15704172224219"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1170422214216"><a name="p1170422214216"></a><a name="p1170422214216"></a>LOS_SwtmrStop</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p17705122211426"><a name="p17705122211426"></a><a name="p17705122211426"></a>停止软件定时器</p>
</td>
</tr>
<tr id="row12705222154214"><td class="cellrowborder" valign="top" width="20.6020602060206%" headers="mcps1.2.4.1.1 "><p id="p0705622134214"><a name="p0705622134214"></a><a name="p0705622134214"></a>获得软件定时剩余Tick数</p>
</td>
<td class="cellrowborder" valign="top" width="29.542954295429542%" headers="mcps1.2.4.1.2 "><p id="p177052220424"><a name="p177052220424"></a><a name="p177052220424"></a>LOS_SwtmrTimeGet</p>
</td>
<td class="cellrowborder" valign="top" width="49.85498549854985%" headers="mcps1.2.4.1.3 "><p id="p3705122264210"><a name="p3705122264210"></a><a name="p3705122264210"></a>获得软件定时器剩余Tick数</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section1344817403575"></a>
软件定时器的典型开发流程:
1. 配置软件定时器。
- 确认配置项LOSCFG\_BASE\_CORE\_SWTMR和LOSCFG\_BASE\_IPC\_QUEUE为打开状态;
- 配置LOSCFG\_BASE\_CORE\_SWTMR\_LIMIT最大支持的软件定时器数;
- 配置OS\_SWTMR\_HANDLE\_QUEUE\_SIZE软件定时器队列最大长度;
2. 创建定时器LOS\_SwtmrCreate。
- 创建一个指定计时时长、指定超时处理函数、指定触发模式的软件定时器;
- 返回函数运行结果,成功或失败;
3. 启动定时器LOS\_SwtmrStart。
4. 获得软件定时器剩余Tick数LOS\_SwtmrTimeGet。
5. 停止定时器LOS\_SwtmrStop。
6. 删除定时器LOS\_SwtmrDelete。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 软件定时器的回调函数中不要做过多操作,不要使用可能引起任务挂起或者阻塞的接口或操作。
>- 软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级设定为0,且不允许修改 。
>- 系统可配置的软件定时器资源个数是指:整个系统可使用的软件定时器资源总个数,而并非是用户可使用的软件定时器资源个数。例如:系统软件定时器多占用一个软件定时器资源数,那么用户能使用的软件定时器资源就会减少一个。
>- 创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源。
>- 创建单次不自删除属性的定时器,用户需要调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。
### 编程实例<a name="section114416313585"></a>
**前置条件**
- 在los\_config.h中,将LOSCFG\_BASE\_CORE\_SWTMR配置项打开。
- 配置好LOSCFG\_BASE\_CORE\_SWTMR\_LIMIT最大支持的软件定时器数。
- 配置好OS\_SWTMR\_HANDLE\_QUEUE\_SIZE软件定时器队列最大长度。
**编程示例**
```
#include "los_swtmr.h"
void Timer1_Callback(uint32_t arg);
void Timer2_Callback(uint32_t arg);
UINT32 g_timercount1 = 0;
UINT32 g_timercount2 = 0;
void Timer1_Callback(uint32_t arg) // 回调函数1
{
unsigned long tick_last1;
g_timercount1++;
tick_last1=(UINT32)LOS_TickCountGet(); // 获取当前Tick数
PRINTK("g_timercount1=%d\n",g_timercount1);
PRINTK("tick_last1=%d\n",tick_last1);
}
void Timer2_Callback(uint32_t arg) // 回调函数2
{
unsigned long tick_last2;
tick_last2=(UINT32)LOS_TickCountGet();
g_timercount2 ++;
PRINTK("g_timercount2=%d\n",g_timercount2);
PRINTK("tick_last2=%d\n",tick_last2);
}
void Timer_example(void)
{
UINT16 id1;
UINT16 id2; // timer id
UINT32 uwTick;
/* 创建单次软件定时器,Tick数为1000,启动到1000Tick数时执行回调函数1 */
LOS_SwtmrCreate (1000, LOS_SWTMR_MODE_ONCE, Timer1_Callback, &id1, 1);
/* 创建周期性软件定时器,每100Tick数执行回调函数2 */
LOS_SwtmrCreate(100, LOS_SWTMR_MODE_PERIOD, Timer2_Callback, &id2, 1);
PRINTK("create Timer1 success\n");
LOS_SwtmrStart (id1); //启动单次软件定时器
dprintf("start Timer1 success\n");
LOS_TaskDelay(200); // 延时200Tick数
LOS_SwtmrTimeGet(id1, &uwTick); // 获得单次软件定时器剩余Tick数
PRINTK("uwTick =%d\n", uwTick);
LOS_SwtmrStop(id1); // 停止软件定时器
PRINTK("stop Timer1 success\n");
LOS_SwtmrStart(id1);
LOS_TaskDelay(1000);
LOS_SwtmrDelete(id1); // 删除软件定时器
PRINTK("delete Timer1 success\n");
LOS_SwtmrStart(id2); // 启动周期性软件定时器
PRINTK("start Timer2\n");
LOS_TaskDelay(1000);
LOS_SwtmrStop(id2);
LOS_SwtmrDelete(id2);
}
```
**运行结果**
```
create Timer1 success
start Timer1 success
uwTick =800
stop Timer1 success
g_timercount1=1
tick_last1=1201
delete Timer1 success
start Timer2
g_timercount2 =1
tick_last1=1301
g_timercount2 =2
tick_last1=1401
g_timercount2 =3
tick_last1=1501
g_timercount2 =4
tick_last1=1601
g_timercount2 =5
tick_last1=1701
g_timercount2 =6
tick_last1=1801
g_timercount2 =7
tick_last1=1901
g_timercount2 =8
tick_last1=2001
g_timercount2 =9
tick_last1=2101
g_timercount2 =10
tick_last1=2201
```
# 时间管理<a name="ZH-CN_TOPIC_0000001123753363"></a>
- [基本概念](#section12903185785119)
- [开发指导](#section430981720522)
- [接口说明](#section1040142705214)
- [开发流程](#section1381224710522)
- [编程实例](#section1344610245416)
## 基本概念<a name="section12903185785119"></a>
时间管理以系统时钟为基础。时间管理提供给应用程序所有和时间有关的服务。系统时钟是由定时/计数器产生的输出脉冲触发中断而产生的,一般定义为整数或长整数。输出脉冲的周期叫做一个“时钟滴答”。系统时钟也称为时标或者Tick。一个Tick的时长可以静态配置。用户是以秒、毫秒为单位计时,而操作系统时钟计时是以Tick为单位的,当用户需要对系统操作时,例如任务挂起、延时等,输入秒为单位的数值,此时需要时间管理模块对二者进行转换。
Tick与秒之间的对应关系可以配置。
- **Cycle**
系统最小的计时单位。Cycle的时长由系统主频决定,系统主频就是每秒钟的Cycle数。
- **Tick**
Tick是操作系统的基本时间单位,对应的时长由系统主频及每秒Tick数决定,由用户配置。
OpenHarmony系统的时间管理模块提供时间转换、统计、延迟功能以满足用户对时间相关需求的实现。
## 开发指导<a name="section430981720522"></a>
用户需要了解当前系统运行的时间以及Tick与秒、毫秒之间的转换关系时,需要使用到时间管理模块的接口。
### 接口说明<a name="section1040142705214"></a>
OpenHarmony LiteOS-A内核的时间管理提供下面几种功能,接口详细信息可以查看API参考。
**表 1** 时间管理相关接口说明
<a name="table1316220185211"></a>
<table><thead align="left"><tr id="row191622182021"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p13162121815218"><a name="p13162121815218"></a><a name="p13162121815218"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p12162618623"><a name="p12162618623"></a><a name="p12162618623"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p16162118427"><a name="p16162118427"></a><a name="p16162118427"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row04981218910"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p6462616696"><a name="p6462616696"></a><a name="p6462616696"></a>时间转换</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p164931214913"><a name="p164931214913"></a><a name="p164931214913"></a>LOS_MS2Tick</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p8504121996"><a name="p8504121996"></a><a name="p8504121996"></a>毫秒转换成Tick</p>
</td>
</tr>
<tr id="row7162101814216"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p816311185217"><a name="p816311185217"></a><a name="p816311185217"></a>LOS_Tick2MS</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p161632181721"><a name="p161632181721"></a><a name="p161632181721"></a>Tick转换成毫秒</p>
</td>
</tr>
<tr id="row1516317181227"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1077619231696"><a name="p1077619231696"></a><a name="p1077619231696"></a>时间统计</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p181638181921"><a name="p181638181921"></a><a name="p181638181921"></a>LOS_TickCountGet</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p615864811116"><a name="p615864811116"></a><a name="p615864811116"></a>获取当前Tick数</p>
</td>
</tr>
<tr id="row101631818620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p71633181125"><a name="p71633181125"></a><a name="p71633181125"></a>LOS_CyclePerTickGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p151631718124"><a name="p151631718124"></a><a name="p151631718124"></a>每个Tick的cycle数</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section1381224710522"></a>
1. 调用时间转换接口;
2. 获取系统Tick数完成时间统计等。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 获取系统Tick数需要在系统时钟使能之后。
>- 时间管理不是单独的功能模块,依赖于los\_config.h中的OS\_SYS\_CLOCK和LOSCFG\_BASE\_CORE\_TICK\_PER\_SECOND两个配置选项。
>- 系统的Tick数在关中断的情况下不进行计数,故系统Tick数不能作为准确时间计算。
### 编程实例<a name="section1344610245416"></a>
前置条件:
- 配置好LOSCFG\_BASE\_CORE\_TICK\_PER\_SECOND,即系统每秒的Tick数。
- 配置好OS\_SYS\_CLOCK 系统时钟频率,单位:Hz。
**示例代码**
时间转换:
```
VOID Example_TransformTime(VOID)
{
UINT32 uwMs;
UINT32 uwTick;
uwTick = LOS_MS2Tick(10000); //10000 ms数转换为Tick数
PRINTK("uwTick = %d \n",uwTick);
uwMs= LOS_Tick2MS(100); //100 Tick数转换为ms数
PRINTK("uwMs = %d \n",uwMs);
}
```
时间统计和时间延迟:
```
VOID Example_GetTime(VOID)
{
UINT32 uwcyclePerTick;
UINT64 uwTickCount;
uwcyclePerTick = LOS_CyclePerTickGet(); //每个Tick多少Cycle数
if(0 != uwcyclePerTick)
{
PRINTK("LOS_CyclePerTickGet = %d \n", uwcyclePerTick);
}
uwTickCount = LOS_TickCountGet(); //获取Tick数
if(0 != uwTickCount)
{
PRINTK("LOS_TickCountGet = %d \n", (UINT32)uwTickCount);
}
LOS_TaskDelay(200);//延迟200 Tick
uwTickCount = LOS_TickCountGet();
if(0 != uwTickCount)
{
PRINTK("LOS_TickCountGet after delay = %d \n", (UINT32)uwTickCount);
}
}
```
**结果验证**
编译运行的结果如下:
时间转换:
```
uwTick = 10000
uwMs = 100
```
时间统计和时间延迟:
```
LOS_CyclePerTickGet = 49500
LOS_TickCountGet = 5042
LOS_TickCountGet after delay = 5242
```
# 事件<a name="ZH-CN_TOPIC_0000001078753124"></a>
- [基本概念](#section122115620816)
- [运行机制](#section94611116593)
- [事件控制块](#section1161415384467)
- [事件运作原理](#section187761153144617)
- [开发指导](#section44744471891)
- [接口说明](#section172373513919)
- [开发流程](#section1118215161013)
- [编程实例](#section19986143311020)
- [实例描述](#section128221510145718)
- [编程示例](#section71507479577)
- [结果验证](#section16570171645813)
## 基本概念<a name="section122115620816"></a>
事件(Event)是一种任务间通信的机制,可用于任务间的同步。
多任务环境下,任务之间往往需要同步操作,一个等待即是一个同步。事件可以提供一对多、多对多的同步操作。
- 一对多同步模型:一个任务等待多个事件的触发。可以是任意一个事件发生时唤醒任务处理事件,也可以是几个事件都发生后才唤醒任务处理事件。
- 多对多同步模型:多个任务等待多个事件的触发。
OpenHarmony LiteOS-A的事件模块提供的事件,具有如下特点:
- 任务通过创建事件控制块来触发事件或等待事件。
- 事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。第25位不可用,因此最多可支持31种事件类型。
- 事件仅用于任务间的同步,不提供数据传输功能。
- 多次向事件控制块写入同一事件类型,在被清零前等效于只写入一次。
- 多个任务可以对同一事件进行读写操作。
- 支持事件读写超时机制。
## 运行机制<a name="section94611116593"></a>
### 事件控制块<a name="section1161415384467"></a>
```
/**
* 事件控制块数据结构
*/
typedef struct tagEvent {
UINT32 uwEventID; /* 事件集合,表示已经处理(写入和清零)的事件集合 */
LOS_DL_LIST stEventList; /* 等待特定事件的任务链表 */
} EVENT_CB_S, *PEVENT_CB_S;
```
### 事件运作原理<a name="section187761153144617"></a>
**事件初始化:**会创建一个事件控制块,该控制块维护一个已处理的事件集合,以及等待特定事件的任务链表。
**写事件:**会向事件控制块写入指定的事件,事件控制块更新事件集合,并遍历任务链表,根据任务等待具体条件满足情况决定是否唤醒相关任务。
**读事件:**如果读取的事件已存在时,会直接同步返回。其他情况会根据超时时间以及事件触发情况,来决定返回时机:等待的事件条件在超时时间耗尽之前到达,阻塞任务会被直接唤醒,否则超时时间耗尽该任务才会被唤醒。
读事件条件满足与否取决于入参eventMask和mode,eventMask即需要关注的事件类型掩码。mode是具体处理方式,分以下三种情况:
- LOS\_WAITMODE\_AND:逻辑与,基于接口传入的事件类型掩码eventMask,只有这些事件都已经发生才能读取成功,否则该任务将阻塞等待或者返回错误码。。
- LOS\_WAITMODE\_OR:逻辑或,基于接口传入的事件类型掩码eventMask,只要这些事件中有任一种事件发生就可以读取成功,否则该任务将阻塞等待或者返回错误码。
- LOS\_WAITMODE\_CLR:这是一种附加读取模式,需要与所有事件模式或任一事件模式结合使用(LOS\_WAITMODE\_AND | LOS\_WAITMODE\_CLR或 LOS\_WAITMODE\_OR | LOS\_WAITMODE\_CLR)。在这种模式下,当设置的所有事件模式或任一事件模式读取成功后,会自动清除事件控制块中对应的事件类型位。
**事件清零:**根据指定掩码,去对事件控制块的事件集合进行清零操作。当掩码为0时,表示将事件集合全部清零。当掩码为0xffff时,表示不清除任何事件,保持事件集合原状。
**事件销毁:**销毁指定的事件控制块。
**图 1** 事件运作原理图<a name="fig17799175324612"></a>
![](figure/事件运作原理图-21.png "事件运作原理图-21")
## 开发指导<a name="section44744471891"></a>
### 接口说明<a name="section172373513919"></a>
OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。
**表 1** 事件模块接口
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row0415737175610"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p9598124913544"><a name="p9598124913544"></a><a name="p9598124913544"></a>初始化事件</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p77891354175812"><a name="p77891354175812"></a><a name="p77891354175812"></a>LOS_EventInit</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p2334141425515"><a name="p2334141425515"></a><a name="p2334141425515"></a>初始化一个事件控制块</p>
</td>
</tr>
<tr id="row421753455514"><td class="cellrowborder" rowspan="2" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p13441112105813"><a name="p13441112105813"></a><a name="p13441112105813"></a>读/写事件</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p17234205011559"><a name="p17234205011559"></a><a name="p17234205011559"></a>LOS_EventRead</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p1621275475517"><a name="p1621275475517"></a><a name="p1621275475517"></a>读取指定事件类型,超时时间为相对时间:单位为Tick</p>
</td>
</tr>
<tr id="row13129193718555"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17477615564"><a name="p17477615564"></a><a name="p17477615564"></a>LOS_EventWrite</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p10271958567"><a name="p10271958567"></a><a name="p10271958567"></a>写指定的事件类型</p>
</td>
</tr>
<tr id="row1831124035511"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p1313401559"><a name="p1313401559"></a><a name="p1313401559"></a>清除事件</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p7788152419567"><a name="p7788152419567"></a><a name="p7788152419567"></a>LOS_EventClear</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p14862153525620"><a name="p14862153525620"></a><a name="p14862153525620"></a>清除指定的事件类型</p>
</td>
</tr>
<tr id="row1525316428553"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p4253144265519"><a name="p4253144265519"></a><a name="p4253144265519"></a>校验事件掩码</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p768611115563"><a name="p768611115563"></a><a name="p768611115563"></a>LOS_EventPoll</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p13998115465617"><a name="p13998115465617"></a><a name="p13998115465617"></a>根据用户传入的事件ID、事件掩码及读取模式,返回用户传入的事件是否符合预期</p>
</td>
</tr>
<tr id="row6447135825614"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p104471658155615"><a name="p104471658155615"></a><a name="p104471658155615"></a>销毁事件</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p15259169573"><a name="p15259169573"></a><a name="p15259169573"></a>LOS_EventDestroy</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p32592615573"><a name="p32592615573"></a><a name="p32592615573"></a>销毁指定的事件控制块</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section1118215161013"></a>
事件的典型开发流程:
1. 初始化事件控制块
2. 阻塞读事件控制块
3. 写入相关事件
4. 阻塞任务被唤醒,读取事件并检查是否满足要求
5. 处理事件控制块
6. 事件控制块销毁
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 进行事件读写操作时,事件的第25位为保留位,不可以进行位设置。
>- 对同一事件反复写入,算作一次写入。
### 编程实例<a name="section19986143311020"></a>
### 实例描述<a name="section128221510145718"></a>
示例中,任务Example\_TaskEntry创建一个任务Example\_Event,Example\_Event读事件阻塞,Example\_TaskEntry向该任务写事件。可以通过示例日志中打印的先后顺序理解事件操作时伴随的任务切换。
1. 在任务Example\_TaskEntry创建任务Example\_Event,其中任务Example\_Event优先级高于Example\_TaskEntry。
2. 在任务Example\_Event中读事件0x00000001,阻塞,发生任务切换,执行任务Example\_TaskEntry。
3. 在任务Example\_TaskEntry向任务Example\_Event写事件0x00000001,发生任务切换,执行任务Example\_Event。
4. Example\_Event得以执行,直到任务结束。
5. Example\_TaskEntry得以执行,直到任务结束。
### 编程示例<a name="section71507479577"></a>
示例代码如下:
```
#include "los_event.h"
#include "los_task.h"
#include "securec.h"
/* 任务ID */
UINT32 g_testTaskId;
/* 事件控制结构体 */
EVENT_CB_S g_exampleEvent;
/* 等待的事件类型 */
#define EVENT_WAIT 0x00000001
/* 用例任务入口函数 */
VOID Example_Event(VOID)
{
UINT32 event;
/* 超时等待方式读事件,超时时间为100 ticks, 若100 ticks后未读取到指定事件,读事件超时,任务直接唤醒 */
printf("Example_Event wait event 0x%x \n", EVENT_WAIT);
event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, 100);
if (event == EVENT_WAIT) {
printf("Example_Event,read event :0x%x\n", event);
} else {
printf("Example_Event,read event timeout\n");
}
}
UINT32 Example_EventEntry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S task1;
/* 事件初始化 */
ret = LOS_EventInit(&g_exampleEvent);
if (ret != LOS_OK) {
printf("init event failed .\n");
return -1;
}
/* 创建任务 */
(VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Event;
task1.pcName = "EventTsk1";
task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task1.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_testTaskId, &task1);
if (ret != LOS_OK) {
printf("task create failed.\n");
return LOS_NOK;
}
/* 写g_testTaskId 等待事件 */
printf("Example_TaskEntry write event.\n");
ret = LOS_EventWrite(&g_exampleEvent, EVENT_WAIT);
if (ret != LOS_OK) {
printf("event write failed.\n");
return LOS_NOK;
}
/* 清标志位 */
printf("EventMask:%d\n", g_exampleEvent.uwEventID);
LOS_EventClear(&g_exampleEvent, ~g_exampleEvent.uwEventID);
printf("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;
}
```
### 结果验证<a name="section16570171645813"></a>
编译运行得到的结果为:
```
Example_Event wait event 0x1
Example_TaskEntry write event.
Example_Event,read event :0x1
EventMask:1
EventMask:0
```
# 互斥锁<a name="ZH-CN_TOPIC_0000001078912734"></a>
- [基本概念](#section85865329185)
- [运行机制](#section8547454201819)
- [开发指导](#section2038861117194)
- [接口说明](#section11168318131917)
- [开发流程](#section4201191122116)
- [编程实例](#section10679328202117)
## 基本概念<a name="section85865329185"></a>
互斥锁又称互斥型信号量,用于实现对共享资源的独占式处理。当有任务持有时,这个任务获得该互斥锁的所有权。当该任务释放它时,任务失去该互斥锁的所有权。当一个任务持有互斥锁时,其他任务将不能再持有该互斥锁。多任务环境下往往存在多个任务竞争同一共享资源的应用场景,互斥锁可被用于对共享资源的保护从而实现独占式访问。
互斥量属性包含3个属性:协议属性、优先级上限属性和类型属性。协议属性用于处理不同优先级的任务申请互斥锁,协议属性包含如下三种:
- LOS\_MUX\_PRIO\_NONE
不对申请互斥锁的任务的优先级进行继承或保护操作。
- LOS\_MUX\_PRIO\_INHERIT
优先级继承属性,默认设置为该属性,对申请互斥锁的任务的优先级进行继承。在互斥锁设置为本协议属性情况下,申请互斥锁时,如果高优先级任务阻塞于互斥锁,则把持有互斥锁任务的优先级备份到任务控制块的优先级位图中,然后把任务优先级设置为和高优先级任务相同的优先级;持有互斥锁的任务释放互斥锁时,从任务控制块的优先级位图恢复任务优先级。
- LOS\_MUX\_PRIO\_PROTECT
优先级保护属性,对申请互斥锁的任务的优先级进行保护。在互斥锁设置为本协议属性情况下,申请互斥锁时,如果任务优先级小于互斥锁优先级上限,则把任务优先级备份到任务控制块的优先级位图中,然后把任务优先级设置为互斥锁优先级上限属性值;释放互斥锁时,从任务控制块的优先级位图恢复任务优先级。
互斥锁的类型属性用于标记是否检测死锁,是否支持递归持有,类型属性包含如下三种:
- LOS\_MUX\_NORMAL
普通互斥锁,不会检测死锁。如果任务试图对一个互斥锁重复持有,将会引起这个线程的死锁。如果试图释放一个由别的任务持有的互斥锁,或者如果一个任务试图重复释放互斥锁都会引发不可预料的结果。
- LOS\_MUX\_RECURSIVE
递归互斥锁,默认设置为该属性。在互斥锁设置为本类型属性情况下,允许同一个任务对互斥锁进行多次持有锁,持有锁次数和释放锁次数相同,其他任务才能持有该互斥锁。如果试图持有已经被其他任务持有的互斥锁,或者如果试图释放已经被释放的互斥锁,会返回错误码。
- LOS\_MUX\_ERRORCHECK
错误检测互斥锁,会自动检测死锁。在互斥锁设置为本类型属性情况下,如果任务试图对一个互斥锁重复持有,或者试图释放一个由别的任务持有的互斥锁,或者如果一个任务试图释放已经被释放的互斥锁,都会返回错误码。
## 运行机制<a name="section8547454201819"></a>
多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的,需要任务进行独占式处理。互斥锁怎样来避免这种冲突呢?
用互斥锁处理非共享资源的同步访问时,如果有任务访问该资源,则互斥锁为加锁状态。此时其他任务如果想访问这个公共资源则会被阻塞,直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性。
**图 1** 互斥锁运作示意图<a name="fig16821181173811"></a>
![](figure/互斥锁运作示意图-23.png "互斥锁运作示意图-23")
## 开发指导<a name="section2038861117194"></a>
### 接口说明<a name="section11168318131917"></a>
**表 1** 互斥锁模块接口
<a name="table37108292611"></a>
<table><thead align="left"><tr id="row8711112919610"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p3711102912617"><a name="p3711102912617"></a><a name="p3711102912617"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.31333133313331%" id="mcps1.2.4.1.2"><p id="p1671110293610"><a name="p1671110293610"></a><a name="p1671110293610"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.35333533353336%" id="mcps1.2.4.1.3"><p id="p87114292617"><a name="p87114292617"></a><a name="p87114292617"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row332716281313"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1795312108911"><a name="p1795312108911"></a><a name="p1795312108911"></a>初始化和销毁互斥锁</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1932716285312"><a name="p1932716285312"></a><a name="p1932716285312"></a>LOS_MuxInit</p>
</td>
<td class="cellrowborder" valign="top" width="33.35333533353336%" headers="mcps1.2.4.1.3 "><p id="p932762812319"><a name="p932762812319"></a><a name="p932762812319"></a>互斥锁初始化</p>
</td>
</tr>
<tr id="row37115291166"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p127613211335"><a name="p127613211335"></a><a name="p127613211335"></a>LOS_MuxDestroy</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p137111129965"><a name="p137111129965"></a><a name="p137111129965"></a>销毁指定的互斥锁</p>
</td>
</tr>
<tr id="row17711329268"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p18125182815396"><a name="p18125182815396"></a><a name="p18125182815396"></a>互斥锁的申请和释放</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p215615953415"><a name="p215615953415"></a><a name="p215615953415"></a>LOS_MuxLock</p>
</td>
<td class="cellrowborder" valign="top" width="33.35333533353336%" headers="mcps1.2.4.1.3 "><p id="p20994162353515"><a name="p20994162353515"></a><a name="p20994162353515"></a>申请指定的互斥锁</p>
</td>
</tr>
<tr id="row5711192912616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p7974187183520"><a name="p7974187183520"></a><a name="p7974187183520"></a>LOS_MuxTrylock</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1271110291969"><a name="p1271110291969"></a><a name="p1271110291969"></a>尝试申请指定的互斥锁,不阻塞</p>
</td>
</tr>
<tr id="row1571162918615"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p13021319143515"><a name="p13021319143515"></a><a name="p13021319143515"></a>LOS_MuxUnlock</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p107118291660"><a name="p107118291660"></a><a name="p107118291660"></a>释放指定的互斥锁</p>
</td>
</tr>
<tr id="row344193024114"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p16441730114110"><a name="p16441730114110"></a><a name="p16441730114110"></a>校验互斥锁</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1544183074110"><a name="p1544183074110"></a><a name="p1544183074110"></a>LOS_MuxIsValid</p>
</td>
<td class="cellrowborder" valign="top" width="33.35333533353336%" headers="mcps1.2.4.1.3 "><p id="p3441193017416"><a name="p3441193017416"></a><a name="p3441193017416"></a>判断互斥锁释放有效</p>
</td>
</tr>
<tr id="row1065116418421"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p2189182734211"><a name="p2189182734211"></a><a name="p2189182734211"></a>初始化和销毁互斥锁属性</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1565244144210"><a name="p1565244144210"></a><a name="p1565244144210"></a>LOS_MuxAttrInit</p>
</td>
<td class="cellrowborder" valign="top" width="33.35333533353336%" headers="mcps1.2.4.1.3 "><p id="p14652342426"><a name="p14652342426"></a><a name="p14652342426"></a>互斥锁属性初始化</p>
</td>
</tr>
<tr id="row538718619427"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p538756104217"><a name="p538756104217"></a><a name="p538756104217"></a>LOS_MuxAttrDestroy</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p23875654210"><a name="p23875654210"></a><a name="p23875654210"></a>销毁指定的互斥锁属性</p>
</td>
</tr>
<tr id="row8143848467"><td class="cellrowborder" rowspan="8" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p2926915154717"><a name="p2926915154717"></a><a name="p2926915154717"></a>设置和获取互斥锁属性</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p171441842465"><a name="p171441842465"></a><a name="p171441842465"></a>LOS_MuxAttrGetType</p>
</td>
<td class="cellrowborder" valign="top" width="33.35333533353336%" headers="mcps1.2.4.1.3 "><p id="p151444418461"><a name="p151444418461"></a><a name="p151444418461"></a>获取互斥锁类型属性</p>
</td>
</tr>
<tr id="row99314413464"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p793218404613"><a name="p793218404613"></a><a name="p793218404613"></a>LOS_MuxAttrSetType</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p51371843194813"><a name="p51371843194813"></a><a name="p51371843194813"></a>设置互斥锁类型属性</p>
</td>
</tr>
<tr id="row204470514615"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p13447115154614"><a name="p13447115154614"></a><a name="p13447115154614"></a>LOS_MuxAttrGetProtocol</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p20871044144720"><a name="p20871044144720"></a><a name="p20871044144720"></a>获取互斥锁协议属性</p>
</td>
</tr>
<tr id="row69051358465"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10906165124617"><a name="p10906165124617"></a><a name="p10906165124617"></a>LOS_MuxAttrSetProtocol</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1690617554610"><a name="p1690617554610"></a><a name="p1690617554610"></a>设置互斥锁协议属性</p>
</td>
</tr>
<tr id="row133571666467"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p6357146154616"><a name="p6357146154616"></a><a name="p6357146154616"></a>LOS_MuxAttrGetPrioceiling</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p559511469478"><a name="p559511469478"></a><a name="p559511469478"></a>获取互斥锁优先级上限属性</p>
</td>
</tr>
<tr id="row5789065465"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1778916634614"><a name="p1778916634614"></a><a name="p1778916634614"></a>LOS_MuxAttrSetPrioceiling</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p16789126134614"><a name="p16789126134614"></a><a name="p16789126134614"></a>设置互斥锁优先级上限属性</p>
</td>
</tr>
<tr id="row10251772469"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p199321752124718"><a name="p199321752124718"></a><a name="p199321752124718"></a>LOS_MuxGetPrioceiling</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1128349114718"><a name="p1128349114718"></a><a name="p1128349114718"></a>获取互斥锁优先级上限属性</p>
</td>
</tr>
<tr id="row197256714468"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p72518754614"><a name="p72518754614"></a><a name="p72518754614"></a>LOS_MuxSetPrioceiling</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p177254713460"><a name="p177254713460"></a><a name="p177254713460"></a>设置互斥锁优先级上限属性</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section4201191122116"></a>
互斥锁典型场景的开发流程:
1. 初始化互斥锁LOS\_MuxInit。
2. 申请互斥锁LOS\_MuxLock。
申请模式有三种:无阻塞模式、永久阻塞模式、定时阻塞模式。
- 无阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有任务持有,或者持有该互斥锁的任务和申请该互斥锁的任务为同一个任务,则申请成功;
- 永久阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则,该任务进入阻塞态,系统切换到就绪任务中优先级高者继续执行。任务进入阻塞态后,直到有其他任务释放该互斥锁,阻塞任务才会重新得以执行;
- 定时阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则该任务进入阻塞态,系统切换到就绪任务中优先级高者继续执行。任务进入阻塞态后,指定时间超时前有其他任务释放该互斥锁,或者用 户指定时间超时后,阻塞任务才会重新得以执行。
3. 释放互斥锁LOS\_MuxUnlock。
- 如果有任务阻塞于指定互斥锁,则唤醒被阻塞任务中优先级高的,该任务进入就绪态,并进行任务调度;
- 如果没有任务阻塞于指定互斥锁,则互斥锁释放成功。
4. 销毁互斥锁LOS\_MuxDestroy。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 两个任务不能对同一把互斥锁加锁。如果某任务对已被持有的互斥锁加锁,则该任务会被挂起,直到持有该锁的任务对互斥锁解锁,才能执行对这把互斥锁的加锁操作。
>- 互斥锁不能在中断服务程序中使用。
>- LiteOS-A内核作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁。
### 编程实例<a name="section10679328202117"></a>
**实例描述**
本实例实现如下流程:
1. 任务Example\_TaskEntry创建一个互斥锁,锁任务调度,创建两个任务Example\_MutexTask1、Example\_MutexTask2。Example\_MutexTask2优先级高于Example\_MutexTask1,解锁任务调度。
2. Example\_MutexTask2被调度,以永久阻塞模式申请互斥锁,并成功获取到该互斥锁,然后任务休眠100Tick,Example\_MutexTask2挂起,Example\_MutexTask1被唤醒。
3. Example\_MutexTask1以定时阻塞模式申请互斥锁,等待时间为10Tick,因互斥锁仍被Example\_MutexTask2持有,Example\_MutexTask1挂起。10Tick超时时间到达后,Example\_MutexTask1被唤醒,以永久阻塞模式申请互斥锁,因互斥锁仍被Example\_MutexTask2持有,Example\_MutexTask1挂起。
4. 100Tick休眠时间到达后,Example\_MutexTask2被唤醒, 释放互斥锁,唤醒Example\_MutexTask1。Example\_MutexTask1成功获取到互斥锁后,释放,删除互斥锁。
**示例代码**
示例代码如下:
```
#include <string.h>
#include "los_mux.h"
/* 互斥锁 */
LosMux g_testMux;
/* 任务ID */
UINT32 g_testTaskId01;
UINT32 g_testTaskId02;
VOID Example_MutexTask1(VOID)
{
UINT32 ret;
printf("task1 try to get mutex, wait 10 ticks.\n");
/* 申请互斥锁 */
ret = LOS_MuxLock(&g_testMux, 10);
if (ret == LOS_OK) {
printf("task1 get mutex g_testMux.\n");
/* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux);
return;
}
if (ret == LOS_ETIMEDOUT ) {
printf("task1 timeout and try to get mutex, wait forever.\n");
/* 申请互斥锁 */
ret = LOS_MuxLock(&g_testMux, LOS_WAIT_FOREVER);
if (ret == LOS_OK) {
printf("task1 wait forever, get mutex g_testMux.\n");
/* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux);
/* 删除互斥锁 */
LOS_MuxDestroy(&g_testMux);
printf("task1 post and delete mutex g_testMux.\n");
return;
}
}
return;
}
VOID Example_MutexTask2(VOID)
{
printf("task2 try to get mutex, wait forever.\n");
/* 申请互斥锁 */
(VOID)LOS_MuxLock(&g_testMux, LOS_WAIT_FOREVER);
printf("task2 get mutex g_testMux and suspend 100 ticks.\n");
/* 任务休眠100Ticks */
LOS_TaskDelay(100);
printf("task2 resumed and post the g_testMux\n");
/* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux);
return;
}
UINT32 Example_MutexEntry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S task1;
TSK_INIT_PARAM_S task2;
/* 初始化互斥锁 */
LOS_MuxInit(&g_testMux, NULL);
/* 锁任务调度 */
LOS_TaskLock();
/* 创建任务1 */
memset(&task1, 0, sizeof(TSK_INIT_PARAM_S));
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_MutexTask1;
task1.pcName = "MutexTsk1";
task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task1.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_testTaskId01, &task1);
if (ret != LOS_OK) {
printf("task1 create failed.\n");
return LOS_NOK;
}
/* 创建任务2 */
memset(&task2, 0, sizeof(TSK_INIT_PARAM_S));
task2.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_MutexTask2;
task2.pcName = "MutexTsk2";
task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task2.usTaskPrio = 4;
ret = LOS_TaskCreate(&g_testTaskId02, &task2);
if (ret != LOS_OK) {
printf("task2 create failed.\n");
return LOS_NOK;
}
/* 解锁任务调度 */
LOS_TaskUnlock();
return LOS_OK;
}
```
**结果验证**
编译运行得到的结果为:
```
task1 try to get mutex, wait 10 ticks.
task2 try to get mutex, wait forever.
task2 get mutex g_testMux and suspend 100 ticks.
task1 timeout and try to get mutex, wait forever.
task2 resumed and post the g_testMux
task1 wait forever, get mutex g_testMux.
task1 post and delete mutex g_testMux.
```
# 消息队列<a name="ZH-CN_TOPIC_0000001078912736"></a>
- [基本概念](#section81171363232)
- [运行机制](#section1074515132316)
- [队列控制块](#section194431851201315)
- [队列运作原理](#section89875741418)
- [开发指导](#section827981242419)
- [接口说明](#section19327151642413)
- [开发流程](#section1390154210243)
- [编程实例](#section27132341285)
- [实例描述](#section197311443141017)
- [编程示例](#section972214490107)
- [结果验证](#section19287165416106)
## 基本概念<a name="section81171363232"></a>
队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。
任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。
可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将都队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。
消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用,可以使用队列实现任务异步通信,队列具有如下特性:
- 消息以先进先出的方式排队,支持异步读写。
- 读队列和写队列都支持超时机制。
- 每读取一条消息,就会将该消息节点设置为空闲。
- 发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。
- 一个任务能够从任意一个消息队列接收和发送消息。
- 多个任务能够从同一个消息队列接收和发送消息。
- 创建队列时所需的队列空间,接口内系统自行动态申请内存。
## 运行机制<a name="section1074515132316"></a>
### 队列控制块<a name="section194431851201315"></a>
```
/**
* 队列控制块数据结构
*/
typedef struct {
UINT8 *queueHandle; /**< Pointer to a queue handle */
UINT16 queueState; /**< Queue state */
UINT16 queueLen; /**< Queue length */
UINT16 queueSize; /**< Node size */
UINT32 queueID; /**< queueID */
UINT16 queueHead; /**< Node head */
UINT16 queueTail; /**< Node tail */
UINT16 readWriteableCnt[OS_QUEUE_N_RW]; /**< Count of readable or writable resources, 0:readable, 1:writable */
LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist */
LOS_DL_LIST memList; /**< Pointer to the memory linked list */
} LosQueueCB;
```
每个队列控制块中都含有队列状态,表示该队列的使用情况:
- OS\_QUEUE\_UNUSED:队列未被使用。
- OS\_QUEUE\_INUSED:队列被使用中。
### 队列运作原理<a name="section89875741418"></a>
- 创建队列时,创建队列成功会返回队列ID。
- 在队列控制块中维护着一个消息头节点位置Head和一个消息尾节点位置Tail,用于表示当前队列中消息的存储情况。Head表示队列中被占用的消息节点的起始位置。Tail表示被占用的消息节点的结束位置,也是空闲消息节点的起始位置。队列刚创建时,Head和Tail均指向队列起始位置。
- 写队列时,根据readWriteableCnt\[1\]判断队列是否可以写入,不能对已满(readWriteableCnt\[1\]为0)队列进行写操作。写队列支持两种写入方式:向队列尾节点写入,也可以向队列头节点写入。尾节点写入时,根据Tail找到起始空闲消息节点作为数据写入对象,如果Tail已经指向队列尾部则采用回卷方式。头节点写入时,将Head的前一个节点作为数据写入对象,如果Head指向队列起始位置则采用回卷方式。
- 读队列时,根据readWriteableCnt\[0\]判断队列是否有消息需要读取,对全部空闲(readWriteableCnt\[0\]为0)队列进行读操作会引起任务挂起。如果队列可以读取消息,则根据Head找到最先写入队列的消息节点进行读取。如果Head已经指向队列尾部则采用回卷方式。
- 删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态,并释放队列所占内存。
图 1 队列读写数据操作示意图
![](figure/zh-cn_image_0000001132875772.png)
上图对读写队列做了示意,图中只画了尾节点写入方式,没有画头节点写入,但是两者是类似的。
## 开发指导<a name="section827981242419"></a>
### 接口说明<a name="section19327151642413"></a>
<a name="table10903105695114"></a>
<table><thead align="left"><tr id="row1293645645110"><th class="cellrowborder" valign="top" width="23.56%" id="mcps1.1.4.1.1"><p id="p59361562512"><a name="p59361562512"></a><a name="p59361562512"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="24.29%" id="mcps1.1.4.1.2"><p id="p1393665645118"><a name="p1393665645118"></a><a name="p1393665645118"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="52.15%" id="mcps1.1.4.1.3"><p id="p119363564516"><a name="p119363564516"></a><a name="p119363564516"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row1693665613516"><td class="cellrowborder" rowspan="2" valign="top" width="23.56%" headers="mcps1.1.4.1.1 "><p id="p193675615514"><a name="p193675615514"></a><a name="p193675615514"></a>创建/删除消息队列</p>
</td>
<td class="cellrowborder" valign="top" width="24.29%" headers="mcps1.1.4.1.2 "><p id="p11936115612514"><a name="p11936115612514"></a><a name="p11936115612514"></a>LOS_QueueCreate</p>
</td>
<td class="cellrowborder" valign="top" width="52.15%" headers="mcps1.1.4.1.3 "><p id="p1593620562517"><a name="p1593620562517"></a><a name="p1593620562517"></a>创建一个消息队列,由系统动态申请队列空间</p>
</td>
</tr>
<tr id="row79361156175113"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p893615567517"><a name="p893615567517"></a><a name="p893615567517"></a>LOS_QueueDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p4936155695111"><a name="p4936155695111"></a><a name="p4936155695111"></a>根据队列ID删除一个指定队列</p>
</td>
</tr>
<tr id="row093614566519"><td class="cellrowborder" rowspan="3" valign="top" width="23.56%" headers="mcps1.1.4.1.1 "><p id="p1593685614513"><a name="p1593685614513"></a><a name="p1593685614513"></a>读/写队列(不带拷贝)</p>
</td>
<td class="cellrowborder" valign="top" width="24.29%" headers="mcps1.1.4.1.2 "><p id="p6936556155118"><a name="p6936556155118"></a><a name="p6936556155118"></a>LOS_QueueRead</p>
</td>
<td class="cellrowborder" valign="top" width="52.15%" headers="mcps1.1.4.1.3 "><p id="p11936556155118"><a name="p11936556155118"></a><a name="p11936556155118"></a>读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址)</p>
</td>
</tr>
<tr id="row199369565518"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p393655620513"><a name="p393655620513"></a><a name="p393655620513"></a>LOS_QueueWrite</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p12936256175120"><a name="p12936256175120"></a><a name="p12936256175120"></a>向指定队列尾节点中写入入参bufferAddr的值(即buffer的地址)</p>
</td>
</tr>
<tr id="row1293615635114"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p893625665119"><a name="p893625665119"></a><a name="p893625665119"></a>LOS_QueueWriteHead</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p193620566515"><a name="p193620566515"></a><a name="p193620566515"></a>向指定队列头节点中写入入参bufferAddr的值(即buffer的地址)</p>
</td>
</tr>
<tr id="row593675635117"><td class="cellrowborder" rowspan="3" valign="top" width="23.56%" headers="mcps1.1.4.1.1 "><p id="p293675615111"><a name="p293675615111"></a><a name="p293675615111"></a>读/写队列(带拷贝)</p>
</td>
<td class="cellrowborder" valign="top" width="24.29%" headers="mcps1.1.4.1.2 "><p id="p14936356155113"><a name="p14936356155113"></a><a name="p14936356155113"></a>LOS_QueueReadCopy</p>
</td>
<td class="cellrowborder" valign="top" width="52.15%" headers="mcps1.1.4.1.3 "><p id="p11936155616510"><a name="p11936155616510"></a><a name="p11936155616510"></a>读取指定队列头节点中的数据</p>
</td>
</tr>
<tr id="row093619569510"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p179361256175117"><a name="p179361256175117"></a><a name="p179361256175117"></a>LOS_QueueWriteCopy</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p6936155616515"><a name="p6936155616515"></a><a name="p6936155616515"></a>向指定队列尾节点中写入入参bufferAddr中保存的数据</p>
</td>
</tr>
<tr id="row16936856185111"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p49361156195113"><a name="p49361156195113"></a><a name="p49361156195113"></a>LOS_QueueWriteHeadCopy</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p1193625675116"><a name="p1193625675116"></a><a name="p1193625675116"></a>向指定队列头节点中<em id="i1183903561620"><a name="i1183903561620"></a><a name="i1183903561620"></a>写入入参</em>bufferAddr中保存的数据</p>
</td>
</tr>
<tr id="row1936756155114"><td class="cellrowborder" valign="top" width="23.56%" headers="mcps1.1.4.1.1 "><p id="p149371956105114"><a name="p149371956105114"></a><a name="p149371956105114"></a>获取队列信息</p>
</td>
<td class="cellrowborder" valign="top" width="24.29%" headers="mcps1.1.4.1.2 "><p id="p7937145613516"><a name="p7937145613516"></a><a name="p7937145613516"></a>LOS_QueueInfoGet</p>
</td>
<td class="cellrowborder" valign="top" width="52.15%" headers="mcps1.1.4.1.3 "><p id="p19371356175110"><a name="p19371356175110"></a><a name="p19371356175110"></a>获取指定队列的信息,包括队列ID、队列长度、消息节点大小、头节点、尾节点、可读节点数量、可写节点数量、等待读操作的任务、等待写操作的任务</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section1390154210243"></a>
1. 用LOS\_QueueCreate创建队列。创建成功后,可以得到队列ID。
2. 通过LOS\_QueueWrite或者LOS\_QueueWriteCopy写队列。
3. 通过LOS\_QueueRead或者LOS\_QueueReadCopy读队列。
4. 通过LOS\_QueueInfoGet获取队列信息。
5. 通过LOS\_QueueDelete删除队列。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 系统支持的最大队列数是指:整个系统的队列资源总个数,而非用户能使用的个数。例如:系统软件定时器多占用一个队列资源,那么用户能使用的队列资源就会减少一个。
>- 创建队列时传入的队列名和flags暂时未使用,作为以后的预留参数。
>- 队列接口函数中的入参timeOut是相对时间。
>- LOS\_QueueReadCopy和LOS\_QueueWriteCopy及LOS\_QueueWriteHeadCopy是一组接口,LOS\_QueueRead和LOS\_QueueWrite及LOS\_QueueWriteHead是一组接口,每组接口需要配套使用。
>- 鉴于LOS\_QueueWrite和LOS\_QueueWriteHead和LOS\_QueueRead这组接口实际操作的是数据地址,用户必须保证调用LOS\_QueueRead获取到的指针所指向的内存区域在读队列期间没有被异常修改或释放,否则可能导致不可预知的后果。
>- 鉴于LOS\_QueueWrite和LOS\_QueueWriteHead和LOS\_QueueRead这组接口实际操作的是数据地址,也就意味着实际写和读的消息长度仅仅是一个指针数据,因此用户使用这组接口之前,需确保创建队列时的消息节点大小,为一个指针的长度,避免不必要的浪费和读取失败。
## 编程实例<a name="section27132341285"></a>
### 实例描述<a name="section197311443141017"></a>
创建一个队列,两个任务。任务1调用写队列接口发送消息,任务2通过读队列接口接收消息。
1. 通过LOS\_TaskCreate创建任务1和任务2。
2. 通过LOS\_QueueCreate创建一个消息队列。
3. 在任务1 SendEntry中发送消息。
4. 在任务2 RecvEntry中接收消息。
5. 通过LOS\_QueueDelete删除队列。
### 编程示例<a name="section972214490107"></a>
示例代码如下:
```
#include "los_task.h"
#include "los_queue.h"
static UINT32 g_queue;
#define BUFFER_LEN 50
VOID SendEntry(VOID)
{
UINT32 ret = 0;
CHAR abuf[] = "test message";
UINT32 len = sizeof(abuf);
ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0);
if(ret != LOS_OK) {
printf("send message failure, error: %x\n", ret);
}
}
VOID RecvEntry(VOID)
{
UINT32 ret = 0;
CHAR readBuf[BUFFER_LEN] = {0};
UINT32 readLen = BUFFER_LEN;
//休眠1s
usleep(1000000);
ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0);
if(ret != LOS_OK) {
printf("recv message failure, error: %x\n", ret);
}
printf("recv message: %s\n", readBuf);
ret = LOS_QueueDelete(g_queue);
if(ret != LOS_OK) {
printf("delete the queue failure, error: %x\n", ret);
}
printf("delete the queue success!\n");
}
UINT32 ExampleQueue(VOID)
{
printf("start queue example\n");
UINT32 ret = 0;
UINT32 task1, task2;
TSK_INIT_PARAM_S initParam = {0};
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry;
initParam.usTaskPrio = 9;
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
initParam.pcName = "SendQueue";
LOS_TaskLock();
ret = LOS_TaskCreate(&task1, &initParam);
if(ret != LOS_OK) {
printf("create task1 failed, error: %x\n", ret);
return ret;
}
initParam.pcName = "RecvQueue";
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry;
ret = LOS_TaskCreate(&task2, &initParam);
if(ret != LOS_OK) {
printf("create task2 failed, error: %x\n", 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();
return ret;
}
```
### 结果验证<a name="section19287165416106"></a>
编译运行得到的结果为:
```
start test example
create the queue success!
recv message: test message
delete the queue success!
```
# 读写锁<a name="ZH-CN_TOPIC_0000001078912738"></a>
- [基本概念](#section4692105214260)
- [运行机制](#section1239111562720)
- [开发指导](#section11643194275)
- [接口说明](#section15335332122717)
- [开发流程](#section14774114882714)
## 基本概念<a name="section4692105214260"></a>
读写锁与互斥锁类似,可用来同步同一进程中的各个任务,但与互斥锁不同的是,其允许多个读操作并发重入,而写操作互斥。
相对于互斥锁的开锁或闭锁状态,读写锁有三种状态:读模式下的锁,写模式下的锁,无锁。
读写锁的使用规则:
- 保护区无写模式下的锁,任何任务均可以为其增加读模式下的锁。
- 保护区处于无锁状态下,才可增加写模式下的锁。
多任务环境下往往存在多个任务访问同一共享资源的应用场景,读模式下的锁以共享状态对保护区访问,而写模式下的锁可被用于对共享资源的保护从而实现独占式访问。
这种共享-独占的方式非常适合多任务中读数据频率远大于写数据频率的应用中,提高应用多任务并发度。
## 运行机制<a name="section1239111562720"></a>
相较于互斥锁,读写锁如何实现读模式下的锁及写模式下的锁来控制多任务的读写访问呢?
- 若A任务首次获取了写模式下的锁,有其他任务来获取或尝试获取读模式下的锁,均无法再上锁。
- 若A任务获取了读模式下的锁,当有任务来获取或尝试获取读模式下的锁时,读写锁计数均加一。
## 开发指导<a name="section11643194275"></a>
### 接口说明<a name="section15335332122717"></a>
**表 1** 读写锁模块接口
<a name="table37108292611"></a>
<table><thead align="left"><tr id="row8711112919610"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p3711102912617"><a name="p3711102912617"></a><a name="p3711102912617"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p1671110293610"><a name="p1671110293610"></a><a name="p1671110293610"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p87114292617"><a name="p87114292617"></a><a name="p87114292617"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row37115291166"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1795312108911"><a name="p1795312108911"></a><a name="p1795312108911"></a>读写锁的创建和删除</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1671120293611"><a name="p1671120293611"></a><a name="p1671120293611"></a>LOS_RwlockInit</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p171112291967"><a name="p171112291967"></a><a name="p171112291967"></a>创建读写锁</p>
</td>
</tr>
<tr id="row17711329268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p071114291864"><a name="p071114291864"></a><a name="p071114291864"></a>LOS_RwlockDestroy</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p137111129965"><a name="p137111129965"></a><a name="p137111129965"></a>删除指定的读写锁</p>
</td>
</tr>
<tr id="row5711192912616"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p86087143910"><a name="p86087143910"></a><a name="p86087143910"></a>读模式下的锁的申请</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1171112295614"><a name="p1171112295614"></a><a name="p1171112295614"></a>LOS_RwlockRdLock</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1271110291969"><a name="p1271110291969"></a><a name="p1271110291969"></a>申请指定的读模式下的锁</p>
</td>
</tr>
<tr id="row1571162918615"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1564192618292"><a name="p1564192618292"></a><a name="p1564192618292"></a>LOS_RwlockTryRdLock</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p107118291660"><a name="p107118291660"></a><a name="p107118291660"></a>尝试申请指定的读模式下的锁</p>
</td>
</tr>
<tr id="row189551130172817"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p7951153082815"><a name="p7951153082815"></a><a name="p7951153082815"></a>写模式下的锁的申请</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p111591404308"><a name="p111591404308"></a><a name="p111591404308"></a>LOS_RwlockWrLock</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p11951183013281"><a name="p11951183013281"></a><a name="p11951183013281"></a>申请指定的写模式下的锁</p>
</td>
</tr>
<tr id="row199551530122820"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p32171573014"><a name="p32171573014"></a><a name="p32171573014"></a>LOS_RwlockTryWrLock</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p5951123092819"><a name="p5951123092819"></a><a name="p5951123092819"></a>尝试申请指定的写模式下的锁</p>
</td>
</tr>
<tr id="row1642820328301"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1542823210305"><a name="p1542823210305"></a><a name="p1542823210305"></a>读写锁的释放</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p174281324308"><a name="p174281324308"></a><a name="p174281324308"></a>LOS_RwlockUnLock</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1342810327309"><a name="p1342810327309"></a><a name="p1342810327309"></a>释放指定读写锁</p>
</td>
</tr>
<tr id="row11318134133111"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p73182345312"><a name="p73182345312"></a><a name="p73182345312"></a>读写锁有效性判断</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1031813416318"><a name="p1031813416318"></a><a name="p1031813416318"></a>LOS_RwlockIsValid</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p43187342311"><a name="p43187342311"></a><a name="p43187342311"></a>判断读写锁有效性</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section14774114882714"></a>
读写锁典型场景的开发流程:
1. 创建读写锁LOS\_RwlockInit。
2. 申请读模式下的锁LOS\_RwlockRdLock或写模式下的锁LOS\_RwlockWrLock。
申请读模式下的锁:
- 若无人持有锁,读任务可获得锁。
- 若有人持有锁,读任务可获得锁,读取顺序按照任务优先级。
- 若有人(非自己)持有写模式下的锁,则当前任务无法获得锁,直到写模式下的锁释放。
申请写模式下的锁:
- 若该锁当前没有任务持有,或者持有该读模式下的锁的任务和申请该锁的任务为同一个任务,则申请成功,可立即获得写模式下的锁。
- 若该锁当前已经存在读模式下的锁,且读取任务优先级较高,则当前任务挂起,直到读模式下的锁释放。
3.申请读模式下的锁和写模式下的锁均有三种:无阻塞模式、永久阻塞模式、定时阻塞模式,区别在于挂起任务的时间。
4.释放读写锁LOS\_RwlockUnLock。
- 如果有任务阻塞于指定读写锁,则唤醒被阻塞任务中优先级高的,该任务进入就绪态,并进行任务调度;
- 如果没有任务阻塞于指定读写锁,则读写锁释放成功。
5. 删除读写锁LOS\_RwlockDestroy。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 读写锁不能在中断服务程序中使用。
>- LiteOS-A内核作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得读写锁之后,应该尽快释放该锁。
>- 持有读写锁的过程中,不得再调用LOS\_TaskPriSet等接口更改持有读写锁任务的优先级
# 信号量<a name="ZH-CN_TOPIC_0000001078912740"></a>
- [基本概念](#section1577111168131)
- [运行机制](#section118423019134)
- [开发指导](#section01419503131)
- [接口说明](#section1232345431312)
- [开发流程](#section154261711141419)
- [编程实例](#section658135571417)
- [实例描述](#section125244411653)
- [编程示例](#section1742105514512)
- [结果验证](#section11297301617)
## 基本概念<a name="section1577111168131"></a>
信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。
一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数,其值的含义分两种情况:
- 0,表示该信号量当前不可获取,因此可能存在正在等待该信号量的任务。
- 正值,表示该信号量当前可被获取。
以同步为目的的信号量和以互斥为目的的信号量在使用上有如下不同:
- 用作互斥时,初始信号量计数值不为0,表示可用的共享资源个数。在需要使用共享资源前,先获取信号量,然后使用一个共享资源,使用完毕后释放信号量。这样在共享资源被取完,即信号量计数减至0时,其他需要获取信号量的任务将被阻塞,从而保证了共享资源的互斥访问。另外,当共享资源数为1时,建议使用二值信号量,一种类似于互斥锁的机制。
- 用作同步时,初始信号量计数值为0。任务1获取信号量而阻塞,直到任务2或者某中断释放信号量,任务1才得以进入Ready或Running态,从而达到了任务间的同步。
## 运行机制<a name="section118423019134"></a>
**信号量控制块**
```
/**
* 信号量控制块数据结构
*/
typedef struct {
UINT16 semStat; /* 信号量状态 */
UINT16 semType; /* 信号量类型 */
UINT16 semCount; /* 信号量计数 */
UINT16 semId; /* 信号量索引号 */
LOS_DL_LIST semList; /* 挂接阻塞于该信号量的任务 */
} LosSemCB;
```
**信号量运作原理**
信号量允许多个任务在同一时刻访问共享资源,但会限制同一时刻访问此资源的最大任务数目。当访问资源的任务数达到该资源允许的最大数量时,会阻塞其他试图获取该资源的任务,直到有任务释放该信号量。
- 信号量初始化
初始化时为配置的N个信号量申请内存(N值可以由用户自行配置,通过LOSCFG\_BASE\_IPC\_SEM\_LIMIT宏实现),并把所有信号量初始化成未使用,加入到未使用链表中供系统使用
- 信号量创建
从未使用的信号量链表中获取一个信号量,并设定初值。
- 信号量申请
若其计数器值大于0,则直接减1返回成功。否则任务阻塞,等待其它任务释放该信号量,等待的超时时间可设定。当任务被一个信号量阻塞时,将该任务挂到信号量等待任务队列的队尾。
- 信号量释放
若没有任务等待该信号量,则直接将计数器加1返回。否则唤醒该信号量等待任务队列上的第一个任务。
- 信号量删除
将正在使用的信号量置为未使用信号量,并挂回到未使用链表。
运行示意图如下图所示:
**图 1** 信号量运作示意图<a name="fig467314634214"></a>
![](figure/信号量运作示意图-22.png "信号量运作示意图-22")
## 开发指导<a name="section01419503131"></a>
### 接口说明<a name="section1232345431312"></a>
**表 1** 信号量模块接口
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row0415737175610"><td class="cellrowborder" rowspan="3" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p8866127195914"><a name="p8866127195914"></a><a name="p8866127195914"></a>创建/删除信号量</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p58621910185914"><a name="p58621910185914"></a><a name="p58621910185914"></a>LOS_SemCreate</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p48623102592"><a name="p48623102592"></a><a name="p48623102592"></a>创建信号量,返回信号量ID</p>
</td>
</tr>
<tr id="row1213865218584"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20862510115911"><a name="p20862510115911"></a><a name="p20862510115911"></a>LOS_BinarySemCreate</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1886211011599"><a name="p1886211011599"></a><a name="p1886211011599"></a>创建二值信号量,其计数值最大为1</p>
</td>
</tr>
<tr id="row3231257145813"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p38621410205919"><a name="p38621410205919"></a><a name="p38621410205919"></a>LOS_SemDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p586261085913"><a name="p586261085913"></a><a name="p586261085913"></a>删除指定的信号量</p>
</td>
</tr>
<tr id="row73651459105815"><td class="cellrowborder" rowspan="2" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p16927183515593"><a name="p16927183515593"></a><a name="p16927183515593"></a>申请/释放信号量</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p955271555916"><a name="p955271555916"></a><a name="p955271555916"></a>LOS_SemPend</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p555221518598"><a name="p555221518598"></a><a name="p555221518598"></a>申请指定的信号量,并设置超时时间</p>
</td>
</tr>
<tr id="row178321454145812"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17552101519596"><a name="p17552101519596"></a><a name="p17552101519596"></a>LOS_SemPost</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1555261595915"><a name="p1555261595915"></a><a name="p1555261595915"></a>释放指定的信号量</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section154261711141419"></a>
1. 创建信号量LOS\_SemCreate,若要创建二值信号量则调用LOS\_BinarySemCreate。
2. 申请信号量LOS\_SemPend。
3. 释放信号量LOS\_SemPost。
4. 删除信号量LOS\_SemDelete。
>![](../public_sys-resources/icon-note.gif) **说明:**
>由于中断不能被阻塞,因此不能在中断中使用阻塞模式申请信号量。
### 编程实例<a name="section658135571417"></a>
### 实例描述<a name="section125244411653"></a>
本实例实现如下功能:
1. 测试任务ExampleSem创建一个信号量,锁任务调度,创建两个任务ExampleSemTask1、ExampleSemTask2, ExampleSemTask2优先级高于ExampleSemTask1,两个任务中申请同一信号量,解锁任务调度后两任务阻塞,测试任务ExampleSem释放信号量。
2. ExampleSemTask2得到信号量,被调度,然后任务休眠20Tick,ExampleSemTask2延迟,ExampleSemTask1被唤醒。
3. ExampleSemTask1定时阻塞模式申请信号量,等待时间为10Tick,因信号量仍被ExampleSemTask2持有,ExampleSemTask1挂起,10Tick后仍未得到信号量,ExampleSemTask1被唤醒,试图以永久阻塞模式申请信号量,ExampleSemTask1挂起。
4. 20Tick后ExampleSemTask2唤醒, 释放信号量后,ExampleSemTask1得到信号量被调度运行,最后释放信号量。
5. ExampleSemTask1执行完,40Tick后任务ExampleSem被唤醒,执行删除信号量。
### 编程示例<a name="section1742105514512"></a>
示例代码如下:
```
#include "los_sem.h"
#include "securec.h"
/* 任务ID */
static UINT32 g_testTaskId01;
static UINT32 g_testTaskId02;
/* 测试任务优先级 */
#define TASK_PRIO_TEST 5
/* 信号量结构体id */
static UINT32 g_semId;
VOID ExampleSemTask1(VOID)
{
UINT32 ret;
printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
/* 定时阻塞模式申请信号量,定时时间为10ticks */
ret = LOS_SemPend(g_semId, 10);
/* 申请到信号量 */
if (ret == LOS_OK) {
LOS_SemPost(g_semId);
return;
}
/* 定时时间到,未申请到信号量 */
if (ret == LOS_ERRNO_SEM_TIMEOUT) {
printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
/*永久阻塞模式申请信号量*/
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
printf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
if (ret == LOS_OK) {
LOS_SemPost(g_semId);
return;
}
}
}
VOID ExampleSemTask2(VOID)
{
UINT32 ret;
printf("ExampleSemTask2 try get sem g_semId wait forever.\n");
/* 永久阻塞模式申请信号量 */
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
if (ret == LOS_OK) {
printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
}
/* 任务休眠20 ticks */
LOS_TaskDelay(20);
printf("ExampleSemTask2 post sem g_semId.\n");
/* 释放信号量 */
LOS_SemPost(g_semId);
return;
}
UINT32 ExampleSem(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S task1;
TSK_INIT_PARAM_S task2;
/* 创建信号量 */
LOS_SemCreate(0, &g_semId);
/* 锁任务调度 */
LOS_TaskLock();
/* 创建任务1 */
(VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1;
task1.pcName = "TestTask1";
task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task1.usTaskPrio = TASK_PRIO_TEST;
ret = LOS_TaskCreate(&g_testTaskId01, &task1);
if (ret != LOS_OK) {
printf("task1 create failed .\n");
return LOS_NOK;
}
/* 创建任务2 */
(VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2;
task2.pcName = "TestTask2";
task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task2.usTaskPrio = (TASK_PRIO_TEST - 1);
ret = LOS_TaskCreate(&g_testTaskId02, &task2);
if (ret != LOS_OK) {
printf("task2 create failed.\n");
return LOS_NOK;
}
/* 解锁任务调度 */
LOS_TaskUnlock();
ret = LOS_SemPost(g_semId);
/* 任务休眠400 ticks */
LOS_TaskDelay(400);
/* 删除信号量 */
LOS_SemDelete(g_semId);
return LOS_OK;
}
```
### 结果验证<a name="section11297301617"></a>
编译运行得到的结果为:
```
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 timeout and try get sem g_semId wait forever.
ExampleSemTask2 post sem g_semId.
ExampleSemTask1 wait_forever and get sem g_semId.
```
# 用户态快速互斥锁<a name="ZH-CN_TOPIC_0000001078912732"></a>
- [基本概念](#section643519912920)
- [运行机制](#section16834132502910)
## 基本概念<a name="section643519912920"></a>
Futex\(Fast userspace mutex,用户态快速互斥锁\)是内核提供的一种系统调用能力,通常作为基础组件与用户态的相关锁逻辑结合组成用户态锁,是一种用户态与内核态共同作用的锁,例如用户态mutex锁、barrier与cond同步锁、读写锁。其用户态部分负责锁逻辑,内核态部分负责锁调度。
当用户态线程请求锁时,先在用户态进行锁状态的判断维护,若此时不产生锁的竞争,则直接在用户态进行上锁返回;反之,则需要进行线程的挂起操作,通过Futex系统调用请求内核介入来挂起线程,并维护阻塞队列。
当用户态线程释放锁时,先在用户态进行锁状态的判断维护,若此时没有其他线程被该锁阻塞,则直接在用户态进行解锁返回;反之,则需要进行阻塞线程的唤醒操作,通过Futex系统调用请求内核介入来唤醒阻塞队列中的线程。
## 运行机制<a name="section16834132502910"></a>
当用户态产生锁的竞争或释放需要进行相关线程的调度操作时,会触发Futex系统调用进入内核,此时会将用户态锁的地址传入内核,并在内核的Futex中以锁地址来区分用户态的每一把锁,因为用户态可用虚拟地址空间为1GiB,为了便于查找、管理,内核Futex采用哈希桶来存放用户态传入的锁。
当前哈希桶共有80个,0\~63号桶用于存放私有锁(以虚拟地址进行哈希),64\~79号桶用于存放共享锁(以物理地址进行哈希),私有/共享属性通过用户态锁的初始化以及Futex系统调用入参确定。
**图 1** Futex设计图<a name="fig651353710598"></a>
![](figure/Futex设计图.jpg "Futex设计图")
如图1,每个futex哈希桶中存放被futex\_list串联起来的哈希值相同的futex node,每个futex node对应一个被挂起的task,node中key值唯一标识一把用户态锁,具有相同key值的node被queue\_list串联起来表示被同一把锁阻塞的task队列。
Futex有以下三种操作:
**表 1** Futex模块接口
<a name="table1316220185211"></a>
<table><thead align="left"><tr id="row191622182021"><th class="cellrowborder" valign="top" width="27.09270927092709%" id="mcps1.2.4.1.1"><p id="p13162121815218"><a name="p13162121815218"></a><a name="p13162121815218"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="26.52265226522652%" id="mcps1.2.4.1.2"><p id="p12162618623"><a name="p12162618623"></a><a name="p12162618623"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="46.384638463846386%" id="mcps1.2.4.1.3"><p id="p16162118427"><a name="p16162118427"></a><a name="p16162118427"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row04981218910"><td class="cellrowborder" valign="top" width="27.09270927092709%" headers="mcps1.2.4.1.1 "><p id="p6462616696"><a name="p6462616696"></a><a name="p6462616696"></a>设置线程等待</p>
</td>
<td class="cellrowborder" valign="top" width="26.52265226522652%" headers="mcps1.2.4.1.2 "><p id="p164931214913"><a name="p164931214913"></a><a name="p164931214913"></a>OsFutexWait</p>
</td>
<td class="cellrowborder" valign="top" width="46.384638463846386%" headers="mcps1.2.4.1.3 "><p id="p8504121996"><a name="p8504121996"></a><a name="p8504121996"></a>向Futex表中插入代表被阻塞的线程的node</p>
</td>
</tr>
<tr id="row7162101814216"><td class="cellrowborder" valign="top" width="27.09270927092709%" headers="mcps1.2.4.1.1 "><p id="p37331032985"><a name="p37331032985"></a><a name="p37331032985"></a>唤醒被阻塞线程</p>
</td>
<td class="cellrowborder" valign="top" width="26.52265226522652%" headers="mcps1.2.4.1.2 "><p id="p816311185217"><a name="p816311185217"></a><a name="p816311185217"></a>OsFutexWake</p>
</td>
<td class="cellrowborder" valign="top" width="46.384638463846386%" headers="mcps1.2.4.1.3 "><p id="p161632181721"><a name="p161632181721"></a><a name="p161632181721"></a>唤醒一个被指定锁阻塞的线程</p>
</td>
</tr>
<tr id="row101631818620"><td class="cellrowborder" valign="top" width="27.09270927092709%" headers="mcps1.2.4.1.1 "><p id="p146111936887"><a name="p146111936887"></a><a name="p146111936887"></a>调整锁的地址</p>
</td>
<td class="cellrowborder" valign="top" width="26.52265226522652%" headers="mcps1.2.4.1.2 "><p id="p71633181125"><a name="p71633181125"></a><a name="p71633181125"></a>OsFutexRequeue</p>
</td>
<td class="cellrowborder" valign="top" width="46.384638463846386%" headers="mcps1.2.4.1.3 "><p id="p151631718124"><a name="p151631718124"></a><a name="p151631718124"></a>调整指定锁在Futex表中的位置</p>
</td>
</tr>
</tbody>
</table>
>![](../public_sys-resources/icon-note.gif) **说明:**
>Futex系统调用通常与用户态逻辑共同组成用户态锁,故推荐使用用户态POSIX接口的锁。
# 信号<a name="ZH-CN_TOPIC_0000001078912742"></a>
- [基本概念](#section172788254307)
- [运行机制](#section1249693812301)
## 基本概念<a name="section172788254307"></a>
信号\(signal\)是一种常用的进程间异步通信机制,用软件的方式模拟中断信号,当一个进程需要传递信息给另一个进程时,则会发送一个信号给内核,再由内核将信号传递至指定进程,而指定进程不必进行等待信号的动作。
## 运行机制<a name="section1249693812301"></a>
信号的运作流程分为三个部分,如表1:
**表 1** 信号的运作流程及相关接口(用户态接口)
<a name="table1316220185211"></a>
<table><thead align="left"><tr id="row191622182021"><th class="cellrowborder" valign="top" width="27.09270927092709%" id="mcps1.2.4.1.1"><p id="p13162121815218"><a name="p13162121815218"></a><a name="p13162121815218"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="26.49264926492649%" id="mcps1.2.4.1.2"><p id="p12162618623"><a name="p12162618623"></a><a name="p12162618623"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="46.41464146414641%" id="mcps1.2.4.1.3"><p id="p16162118427"><a name="p16162118427"></a><a name="p16162118427"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row04981218910"><td class="cellrowborder" rowspan="2" valign="top" width="27.09270927092709%" headers="mcps1.2.4.1.1 "><p id="p6462616696"><a name="p6462616696"></a><a name="p6462616696"></a>注册信号回调函数</p>
</td>
<td class="cellrowborder" valign="top" width="26.49264926492649%" headers="mcps1.2.4.1.2 "><p id="p164931214913"><a name="p164931214913"></a><a name="p164931214913"></a>signal</p>
</td>
<td class="cellrowborder" valign="top" width="46.41464146414641%" headers="mcps1.2.4.1.3 "><p id="p8504121996"><a name="p8504121996"></a><a name="p8504121996"></a>注册系统总入口及注册和去注册某信号的回调函数。</p>
</td>
</tr>
<tr id="row5449183942119"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p5450153922110"><a name="p5450153922110"></a><a name="p5450153922110"></a>sigaction</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1945083962113"><a name="p1945083962113"></a><a name="p1945083962113"></a>仅支持SIGINFO的选项。</p>
</td>
</tr>
<tr id="row7162101814216"><td class="cellrowborder" rowspan="5" valign="top" width="27.09270927092709%" headers="mcps1.2.4.1.1 "><p id="p37331032985"><a name="p37331032985"></a><a name="p37331032985"></a>发送信号</p>
</td>
<td class="cellrowborder" valign="top" width="26.49264926492649%" headers="mcps1.2.4.1.2 "><p id="p816311185217"><a name="p816311185217"></a><a name="p816311185217"></a>kill</p>
</td>
<td class="cellrowborder" rowspan="5" align="left" valign="top" width="46.41464146414641%" headers="mcps1.2.4.1.3 "><p id="p161632181721"><a name="p161632181721"></a><a name="p161632181721"></a>发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。</p>
</td>
</tr>
<tr id="row129182420243"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p149191745248"><a name="p149191745248"></a><a name="p149191745248"></a>pthread_kill</p>
</td>
</tr>
<tr id="row1026214719240"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1226313762411"><a name="p1226313762411"></a><a name="p1226313762411"></a>raise</p>
</td>
</tr>
<tr id="row05632094242"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p45643914245"><a name="p45643914245"></a><a name="p45643914245"></a>alarm</p>
</td>
</tr>
<tr id="row3241512122417"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p324211202414"><a name="p324211202414"></a><a name="p324211202414"></a>abort</p>
</td>
</tr>
<tr id="row101631818620"><td class="cellrowborder" valign="top" width="27.09270927092709%" headers="mcps1.2.4.1.1 "><p id="p146111936887"><a name="p146111936887"></a><a name="p146111936887"></a>触发回调</p>
</td>
<td class="cellrowborder" valign="top" width="26.49264926492649%" headers="mcps1.2.4.1.2 "><p id="p71633181125"><a name="p71633181125"></a><a name="p71633181125"></a></p>
</td>
<td class="cellrowborder" valign="top" width="46.41464146414641%" headers="mcps1.2.4.1.3 "><p id="p1126941694213"><a name="p1126941694213"></a><a name="p1126941694213"></a>由系统调用与中断触发,内核态与用户态切换前会先进入用户态指定函数并处理完相应回调函数,再回到原用户态程序继续运行。</p>
</td>
</tr>
</tbody>
</table>
>![](../public_sys-resources/icon-note.gif) **说明:**
>信号机制为提供给用户态程序进程间通信的能力,故推荐使用上表1列出的用户态POSIX相关接口。
>注册回调函数:
>```
>void *signal(int sig, void (*func)(int))(int);
>```
>a. 31 号信号,会注册该进程的回调函数处理入口,不可重入。
>b. 0-30 号信号,判断注册回调函数,注册与去注册回调函数。
>```
>int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict);
>```
>仅支持SIGINFO的选项,SIGINFO内容见sigtimedwait接口内描述。
>发送信号:
>a. 信号的默认行为不支持STOP及COTINUE,无COREDUMP功能。
>b. 不能屏蔽SIGSTOP、SIGKILL、SIGCONT。
>c. 杀死进程后,若父进程不回收,会产生僵尸进程。
>d. 异步信号,发送信号给某进程后,直到该进程被调度后才会执行信号回调(为安全起见,杀死进程的动作是进程自己执行的,内核不能通过信号强制杀死对方)。
>e. 进程消亡会发送SIGCHLD给父进程,发送动作无法取消。
>f. 无法通过信号唤醒正在DELAY状态的进程。触发调度需要usleep\(10000\)即10ms才能完成进程调度转让。
# 内核通信机制<a name="ZH-CN_TOPIC_0000001123795189"></a>
- **[事件](kernel-small-basic-trans-event.md)**
- **[信号量](kernel-small-basic-trans-semaphore.md)**
- **[互斥锁](kernel-small-basic-trans-mutex.md)**
- **[消息队列](kernel-small-basic-trans-queue.md)**
- **[读写锁](kernel-small-basic-trans-rwlock.md)**
- **[用户态快速互斥锁](kernel-small-basic-trans-user-mutex.md)**
- **[信号](kernel-small-basic-trans-user-signal.md)**
# 基础内核<a name="ZH-CN_TOPIC_0000001123091601"></a>
- **[中断及异常处理](kernel-small-basic-interrupt.md)**
- **[进程管理](kernel-small-basic-process.md)**
- **[内存管理](kernel-small-basic-memory.md)**
- **[内核通信机制](kernel-small-basic-trans.md)**
- **[时间管理](kernel-small-basic-time.md)**
- **[软件定时器](kernel-small-basic-softtimer.md)**
- **[原子操作](kernel-small-basic-atomic.md)**
# 适配新的文件系统<a name="ZH-CN_TOPIC_0000001078936814"></a>
- [基本概念](#section19480121811422)
- [适配Mount接口](#section147051940104212)
- [适配Lookup接口](#section11930181394317)
- [适配总结和注意事项](#section5617183014319)
## 基本概念<a name="section19480121811422"></a>
所谓对接VFS层,其实就是指实现VFS层定义的若干接口函数,可根据文件系统的特点和需要适配其中部分接口。一般情况下,支持文件读写,最小的文件系统适配看起来是这样的:
```
struct MountOps g_yourFsMountOps = {
.Mount = YourMountMethod,
};
struct file_operations_vfs g_yourFsFileOps = {
.read = YourReadMethod,
.write = YourWriteMethod,
}
struct VnodeOps g_yourFsVnodeOps = {
.Create = YourCreateMethod;
.Lookup = YourLookupMethod;
.Reclaim = YourReclaimMethod;
};
FSMAP_ENTRY(yourfs_fsmap, "your fs name", g_yourFsMountOps, TRUE, TRUE); // 注册文件系统
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>1. open和close接口不是必须要实现的接口,因为这两个接口是对文件的操作,对下层的文件系统一般是不感知的,只有当要适配的文件系统需要在open和close时做一些特别的操作时,才需要实现。
>2. 适配文件系统,对基础知识的要求较高,适配者需要对要适配的文件系统的原理和实现具有深刻的理解,本节中不会事无巨细地介绍相关的基础知识,如果您在适配的过程中遇到疑问,建议参考kernel/liteos\_a/fs目录下已经适配好的文件系统的代码,可能就会豁然开朗。
## 适配Mount接口<a name="section147051940104212"></a>
Mount是文件系统第一个被调用的接口,该接口一般会读取驱动的参数,根据配置对文件系统的进行初始化,最后生成文件系统的root节点。Mount接口的定义如下:
```
int (*Mount)(struct Mount *mount, struct Vnode *blkDriver, const void *data);
```
其中,第一个参数struct Mount \*mount是Mount点的信息,适配时需要填写的是下面的变量:
```
struct Mount {
const struct MountOps *ops; /* Mount相关的函数钩子 */
struct Vnode *vnodeCovered; /* Mount之后的文件系统root节点 */
void *data; /* Mount点的私有数据 */
};
```
第二个参数struct Vnode \*blkDriver是驱动节点,可以通过这个节点访问驱动。
第三个参数const void \*data是mount命令传入的数据,可以根据文件系统的需要处理。
下面以JFFS2为例,详细看一下mount接口是如何适配的:
```
int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
{
int ret;
int partNo;
mtd_partition *p = NULL;
struct MtdDev *mtd = NULL;
struct Vnode *pv = NULL;
struct jffs2_inode *rootNode = NULL;
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
/* 首先是从驱动节点中获取文件系统需要的信息,例如jffs2读取的是分区的编号 */
p = (mtd_partition *)((struct drv_data *)blkDriver->data)->priv;
mtd = (struct MtdDev *)(p->mtd_info);
if (mtd == NULL || mtd->type != MTD_NORFLASH) {
LOS_MuxUnlock(&g_jffs2FsLock);
return -EINVAL;
}
partNo = p->patitionnum;
/* 然后生成一个文件系统的根Vnode,这里注意不要搞混rootNode和根Vnode,rootNode类型是inode,是jffs2内部维护的私有数据,而Vnode是VFS的概念,是通用的文件节点,
这一步实际上就是把文件系统内部的私有信息保存到Vnode中,这样就可以通过Vnode直接找到文件系统中的对应文件。
*/
ret = jffs2_mount(partNo, &rootNode);
if (ret != 0) {
LOS_MuxUnlock(&g_jffs2FsLock);
return ret;
}
ret = VnodeAlloc(&g_jffs2Vops, &pv);
if (ret != 0) {
LOS_MuxUnlock(&g_jffs2FsLock);
goto ERROR_WITH_VNODE;
}
/* 下面这段填写的是关于这个Vnode对应文件的相关信息,uid\gid\mode这部分信息,有的文件系统可能不支持,可以不填 */
pv->type = VNODE_TYPE_DIR;
pv->data = (void *)rootNode;
pv->originMount = mnt;
pv->fop = &g_jffs2Fops;
mnt->data = p;
mnt->vnodeCovered = pv;
pv->uid = rootNode->i_uid;
pv->gid = rootNode->i_gid;
pv->mode = rootNode->i_mode;
/* 这里的HashInsert是为了防止重复生成已经生成过的Vnode, 第二个参数一般会选择本文件系统内可以唯一确定某一个文件的信息,例如这里是jffs2内部inode的地址 */
(void)VfsHashInsert(pv, rootNode->i_ino);
g_jffs2PartList[partNo] = blkDriver;
LOS_MuxUnlock(&g_jffs2FsLock);
return 0;
ERROR_WITH_VNODE:
return ret;
}
...
...
const struct MountOps jffs_operations = {
.Mount = VfsJffs2Bind,
...
...
};
```
总结:
1. 首先从驱动节点中获取需要的私有信息。
2. 根据私有信息,生成文件系统的根节点。
## 适配Lookup接口<a name="section11930181394317"></a>
Lookup是查找文件的接口,它的函数原型是:
```
int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);
```
很好理解,就是从父节点parent开始,根据文件名name和文件名长度len,查找到对应的vnode返回给上层。
这个接口适配起来思路很清晰,给了父节点的信息和文件名,实现从父目录中查询名字为name的文件这个功能,同样以JFFS2为例:
```
int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct Vnode **ppVnode)
{
int ret;
struct Vnode *newVnode = NULL;
struct jffs2_inode *node = NULL;
struct jffs2_inode *parentNode = NULL;
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
/* 首先从private data中提取父节点的信息 */
parentNode = (struct jffs2_inode *)parentVnode->data;
/* 然后查询得到目标节点的信息,注意这里调用的jffs2_lookup是jffs2本身的查询函数,每个文件系统都有自己的查询函数,通过父节点的信息和VFS的查询函数对接起来 */
node = jffs2_lookup(parentNode, (const unsigned char *)path, len);
if (!node) {
LOS_MuxUnlock(&g_jffs2FsLock);
return -ENOENT;
}
/* 接着先校验一下查找到的目标是否已经有现成的vnode了,这里对应之前提到的VfsHashInsert */
(void)VfsHashGet(parentVnode->originMount, node->i_ino, &newVnode, NULL, NULL);
LOS_MuxUnlock(&g_jffs2FsLock);
if (newVnode) {
newVnode->parent = parentVnode;
*ppVnode = newVnode;
return 0;
}
/* 如果vnode不存在,就新生成一个vnode,并填写相关信息 */
ret = VnodeAlloc(&g_jffs2Vops, &newVnode);
if (ret != 0) {
PRINT_ERR("%s-%d, ret: %x\n", __FUNCTION__, __LINE__, ret);
(void)jffs2_iput(node);
LOS_MuxUnlock(&g_jffs2FsLock);
return ret;
}
Jffs2SetVtype(node, newVnode);
newVnode->fop = parentVnode->fop;
newVnode->data = node;
newVnode->parent = parentVnode;
newVnode->originMount = parentVnode->originMount;
newVnode->uid = node->i_uid;
newVnode->gid = node->i_gid;
newVnode->mode = node->i_mode;
/* 同时不要忘记将新生成的vnode插入hashtable中 */
(void)VfsHashInsert(newVnode, node->i_ino);
*ppVnode = newVnode;
LOS_MuxUnlock(&g_jffs2FsLock);
return 0;
}
```
总结:
1. 从父节点获取私有数据;
2. 根据私有信息查询到目标文件的私有数据;
3. 通过目标文件的私有数据生成目标Vnode。
## 适配总结和注意事项<a name="section5617183014319"></a>
通过上面两个接口的适配,其实可以发现一个规律,不管是什么接口,基本都遵循下面的适配步骤:
1. 通过入参的vnode获取文件系统所需的私有数据。
2. 使用私有数据完成接口的功能。
3. 将结果包装成vnode或接口要求的其他返回格式,返回给上层。
核心的逻辑其实在使用私有数据完成接口的功能,这些接口都是些文件系统的通用功能,文件系统在移植前本身应该都有相应实现,所以关键是归纳总结出文件系统所需的私有数据是什么,将其存储在vnode中,供之后使用。一般情况下,私有数据的内容是可以唯一定位到文件在存储介质上位置的信息,大部分文件系统本身都会有类似数据结构可以直接使用,比如JFFS2的inode数据结构。
>![](../public_sys-resources/icon-caution.gif) **注意:**
>1. 文件系统中的Lookup接口不是访问文件必经的路径,仅在上层路径缓存失效时才会调用到。
>2. 通过VfsHashGet找到了已经存在的Vnode,不要直接将其作为结果返回,其储存的信息可能已经失效,请更新相应字段后再返回。
>3. Vnode会根据内存占用在后台自动释放,需要持久保存的信息,不要只保存在Vnode中。
>4. Reclaim接口在Vnode释放时会自动调用,请在这个接口中释放私有数据中的资源。
# FAT<a name="ZH-CN_TOPIC_0000001078576202"></a>
- [基本概念](#section621393911385)
- [运行机制](#section10796155213381)
- [开发指导](#section144094483919)
- [开发流程](#section139086116394)
## 基本概念<a name="section621393911385"></a>
FAT文件系统是File Allocation Table(文件配置表)的简称,主要包括DBR区、FAT区、DATA区三个区域。其中,FAT区各个表项记录存储设备中对应簇的信息,包括簇是否被使用、文件下一个簇的编号、是否文件结尾等。FAT文件系统有FAT12、FAT16、FAT32等多种格式,其中,12、16、32表示对应格式中FAT表项的字节数,它们同时也限制了文件系统中的最大文件大小。FAT文件系统支持多种介质,特别在可移动存储介质(U盘、SD卡、移动硬盘等)上广泛使用,使嵌入式设备和Windows、Linux等桌面系统保持很好的兼容性,方便用户管理操作文件。
OpenHarmony内核支持FAT12、FAT16与FAT32三种格式的FAT文件系统,具有代码量小、资源占用小、可裁切、支持多种物理介质等特性,并且与Windows、Linux等系统保持兼容,支持多设备、多分区识别等功能。OpenHarmony内核支持硬盘多分区,可以在主分区以及逻辑分区上创建FAT文件系统。
## 运行机制<a name="section10796155213381"></a>
FAT文件系统设计与物理布局的相关文档在互联网上非常丰富,请开发者自行搜索查看。
OpenHarmony LiteOS-A内核通过Bcache提升FAT文件系统性能,Bcache是block cache的简称。当发生读写时,Bcache会缓存读写扇区附近的扇区,以减少I/O次数,提高性能。Bcache的基本缓存单位为block,每个block大小一致(默认有28个block,每个block缓存64个扇区的数据)。当Bcache脏块率(脏扇区数/总扇区数)达到阈值时,会触发写回;如果脏块率未达到阈值,则不会将缓存数据写回磁盘。如果需要保证数据写回,开发者应当调用sync和fsync触发写回。FAT文件系统的部分接口也会触发写回操作(如close、umount等),但开发者不应当基于这些接口触发写回。
## 开发指导<a name="section144094483919"></a>
### 开发流程<a name="section139086116394"></a>
基本使用流程为挂载→操作→卸载。
SD卡或MMC的设备名为mmcblk\[x\]p\[y\],文件系统类型为“vfat”。
示例:
```
mount("/dev/mmcblk0p0", "/mnt", "vfat", 0, NULL);
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>- FAT文件系统中,单个文件不能大于4 GiB。
>- 当有两个SD卡插槽时,卡0和卡1不固定,先插上的为卡0,后插上的为卡1。
>- 当多分区功能打开,存在多分区的情况下,卡0注册的设备节点/dev/mmcblk0\(主设备\)和/dev/mmcblk0p0\(次设备\)是同一个设备,禁止对主设备进行操作。
>- 为避免SD卡使用异常或内存泄漏,SD卡使用过程中拔卡,用户必须先关闭正处于打开状态的文件和目录,并且卸载挂载节点。
>- 在format操作之前,需要首先umount挂载点。
>- 当Bcache功能生效时,需要注意:
> - 当mount函数的入参为MS\_NOSYNC时,FAT不会主动将cache的内容写回存储器件。FAT的如下接口(open、close、 unlink、rename、mkdir、rmdir、truncate)不会自动进行sync操作,速度可以提升,但是需要上层主动调用sync来进行数据同步,否则可能会数据丢失。
> - Bcache有定时写回功能。在menuconfig中开启LOSCFG\_FS\_FAT\_CACHE\_SYNC\_THREAD选项,打开后系统会创建一个任务定时写回Bcache中的数据,默认每隔5秒检查Bcache中脏数据块比例,超过80%时进行sync操作,将Bcache中的脏数据全部写回磁盘。任务优先级、刷新时间间隔以及脏数据块比例的阈值可分别通过接口LOS\_SetSyncThreadPrio、 LOS\_SetSyncThreadInterval和LOS\_SetDirtyRatioThreshold设置。
> - 当前cache的默认大小为28个块,每个块64个扇区。
# JFFS2<a name="ZH-CN_TOPIC_0000001052810482"></a> # JFFS2<a name="ZH-CN_TOPIC_0000001123521625"></a>
- [概述](#section01261544730) - [基本概念](#section11411110155919)
- [注意事项](#section94343420) - [运行机制](#section23911025195913)
- [开发指导](#section14979101812411) - [开发指导](#section179711119014)
## 概述<a name="section01261544730"></a> ## 基本概念<a name="section11411110155919"></a>
JFFS2是Journalling Flash File System Version 2(日志文件系统)的缩写,是MTD设备上实现的日志型文件系统。JFFS2主要应用于NOR FLASH,其特点是:可读写、支持数据压缩、提供了崩溃/掉电安全保护、提供“写平衡”支持等 JFFS2是Journalling Flash File System Version 2(日志文件系统)的缩写,是针对MTD设备的日志型文件系统
闪存与磁盘介质有许多差异,因此直接将磁盘文件系统运行在闪存上存在性能和安全性上的不足。为解决这一问题,需要实现一个特别针对闪存的文件系统,JFFS2就是这样一种文件系统。 OpenHarmony内核的JFFS2主要应用于NOR FLASH闪存,其特点是:可读写、支持数据压缩、提供了崩溃/掉电安全保护、提供“写平衡”支持等。闪存与磁盘介质有许多差异,直接将磁盘文件系统运行在闪存设备上,会导致性能和安全问题。为解决这一问题,需要实现一个特别针对闪存的文件系统,JFFS2就是这样一种文件系统。
OpenHarmony内核的JFFS2主要应用于对NOR Flash闪存的文件管理,并且支持多分区。 ## 运行机制<a name="section23911025195913"></a>
## 注意事项<a name="section94343420"></a> 关于JFFS2文件系统的在存储设备上的实际物理布局,及文件系统本身的规格说明,请参考JFFS2的[官方规格说明文档](https://sourceware.org/jffs2/)
- 目前JFFS2文件系统用于NOR Flash,最终调用NOR Flash驱动接口,因此使用JFFS2文件系统之前要确保硬件上有NOR Flash,且驱动初始化成功(spinor\_init\(\)返回0)。 这里仅列举几个对开发者和使用者会有一定影响的JFFS2的重要机制/特征:
- 系统会自动对起始地址和分区大小根据block大小进行对齐操作。有效的分区号为0\~19。 1. Mount机制及速度问题:按照JFFS2的设计,所有的文件会按照一定的规则,切分成大小不等的节点,依次存储到flash设备上。在mount流程中,需要获取到所有的这些节点信息并缓存到内存里。因此,mount速度和flash设备的大小和文件数量的多少成线性比例关系。这是JFFS2的原生设计问题,对于mount速度非常介意的用户,可以在内核编译时开启“Enable JFFS2 SUMMARY”选项,可以极大提升mount的速度。这个选项的原理是将mount需要的信息提前存储到flash上,在mount时读取并解析这块内容,使得mount的速度变得相对恒定。这个实际是空间换时间的做法,会消耗8%左右的额外空间。
2. 写平衡的支持:由于flash设备的物理属性,读写都只能基于某个特定大小的“块”进行,为了防止某些特定的块磨损过于严重,在JFFS2中需要对写入的块进行“平衡”的管理,保证所有的块的写入次数都是相对平均的,进而保证flash设备的整体寿命。
3. GC\(garbage collection\)机制:在JFFS2里发生删除动作,实际的物理空间并不会立即释放,而是由独立的GC线程来做空间整理和搬移等GC动作,和所有的GC机制一样,在JFFS2里的GC会对瞬时的读写性能有一定影响。另外,为了有空间能被用来做空间整理,JFFS2会对每个分区预留3块左右的空间,这个空间是用户不可见的。
4. 压缩机制:当前使用的JFFS2,底层会自动的在每次读/写时进行解压/压缩动作,实际IO的大小和用户请求读写的大小并不会一样。特别在写入时,不能通过写入大小来和flash剩余空间的大小来预估写入一定会成功或者失败。
5. 硬链接机制:JFFS2支持硬链接,底层实际占用的物理空间是一份,对于同一个文件的多个硬连接,并不会增加空间的占用;反之,只有当删除了所有的硬链接时,实际物理空间才会被释放。
- 目前支持mkfs.jffs2工具,用户可根据自己实际情况修改参数值,其他用法用户可自行搜索查看。 ## 开发指导<a name="section179711119014"></a>
- open打开一个文件,参数有O\_TRUNC时,会将文件中的内容清空 对于基于JFFS2和nor flash的开发,总体而言,与其他文件系统非常相似,因为都有VFS层来屏蔽了具体文件系统的差异,对外接口体现也都是标准的POSIX接口
- 目前JFFS2文件系统支持的操作有:open, close, read, write, seek, opendir, closedir, readdir, readdir\_r, rewinddir, statfs, sync, remove, unlink, mkdir, rmdir, rename, stat, stat64, seek64, mmap, mount, umount, chmod, chown。 对于整个裸nor flash设备而言,没有集中的地方来管理和记录分区的信息。因此,需要通过其他的配置方式来传递这部分信息(当前使用的方式是在烧写镜像的时候,使用bootargs参数配置的),然后在代码中调用相应的接口来添加分区,再进行挂载动作。
- JFFS2支持以只读属性挂载,当mount函数的入参mountflags为MS\_RDONLY时,JFFS将开启只读属性,所有的带有写入的接口,如write、mkdir、unlink,以及通过非O\_RDONLY属性打开的文件,将均被拒绝,并传出EACCESS错误码。
## 开发指导<a name="section14979101812411"></a>
**添加JFFS2分区**
调用add\_mtd\_partition函数添加JFFS2分区,该函数会自动为设备节点命名,对于JFFS2,其命名规则是“/dev/spinorblk”加上分区号。
add\_mtd\_partition函数有四个参数,第一个参数表示介质,有“nand”和“spinor”两种,JFFS2分区在“spinor”上使用,而“nand”是提供给YAFFS2使用的。
第二个参数表示起始地址,第三个参数表示分区大小,这两个参数都以16进制的形式传入。
最后一个参数表示分区号,有效值为0\~19。
```
INT32 uwRet;
if (uwRet = add_mtd_partition("spinor", 0x100000, 0x800000, 0) != 0) {
dprintf("add jffs2 partition failed, return %d\n", uwRet);
} else {
dprintf("Mount jffs2 on spinor.\n");
uwRet = mount("/dev/spinorblk0", "/jffs0", "jffs2", 0, NULL);
if (uwRet) {
dprintf("mount jffs2 err %d\n", uwRet);
dprintf("Mount jffs2 on nor finished.\n");
}
}
if (uwRet = add_mtd_partition("spinor", 0x900000, 0x200000, 1) != 0) {
dprintf("add jffs2 partition failed, return %d\n", uwRet);
}
```
成功后,在Shell中可以使用partition spinor命令查看spinor flash分区信息。
```
OHOS # partition spinor
spinor partition num:0, dev name:/dev/spinorblk0, mountpt:/jffs0, startaddr:0x0100000,length:0x0800000
spinor partition num:1, dev name:/dev/spinorblk1, mountpt:(null), startaddr:0x0900000,length:0x0200000
```
**挂载JFFS2**
调用mount\(\)函数实现设备节点和挂载点的挂载。
该函数有五个参数,第一个参数表示设备节点,这个参数需要和add\_mtd\_partition\(\)函数对应起来,第二个参数表示挂载点。第三个参数表示文件系统类型。
最后两个参数表示挂载标志和数据,默认为0和NULL;这一操作也可以在Shell中使用mount命令实现,最后两个参数不需要用户给出。
运行命令:
```
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
```
将从串口得到如下回应信息,表明挂载成功。
```
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
mount OK
```
挂载成功后,用户就能对norflash进行读写操作。
**卸载JFFS2**
调用umount\(\)函数卸载分区,只需要正确给出挂载点即可。
运行命令:
```
OHOS # umount /jffs1
```
将从串口得到如下回应信息,表明卸载成功。
```
OHOS # umount /jffs1
umount ok
```
**删除JFFS2分区**
调用delete\_mtd\_partition删除已经卸载的分区。
该函数有两个参数,第一个参数是分区号,第二个参数为介质类型,该函数与add\_mtd\_partition\(\)函数对应。
```
INT32 uwRet;
uwRet = delete_mtd_partition(1,"spinor");
if(uwRet != 0) {
printf("delete jffs2 error\n");
} else {
printf("delete jffs2 ok\n");
}
OHOS # partition spinor
spinor partition num:0, dev name:/dev/spinorblk0, mountpt:/jffs0, startaddr:0x0100000,length:0x0800000
```
**制作JFFS2文件系统镜像** **制作JFFS2文件系统镜像**
...@@ -132,7 +36,7 @@ spinor partition num:0, dev name:/dev/spinorblk0, mountpt:/jffs0, startaddr:0x01 ...@@ -132,7 +36,7 @@ spinor partition num:0, dev name:/dev/spinorblk0, mountpt:/jffs0, startaddr:0x01
./mkfs.jffs2 -d rootfs/ -o rootfs.jffs2 ./mkfs.jffs2 -d rootfs/ -o rootfs.jffs2
``` ```
**表 1** 指令含义表 **表 1** 指令含义表(更详细的介绍可以通过mkfs.jffs2 --help来查看)
<a name="table1925613541465"></a> <a name="table1925613541465"></a>
<table><thead align="left"><tr id="row325613545615"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p153851336772"><a name="p153851336772"></a><a name="p153851336772"></a>指令</p> <table><thead align="left"><tr id="row325613545615"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p153851336772"><a name="p153851336772"></a><a name="p153851336772"></a>指令</p>
...@@ -169,3 +73,43 @@ spinor partition num:0, dev name:/dev/spinorblk0, mountpt:/jffs0, startaddr:0x01 ...@@ -169,3 +73,43 @@ spinor partition num:0, dev name:/dev/spinorblk0, mountpt:/jffs0, startaddr:0x01
</tbody> </tbody>
</table> </table>
**挂载JFFS2分区**
调用int mount\(const char \*source, const char \*target, const char \*filesystemtype, unsigned long mountflags, const void \*data\)函数实现设备节点和挂载点的挂载。
该函数有五个参数,第一个参数const char \*source,表示设备节点,第二个参数const char \*target表示挂载点。第三个参数 const char \*filesystemtype,表示文件系统类型。
最后两个参数unsigned long mountflags和const void \*data表示挂载标志和数据,默认为0和NULL;这一操作也可以在Shell中使用mount命令实现,最后两个参数不需要用户给出。
运行命令:
```
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
```
将从串口得到如下回应信息,表明挂载成功。
```
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
mount OK
```
挂载成功后,用户就能对norflash进行读写操作。
**卸载JFFS2分区**
调用int umount\(const char \*target\)函数卸载分区,只需要正确给出挂载点即可。
运行命令:
```
OHOS # umount /jffs1
```
将从串口得到如下回应信息,表明卸载成功。
```
OHOS # umount /jffs1
umount ok
```
# NFS<a name="ZH-CN_TOPIC_0000001078704660"></a>
- [基本概念](#section195414101464)
- [运行机制](#section165621321194618)
- [开发指导](#section7454935184611)
## 基本概念<a name="section195414101464"></a>
NFS是Network File System(网络文件系统)的缩写。它最大的功能是可以通过网络,让不同的机器、不同的操作系统彼此分享其他用户的文件。因此,用户可以简单地将它看做是一个文件系统服务,在一定程度上相当于Windows环境下的共享文件夹。
## 运行机制<a name="section165621321194618"></a>
OpenHarmony LiteOS-A内核的NFS文件系统指的是NFS的客户端,NFS客户端能够将远程的NFS服务端分享的目录挂载到本地的机器中,运行程序和共享文件,但不占用当前系统的存储空间,在本地端的机器看起来,远程服务端的目录就好像是自己的一个磁盘一样。
## 开发指导<a name="section7454935184611"></a>
1. 搭建NFS服务器
这里以Ubuntu操作系统为例,说明服务器端设置步骤。
- 安装NFS服务器软件。
设置好Ubuntu系统的下载源,保证网络连接好的情况下执行:
```
sudo apt-get install nfs-kernel-server
```
- 创建用于挂载的目录并设置完全权限
```
mkdir -p /home/sqbin/nfs
sudo chmod 777 /home/sqbin/nfs
```
- 设置和启动NFS server。
修改NFS配置文件/etc/exports,添加如下一行:
```
/home/sqbin/nfs *(rw,no_root_squash,async)
```
其中/home/sqbin/nfs是NFS共享的根目录。
执行以下命令启动NFS server:
```
sudo /etc/init.d/nfs-kernel-server start
```
执行以下命令重启NFS server:
```
sudo /etc/init.d/nfs-kernel-server restart
```
1. 设置单板为NFS客户端
本指导中的NFS客户端指运行OpenHarmony内核的设备。
- 硬件连接设置。
OpenHarmony内核设备连接到NFS服务器的网络。设置两者IP,使其处于同一网段。比如,设置NFS服务器的IP为10.67.212.178/24,设置OpenHarmony内核设备IP为10.67.212.3/24,注意:此IP为内网私有IP地址,用户使用时有差异,以用户实际IP为准。
OpenHarmony内核设备上的IP信息可通过ifconfig命令查看。
- 启动网络,确保单板到NFS服务器之间的网络通畅。
启动以太网或者其他类型网络,使用ping命令检查到服务器的网络是否通畅。
```
OHOS # ping 10.67.212.178
[0]Reply from 10.67.212.178: time=1ms TTL=63
[1]Reply from 10.67.212.178: time=0ms TTL=63
[2]Reply from 10.67.212.178: time=1ms TTL=63
[3]Reply from 10.67.212.178: time=1ms TTL=63
--- 10.67.212.178 ping statistics ---
4 packets transmitted, 4 received, 0 loss
```
客户端NFS初始化,运行命令:
```
OHOS # mkdir /nfs
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
```
将从串口得到如下回应信息,表明初始化NFS客户端成功。
```
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
Mount nfs on 10.67.212.178:/home/sqbin/nfs, uid:1011, gid:1000
Mount nfs finished.
```
该命令将服务器10.67.212.178上的/home/sqbin/nfs目录挂载到OpenHarmony内核设备上的/nfs上。
>![](../public_sys-resources/icon-note.gif) **说明:**
>本例默认nfs server已经配置可用,即示例中服务器10.67.212.178上的/home/sqbin/nfs已配置可访问。
>mount命令的格式为:
>```
>mount <SERVER_IP:SERVER_PATH> <CLIENT_PATH> nfs
>```
>其中“SERVER\_IP”表示服务器的IP地址;“SERVER\_PATH”表示服务器端NFS共享目录路径;“CLIENT\_PATH”表示设备上的NFS路径,“nfs”表示客户端要挂载的路径,可以根据自己需要替换。
>如果不想有NFS访问权限限制,可以在Linux命令行将NFS根目录权限设置成777:
>```
>chmod -R 777 /home/sqbin/nfs
>```
>至此,NFS客户端设置完毕。NFS文件系统已成功挂载。
1. 利用NFS共享文件
在NFS服务器下新建目录dir,并保存。在OpenHarmony内核下运行ls命令:
```
OHOS # ls /nfs
```
则可从串口得到如下回应:
```
OHOS # ls /nfs
Directory /nfs:
drwxr-xr-x 0 u:0 g:0 dir
```
可见,刚刚在NFS服务器上新建的dir目录已同步到客户端\(OpenHarmony内核系统\)的/nfs目录,两者保持同步。
同样地,在客户端\(OpenHarmony内核系统\)上创建文件和目录,在NFS服务器上也可以访问,读者可自行体验。
>![](../public_sys-resources/icon-note.gif) **说明:**
>目前,NFS客户端仅支持NFS v3部分规范要求,因此对于规范支持不全的服务器,无法完全兼容。在开发测试过程中,建议使用Linux的NFS server,其对NFS支持很完善。
# Procfs<a name="ZH-CN_TOPIC_0000001123696719"></a>
- [基本概念](#section146801917174017)
- [运行机制](#section479762916408)
- [开发指导](#section1221174524014)
- [编程实例](#section52016575401)
## 基本概念<a name="section146801917174017"></a>
procfs是进程文件系统的简称,是一种虚拟文件系统,他用文件的形式,展示进程或其他系统信息。相比调用接口的方式获取信息,以文件操作的方式获取系统信息更为方便。
## 运行机制<a name="section479762916408"></a>
OpenHarmony内核中,procfs在开机时会自动挂载到/proc目录下,仅支持内核模块创建文件节点来提供查询服务。
## 开发指导<a name="section1221174524014"></a>
procfs文件的创建无法使用一般的文件系统接口,需要使用ProcMkdir接口创建目录,使用CreateProcEntry接口创建文件。文件节点功能的开发就是实现read和write函数的钩子挂到CreateProcEntry创建的文件中。当用户使用读写procfs的文件时,就会调用到钩子函数来实现自定义的功能。
### 编程实例<a name="section52016575401"></a>
下面我们以创建/proc/hello/world文件为例,实现如下功能:
1.在/proc/hello/world位置创建一个文件
2.当读文件内容时,返回"HelloWorld!"
3.当写文件内容时,打印写入的内容
```
#include "proc_fs.h"
static int TestRead(struct SeqBuf *buf, void *arg)
{
LosBufPrintf(buf, "Hello World!\n"); /* 将数据打印到buffer中,这个buffer中的数据会返回到read的结果中 */
return 0;
}
static int TestWrite(struct ProcFile *pf, const char *buffer, size_t buflen, loff_t *ppos)
{
if ((buffer == NULL) || (buflen <= 0)) {
return -EINVAL;
}
PRINTK("your input is: %s\n", buffer); /* 注意和上面的read接口区别,这是对write接口输入命令的反馈,这个打印只会打印到控制台 */
return buflen;
}
static const struct ProcFileOperations HELLO_WORLD_OPS = {
.read = TestRead,
.write = TestWrite,
};
void HelloWorldInit(void)
{
/* 创建hello目录 */
struct ProcDirEntry *dir = ProcMkdir("hello", NULL);
if (dir == NULL) {
PRINT_ERR("create dir failed!\n");
return;
}
/* 创建world文件 */
struct ProcDirEntry *entry = CreateProcEntry("world", 0, dir);
if (entry == NULL) {
PRINT_ERR("create entry failed!\n");
return;
}
/* 将自定义的read和write钩子挂到文件中 */
entry->procFileOps = &HELLO_WORLD_OPS;
}
```
**结果验证**
启动后在shell输入如下命令
```
OHOS # cat /proc/hello/world
OHOS # Hello World!
OHOS # echo "yo" > /proc/hello/world
OHOS # your input is: yo
```
# Ramfs<a name="ZH-CN_TOPIC_0000001078864272"></a>
- [基本概念](#section9507151014420)
- [运行机制](#section1859711263447)
- [开发指导](#section163554380448)
## 基本概念<a name="section9507151014420"></a>
RAMFS是一个可动态调整大小的基于RAM的文件系统。RAMFS没有后备存储源。向RAMFS中进行的文件写操作也会分配目录项和页缓存,但是数据并不写回到任何其他存储介质上,掉电后数据丢失。
## 运行机制<a name="section1859711263447"></a>
RAMFS文件系统把所有的文件都放在 RAM 中,所以读/写操作发生在RAM中,可以用RAMFS来存储一些临时性或经常要修改的数据,例如/tmp和/var目录,这样既避免了对存储器的读写损耗,也提高了数据读写速度。
## 开发指导<a name="section163554380448"></a>
挂载:
```
mount(NULL, "/dev/shm", "ramfs", 0, NULL)
```
创建目录:
```
mkdir(pathname, mode)
```
创建文件:
```
open(pathname, O_NONBLOCK | O_CREAT | O_RDWR, mode)
```
读取目录:
```
dir = opendir(pathname)
ptr = readdir(dir)
closedir(dir)
```
删除文件:
```
unlink(pathname)
```
删除目录:
```
rmdir(pathname)
```
去挂载:
```
umount("/dev/shm")
```
>![](../public_sys-resources/icon-caution.gif) **注意:**
>- RAMFS只能挂载一次,一次挂载成功后,后面不能继续挂载到其他目录。
>- RAMFS属于调测功能,默认配置为关闭,正式产品中不要使用该功能。
# 支持的文件系统<a name="ZH-CN_TOPIC_0000001124888127"></a>
- **[FAT](kernel-small-bundles-fs-support-fat.md)**
- **[JFFS2](kernel-small-bundles-fs-support-jffs2.md)**
- **[NFS](kernel-small-bundles-fs-support-nfs.md)**
- **[Ramfs](kernel-small-bundles-fs-support-ramfs.md)**
- **[Procfs](kernel-small-bundles-fs-support-procfs.md)**
# 虚拟文件系统<a name="ZH-CN_TOPIC_0000001123796667"></a>
- [基本概念](#section1253851143520)
- [运行机制](#section14915913123510)
- [开发指导](#section1759563620358)
- [接口说明](#section17865142133511)
- [开发流程](#section64113023616)
- [编程实例](#section236041883618)
## 基本概念<a name="section1253851143520"></a>
VFS(Virtual File System)是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用关心底层的存储介质和文件系统类型,提高开发效率。
OpenHarmony内核中,VFS框架是通过在内存中的树结构来实现的,树的每个结点都是一个Vnode结构体,父子结点的关系以PathCache结构体保存。VFS最主要的两个功能是:
- 查找节点。
- 统一调用(标准)。
## 运行机制<a name="section14915913123510"></a>
当前,VFS层主要通过函数指针,实现对不同文件系统类型调用不同接口实现标准接口功能;通过Vnode与PathCache机制,提升路径搜索以及文件访问的性能;通过挂载点管理进行分区管理;通过FD管理进行进程间FD隔离等。下面将对这些机制进行简要说明。
1. 文件系统操作函数指针:VFS层通过函数指针的形式,将统一调用按照不同的文件系统类型,分发到不同文件系统中进行底层操作。各文件系统的各自实现一套Vnode操作、挂载点操作以及文件操作接口,并以函数指针结构体的形式存储于对应Vnode、挂载点、File结构体中,实现VFS层对下访问。
2. Vnode:Vnode是具体文件或目录在VFS层的抽象封装,它屏蔽了不同文件系统的差异,实现资源的统一管理。Vnode节点主要有以下几种类型:
- 挂载点:挂载具体文件系统,如/、/storage
- 设备节点:/dev目录下的节点,对应于一个设备,如/dev/mmcblk0
- 文件/目录节点:对应于具体文件系统中的文件/目录,如/bin/init
Vnode通过哈希以及LRU机制进行管理。当系统启动后,对文件或目录的访问会优先从哈希链表中查找Vnode缓存,若缓存没有命中,则并从对应文件系统中搜索目标文件或目录,创建并缓存对应的Vnode。当Vnode缓存数量达到上限时,将淘汰长时间未访问的Vnode,其中挂载点Vnode与设备节点Vnode不参与淘汰。当前系统中Vnode的规格默认为512,该规格可以通过LOSCFG\_MAX\_VNODE\_SIZE进行配置。Vnode数量过大,会造成较大的内存占用;Vnode数量过少,则会造成搜索性能下降。下图展示了Vnode的创建流程。
**图 1** Vnode创建流程<a name="fig1453197573"></a>
![](figure/Vnode创建流程.png "Vnode创建流程")
1. PathCache:PathCache是路径缓存,与Vnode对应。PathCache同样通过哈希链表存储,通过父Vnode中缓存的PathCache可以快速获取子Vnode,加速路径查找。下图展示了文件/目录的查找流程。
**图 2** 文件查找流程<a name="fig1881815597396"></a>
![](figure/文件查找流程.png "文件查找流程")
1. PageCache:PageCache是文件级别的内核缓存。当前PageCache仅支持对二进制文件操作,在初次访问该文件时通过mmap映射到内存中,减少内核内存的占用,也大大提升了对同一个文件的读写操作速度。另外基于PageCache可实现以文件为基底的进程间通信。
2. fd管理:Fd(File Description)是描述一个打开的文件/目录的描述符。当前OpenHarmony内核中,fd总规格为896,分为三种类型:
- 普通文件描述符,系统总规格为512。
- Socket描述符,系统总规格为128。
- 消息队列描述符,系统总规格为256。
当前OpenHarmony内核中,对不同进程中的fd进行隔离,即进程只能访问本进程的fd,所有进程的fd映射到全局fd表中进行统一分配管理。进程的文件描述符最多有256个。
3. 挂载点管理:当前OpenHarmony内核中,对系统中所有挂载点通过链表进行统一管理。挂载点结构体中,记录了该挂载分区内的所有Vnode。当分区卸载时,会释放分区内的所有Vnode。
## 开发指导<a name="section1759563620358"></a>
### 接口说明<a name="section17865142133511"></a>
当前文件系统支持的接口如下表所示,表格中的“×”代表对应文件系统不支持该接口。
**表 1** 支持接口列表
<a name="table17301515163415"></a>
<table><thead align="left"><tr id="row1730115183416"><th class="cellrowborder" valign="top" width="22.547745225477453%" id="mcps1.2.9.1.1"><p id="p830131563412"><a name="p830131563412"></a><a name="p830131563412"></a>分类</p>
</th>
<th class="cellrowborder" valign="top" width="22.547745225477453%" id="mcps1.2.9.1.2"><p id="p43011512345"><a name="p43011512345"></a><a name="p43011512345"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="22.547745225477453%" id="mcps1.2.9.1.3"><p id="p1130101519342"><a name="p1130101519342"></a><a name="p1130101519342"></a>功能</p>
</th>
<th class="cellrowborder" valign="top" width="5.499450054994501%" id="mcps1.2.9.1.4"><p id="p107591639173415"><a name="p107591639173415"></a><a name="p107591639173415"></a>FAT</p>
</th>
<th class="cellrowborder" valign="top" width="5.949405059494051%" id="mcps1.2.9.1.5"><p id="p540384933412"><a name="p540384933412"></a><a name="p540384933412"></a>JFFS2</p>
</th>
<th class="cellrowborder" valign="top" width="6.419358064193579%" id="mcps1.2.9.1.6"><p id="p1912513588343"><a name="p1912513588343"></a><a name="p1912513588343"></a>NFS</p>
</th>
<th class="cellrowborder" valign="top" width="6.95930406959304%" id="mcps1.2.9.1.7"><p id="p1057755183515"><a name="p1057755183515"></a><a name="p1057755183515"></a>TMPFS</p>
</th>
<th class="cellrowborder" valign="top" width="7.529247075292471%" id="mcps1.2.9.1.8"><p id="p25201318183510"><a name="p25201318183510"></a><a name="p25201318183510"></a>PROCFS</p>
</th>
</tr>
</thead>
<tbody><tr id="row53018152343"><td class="cellrowborder" rowspan="16" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.1 "><p id="p151510381154"><a name="p151510381154"></a><a name="p151510381154"></a>文件操作</p>
</td>
<td class="cellrowborder" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.2 "><p id="p5302152348"><a name="p5302152348"></a><a name="p5302152348"></a>open</p>
</td>
<td class="cellrowborder" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.3 "><p id="p8301815103412"><a name="p8301815103412"></a><a name="p8301815103412"></a>打开文件</p>
</td>
<td class="cellrowborder" valign="top" width="5.499450054994501%" headers="mcps1.2.9.1.4 "><p id="p294710215329"><a name="p294710215329"></a><a name="p294710215329"></a></p>
</td>
<td class="cellrowborder" valign="top" width="5.949405059494051%" headers="mcps1.2.9.1.5 "><p id="p9261258325"><a name="p9261258325"></a><a name="p9261258325"></a></p>
</td>
<td class="cellrowborder" valign="top" width="6.419358064193579%" headers="mcps1.2.9.1.6 "><p id="p1531472803219"><a name="p1531472803219"></a><a name="p1531472803219"></a></p>
</td>
<td class="cellrowborder" valign="top" width="6.95930406959304%" headers="mcps1.2.9.1.7 "><p id="p1081010131337"><a name="p1081010131337"></a><a name="p1081010131337"></a></p>
</td>
<td class="cellrowborder" valign="top" width="7.529247075292471%" headers="mcps1.2.9.1.8 "><p id="p9730516133310"><a name="p9730516133310"></a><a name="p9730516133310"></a></p>
</td>
</tr>
<tr id="row1231181593416"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p1631141515344"><a name="p1631141515344"></a><a name="p1631141515344"></a>read/pread/readv/preadv</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p731115173413"><a name="p731115173413"></a><a name="p731115173413"></a>读取文件</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p49398914559"><a name="p49398914559"></a><a name="p49398914559"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p17960592553"><a name="p17960592553"></a><a name="p17960592553"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p69811093556"><a name="p69811093556"></a><a name="p69811093556"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1599119915554"><a name="p1599119915554"></a><a name="p1599119915554"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p121101016557"><a name="p121101016557"></a><a name="p121101016557"></a></p>
</td>
</tr>
<tr id="row631215173419"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p1312013310440"><a name="p1312013310440"></a><a name="p1312013310440"></a>write/pwrite/writev/pwritev</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1631201513418"><a name="p1631201513418"></a><a name="p1631201513418"></a>写入文件</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1210121018551"><a name="p1210121018551"></a><a name="p1210121018551"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p1120710185512"><a name="p1120710185512"></a><a name="p1120710185512"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p1529510185513"><a name="p1529510185513"></a><a name="p1529510185513"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p133911014559"><a name="p133911014559"></a><a name="p133911014559"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p94881019559"><a name="p94881019559"></a><a name="p94881019559"></a></p>
</td>
</tr>
<tr id="row13820154164814"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p1982084154815"><a name="p1982084154815"></a><a name="p1982084154815"></a>lseek</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p18201148481"><a name="p18201148481"></a><a name="p18201148481"></a>设置文件偏移</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1477251395513"><a name="p1477251395513"></a><a name="p1477251395513"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p979119136551"><a name="p979119136551"></a><a name="p979119136551"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p138102013175517"><a name="p138102013175517"></a><a name="p138102013175517"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p482041319556"><a name="p482041319556"></a><a name="p482041319556"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p4667132210334"><a name="p4667132210334"></a><a name="p4667132210334"></a>×</p>
</td>
</tr>
<tr id="row18311215103413"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p29893124420"><a name="p29893124420"></a><a name="p29893124420"></a>close</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p16317151345"><a name="p16317151345"></a><a name="p16317151345"></a>关闭文件</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1830101311552"><a name="p1830101311552"></a><a name="p1830101311552"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p083916133557"><a name="p083916133557"></a><a name="p083916133557"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p7848141318556"><a name="p7848141318556"></a><a name="p7848141318556"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p98581213135515"><a name="p98581213135515"></a><a name="p98581213135515"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1422632414334"><a name="p1422632414334"></a><a name="p1422632414334"></a></p>
</td>
</tr>
<tr id="row1775494216429"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p2755144216427"><a name="p2755144216427"></a><a name="p2755144216427"></a>unlink</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1475534213424"><a name="p1475534213424"></a><a name="p1475534213424"></a>删除文件</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p11868171355516"><a name="p11868171355516"></a><a name="p11868171355516"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p78771813175517"><a name="p78771813175517"></a><a name="p78771813175517"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p488641355510"><a name="p488641355510"></a><a name="p488641355510"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p12895121315517"><a name="p12895121315517"></a><a name="p12895121315517"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p51901414341"><a name="p51901414341"></a><a name="p51901414341"></a>×</p>
</td>
</tr>
<tr id="row730533465319"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p134325815218"><a name="p134325815218"></a><a name="p134325815218"></a>fstat</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p03438583528"><a name="p03438583528"></a><a name="p03438583528"></a>查询文件信息</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p190418132555"><a name="p190418132555"></a><a name="p190418132555"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p109131713145518"><a name="p109131713145518"></a><a name="p109131713145518"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p20922161345511"><a name="p20922161345511"></a><a name="p20922161345511"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p129311134558"><a name="p129311134558"></a><a name="p129311134558"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1634395895213"><a name="p1634395895213"></a><a name="p1634395895213"></a></p>
</td>
</tr>
<tr id="row12854143815611"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p12854123817564"><a name="p12854123817564"></a><a name="p12854123817564"></a>fallocate</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p158541938165619"><a name="p158541938165619"></a><a name="p158541938165619"></a>预分配大小</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p2092312119324"><a name="p2092312119324"></a><a name="p2092312119324"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p58541638155611"><a name="p58541638155611"></a><a name="p58541638155611"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p485410387565"><a name="p485410387565"></a><a name="p485410387565"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p9250515446"><a name="p9250515446"></a><a name="p9250515446"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p12178113643319"><a name="p12178113643319"></a><a name="p12178113643319"></a>×</p>
</td>
</tr>
<tr id="row231161563416"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p15311154341"><a name="p15311154341"></a><a name="p15311154341"></a>truncate</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p73111513417"><a name="p73111513417"></a><a name="p73111513417"></a>文件截断</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p4553163085512"><a name="p4553163085512"></a><a name="p4553163085512"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p155722303558"><a name="p155722303558"></a><a name="p155722303558"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p01250585343"><a name="p01250585343"></a><a name="p01250585343"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p815106143319"><a name="p815106143319"></a><a name="p815106143319"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p20697173810337"><a name="p20697173810337"></a><a name="p20697173810337"></a>×</p>
</td>
</tr>
<tr id="row931815133419"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p63151593415"><a name="p63151593415"></a><a name="p63151593415"></a>link</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1631101523414"><a name="p1631101523414"></a><a name="p1631101523414"></a>创建硬链接</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p18718522143115"><a name="p18718522143115"></a><a name="p18718522143115"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p1147101520321"><a name="p1147101520321"></a><a name="p1147101520321"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p17125185815342"><a name="p17125185815342"></a><a name="p17125185815342"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1985892113312"><a name="p1985892113312"></a><a name="p1985892113312"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p17342840113315"><a name="p17342840113315"></a><a name="p17342840113315"></a>×</p>
</td>
</tr>
<tr id="row131151523420"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p113251513342"><a name="p113251513342"></a><a name="p113251513342"></a>symlink</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1832215133420"><a name="p1832215133420"></a><a name="p1832215133420"></a>创建软链接</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p5780143585510"><a name="p5780143585510"></a><a name="p5780143585510"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p1879183525516"><a name="p1879183525516"></a><a name="p1879183525516"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p412505873415"><a name="p412505873415"></a><a name="p412505873415"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p13207802451"><a name="p13207802451"></a><a name="p13207802451"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1947920415337"><a name="p1947920415337"></a><a name="p1947920415337"></a>×</p>
</td>
</tr>
<tr id="row382917545412"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p158308546414"><a name="p158308546414"></a><a name="p158308546414"></a>readlink</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p58301454144111"><a name="p58301454144111"></a><a name="p58301454144111"></a>读取软链接</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p14802935155512"><a name="p14802935155512"></a><a name="p14802935155512"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p8812193535516"><a name="p8812193535516"></a><a name="p8812193535516"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p68301754134120"><a name="p68301754134120"></a><a name="p68301754134120"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p132078004517"><a name="p132078004517"></a><a name="p132078004517"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p147954143315"><a name="p147954143315"></a><a name="p147954143315"></a>×</p>
</td>
</tr>
<tr id="row1511111910388"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p143496410465"><a name="p143496410465"></a><a name="p143496410465"></a>dup</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p17349942461"><a name="p17349942461"></a><a name="p17349942461"></a>复制文件句柄</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1299875075513"><a name="p1299875075513"></a><a name="p1299875075513"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p5183517557"><a name="p5183517557"></a><a name="p5183517557"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p133845110558"><a name="p133845110558"></a><a name="p133845110558"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p15488511558"><a name="p15488511558"></a><a name="p15488511558"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p15817510554"><a name="p15817510554"></a><a name="p15817510554"></a></p>
</td>
</tr>
<tr id="row512919173399"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p350604555614"><a name="p350604555614"></a><a name="p350604555614"></a>fsync</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p12506184516569"><a name="p12506184516569"></a><a name="p12506184516569"></a>文件内容刷入设备</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p13875181213213"><a name="p13875181213213"></a><a name="p13875181213213"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p0506145165613"><a name="p0506145165613"></a><a name="p0506145165613"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p6506124555620"><a name="p6506124555620"></a><a name="p6506124555620"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1925165204418"><a name="p1925165204418"></a><a name="p1925165204418"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1795065310333"><a name="p1795065310333"></a><a name="p1795065310333"></a>×</p>
</td>
</tr>
<tr id="row11374165313411"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p3724551105613"><a name="p3724551105613"></a><a name="p3724551105613"></a>ioctl</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p8724165112564"><a name="p8724165112564"></a><a name="p8724165112564"></a>设备控制</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p8724251165616"><a name="p8724251165616"></a><a name="p8724251165616"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p2725185119569"><a name="p2725185119569"></a><a name="p2725185119569"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p6725125118565"><a name="p6725125118565"></a><a name="p6725125118565"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p172511584419"><a name="p172511584419"></a><a name="p172511584419"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p795045363314"><a name="p795045363314"></a><a name="p795045363314"></a>×</p>
</td>
</tr>
<tr id="row1566230193619"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p8804322192315"><a name="p8804322192315"></a><a name="p8804322192315"></a>fcntl</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p2891723102316"><a name="p2891723102316"></a><a name="p2891723102316"></a>文件控制操作</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p16968175595517"><a name="p16968175595517"></a><a name="p16968175595517"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p69788557556"><a name="p69788557556"></a><a name="p69788557556"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p4987135555516"><a name="p4987135555516"></a><a name="p4987135555516"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1599755565514"><a name="p1599755565514"></a><a name="p1599755565514"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p551453173620"><a name="p551453173620"></a><a name="p551453173620"></a></p>
</td>
</tr>
<tr id="row98781157114116"><td class="cellrowborder" rowspan="17" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.1 "><p id="p10322754163618"><a name="p10322754163618"></a><a name="p10322754163618"></a>目录操作</p>
</td>
<td class="cellrowborder" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.2 "><p id="p98795579417"><a name="p98795579417"></a><a name="p98795579417"></a>mkdir</p>
</td>
<td class="cellrowborder" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.3 "><p id="p12879757144119"><a name="p12879757144119"></a><a name="p12879757144119"></a>创建目录</p>
</td>
<td class="cellrowborder" valign="top" width="5.499450054994501%" headers="mcps1.2.9.1.4 "><p id="p1361756205516"><a name="p1361756205516"></a><a name="p1361756205516"></a></p>
</td>
<td class="cellrowborder" valign="top" width="5.949405059494051%" headers="mcps1.2.9.1.5 "><p id="p717956115512"><a name="p717956115512"></a><a name="p717956115512"></a></p>
</td>
<td class="cellrowborder" valign="top" width="6.419358064193579%" headers="mcps1.2.9.1.6 "><p id="p32813566552"><a name="p32813566552"></a><a name="p32813566552"></a></p>
</td>
<td class="cellrowborder" valign="top" width="6.95930406959304%" headers="mcps1.2.9.1.7 "><p id="p537115611555"><a name="p537115611555"></a><a name="p537115611555"></a></p>
</td>
<td class="cellrowborder" valign="top" width="7.529247075292471%" headers="mcps1.2.9.1.8 "><p id="p9879165719415"><a name="p9879165719415"></a><a name="p9879165719415"></a>×</p>
</td>
</tr>
<tr id="row362155116544"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p166210511546"><a name="p166210511546"></a><a name="p166210511546"></a>opendir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p11621651135417"><a name="p11621651135417"></a><a name="p11621651135417"></a>打开目录</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1863161175612"><a name="p1863161175612"></a><a name="p1863161175612"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p16655191105612"><a name="p16655191105612"></a><a name="p16655191105612"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p267518118566"><a name="p267518118566"></a><a name="p267518118566"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p18686011561"><a name="p18686011561"></a><a name="p18686011561"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p369611105616"><a name="p369611105616"></a><a name="p369611105616"></a></p>
</td>
</tr>
<tr id="row183271724212"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p23313179429"><a name="p23313179429"></a><a name="p23313179429"></a>readdir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1433617124218"><a name="p1433617124218"></a><a name="p1433617124218"></a>读取目录</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1470631135613"><a name="p1470631135613"></a><a name="p1470631135613"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p0715810565"><a name="p0715810565"></a><a name="p0715810565"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p67251414566"><a name="p67251414566"></a><a name="p67251414566"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p14734511565"><a name="p14734511565"></a><a name="p14734511565"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1474419165617"><a name="p1474419165617"></a><a name="p1474419165617"></a></p>
</td>
</tr>
<tr id="row11310111512553"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p183101215155514"><a name="p183101215155514"></a><a name="p183101215155514"></a>closedir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p2031018155555"><a name="p2031018155555"></a><a name="p2031018155555"></a>关闭目录</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p177544125617"><a name="p177544125617"></a><a name="p177544125617"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p576311175619"><a name="p576311175619"></a><a name="p576311175619"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p18772171115612"><a name="p18772171115612"></a><a name="p18772171115612"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1978310112562"><a name="p1978310112562"></a><a name="p1978310112562"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p27921517569"><a name="p27921517569"></a><a name="p27921517569"></a></p>
</td>
</tr>
<tr id="row1774355219252"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p1074365218251"><a name="p1074365218251"></a><a name="p1074365218251"></a>telldir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p5743125232520"><a name="p5743125232520"></a><a name="p5743125232520"></a>获取目录偏移</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1880251135614"><a name="p1880251135614"></a><a name="p1880251135614"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p681110105618"><a name="p681110105618"></a><a name="p681110105618"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p1682112135612"><a name="p1682112135612"></a><a name="p1682112135612"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1583019165610"><a name="p1583019165610"></a><a name="p1583019165610"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p148397175618"><a name="p148397175618"></a><a name="p148397175618"></a></p>
</td>
</tr>
<tr id="row463867132610"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p463919772612"><a name="p463919772612"></a><a name="p463919772612"></a>seekdir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p163917702620"><a name="p163917702620"></a><a name="p163917702620"></a>设置目录偏移</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p08494113563"><a name="p08494113563"></a><a name="p08494113563"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p19858121175618"><a name="p19858121175618"></a><a name="p19858121175618"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p16867131175616"><a name="p16867131175616"></a><a name="p16867131175616"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p487621145618"><a name="p487621145618"></a><a name="p487621145618"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1088611118566"><a name="p1088611118566"></a><a name="p1088611118566"></a></p>
</td>
</tr>
<tr id="row1361903616456"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p186191936144513"><a name="p186191936144513"></a><a name="p186191936144513"></a>rewinddir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p186198365451"><a name="p186198365451"></a><a name="p186198365451"></a>重置目录偏移</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p82717515564"><a name="p82717515564"></a><a name="p82717515564"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p1128175145610"><a name="p1128175145610"></a><a name="p1128175145610"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p729113545616"><a name="p729113545616"></a><a name="p729113545616"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p163003585620"><a name="p163003585620"></a><a name="p163003585620"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p10950175314334"><a name="p10950175314334"></a><a name="p10950175314334"></a>×</p>
</td>
</tr>
<tr id="row1145016117201"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p9545171282019"><a name="p9545171282019"></a><a name="p9545171282019"></a>scandir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p9451131102012"><a name="p9451131102012"></a><a name="p9451131102012"></a>读取目录数据</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p230917512566"><a name="p230917512566"></a><a name="p230917512566"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p1831815155615"><a name="p1831815155615"></a><a name="p1831815155615"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p53275555611"><a name="p53275555611"></a><a name="p53275555611"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1033611512565"><a name="p1033611512565"></a><a name="p1033611512565"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p345131118206"><a name="p345131118206"></a><a name="p345131118206"></a></p>
</td>
</tr>
<tr id="row623472084218"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p92341220134219"><a name="p92341220134219"></a><a name="p92341220134219"></a>rmdir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1234220144217"><a name="p1234220144217"></a><a name="p1234220144217"></a>删除目录</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1034615175618"><a name="p1034615175618"></a><a name="p1034615175618"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p123567595611"><a name="p123567595611"></a><a name="p123567595611"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p63654555619"><a name="p63654555619"></a><a name="p63654555619"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1737485135619"><a name="p1737485135619"></a><a name="p1737485135619"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p179508533337"><a name="p179508533337"></a><a name="p179508533337"></a>×</p>
</td>
</tr>
<tr id="row1991017101176"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p09101210171712"><a name="p09101210171712"></a><a name="p09101210171712"></a>chdir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1091014106172"><a name="p1091014106172"></a><a name="p1091014106172"></a>切换当前路径</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p1338219545610"><a name="p1338219545610"></a><a name="p1338219545610"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p173911585618"><a name="p173911585618"></a><a name="p173911585618"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p13400053567"><a name="p13400053567"></a><a name="p13400053567"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p2040916516565"><a name="p2040916516565"></a><a name="p2040916516565"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p497687155612"><a name="p497687155612"></a><a name="p497687155612"></a></p>
</td>
</tr>
<tr id="row735414923319"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p19181108339"><a name="p19181108339"></a><a name="p19181108339"></a>getcwd</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p19354129143316"><a name="p19354129143316"></a><a name="p19354129143316"></a>获取当前路径</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p5419165105610"><a name="p5419165105610"></a><a name="p5419165105610"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p64281059561"><a name="p64281059561"></a><a name="p64281059561"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p174375585616"><a name="p174375585616"></a><a name="p174375585616"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p5446452567"><a name="p5446452567"></a><a name="p5446452567"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p5986171564"><a name="p5986171564"></a><a name="p5986171564"></a></p>
</td>
</tr>
<tr id="row080771185710"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p19826155733610"><a name="p19826155733610"></a><a name="p19826155733610"></a>realpath</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p766310254365"><a name="p766310254365"></a><a name="p766310254365"></a>相对/绝对路径转换</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p04551758568"><a name="p04551758568"></a><a name="p04551758568"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p124644516565"><a name="p124644516565"></a><a name="p124644516565"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p204731052562"><a name="p204731052562"></a><a name="p204731052562"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p34822575610"><a name="p34822575610"></a><a name="p34822575610"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p2996107145611"><a name="p2996107145611"></a><a name="p2996107145611"></a></p>
</td>
</tr>
<tr id="row194318220214"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p153666165451"><a name="p153666165451"></a><a name="p153666165451"></a>rename</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1136671615455"><a name="p1136671615455"></a><a name="p1136671615455"></a>文件/目录重命名</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p349119515619"><a name="p349119515619"></a><a name="p349119515619"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p95004515561"><a name="p95004515561"></a><a name="p95004515561"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p6509253569"><a name="p6509253569"></a><a name="p6509253569"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p155199525619"><a name="p155199525619"></a><a name="p155199525619"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p3342940193313"><a name="p3342940193313"></a><a name="p3342940193313"></a>×</p>
</td>
</tr>
<tr id="row944217272374"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p1044272714376"><a name="p1044272714376"></a><a name="p1044272714376"></a>chmod</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1044214273374"><a name="p1044214273374"></a><a name="p1044214273374"></a>修改文件/目录属性</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p43281412135617"><a name="p43281412135617"></a><a name="p43281412135617"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p1234641219566"><a name="p1234641219566"></a><a name="p1234641219566"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p17442927123717"><a name="p17442927123717"></a><a name="p17442927123717"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1644262714375"><a name="p1644262714375"></a><a name="p1644262714375"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1844218271376"><a name="p1844218271376"></a><a name="p1844218271376"></a>×</p>
</td>
</tr>
<tr id="row74691154211"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p1747111124210"><a name="p1747111124210"></a><a name="p1747111124210"></a>chown</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p0471911114215"><a name="p0471911114215"></a><a name="p0471911114215"></a>修改文件/目录所有者</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p836713125561"><a name="p836713125561"></a><a name="p836713125561"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p12377171265616"><a name="p12377171265616"></a><a name="p12377171265616"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p122061697438"><a name="p122061697438"></a><a name="p122061697438"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p2206159114316"><a name="p2206159114316"></a><a name="p2206159114316"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p920609134316"><a name="p920609134316"></a><a name="p920609134316"></a>×</p>
</td>
</tr>
<tr id="row1036123420529"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p730583495314"><a name="p730583495314"></a><a name="p730583495314"></a>stat/lstat</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p1630513410532"><a name="p1630513410532"></a><a name="p1630513410532"></a>查询文件/目录信息</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p338719123568"><a name="p338719123568"></a><a name="p338719123568"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p113961712125612"><a name="p113961712125612"></a><a name="p113961712125612"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p19388161745612"><a name="p19388161745612"></a><a name="p19388161745612"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p163981517185615"><a name="p163981517185615"></a><a name="p163981517185615"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p16287141955616"><a name="p16287141955616"></a><a name="p16287141955616"></a></p>
</td>
</tr>
<tr id="row16466943145113"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p4871175874615"><a name="p4871175874615"></a><a name="p4871175874615"></a>access</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p187125818465"><a name="p187125818465"></a><a name="p187125818465"></a>查询文件/目录访问权限</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p240531211562"><a name="p240531211562"></a><a name="p240531211562"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p141515129564"><a name="p141515129564"></a><a name="p141515129564"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p1640821725613"><a name="p1640821725613"></a><a name="p1640821725613"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p114181417125618"><a name="p114181417125618"></a><a name="p114181417125618"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p1829741985617"><a name="p1829741985617"></a><a name="p1829741985617"></a></p>
</td>
</tr>
<tr id="row780042214211"><td class="cellrowborder" rowspan="5" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.1 "><p id="p206804542364"><a name="p206804542364"></a><a name="p206804542364"></a>分区操作</p>
</td>
<td class="cellrowborder" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.2 "><p id="p1380192264218"><a name="p1380192264218"></a><a name="p1380192264218"></a>mount</p>
</td>
<td class="cellrowborder" valign="top" width="22.547745225477453%" headers="mcps1.2.9.1.3 "><p id="p38011522104210"><a name="p38011522104210"></a><a name="p38011522104210"></a>挂载分区</p>
</td>
<td class="cellrowborder" valign="top" width="5.499450054994501%" headers="mcps1.2.9.1.4 "><p id="p10424191245618"><a name="p10424191245618"></a><a name="p10424191245618"></a></p>
</td>
<td class="cellrowborder" valign="top" width="5.949405059494051%" headers="mcps1.2.9.1.5 "><p id="p24341126561"><a name="p24341126561"></a><a name="p24341126561"></a></p>
</td>
<td class="cellrowborder" valign="top" width="6.419358064193579%" headers="mcps1.2.9.1.6 "><p id="p3428151785614"><a name="p3428151785614"></a><a name="p3428151785614"></a></p>
</td>
<td class="cellrowborder" valign="top" width="6.95930406959304%" headers="mcps1.2.9.1.7 "><p id="p12437111785613"><a name="p12437111785613"></a><a name="p12437111785613"></a></p>
</td>
<td class="cellrowborder" valign="top" width="7.529247075292471%" headers="mcps1.2.9.1.8 "><p id="p4307161913563"><a name="p4307161913563"></a><a name="p4307161913563"></a></p>
</td>
</tr>
<tr id="row4684182822512"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p1468412813252"><a name="p1468412813252"></a><a name="p1468412813252"></a>umount</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p26846284258"><a name="p26846284258"></a><a name="p26846284258"></a>卸载分区</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p044321275614"><a name="p044321275614"></a><a name="p044321275614"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p84531312125615"><a name="p84531312125615"></a><a name="p84531312125615"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p244720173564"><a name="p244720173564"></a><a name="p244720173564"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p104571517155619"><a name="p104571517155619"></a><a name="p104571517155619"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p173412575334"><a name="p173412575334"></a><a name="p173412575334"></a>×</p>
</td>
</tr>
<tr id="row5177163172511"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p617843117252"><a name="p617843117252"></a><a name="p617843117252"></a>statfs</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p181781531192519"><a name="p181781531192519"></a><a name="p181781531192519"></a>查询挂载分区信息</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p144623124566"><a name="p144623124566"></a><a name="p144623124566"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p1747251235611"><a name="p1747251235611"></a><a name="p1747251235611"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p446813179565"><a name="p446813179565"></a><a name="p446813179565"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p147781716561"><a name="p147781716561"></a><a name="p147781716561"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p4178133182515"><a name="p4178133182515"></a><a name="p4178133182515"></a></p>
</td>
</tr>
<tr id="row1769881513348"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p156992015143419"><a name="p156992015143419"></a><a name="p156992015143419"></a>format</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p16935183513394"><a name="p16935183513394"></a><a name="p16935183513394"></a>格式化分区</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p19289615195611"><a name="p19289615195611"></a><a name="p19289615195611"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p14186550113916"><a name="p14186550113916"></a><a name="p14186550113916"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p382435053911"><a name="p382435053911"></a><a name="p382435053911"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1246615123918"><a name="p1246615123918"></a><a name="p1246615123918"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p13818525391"><a name="p13818525391"></a><a name="p13818525391"></a>×</p>
</td>
</tr>
<tr id="row4270132114219"><td class="cellrowborder" valign="top" headers="mcps1.2.9.1.1 "><p id="p958455012219"><a name="p958455012219"></a><a name="p958455012219"></a>sync</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.2 "><p id="p125840501224"><a name="p125840501224"></a><a name="p125840501224"></a>分区内容刷入设备</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.3 "><p id="p8300115125612"><a name="p8300115125612"></a><a name="p8300115125612"></a></p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.4 "><p id="p25044812404"><a name="p25044812404"></a><a name="p25044812404"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.5 "><p id="p17501248184019"><a name="p17501248184019"></a><a name="p17501248184019"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.6 "><p id="p1850154824012"><a name="p1850154824012"></a><a name="p1850154824012"></a>×</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.9.1.7 "><p id="p18505483404"><a name="p18505483404"></a><a name="p18505483404"></a>×</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section64113023616"></a>
文件系统的主要开发流程包括挂载/卸载分区,以及系列目录/文件操作。
### 编程实例<a name="section236041883618"></a>
代码实现如下:
```
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define LOS_OK 0
#define LOS_NOK -1
int main(void)
{
int ret;
int fd = -1;
ssize_t len;
off_t off;
char mntName[20] = "/storage";
char devName[20] = "/dev/mmcblk0p0";
char dirName[20] = "/storage/test";
char fileName[20] = "/storage/test/file.txt";
char writeBuf[20] = "Hello OpenHarmony!";
char readBuf[20] = {0};
/* 创建目录“/storage” */
ret = mkdir(mntName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return LOS_NOK;
}
/* 挂载设备“/dev/mmcblk0p0”到“/storage” */
ret = mount(devName, mntName, "vfat", 0, 0);
if (ret != LOS_OK) {
printf("mount failed.\n");
return LOS_NOK;
}
/* 创建目录“/storage/test” */
ret = mkdir(dirName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return LOS_NOK;
}
/* 创建可读写文件“/storage/test/file.txt” */
fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) {
printf("open file failed.\n");
return LOS_NOK;
}
/* 将writeBuf中的内容写入文件 */
len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) {
printf("write file failed.\n");
return LOS_NOK;
}
/* 将文件内容刷入存储设备中 */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return LOS_NOK;
}
/* 将读写指针偏移至文件头 */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return LOS_NOK;
}
/* 将文件内容读出至readBuf中,读取长度为readBuf大小 */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(readBuf)) {
printf("read file failed.\n");
return LOS_NOK;
}
printf("%s\n", readBuf);
/* 关闭文件 */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return LOS_NOK;
}
/* 删除文件“/storage/test/file.txt” */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return LOS_NOK;
}
/* 删除目录“/storage/test” */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return LOS_NOK;
}
/* 卸载分区“/storage” */
ret = umount(mntName);
if (ret != LOS_OK) {
printf("umount failed.\n");
return LOS_NOK;
}
/* 删除目录“/storage” */
ret = rmdir(mntName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return LOS_NOK;
}
return LOS_OK;
}
```
**结果验证**
编译运行得到的结果为:
```
Hello OpenHarmony!
```
# 文件系统<a name="ZH-CN_TOPIC_0000001079023774"></a>
文件系统(File System,或者简称FS),是操作系统中输入输出的一种主要形式,主要负责和内外部的存储设备交互。
文件系统对上通过C库提供的POSIX标准的操作接口,具体可以参考C库的API文档说明。对下,通过内核态的VFS虚拟层,屏蔽了各个具体文件系统的差异。基本架构如下:
**图 1** 文件系统的总体结构
![](figure/zh-cn_image_0000001125101908.png)
- **[虚拟文件系统](kernel-small-bundles-fs-virtual.md)**
- **[支持的文件系统](kernel-small-bundles-fs-support.md)**
- **[适配新的文件系统](kernel-small-bundles-fs-new.md)**
# 轻量级进程间通信<a name="ZH-CN_TOPIC_0000001123520161"></a>
- [基本概念](#section1980994712918)
- [运行机制](#section849811592918)
- [开发指导](#section17571315171017)
- [接口说明](#section725022011103)
## 基本概念<a name="section1980994712918"></a>
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消息)。
## 运行机制<a name="section849811592918"></a>
首先将需要接收IPC消息的任务通过ServiceManager注册成为一个Service,然后通过ServiceManager为该Service任务配置访问权限,即指定哪些任务可以向该Service任务发送IPC消息。LiteIPC的核心思想就是在内核态为每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层用户态程序分别提供代表收取IPC消息的读操作和代表发送IPC消息的写操作。
## 开发指导<a name="section17571315171017"></a>
### 接口说明<a name="section725022011103"></a>
**表 1** LiteIPC模块接口(仅LiteOS-A内部使用)
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row0415737175610"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p8866127195914"><a name="p8866127195914"></a><a name="p8866127195914"></a>模块初始化</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p58621910185914"><a name="p58621910185914"></a><a name="p58621910185914"></a>OsLiteIpcInit</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p48623102592"><a name="p48623102592"></a><a name="p48623102592"></a>初始化LiteIPC模块</p>
</td>
</tr>
<tr id="row1213865218584"><td class="cellrowborder" rowspan="3" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p1219312239566"><a name="p1219312239566"></a><a name="p1219312239566"></a>IPC消息内存池</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p20862510115911"><a name="p20862510115911"></a><a name="p20862510115911"></a>LiteIpcPoolInit</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p1886211011599"><a name="p1886211011599"></a><a name="p1886211011599"></a>初始化进程的IPC消息内存池</p>
</td>
</tr>
<tr id="row3231257145813"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3313428135414"><a name="p3313428135414"></a><a name="p3313428135414"></a>LiteIpcPoolReInit</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p586261085913"><a name="p586261085913"></a><a name="p586261085913"></a>重新初始化进程的IPC消息内存池</p>
</td>
</tr>
<tr id="row73651459105815"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p464344145411"><a name="p464344145411"></a><a name="p464344145411"></a>LiteIpcPoolDelete</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p555221518598"><a name="p555221518598"></a><a name="p555221518598"></a>释放进程的IPC消息内存池</p>
</td>
</tr>
<tr id="row178321454145812"><td class="cellrowborder" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p19527545175517"><a name="p19527545175517"></a><a name="p19527545175517"></a>Service管理</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p756845455415"><a name="p756845455415"></a><a name="p756845455415"></a>LiteIpcRemoveServiceHandle</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p1555261595915"><a name="p1555261595915"></a><a name="p1555261595915"></a>删除指定的Service</p>
</td>
</tr>
</tbody>
</table>
>![](../public_sys-resources/icon-note.gif) **说明:**
>LiteIPC模块接口都只在LiteOS-A内部使用。
# 动态加载与链接<a name="ZH-CN_TOPIC_0000001078523712"></a>
- [基本概念](#section208951139453)
- [运行机制](#section14140155320511)
- [开发指导](#section133501496612)
- [接口说明](#section874113201669)
- [开发流程](#section196712561563)
## 基本概念<a name="section208951139453"></a>
OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及动态链接器构成,内核加载器用于加载应用程序以及动态链接器,动态链接器用于加载应用程序所依赖的共享库,并对应用程序和共享库进行符号重定位。与静态链接相比,动态链接是将应用程序与动态库推迟到运行时再进行链接的一种机制。
**动态链接的优势:**
1. 多个应用程序可以共享一份代码,最小加载单元为页,相对静态链接可以节约磁盘和内存空间。
2. 共享库升级时,理论上将旧版本的共享库覆盖即可(共享库中的接口向下兼容),无需重新链接。
3. 加载地址可以进行随机化处理,防止攻击,保证安全性。
## 运行机制<a name="section14140155320511"></a>
**图 1** 动态加载流程<a name="fig1797764116422"></a>
![](figure/动态加载流程.png "动态加载流程")
1. 内核根据应用程序ELF文件的PT\_LOAD段信息映射至进程空间。对于ET\_EXEC类型的文件,根据PT\_LOAD段中p\_vaddr进行固定地址映射;对于ET\_DYN类型(位置无关的可执行程序,通过编译选项“-fPIE”得到)的文件,内核通过mmap接口选择base基址进行映射(load\_addr = base + p\_vaddr)。
2. 若应用程序是静态链接的(静态链接不支持编译选项“-fPIE”),设置堆栈信息后跳转至应用程序ELF文件中e\_entry指定的地址并运行;若程序是动态链接的,应用程序ELF文件中会有PT\_INTERP段,保存动态链接器的路径信息(ET\_DYN类型)。musl的动态链接器是libc-musl.so的一部分,libc-musl.so的入口即动态链接器的入口。内核通过mmap接口选择base基址进行映射,设置堆栈信息后跳转至base + e\_entry(该e\_entry为动态链接器的入口)地址并运行动态链接器。
3. 动态链接器自举并查找应用程序依赖的所有共享库并对导入符号进行重定位,最后跳转至应用程序的e\_entry(或base + e\_entry),开始运行应用程序。
**图 2** 程序执行流程<a name="fig17879151310447"></a>
![](figure/程序执行流程.png "程序执行流程")
1. 加载器与链接器调用mmap映射PT\_LOAD段;
2. 内核调用map\_pages接口查找并映射pagecache已有的缓存;
3. 程序执行时,内存若无所需代码或数据时触发缺页中断,将elf文件内容读入内存,并将该内存块加入pagecache;
4. 映射步骤3已读入文件内容的内存块;
5. 程序继续执行;
至此,程序将在不断地缺页中断中执行。
## 开发指导<a name="section133501496612"></a>
### 接口说明<a name="section874113201669"></a>
LOS\_DoExecveFile
**函数原型:**
INT32 LOS\_DoExecveFile\(const CHAR \*fileName, CHAR \* const \*argv, CHAR \* const \*envp\);
**函数功能:**根据fileName执行一个新的用户程序。
**参数说明:**
<a name="table13709103919318"></a>
<table><thead align="left"><tr id="row1170923910316"><th class="cellrowborder" valign="top" width="11.92%" id="mcps1.1.3.1.1"><p id="p1709123911313"><a name="p1709123911313"></a><a name="p1709123911313"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="88.08%" id="mcps1.1.3.1.2"><p id="p1970910395313"><a name="p1970910395313"></a><a name="p1970910395313"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row7709113923117"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p1870983993114"><a name="p1870983993114"></a><a name="p1870983993114"></a>fileName</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p870963913111"><a name="p870963913111"></a><a name="p870963913111"></a>二进制可执行文件名,可以是路径名。</p>
</td>
</tr>
<tr id="row0709163973120"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p170993918319"><a name="p170993918319"></a><a name="p170993918319"></a>argv</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p9294182194420"><a name="p9294182194420"></a><a name="p9294182194420"></a>程序执行所需的参数序列,以NULL结尾。无需参数时填入NULL。</p>
</td>
</tr>
<tr id="row341018142206"><td class="cellrowborder" valign="top" width="11.92%" headers="mcps1.1.3.1.1 "><p id="p6411121420204"><a name="p6411121420204"></a><a name="p6411121420204"></a>envp</p>
</td>
<td class="cellrowborder" valign="top" width="88.08%" headers="mcps1.1.3.1.2 "><p id="p4411161412011"><a name="p4411161412011"></a><a name="p4411161412011"></a>程序执行所需的新的环境变量序列,以NULL结尾。无需新的环境变量时填入NULL。</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section196712561563"></a>
LOS\_DoExecveFile接口一般由用户通过execve系列接口利用系统调用机制调用创建新的进程,内核不能直接调用该接口启动新进程。
# 虚拟动态共享库<a name="ZH-CN_TOPIC_0000001078863800"></a>
- [基本概念](#section174577181688)
- [运行机制](#section546363114810)
## 基本概念<a name="section174577181688"></a>
VDSO(Virtual Dynamic Shared Object,虚拟动态共享库)相对于普通的动态共享库,区别在于其so文件不保存在文件系统中,存在于系统镜像中,由内核在运行时确定并提供给应用程序,故称为虚拟动态共享库。
OpenHarmony系统通过VDSO机制实现上层用户态程序可以快速读取内核相关数据的一种通道方法,可用于实现部分系统调用的加速,也可用于实现非系统敏感数据(硬件配置、软件配置)的快速读取。
## 运行机制<a name="section546363114810"></a>
VDSO其核心思想就是内核看护一段内存,并将这段内存映射(只读)进用户态应用程序的地址空间,应用程序通过链接vdso.so后,将某些系统调用替换为直接读取这段已映射的内存从而避免系统调用达到加速的效果。
VDSO总体可分为数据页与代码页两部分:
- 数据页提供内核映射给用户进程的内核时数据;
- 代码页提供屏蔽系统调用的主要逻辑;
**图 1** VDSO系统设计<a name="fig1986131094711"></a>
![](figure/VDSO系统设计.jpg "VDSO系统设计")
如图1所示,当前VDSO机制有以下几个主要步骤:
① 内核初始化时进行VDSO数据页的创建;
② 内核初始化时进行VDSO代码页的创建;
③ 根据系统时钟中断不断将内核一些数据刷新进VDSO的数据页;
④ 用户进程创建时将代码页映射进用户空间;
⑤ 用户程序在动态链接时对VDSO的符号进行绑定;
⑥ 当用户程序进行特定系统调用时(例如clock\_gettime\(CLOCK\_REALTIME\_COARSE, &ts\)),VDSO代码页会将其拦截;
⑦ VDSO代码页将正常系统调用转为直接读取映射好的VDSO数据页;
⑧ 从VDSO数据页中将数据传回VDSO代码页;
⑨ 将从VDSO数据页获取到的数据作为结果返回给用户程序;
>![](../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, &ts\)或者clock\_gettime\(CLOCK\_MONOTONIC\_COARSE, &ts\)即可使用VDSO机制。
>- 使用VDSO机制得到的时间精度会与系统tick中断的精度保持一致,适用于对时间没有高精度要求且短时间内会高频触发clock\_gettime或gettimeofday系统调用的场景,若有高精度要求,不建议采用VDSO机制。
# 系统调用<a name="ZH-CN_TOPIC_0000001123520159"></a>
- [基本概念](#section889710401734)
- [运行机制](#section195177541314)
- [开发指导](#section193492047135419)
- [开发流程](#section7165741122210)
- [编程实例](#section107131418224)
## 基本概念<a name="section889710401734"></a>
OpenHarmony LiteOS-A实现了用户态与内核态的区分隔离,用户态程序不能直接访问内核资源,而系统调用则为用户态程序提供了一种访问内核资源、与内核进行交互的通道。
## 运行机制<a name="section195177541314"></a>
如图1所示,用户程序通过调用System API(系统API,通常是系统提供的POSIX接口)进行内核资源访问与交互请求,POSIX接口内部会触发SVC/SWI异常,完成系统从用户态到内核态的切换,然后对接到内核的Syscall Handler(系统调用统一处理接口)进行参数解析,最终分发至具体的内核处理函数。
**图 1** 系统调用示意图<a name="fig165662915310"></a>
![](figure/系统调用示意图.png "系统调用示意图")
Syscall Handler的具体实现在kernel/liteos\_a/syscall/los\_syscall.c中OsArmA32SyscallHandle函数,在进入系统软中断异常时会调用此函数,并且按照kernel/liteos\_a/syscall/syscall\_lookup.h中的清单进行系统调用的入参解析,执行各系统调用最终对应的内核处理函数。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 系统调用提供基础的用户态程序与内核的交互功能,不建议开发者直接使用系统调用接口,推荐使用内核提供的对外POSIX接口,若需要新增系统调用接口,详见开发指导。
>- 内核向用户态提供的系统调用接口清单详见kernel/liteos\_a/syscall/syscall\_lookup.h,内核相应的系统调用对接函数清单详见kernel/liteos\_a/syscall/los\_syscall.h。
## 开发指导<a name="section193492047135419"></a>
### 开发流程<a name="section7165741122210"></a>
新增系统调用的典型开发流程如下:
1. 在LibC库中确定并添加新增的系统调用号。
2. 在LibC库中新增用户态的函数接口声明及实现。
3. 在内核系统调用头文件中确定并添加新增的系统调用号及对应内核处理函数的声明。
4. 在内核中新增该系统调用对应的内核处理函数。
### 编程实例<a name="section107131418224"></a>
**示例代码**
1. 在LibC库syscall.h.in中新增系统调用号
如下所示,其中\_\_NR\_new\_syscall\_sample为新增系统调用号:
```
...
/* 当前现有的系统调用清单 */
/* OHOS customized syscalls, not compatible with ARM EABI */
#define __NR_OHOS_BEGIN 500
#define __NR_pthread_set_detach (__NR_OHOS_BEGIN + 0)
#define __NR_pthread_join (__NR_OHOS_BEGIN + 1)
#define __NR_pthread_deatch (__NR_OHOS_BEGIN + 2)
#define __NR_creat_user_thread (__NR_OHOS_BEGIN + 3)
#define __NR_processcreat (__NR_OHOS_BEGIN + 4)
#define __NR_processtart (__NR_OHOS_BEGIN + 5)
#define __NR_printf (__NR_OHOS_BEGIN + 6)
#define __NR_dumpmemory (__NR_OHOS_BEGIN + 13)
#define __NR_mkfifo (__NR_OHOS_BEGIN + 14)
#define __NR_mqclose (__NR_OHOS_BEGIN + 15)
#define __NR_realpath (__NR_OHOS_BEGIN + 16)
#define __NR_format (__NR_OHOS_BEGIN + 17)
#define __NR_shellexec (__NR_OHOS_BEGIN + 18)
#define __NR_ohoscapget (__NR_OHOS_BEGIN + 19)
#define __NR_ohoscapset (__NR_OHOS_BEGIN + 20)
#define __NR_new_syscall_sample (__NR_OHOS_BEGIN + 21) /* 新增的系统调用号 __NR_new_syscall_sample:521 */
#define __NR_syscallend (__NR_OHOS_BEGIN + 22)
...
```
2. 在LibC库中新增用户态接口的声明与实现
```
#include "stdio_impl.h"
#include "syscall.h"
...
/* 新增系统调用用户态的接口实现 */
void newSyscallSample(int num)
{
printf("user mode: num = %d\n", num);
__syscall(SYS_new_syscall_sample, num);
return;
}
```
3. 在内核系统调用头文件中新增系统调用号
如下所示,在third\_party/musl/porting/liteos\_a/kernel/include/bits/syscall.h文件中,\_\_NR\_new\_syscall\_sample为新增系统调用号。
```
...
/* 当前现有的系统调用清单 */
/* OHOS customized syscalls, not compatible with ARM EABI */
#define __NR_OHOS_BEGIN 500
#define __NR_pthread_set_detach (__NR_OHOS_BEGIN + 0)
#define __NR_pthread_join (__NR_OHOS_BEGIN + 1)
#define __NR_pthread_deatch (__NR_OHOS_BEGIN + 2)
#define __NR_creat_user_thread (__NR_OHOS_BEGIN + 3)
#define __NR_processcreat (__NR_OHOS_BEGIN + 4)
#define __NR_processtart (__NR_OHOS_BEGIN + 5)
#define __NR_printf (__NR_OHOS_BEGIN + 6)
#define __NR_dumpmemory (__NR_OHOS_BEGIN + 13)
#define __NR_mkfifo (__NR_OHOS_BEGIN + 14)
#define __NR_mqclose (__NR_OHOS_BEGIN + 15)
#define __NR_realpath (__NR_OHOS_BEGIN + 16)
#define __NR_format (__NR_OHOS_BEGIN + 17)
#define __NR_shellexec (__NR_OHOS_BEGIN + 18)
#define __NR_ohoscapget (__NR_OHOS_BEGIN + 19)
#define __NR_ohoscapset (__NR_OHOS_BEGIN + 20)
#define __NR_new_syscall_sample (__NR_OHOS_BEGIN + 21) /* 新增的系统调用号 __NR_new_syscall_sample:521 */
#define __NR_syscallend (__NR_OHOS_BEGIN + 22)
...
```
在kernel/liteos\_a/syscall/syscall\_lookup.h中,增加一行SYSCALL\_HAND\_DEF\(\_\_NR\_new\_syscall\_sample, SysNewSyscallSample, void, ARG\_NUM\_1\):
```
...
/* 当前现有的系统调用清单 */
SYSCALL_HAND_DEF(__NR_chown, SysChown, int, ARG_NUM_3)
SYSCALL_HAND_DEF(__NR_chown32, SysChown, int, ARG_NUM_3)
#ifdef LOSCFG_SECURITY_CAPABILITY
SYSCALL_HAND_DEF(__NR_ohoscapget, SysCapGet, UINT32, ARG_NUM_2)
SYSCALL_HAND_DEF(__NR_ohoscapset, SysCapSet, UINT32, ARG_NUM_1)
#endif
/* 新增系统调用 */
SYSCALL_HAND_DEF(__NR_new_syscall_sample, SysNewSyscallSample, void, ARG_NUM_1)
...
```
4. 在内核中新增内核该系统调用对应的处理函数
如下所示,在kernel/liteos\_a/syscall/los\_syscall.h中,SysNewSyscallSample为新增系统调用的内核处理函数声明:
```
...
/* 当前现有的系统调用内核处理函数声明清单 */
extern int SysClockSettime64(clockid_t clockID, const struct timespec64 *tp);
extern int SysClockGettime64(clockid_t clockID, struct timespec64 *tp);
extern int SysClockGetres64(clockid_t clockID, struct timespec64 *tp);
extern int SysClockNanoSleep64(clockid_t clk, int flags, const struct timespec64 *req, struct timespec64 *rem);
extern int SysTimerGettime64(timer_t timerID, struct itimerspec64 *value);
extern int SysTimerSettime64(timer_t timerID, int flags, const struct itimerspec64 *value, struct itimerspec64 *oldValue);
/* 新增的系统调用内核处理函数声明 */
extern void SysNewSyscallSample(int num);
...
```
新增的系统调用的内核处理函数实现如下:
```
include "los_printf.h"
...
/* 新增系统调用内核处理函数的实现 */
void SysNewSyscallSample(int num)
{
PRINTK("kernel mode: num = %d\n", num);
return;
}
```
**结果验证:**
用户态程序调用newSyscallSample\(10\)接口,得到输出结果如下:
```
/* 用户态接口与内核态接口均有输出,证明系统调用已使能 */
user mode: num = 10
kernel mode: num = 10
```
# 扩展组件<a name="ZH-CN_TOPIC_0000001078204130"></a>
- **[系统调用](kernel-small-bundles-system.md)**
- **[动态加载与链接](kernel-small-bundles-linking.md)**
- **[虚拟动态共享库](kernel-small-bundles-share.md)**
- **[轻量级进程间通信](kernel-small-bundles-ipc.md)**
- **[文件系统](kernel-small-bundles-fs.md)**
# 踩内存检测<a name="ZH-CN_TOPIC_0000001079036352"></a>
- [基础概念](#section17368154517335)
- [功能配置](#section4696190123420)
- [开发指导](#section672362973417)
- [开发流程](#section026014863416)
- [编程实例](#section186311302356)
## 基础概念<a name="section17368154517335"></a>
踩内存检测机制作为内核的可选功能,用于检测动态内存池的完整性。通过该机制,可以及时发现内存池是否发生了踩内存问题,并给出错误信息,便于及时发现系统问题,提高问题解决效率,降低问题定位成本。
## 功能配置<a name="section4696190123420"></a>
LOSCFG\_BASE\_MEM\_NODE\_INTEGRITY\_CHECK:开关宏,默认关闭;若打开这个功能,可以在配置项中开启“Debug-\> Enable integrity check or not”。
1、开启这个功能,每次申请内存,会实时检测内存池的完整性。
2、如果不开启该功能,也可以调用LOS\_MemIntegrityCheck接口检测,但是每次申请内存时,不会实时检测内存完整性,而且由于节点头没有魔鬼数字(开启时才有,省内存),检测的准确性也会相应降低,但对于系统的性能没有影响,故根据实际情况开关该功能。
由于该功能只会检测出哪个内存节点被破坏了,并给出前节点信息(因为内存分布是连续的,当前节点最有可能被前节点破坏)。如果要进一步确认前节点在哪里申请的,需开启内存泄漏检测功能,通过LR记录,辅助定位。
>![](../public_sys-resources/icon-caution.gif) **注意:**
>开启该功能,节点头多了魔鬼数字字段,会增大节点头大小。由于实时检测完整性,故性能影响较大;若性能敏感的场景,可以不开启该功能,使用LOS\_MemIntegrityCheck接口检测。
## 开发指导<a name="section672362973417"></a>
### 开发流程<a name="section026014863416"></a>
通过调用LOS\_MemIntegrityCheck接口检测内存池是否发生了踩内存,如果没有踩内存问题,那么接口返回0且没有log输出;如果存在踩内存问题,那么会输出相关log,详见下文编程实例的结果输出。
### 编程实例<a name="section186311302356"></a>
本实例实现如下功能:
1. 申请两个物理上连续的内存块;
2. 通过memset构造越界访问,踩到下个节点的头4个字节;
3. 调用LOS\_MemIntegrityCheck检测是否发生踩内存。
**示例代码**
代码实现如下:
```
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
#include "los_config.h"
void MemIntegrityTest(void)
{
/* 申请两个物理连续的内存块 */
void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
/* 第一个节点内存块大小是8字节,那么12字节的清零,会踩到第二个内存节点的节点头,构造踩内存场景 */
memset(ptr1, 0, 8 + 4);
LOS_MemIntegrityCheck(LOSCFG_SYS_HEAP_ADDR);
}
```
**结果验证**
编译运行输出log如下:
```
[ERR][OsMemMagicCheckPrint], 2028, memory check error!
memory used but magic num wrong, magic num = 0x00000000 /* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020
/* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */
broken node head LR info: /* 节点的LR信息需要开启内存检测功能才有有效输出 */
LR[0]:0x0800414e
LR[1]:0x08000cc2
LR[2]:0x00000000
pre node head LR info: /* 通过LR信息,可以在汇编文件中查找前节点是哪里申请,然后排查其使用的准确性 */
LR[0]:0x08004144
LR[1]:0x08000cc2
LR[2]:0x00000000
[ERR]Memory interity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* 被破坏节点和其前节点的地址 */
```
# 内存信息统计<a name="ZH-CN_TOPIC_0000001078716768"></a>
- [基础概念](#section52691565235)
- [功能配置](#section470611682411)
- [开发指导](#section9368374243)
- [开发流程](#section679912407257)
- [编程实例](#section1025453412611)
## 基础概念<a name="section52691565235"></a>
内存信息包括内存池大小、内存使用量、剩余内存大小、最大空闲内存、内存水线、内存节点数统计、碎片率等。
- 内存水线:即内存池的最大使用量,每次申请和释放时,都会更新水线值,实际业务可根据该值,优化内存池大小;
- 碎片率:衡量内存池的碎片化程度,碎片率高表现为内存池剩余内存很多,但是最大空闲内存块很小,可以用公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)来度量
- 其他统计信息:调用接口LOS\_MemInfoGet时,会扫描内存池的节点信息,统计出相关信息。
## 功能配置<a name="section470611682411"></a>
LOSCFG\_MEM\_WATERLINE:开关宏,默认关闭;若需要打开这个功能,可以在配置项中开启“Debug-\> Enable memory pool waterline or not”。如需获取内存水线,需要打开该配置。
## 开发指导<a name="section9368374243"></a>
### 开发流程<a name="section679912407257"></a>
关键结构体介绍:
```
typedef struct {
UINT32 totalUsedSize; // 内存池的内存使用量
UINT32 totalFreeSize; // 内存池的剩余内存大小
UINT32 maxFreeNodeSize; // 内存池的最大空闲内存块大小
UINT32 usedNodeNum; // 内存池的非空闲内存块个数
UINT32 freeNodeNum; // 内存池的空闲内存块个数
#if (LOSCFG_MEM_WATERLINE == 1) // 默认关闭,可以通过menuconfig配置工具打开
UINT32 usageWaterLine; // 内存池的水线值
#endif
} LOS_MEM_POOL_STATUS;
```
- 内存水线获取:调用LOS\_MemInfoGet接口,第1个参数是内存池首地址,第2个参数是LOS\_MEM\_POOL\_STATUS类型的句柄,其中字段usageWaterLine即水线值。
- 内存碎片率计算:同样调用LOS\_MemInfoGet接口,可以获取内存池的剩余内存大小和最大空闲内存块大小,然后根据公式(fragment=100-100\*最大空闲内存块大小/剩余内存大小)得出此时的动态内存池碎片率。
### 编程实例<a name="section1025453412611"></a>
本实例实现如下功能:
1. 创建一个监控线程,用于获取内存池的信息;
2. 调用LOS\_MemInfoGet接口,获取内存池的基础信息;
3. 利用公式算出使用率及碎片率。
**示例代码**
代码实现如下:
```
#include <stdio.h>
#include <string.h>
#include "los_task.h"
#include "los_memory.h"
#include "los_config.h"
void MemInfoTaskFunc(void)
{
LOS_MEM_POOL_STATUS poolStatus = {0};
/* pool为要统计信息的内存地址,此处以OS_SYS_MEM_ADDR为例 */
void *pool = OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool, &poolStatus);
/* 算出内存池当前的碎片率百分比 */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize;
/* 算出内存池当前的使用率百分比 */
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,
poolStatus.totalFreeSize, poolStatus.usageWaterLine);
}
int MemTest(void)
{
unsigned int ret;
unsigned int taskID;
TSK_INIT_PARAM_S taskStatus = {0};
taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc;
taskStatus.uwStackSize = 0x1000;
taskStatus.pcName = "memInfo";
taskStatus.usTaskPrio = 10;
ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) {
printf("task create failed\n");
return -1;
}
return 0;
}
```
**结果验证**
编译运行输出的结果如下:
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
```
# 内存泄漏检测<a name="ZH-CN_TOPIC_0000001078876382"></a>
- [基础概念](#section1026719436293)
- [功能配置](#section13991354162914)
- [开发指导](#section95828159308)
- [开发流程](#section369844416304)
- [编程实例](#section460801313313)
## 基础概念<a name="section1026719436293"></a>
内存泄漏检测机制作为内核的可选功能,用于辅助定位动态内存泄漏问题。开启该动能,动态内存机制会自动记录申请内存时的函数调用关系(下文简称LR)。如果出现泄漏,就可以利用这些记录的信息,找到内存申请的地方,方便进一步确认。
## 功能配置<a name="section13991354162914"></a>
1. LOSCFG\_MEM\_LEAKCHECK:开关宏,默认关闭;如需要打开这个功能,可以在配置项中开启“Debug-\> Enable Function call stack of Mem operation recorded”。
2. LOS\_RECORD\_LR\_CNT:记录的LR层数,默认3层;每层LR消耗sizeof\(void \*\)字节数的内存。
3. LOS\_OMIT\_LR\_CNT:忽略的LR层数,默认2层,即从调用LOS\_MemAlloc的函数开始记录,可根据实际情况调整。为啥需要这个配置?有3点原因如下:
- LOS\_MemAlloc接口内部也有函数调用;
- 外部可能对LOS\_MemAlloc接口有封装;
- LOS\_RECORD\_LR\_CNT 配置的LR层数有限;
正确配置这个宏,将无效的LR层数忽略,就可以记录有效的LR层数,节省内存消耗。
## 开发指导<a name="section95828159308"></a>
### 开发流程<a name="section369844416304"></a>
该调测功能可以分析关键的代码逻辑中是否存在内存泄漏。开启这个功能,每次申请内存时,会记录LR信息。在需要检测的代码段前后,调用LOS\_MemUsedNodeShow接口,每次都会打印指定内存池已使用的全部节点信息,对比前后两次的节点信息,新增的节点信息就是疑似泄漏的内存节点。通过LR,可以找到具体申请的代码位置,进一步确认是否泄漏。
调用LOS\_MemUsedNodeShow接口输出的节点信息格式如下:每1行为一个节点信息;第1列为节点地址,可以根据这个地址,使用GDB等手段查看节点完整信息;第2列为节点的大小,等于节点头大小+数据域大小;第3\~5列为函数调用关系LR地址,可以根据这个值,结合汇编文件,查看该节点具体申请的位置。
```
node size LR[0] LR[1] LR[2]
0x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002
0x10017848: 0xe0 0x9b02c24e 0x9b02c246 0x9b008ef0
0x10017928: 0x50 0x9b008ed0 0x9b068902 0x9b0687c4
0x10017978: 0x24 0x9b008ed0 0x9b068924 0x9b0687c4
0x1001799c: 0x30 0x9b02c24e 0x9b02c246 0x9b008ef0
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
```
>![](../public_sys-resources/icon-caution.gif) **注意:**
>开启内存检测会影响内存申请的性能,且每个内存节点都会记录LR地址,内存开销也加大。
### 编程实例<a name="section460801313313"></a>
本实例实现如下功能:构建内存泄漏代码段。
1. 调用OsMemUsedNodeShow接口,输出全部节点信息打印;
2. 申请内存,但没有释放,模拟内存泄漏;
3. 再次调用OsMemUsedNodeShow接口,输出全部节点信息打印;
4. 将两次log进行对比,得出泄漏的节点信息;
5. 通过LR地址,找出泄漏的代码位置;
**示例代码**
代码实现如下:
```
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
#include "los_config.h"
void MemLeakTest(void)
{
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
}
```
**结果验证**
编译运行输出log如下:
```
node size LR[0] LR[1] LR[2]
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
node size LR[0] LR[1] LR[2]
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,差异如下,这些内存节点就是疑似泄漏的内存块:
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
```
部分汇编文件如下:
```
MemLeakTest:
0x80041d4: 0xb510 PUSH {R4, LR}
0x80041d6: 0x4ca8 LDR.N R4, [PC, #0x2a0] ; g_memStart
0x80041d8: 0x0020 MOVS R0, R4
0x80041da: 0xf7fd 0xf93e BL LOS_MemUsedNodeShow ; 0x800145a
0x80041de: 0x2108 MOVS R1, #8
0x80041e0: 0x0020 MOVS R0, R4
0x80041e2: 0xf7fd 0xfbd9 BL LOS_MemAlloc ; 0x8001998
0x80041e6: 0x2108 MOVS R1, #8
0x80041e8: 0x0020 MOVS R0, R4
0x80041ea: 0xf7fd 0xfbd5 BL LOS_MemAlloc ; 0x8001998
0x80041ee: 0x0020 MOVS R0, R4
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a
0x80041f4: 0xbd10 POP {R4, PC}
0x80041f6: 0x0000 MOVS R0, R0
```
其中,通过查找0x080041ee,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。
# 内存调测<a name="ZH-CN_TOPIC_0000001124056309"></a>
- **[内存信息统计](kernel-small-debug-memory-info.md)**
- **[内存泄漏检测](kernel-small-debug-memory-leak.md)**
- **[踩内存检测](kernel-small-debug-memory-corrupt.md)**
# 其他内核调测手段<a name="ZH-CN_TOPIC_0000001173169005"></a>
- **[临终遗言](kernel-small-debug-trace-other-lastwords.md)**
- **[常见问题定位方法](kernel-small-debug-trace-other-faqs.md)**
# CPU占用率<a name="ZH-CN_TOPIC_0000001123188477"></a>
- [基本概念](#section17683419227)
- [运行机制](#section593718536227)
- [开发指导](#section11284210152311)
- [接口说明](#section3745151592312)
- [开发流程](#section122901429182316)
- [编程实例](#section1765785212310)
## 基本概念<a name="section17683419227"></a>
CPU(中央处理器,Central Processing Unit)占用率分为系统CPU占用率、进程CPU占用率、任务CPU占用率和中断CPU占用率。用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规格。通过系统中各个进程/任务/中断的CPU占用情况,判断各个进程/任务/中断的CPU占用率是否符合设计的预期。
- 系统CPU占用率(CPU Percent)
指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示系统满负荷运转。
- 进程CPU占用率
指单个进程的CPU占用率,用于表示单个进程在一段时间内的闲忙程度。进程CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示在一段时间内系统一直在运行该进程。
- 任务CPU占用率
指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示在一段时间内系统一直在运行该任务。
- 中断CPU占用率
指单个中断的CPU占用率,用于表示单个中断在一段时间内的闲忙程度。中断CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示在一段时间内系统一直在运行该中断。
## 运行机制<a name="section593718536227"></a>
OpenHarmony LiteOS-A内核CPUP(CPU Percent,CPU占用率)模块采用进程、任务和中断级记录的方式,在进程/任务切换时,记录进程/任务启动时间,进程/任务切出或者退出时,系统会累加整个进程/任务的占用时间; 在执行中断时系统会累加记录每个中断的执行时间。
OpenHarmony 提供以下四种CPU占用率的信息查询:
- 系统CPU占用率
- 进程CPU占用率
- 任务CPU占用率
- 中断CPU占用率
**CPU占用率的计算方法:**
系统CPU占用率=系统中除idle任务外其他任务运行总时间/系统运行总时间
进程CPU占用率=进程运行总时间/系统运行总时间
任务CPU占用率=任务运行总时间/系统运行总时间
中断CPU占用率=中断运行总时间/系统运行总时间
## 开发指导<a name="section11284210152311"></a>
### 接口说明<a name="section3745151592312"></a>
**表 1** CPUP模块接口
<a name="table147491853163018"></a>
<table><thead align="left"><tr id="row10807205323013"><th class="cellrowborder" valign="top" width="28.3971602839716%" id="mcps1.2.4.1.1"><p id="p980714539304"><a name="p980714539304"></a><a name="p980714539304"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="36.47635236476353%" id="mcps1.2.4.1.2"><p id="p1780715533305"><a name="p1780715533305"></a><a name="p1780715533305"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="35.12648735126487%" id="mcps1.2.4.1.3"><p id="p18807185316301"><a name="p18807185316301"></a><a name="p18807185316301"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row3807145310300"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p174011140141013"><a name="p174011140141013"></a><a name="p174011140141013"></a>系统CPU占用率</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p158071153133013"><a name="p158071153133013"></a><a name="p158071153133013"></a>LOS_HistorySysCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p14808115353010"><a name="p14808115353010"></a><a name="p14808115353010"></a>获取系统历史CPU占用率</p>
</td>
</tr>
<tr id="row147461859201016"><td class="cellrowborder" rowspan="2" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p374720596102"><a name="p374720596102"></a><a name="p374720596102"></a>进程CPU占用率</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p3747859101010"><a name="p3747859101010"></a><a name="p3747859101010"></a>LOS_HistoryProcessCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p1747959131016"><a name="p1747959131016"></a><a name="p1747959131016"></a>获取指定进程历史CPU占用率</p>
</td>
</tr>
<tr id="row2075434812116"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17541648171114"><a name="p17541648171114"></a><a name="p17541648171114"></a>LOS_GetAllProcessCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1575419483116"><a name="p1575419483116"></a><a name="p1575419483116"></a>获取系统所有进程的历史CPU占用率</p>
</td>
</tr>
<tr id="row1480855311301"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p1618792981018"><a name="p1618792981018"></a><a name="p1618792981018"></a>任务CPU占用率</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p9808185353016"><a name="p9808185353016"></a><a name="p9808185353016"></a>LOS_HistoryTaskCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p12808653183016"><a name="p12808653183016"></a><a name="p12808653183016"></a>获取指定任务历史CPU占用率</p>
</td>
</tr>
<tr id="row680812535306"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p13808125314307"><a name="p13808125314307"></a><a name="p13808125314307"></a>中断CPU占用率</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p1480835316303"><a name="p1480835316303"></a><a name="p1480835316303"></a>LOS_GetAllIrqCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p33741531163313"><a name="p33741531163313"></a><a name="p33741531163313"></a>获取系统所有中断的历史CPU占用率</p>
</td>
</tr>
</tbody>
</table>
### 开发流程<a name="section122901429182316"></a>
CPU占用率的典型开发流程:
1. 调用获取系统历史CPU占用率函数LOS\_HistorySysCpuUsage。
2. 调用获取指定进程历史CPU占用率函数LOS\_HistoryProcessCpuUsage。
- 若进程已创建,则关中断,根据不同模式正常获取,恢复中断;
- 若进程未创建,则返回错误码;
3. 调用获取所有进程CPU占用率函数LOS\_GetAllProcessCpuUsage。
- 若CPUP已初始化,则关中断,根据不同模式正常获取,恢复中断;
- 若CPUP未初始化或有非法入参,则返回错误码;
4. 调用获取指定任务历史CPU占用率函数LOS\_HistoryTaskCpuUsage。
- 若任务已创建,则关中断,根据不同模式正常获取,恢复中断;
- 若任务未创建,则返回错误码;
5. 调用获取所有中断CPU占用率函数LOS\_GetAllIrqCpuUsage。
- 若CPUP已初始化,则关中断,根据不同模式正常获取,恢复中断;
- 若CPUP未初始化或有非法入参,则返回错误码;
### 编程实例<a name="section1765785212310"></a>
本实例实现如下功能:
1. 创建一个用于CPUP测试的任务。
2. 获取当前系统CPUP。
3. 以不同模式获取历史系统CPUP。
4. 获取创建的测试任务的CPUP。
5. 以不同模式获取创建的测试任务的CPUP。
前提条件:
在menuconfig 配置中打开cpup控制开关。
**示例代码**
代码实现如下:
```
#include "los_task.h"
#include "los_cpup.h"
#define MODE 4
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
{
printf("entry cpup test example\n");
while(1) {
usleep(100);
}
}
UINT32 ItCpupTest(VOID)
{
UINT32 ret;
UINT32 cpupUse;
TSK_INIT_PARAM_S cpupTestTask = { 0 };
memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S));
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = 0x800;
cpupTestTask.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask);
if(ret != LOS_OK) {
printf("cpupTestTask create failed .\n");
return LOS_NOK;
}
usleep(100);
/* 获取当前系统历史cpu占用率 */
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S);
printf("the history system cpu usage in all time:%u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
/* 获取指定任务的cpu占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S);
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);
return LOS_OK;
}
```
**结果验证**
编译运行得到的结果为:
```
entry cpup test example
the history system cpu usage in all time: 3.0
cpu usage of the cpupTestTask in all time: TaskID:10 usage: 0.0
```
# 进程调测<a name="ZH-CN_TOPIC_0000001173350145"></a>
- **[CPU占用率](kernel-small-debug-process-cpu.md)**
# Shell命令编程实例<a name="ZH-CN_TOPIC_0000001052451603"></a> # Shell命令编程实例<a name="ZH-CN_TOPIC_0000001134006246"></a>
- [实例描述](#section87143612316) - [实例描述](#section87143612316)
- [静态注册方式](#section1660495712314) - [静态注册方式](#section1660495712314)
- [静态注册编程实例](#section0410326242) - [静态注册编程实例](#section1233411684113)
- [动态注册方式](#section6804126192412) - [动态注册方式](#section6804126192412)
- [动态注册编程实例](#section17474410102419) - [动态注册编程实例](#section2335121613418)
## 实例描述<a name="section87143612316"></a> ## 实例描述<a name="section87143612316"></a>
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
4. 重新编译代码后运行。 4. 重新编译代码后运行。
## 静态注册编程实例<a name="section0410326242"></a> ## 静态注册编程实例<a name="section1233411684113"></a>
1. 定义命令所要调用的函数cmd\_test: 1. 定义命令所要调用的函数cmd\_test:
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
2. 重新编译后运行。 2. 重新编译后运行。
## 动态注册编程实例<a name="section17474410102419"></a> ## 动态注册编程实例<a name="section2335121613418"></a>
1. 在用户应用函数中调用osCmdReg函数动态注册命令。 1. 在用户应用函数中调用osCmdReg函数动态注册命令。
......
# cpup<a name="ZH-CN_TOPIC_0000001051451546"></a> # cpup<a name="ZH-CN_TOPIC_0000001133846470"></a>
- [命令功能](#section1842161614217) - [命令功能](#section1842161614217)
- [命令格式](#section5629527427) - [命令格式](#section5629527427)
...@@ -30,10 +30,7 @@ cpup \[_mode_\] \[_taskID_\] ...@@ -30,10 +30,7 @@ cpup \[_mode_\] \[_taskID_\]
</thead> </thead>
<tbody><tr id="row3787mcpsimp"><td class="cellrowborder" valign="top" width="16%" headers="mcps1.2.4.1.1 "><p id="p3789mcpsimp"><a name="p3789mcpsimp"></a><a name="p3789mcpsimp"></a>mode</p> <tbody><tr id="row3787mcpsimp"><td class="cellrowborder" valign="top" width="16%" headers="mcps1.2.4.1.1 "><p id="p3789mcpsimp"><a name="p3789mcpsimp"></a><a name="p3789mcpsimp"></a>mode</p>
</td> </td>
<td class="cellrowborder" valign="top" width="56.99999999999999%" headers="mcps1.2.4.1.2 "><p id="p168830912393"><a name="p168830912393"></a><a name="p168830912393"></a>● 缺省:显示系统最近10s内的CPU占用率。</p> <td class="cellrowborder" valign="top" width="56.99999999999999%" headers="mcps1.2.4.1.2 "><a name="ul1530071303413"></a><a name="ul1530071303413"></a><ul id="ul1530071303413"><li>缺省:显示系统最近10s内的CPU占用率。</li><li>0:显示系统最近10s内的CPU占用率。</li><li>1:显示系统最近1s内的CPU占用率。</li><li>其他数字:显示系统启动至今总的CPU 占用率。</li></ul>
<p id="p1522761212395"><a name="p1522761212395"></a><a name="p1522761212395"></a>● 0:显示系统最近10s内的CPU占用率。</p>
<p id="p325915149394"><a name="p325915149394"></a><a name="p325915149394"></a>● 1:显示系统最近1s内的CPU占用率。</p>
<p id="p3791mcpsimp"><a name="p3791mcpsimp"></a><a name="p3791mcpsimp"></a>● 其他数字:显示系统启动至今总的CPU 占用率。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="27%" headers="mcps1.2.4.1.3 "><p id="p3794mcpsimp"><a name="p3794mcpsimp"></a><a name="p3794mcpsimp"></a>[0,0xFFFFFFFF]</p> <td class="cellrowborder" valign="top" width="27%" headers="mcps1.2.4.1.3 "><p id="p3794mcpsimp"><a name="p3794mcpsimp"></a><a name="p3794mcpsimp"></a>[0,0xFFFFFFFF]</p>
</td> </td>
......
# date<a name="ZH-CN_TOPIC_0000001051770290"></a> # date<a name="ZH-CN_TOPIC_0000001134006248"></a>
- [命令功能](#section56472016338) - [命令功能](#section56472016338)
- [命令格式](#section16635112512316) - [命令格式](#section16635112512316)
......
# dmesg<a name="ZH-CN_TOPIC_0000001052530284"></a> # dmesg<a name="ZH-CN_TOPIC_0000001179845915"></a>
- [命令功能](#section4643204919313) - [命令功能](#section4643204919313)
- [命令格式](#section6553153635) - [命令格式](#section6553153635)
......
# exec<a name="ZH-CN_TOPIC_0000001053502450"></a> # exec<a name="ZH-CN_TOPIC_0000001179965833"></a>
- [命令功能](#section4643204919313) - [命令功能](#section4643204919313)
- [命令格式](#section6553153635) - [命令格式](#section6553153635)
......
# free<a name="ZH-CN_TOPIC_0000001051930299"></a> # free<a name="ZH-CN_TOPIC_0000001133846472"></a>
- [命令功能](#section175151514841) - [命令功能](#section175151514841)
- [命令格式](#section8488721749) - [命令格式](#section8488721749)
......
# help<a name="ZH-CN_TOPIC_0000001052170303"></a> # help<a name="ZH-CN_TOPIC_0000001134006250"></a>
- [命令功能](#section991211345413) - [命令功能](#section991211345413)
- [命令格式](#section19103204016410) - [命令格式](#section19103204016410)
......
# hwi<a name="ZH-CN_TOPIC_0000001051690311"></a> # hwi<a name="ZH-CN_TOPIC_0000001179845917"></a>
- [命令功能](#section445335110416) - [命令功能](#section445335110416)
- [命令格式](#section1795712553416) - [命令格式](#section1795712553416)
...@@ -32,11 +32,11 @@ hwi ...@@ -32,11 +32,11 @@ hwi
1. 显示中断信息(LOSCFG\_CPUP\_INCLUDE\_IRQ关闭) 1. 显示中断信息(LOSCFG\_CPUP\_INCLUDE\_IRQ关闭)
![](figure/zh-cn_image_0000001053826366.png) ![](figure/zh-cn_image_0000001179967527.png)
2. 显示中断信息(LOSCFG\_CPUP\_INCLUDE\_IRQ打开) 2. 显示中断信息(LOSCFG\_CPUP\_INCLUDE\_IRQ打开)
![](figure/zh-cn_image_0000001052810304.png) ![](figure/zh-cn_image_0000001133848164.png)
**表 1** 输出说明 **表 1** 输出说明
......
# kill<a name="ZH-CN_TOPIC_0000001053719629"></a> # kill<a name="ZH-CN_TOPIC_0000001179965835"></a>
- [命令功能](#section366714216619) - [命令功能](#section366714216619)
- [命令格式](#section8833164614615) - [命令格式](#section8833164614615)
......
# log<a name="ZH-CN_TOPIC_0000001052370295"></a> # log<a name="ZH-CN_TOPIC_0000001133846474"></a>
- [命令功能](#section128219131856) - [命令功能](#section128219131856)
- [命令格式](#section3894181710519) - [命令格式](#section3894181710519)
...@@ -70,5 +70,5 @@ log level \[_levelNum_\] ...@@ -70,5 +70,5 @@ log level \[_levelNum_\]
## 输出说明<a name="section14354765415"></a> ## 输出说明<a name="section14354765415"></a>
![](figure/zh-cn_image_0000001052530298.png) ![](figure/zh-cn_image_0000001179847649.png)
# memcheck<a name="ZH-CN_TOPIC_0000001052170276"></a> # memcheck<a name="ZH-CN_TOPIC_0000001134006252"></a>
- [命令功能](#section191633812516) - [命令功能](#section191633812516)
- [命令格式](#section428816435510) - [命令格式](#section428816435510)
......
# oom<a name="ZH-CN_TOPIC_0000001053839618"></a> # oom<a name="ZH-CN_TOPIC_0000001179845919"></a>
- [命令功能](#section366714216619) - [命令功能](#section366714216619)
- [命令格式](#section8833164614615) - [命令格式](#section8833164614615)
- [参数说明](#section12809111019453) - [参数说明](#section12809111019453)
- [使用指南](#section15935131220717) - [使用指南](#section15935131220717)
- [使用实例](#section79281818476)
- [输出说明](#section12742311179) - [输出说明](#section12742311179)
## 命令功能<a name="section366714216619"></a> ## 命令功能<a name="section366714216619"></a>
...@@ -71,13 +70,13 @@ oom -h | --help ...@@ -71,13 +70,13 @@ oom -h | --help
- 参数缺省时,显示oom功能当前配置信息。 - 参数缺省时,显示oom功能当前配置信息。
## 使用实例<a name="section79281818476"></a> >![](../public_sys-resources/icon-note.gif) **说明:**
>当系统内存不足时,会打印出内存不足的提示信息。
当系统内存不足时,会打印出内存不足的提示信息。
## 输出说明<a name="section12742311179"></a> ## 输出说明<a name="section12742311179"></a>
![](figure/zh-cn_image_0000001053710680.png) ![](figure/zh-cn_image_0000001134008030.png)
**表 2** 输出说明 **表 2** 输出说明
......
# pmm<a name="ZH-CN_TOPIC_0000001054783044"></a> # pmm<a name="ZH-CN_TOPIC_0000001179965839"></a>
- [命令功能](#section445335110416) - [命令功能](#section445335110416)
- [命令格式](#section1795712553416) - [命令格式](#section1795712553416)
......
# reset<a name="ZH-CN_TOPIC_0000001053359638"></a> # reset<a name="ZH-CN_TOPIC_0000001133846476"></a>
- [命令功能](#section366714216619) - [命令功能](#section366714216619)
- [命令格式](#section8833164614615) - [命令格式](#section8833164614615)
......
# sem<a name="ZH-CN_TOPIC_0000001052810290"></a> # sem<a name="ZH-CN_TOPIC_0000001134006254"></a>
- [命令功能](#section366714216619) - [命令功能](#section366714216619)
- [命令格式](#section8833164614615) - [命令格式](#section8833164614615)
......
# stack<a name="ZH-CN_TOPIC_0000001054064419"></a> # stack<a name="ZH-CN_TOPIC_0000001179845921"></a>
- [命令功能](#section445335110416) - [命令功能](#section445335110416)
- [命令格式](#section1795712553416) - [命令格式](#section1795712553416)
...@@ -32,7 +32,7 @@ stack ...@@ -32,7 +32,7 @@ stack
**图 1** 系统堆栈使用情况<a name="fig478715471421"></a> **图 1** 系统堆栈使用情况<a name="fig478715471421"></a>
![](figure/zh-cn_image_0000001054624363.png) ![](figure/zh-cn_image_0000001133848370.png)
**表 1** 输出说明 **表 1** 输出说明
......
# su<a name="ZH-CN_TOPIC_0000001052451605"></a> # su<a name="ZH-CN_TOPIC_0000001179965841"></a>
- [命令功能](#section297810431676) - [命令功能](#section297810431676)
- [命令格式](#section157131147876) - [命令格式](#section157131147876)
......
# swtmr<a name="ZH-CN_TOPIC_0000001051611538"></a> # swtmr<a name="ZH-CN_TOPIC_0000001133846478"></a>
- [命令功能](#section166171064814) - [命令功能](#section166171064814)
- [命令格式](#section424011111682) - [命令格式](#section424011111682)
......
# systeminfo<a name="ZH-CN_TOPIC_0000001051451591"></a> # systeminfo<a name="ZH-CN_TOPIC_0000001134006256"></a>
- [命令功能](#section863016434820) - [命令功能](#section863016434820)
- [命令格式](#section139791817795) - [命令格式](#section139791817795)
......
# task<a name="ZH-CN_TOPIC_0000001051451548"></a> # task<a name="ZH-CN_TOPIC_0000001179845923"></a>
- [命令功能](#section0533181714106) - [命令功能](#section0533181714106)
- [命令格式](#section1014412308101) - [命令格式](#section1014412308101)
......
# uname<a name="ZH-CN_TOPIC_0000001051770292"></a> # uname<a name="ZH-CN_TOPIC_0000001179965843"></a>
- [命令功能](#section107697383115) - [命令功能](#section107697383115)
- [命令格式](#section162824341116) - [命令格式](#section162824341116)
...@@ -68,5 +68,5 @@ uname用于显示当前操作系统名称。语法uname -a | -t| -s| -v 描述un ...@@ -68,5 +68,5 @@ uname用于显示当前操作系统名称。语法uname -a | -t| -s| -v 描述un
查看系统信息 查看系统信息
![](figure/zh-cn_image_0000001052370305.png) ![](figure/zh-cn_image_0000001179967909.png)
# vmm<a name="ZH-CN_TOPIC_0000001054144356"></a> # vmm<a name="ZH-CN_TOPIC_0000001133846480"></a>
- [命令功能](#section445335110416) - [命令功能](#section445335110416)
- [命令格式](#section1795712553416) - [命令格式](#section1795712553416)
......
# watch<a name="ZH-CN_TOPIC_0000001052530286"></a> # watch<a name="ZH-CN_TOPIC_0000001134006258"></a>
- [命令功能](#section20643141481314) - [命令功能](#section20643141481314)
- [命令格式](#section1075441721316) - [命令格式](#section1075441721316)
......
# 系统命令<a name="ZH-CN_TOPIC_0000001179965831"></a>
- **[cpup](kernel-small-debug-shell-cmd-cpup.md)**
- **[date](kernel-small-debug-shell-cmd-date.md)**
- **[dmesg](kernel-small-debug-shell-cmd-dmesg.md)**
- **[exec](kernel-small-debug-shell-cmd-exec.md)**
- **[free](kernel-small-debug-shell-cmd-free.md)**
- **[help](kernel-small-debug-shell-cmd-help.md)**
- **[hwi](kernel-small-debug-shell-cmd-hwi.md)**
- **[kill](kernel-small-debug-shell-cmd-kill.md)**
- **[log](kernel-small-debug-shell-cmd-log.md)**
- **[memcheck](kernel-small-debug-shell-cmd-memcheck.md)**
- **[oom](kernel-small-debug-shell-cmd-oom.md)**
- **[pmm](kernel-small-debug-shell-cmd-pmm.md)**
- **[reset](kernel-small-debug-shell-cmd-reset.md)**
- **[sem](kernel-small-debug-shell-cmd-sem.md)**
- **[stack](kernel-small-debug-shell-cmd-stack.md)**
- **[su](kernel-small-debug-shell-cmd-su.md)**
- **[swtmr](kernel-small-debug-shell-cmd-swtmr.md)**
- **[systeminfo](kernel-small-debug-shell-cmd-sysinfo.md)**
- **[task](kernel-small-debug-shell-cmd-task.md)**
- **[uname](kernel-small-debug-shell-cmd-uname.md)**
- **[vmm](kernel-small-debug-shell-cmd-vmm.md)**
- **[watch](kernel-small-debug-shell-cmd-watch.md)**
# Shell命令使用详解<a name="ZH-CN_TOPIC_0000001179845913"></a>
本章节介绍了系统关键命令的功能、格式、参数范围、使用指南和使用实例。
不在本文档范围内的命令,详见[help](kernel-small-debug-shell-cmd-help.md)命令的输出内容,也可以通过命令的“-h | --help”选项,查看该命令的使用帮助。
- **[系统命令](kernel-small-debug-shell-cmd.md)**
- **[文件命令](kernel-small-debug-shell-file.md)**
- **[网络命令](kernel-small-debug-shell-net.md)**
# 用户态异常信息说明<a name="ZH-CN_TOPIC_0000001051770298"></a> # 用户态异常信息说明<a name="ZH-CN_TOPIC_0000001134006276"></a>
用户态在运行过程中,可能由于各种原因出现用户态系统异常,异常信息如下所示: 用户态在运行过程中,可能由于各种原因出现用户态系统异常,异常信息如下所示:
......
# cat<a name="ZH-CN_TOPIC_0000001052170305"></a> # cat<a name="ZH-CN_TOPIC_0000001179965845"></a>
- [命令功能](#section16710153391315) - [命令功能](#section16710153391315)
- [命令格式](#section1699392313158) - [命令格式](#section1699392313158)
......
# cd<a name="ZH-CN_TOPIC_0000001051690313"></a> # cd<a name="ZH-CN_TOPIC_0000001133846482"></a>
- [命令功能](#section11690184921316) - [命令功能](#section11690184921316)
- [命令格式](#section75695409569) - [命令格式](#section75695409569)
......
# chgrp<a name="ZH-CN_TOPIC_0000001052370297"></a> # chgrp<a name="ZH-CN_TOPIC_0000001134006260"></a>
- [命令功能](#section6103119161418) - [命令功能](#section6103119161418)
- [命令格式](#section186958132141) - [命令格式](#section186958132141)
......
# chmod<a name="ZH-CN_TOPIC_0000001052170278"></a> # chmod<a name="ZH-CN_TOPIC_0000001179845927"></a>
- [命令功能](#section13992936121418) - [命令功能](#section13992936121418)
- [命令格式](#section63342439147) - [命令格式](#section63342439147)
......
# chown<a name="ZH-CN_TOPIC_0000001052810292"></a> # chown<a name="ZH-CN_TOPIC_0000001179965847"></a>
- [命令功能](#section247414691513) - [命令功能](#section247414691513)
- [命令格式](#section14773151018159) - [命令格式](#section14773151018159)
......
# cp<a name="ZH-CN_TOPIC_0000001052451607"></a> # cp<a name="ZH-CN_TOPIC_0000001133846484"></a>
- [命令功能](#section6841203041513) - [命令功能](#section6841203041513)
- [命令格式](#section24286359150) - [命令格式](#section24286359150)
...@@ -64,5 +64,5 @@ cp \[_SOURCEFILE_\] \[_DESTFILE_\] ...@@ -64,5 +64,5 @@ cp \[_SOURCEFILE_\] \[_DESTFILE_\]
## 输出说明<a name="section16754183195914"></a> ## 输出说明<a name="section16754183195914"></a>
**图 1** 显示结果如下<a name="fig184025115493"></a> **图 1** 显示结果如下<a name="fig184025115493"></a>
![](figure/显示结果如下-17.png "显示结果如下-17") ![](figure/显示结果如下-24.png "显示结果如下-24")
# format<a name="ZH-CN_TOPIC_0000001051611540"></a> # format<a name="ZH-CN_TOPIC_0000001134006262"></a>
- [命令功能](#section1922331919169) - [命令功能](#section1922331919169)
- [命令格式](#section249226169) - [命令格式](#section249226169)
...@@ -65,5 +65,5 @@ format <_dev\_inodename_\> <_sectors_\> <_option_\> \[_label_\] ...@@ -65,5 +65,5 @@ format <_dev\_inodename_\> <_sectors_\> <_option_\> \[_label_\]
结果如下 结果如下
![](figure/zh-cn_image_0000001052370307.png) ![](figure/zh-cn_image_0000001134008686.png)
# ls<a name="ZH-CN_TOPIC_0000001051451593"></a> # ls<a name="ZH-CN_TOPIC_0000001179845929"></a>
- [命令功能](#section6538163771614) - [命令功能](#section6538163771614)
- [命令格式](#section45881743111616) - [命令格式](#section45881743111616)
......
# lsfd<a name="ZH-CN_TOPIC_0000001051451550"></a> # lsfd<a name="ZH-CN_TOPIC_0000001179965849"></a>
- [命令功能](#section2053406181716) - [命令功能](#section2053406181716)
- [命令格式](#section523771017172) - [命令格式](#section523771017172)
......
# mkdir<a name="ZH-CN_TOPIC_0000001051770294"></a> # mkdir<a name="ZH-CN_TOPIC_0000001133846486"></a>
- [命令功能](#section1083613274175) - [命令功能](#section1083613274175)
- [命令格式](#section820913118178) - [命令格式](#section820913118178)
......
# mount<a name="ZH-CN_TOPIC_0000001052530288"></a> # mount<a name="ZH-CN_TOPIC_0000001134006264"></a>
- [命令功能](#section11631837182) - [命令功能](#section11631837182)
- [命令格式](#section1697638111820) - [命令格式](#section1697638111820)
...@@ -74,5 +74,5 @@ mount后加需要挂载的设备信息、指定目录以及设备文件格式, ...@@ -74,5 +74,5 @@ mount后加需要挂载的设备信息、指定目录以及设备文件格式,
将/dev/mmcblk0p0 挂载到/bin1/vs/sd目录 将/dev/mmcblk0p0 挂载到/bin1/vs/sd目录
![](figure/zh-cn_image_0000001051690323.png) ![](figure/zh-cn_image_0000001134008688.png)
# partinfo<a name="ZH-CN_TOPIC_0000001051930303"></a> # partinfo<a name="ZH-CN_TOPIC_0000001179845931"></a>
- [命令功能](#section1777503617199) - [命令功能](#section1777503617199)
- [命令格式](#section185501447132114) - [命令格式](#section185501447132114)
...@@ -48,5 +48,5 @@ partinfo /dev/mmcblk0p0 ...@@ -48,5 +48,5 @@ partinfo /dev/mmcblk0p0
## 输出说明<a name="section66689331412"></a> ## 输出说明<a name="section66689331412"></a>
![](figure/zh-cn_image_0000001052370303.png) ![](figure/zh-cn_image_0000001133848906.png)
# partition<a name="ZH-CN_TOPIC_0000001052170307"></a> # partition<a name="ZH-CN_TOPIC_0000001179965851"></a>
- [命令功能](#section255095212257) - [命令功能](#section255095212257)
- [命令格式](#section10258056122515) - [命令格式](#section10258056122515)
...@@ -58,5 +58,5 @@ partition \[_nand / spinor_\] ...@@ -58,5 +58,5 @@ partition \[_nand / spinor_\]
查看spinor flash分区信息 查看spinor flash分区信息
![](figure/zh-cn_image_0000001052810300.png) ![](figure/zh-cn_image_0000001179848349.png)
# pwd<a name="ZH-CN_TOPIC_0000001051690315"></a> # pwd<a name="ZH-CN_TOPIC_0000001133846488"></a>
- [命令功能](#section197737712267) - [命令功能](#section197737712267)
- [命令格式](#section1544061016267) - [命令格式](#section1544061016267)
......
# rm<a name="ZH-CN_TOPIC_0000001052370299"></a> # rm<a name="ZH-CN_TOPIC_0000001134006266"></a>
- [命令功能](#section181141523142613) - [命令功能](#section181141523142613)
- [命令格式](#section8800926132619) - [命令格式](#section8800926132619)
......
# rmdir<a name="ZH-CN_TOPIC_0000001052170280"></a> # rmdir<a name="ZH-CN_TOPIC_0000001179845933"></a>
- [命令功能](#section1839611420266) - [命令功能](#section1839611420266)
- [命令格式](#section329574512266) - [命令格式](#section329574512266)
......
# statfs<a name="ZH-CN_TOPIC_0000001052810294"></a> # statfs<a name="ZH-CN_TOPIC_0000001179965853"></a>
- [命令功能](#section153921657152613) - [命令功能](#section153921657152613)
- [命令格式](#section135391102717) - [命令格式](#section135391102717)
......
# sync<a name="ZH-CN_TOPIC_0000001052451609"></a> # sync<a name="ZH-CN_TOPIC_0000001133846490"></a>
- [命令功能](#section1285017122274) - [命令功能](#section1285017122274)
- [命令格式](#section4731516162712) - [命令格式](#section4731516162712)
......
# touch<a name="ZH-CN_TOPIC_0000001051611542"></a> # touch<a name="ZH-CN_TOPIC_0000001134006268"></a>
- [命令功能](#section17541924112716) - [命令功能](#section17541924112716)
- [命令格式](#section866182711274) - [命令格式](#section866182711274)
......
# umount<a name="ZH-CN_TOPIC_0000001051451595"></a> # umount<a name="ZH-CN_TOPIC_0000001179965855"></a>
- [命令功能](#section365125133520) - [命令功能](#section365125133520)
- [命令格式](#section9615254123512) - [命令格式](#section9615254123512)
......
# writeproc<a name="ZH-CN_TOPIC_0000001053240965"></a> # writeproc<a name="ZH-CN_TOPIC_0000001179845935"></a>
- [命令功能](#section366714216619) - [命令功能](#section366714216619)
- [命令格式](#section8833164614615) - [命令格式](#section8833164614615)
......
# 文件命令<a name="ZH-CN_TOPIC_0000001179845925"></a>
- **[cat](kernel-small-debug-shell-file-cat.md)**
- **[cd](kernel-small-debug-shell-file-cd.md)**
- **[chgrp](kernel-small-debug-shell-file-chgrp.md)**
- **[chmod](kernel-small-debug-shell-file-chmod.md)**
- **[chown](kernel-small-debug-shell-file-chown.md)**
- **[cp](kernel-small-debug-shell-file-cp.md)**
- **[format](kernel-small-debug-shell-file-format.md)**
- **[ls](kernel-small-debug-shell-file-ls.md)**
- **[lsfd](kernel-small-debug-shell-file-lsfd.md)**
- **[mkdir](kernel-small-debug-shell-file-mkdir.md)**
- **[mount](kernel-small-debug-shell-file-mount.md)**
- **[partinfo](kernel-small-debug-shell-file-partinfo.md)**
- **[partition](kernel-small-debug-shell-file-partition.md)**
- **[pwd](kernel-small-debug-shell-file-pwd.md)**
- **[rm](kernel-small-debug-shell-file-rm.md)**
- **[rmdir](kernel-small-debug-shell-file-rmdir.md)**
- **[statfs](kernel-small-debug-shell-file-statfs.md)**
- **[sync](kernel-small-debug-shell-file-sync.md)**
- **[touch](kernel-small-debug-shell-file-touch.md)**
- **[writeproc](kernel-small-debug-shell-file-write.md)**
- **[umount](kernel-small-debug-shell-file-umount.md)**
# Shell命令开发指导<a name="ZH-CN_TOPIC_0000001052370293"></a> # Shell命令开发指导<a name="ZH-CN_TOPIC_0000001133846468"></a>
- [开发指导](#section22071515161018) - [开发指导](#section13408945163812)
## 开发指导<a name="section22071515161018"></a> ## 开发指导<a name="section13408945163812"></a>
新增Shell命令的典型开发流程如下: 新增Shell命令的典型开发流程如下:
...@@ -75,7 +75,6 @@ ...@@ -75,7 +75,6 @@
如:上述“ls”命令注册时,需在build/mk/liteos\_tables\_ldflags.mk中添加“-uls\_shellcmd”。其中-u后面跟SHELLCMD\_ENTRY的第一个参数。 如:上述“ls”命令注册时,需在build/mk/liteos\_tables\_ldflags.mk中添加“-uls\_shellcmd”。其中-u后面跟SHELLCMD\_ENTRY的第一个参数。
2. 动态注册命令方式: 2. 动态注册命令方式:
注册函数原型: 注册函数原型:
...@@ -125,7 +124,6 @@ ...@@ -125,7 +124,6 @@
osCmdReg(CMD_TYPE_EX, "ls", XARGS, (CMD_CBK_FUNC)osShellCmdLs) osCmdReg(CMD_TYPE_EX, "ls", XARGS, (CMD_CBK_FUNC)osShellCmdLs)
``` ```
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
>命令关键字必须是唯一的,也即两个不同的命令项不能拥有相同的命令关键字,否则只会执行其中一个。 >命令关键字必须是唯一的,也即两个不同的命令项不能拥有相同的命令关键字,否则只会执行其中一个。
>Shell在执行用户命令时,如果存在多个命令关键字相同的命令,只会执行其中在"help"命令中排序在最前面的一个。 >Shell在执行用户命令时,如果存在多个命令关键字相同的命令,只会执行其中在"help"命令中排序在最前面的一个。
...@@ -161,7 +159,7 @@ ...@@ -161,7 +159,7 @@
4. 输入Shell命令,有两种输入方式: 4. 输入Shell命令,有两种输入方式:
- 在串口工具中直接输入Shell命令。 - 在串口工具中直接输入Shell命令。
- 在telnet工具中输入Shell命令(telnet使用方式详见[telnet](kernel-lite-small-shell-cmd-net-tel.md))。 - 在telnet工具中输入Shell命令(telnet使用方式详见[telnet](kernel-small-debug-shell-net-telnet.md))。
# 魔法键使用方法<a name="ZH-CN_TOPIC_0000001051451554"></a> # 魔法键使用方法<a name="ZH-CN_TOPIC_0000001133846498"></a>
- [使用场景](#section2350114718546) - [使用场景](#section2350114718546)
- [使用方法](#section3305151511559) - [使用方法](#section3305151511559)
......
# arp<a name="ZH-CN_TOPIC_0000001052530290"></a> # arp<a name="ZH-CN_TOPIC_0000001134006270"></a>
- [命令功能](#section201149459368) - [命令功能](#section201149459368)
- [命令格式](#section579813484364) - [命令格式](#section579813484364)
......
# dhclient<a name="ZH-CN_TOPIC_0000001053200896"></a> # dhclient<a name="ZH-CN_TOPIC_0000001179845937"></a>
- [命令功能](#section366714216619) - [命令功能](#section366714216619)
- [命令格式](#section8833164614615) - [命令格式](#section8833164614615)
...@@ -110,7 +110,7 @@ dhclient -sd 8.8.8.8 ...@@ -110,7 +110,7 @@ dhclient -sd 8.8.8.8
## 使用实例<a name="section79281818476"></a> ## 使用实例<a name="section79281818476"></a>
![](figure/zh-cn_image_0000001053224218.png) ![](figure/zh-cn_image_0000001179848731.png)
## 输出说明<a name="section12742311179"></a> ## 输出说明<a name="section12742311179"></a>
......
# dns<a name="ZH-CN_TOPIC_0000001051930305"></a> # dns<a name="ZH-CN_TOPIC_0000001179965857"></a>
- [命令功能](#section997513673713) - [命令功能](#section997513673713)
- [命令格式](#section146015943711) - [命令格式](#section146015943711)
......
# ifconfig<a name="ZH-CN_TOPIC_0000001052170309"></a> # ifconfig<a name="ZH-CN_TOPIC_0000001133846494"></a>
- [命令功能](#section174940284379) - [命令功能](#section174940284379)
- [命令格式](#section136073203715) - [命令格式](#section136073203715)
...@@ -42,8 +42,7 @@ ifconfig ...@@ -42,8 +42,7 @@ ifconfig
</thead> </thead>
<tbody><tr id="row2018mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2020mcpsimp"><a name="p2020mcpsimp"></a><a name="p2020mcpsimp"></a>不带参数</p> <tbody><tr id="row2018mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2020mcpsimp"><a name="p2020mcpsimp"></a><a name="p2020mcpsimp"></a>不带参数</p>
</td> </td>
<td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2022mcpsimp"><a name="p2022mcpsimp"></a><a name="p2022mcpsimp"></a>打印所有网卡的IP地址、网络掩码、网</p> <td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2022mcpsimp"><a name="p2022mcpsimp"></a><a name="p2022mcpsimp"></a>打印所有网卡的IP地址、网络掩码、网关、硬件mac地址、MTU、运行状态等信息。</p>
<p id="p2023mcpsimp"><a name="p2023mcpsimp"></a><a name="p2023mcpsimp"></a>关、硬件mac地址、MTU、运行状态等信息。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2025mcpsimp"><a name="p2025mcpsimp"></a><a name="p2025mcpsimp"></a>N/A</p> <td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2025mcpsimp"><a name="p2025mcpsimp"></a><a name="p2025mcpsimp"></a>N/A</p>
</td> </td>
...@@ -71,25 +70,21 @@ ifconfig ...@@ -71,25 +70,21 @@ ifconfig
</tr> </tr>
<tr id="row2047mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2049mcpsimp"><a name="p2049mcpsimp"></a><a name="p2049mcpsimp"></a>netmask</p> <tr id="row2047mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2049mcpsimp"><a name="p2049mcpsimp"></a><a name="p2049mcpsimp"></a>netmask</p>
</td> </td>
<td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2051mcpsimp"><a name="p2051mcpsimp"></a><a name="p2051mcpsimp"></a>设置子网掩码,后面要掩码参数,比如</p> <td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2051mcpsimp"><a name="p2051mcpsimp"></a><a name="p2051mcpsimp"></a>设置子网掩码,后面要掩码参数,比如255.255.255.0。</p>
<p id="p2052mcpsimp"><a name="p2052mcpsimp"></a><a name="p2052mcpsimp"></a>255.255.255.0。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2054mcpsimp"><a name="p2054mcpsimp"></a><a name="p2054mcpsimp"></a>N/A</p> <td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2054mcpsimp"><a name="p2054mcpsimp"></a><a name="p2054mcpsimp"></a>N/A</p>
</td> </td>
</tr> </tr>
<tr id="row2055mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2057mcpsimp"><a name="p2057mcpsimp"></a><a name="p2057mcpsimp"></a>gateway</p> <tr id="row2055mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2057mcpsimp"><a name="p2057mcpsimp"></a><a name="p2057mcpsimp"></a>gateway</p>
</td> </td>
<td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2059mcpsimp"><a name="p2059mcpsimp"></a><a name="p2059mcpsimp"></a>设置网关,后面跟网关参数,比如</p> <td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2059mcpsimp"><a name="p2059mcpsimp"></a><a name="p2059mcpsimp"></a>设置网关,后面跟网关参数,比如192.168.1.1。</p>
<p id="p2060mcpsimp"><a name="p2060mcpsimp"></a><a name="p2060mcpsimp"></a>192.168.1.1。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2062mcpsimp"><a name="p2062mcpsimp"></a><a name="p2062mcpsimp"></a>N/A</p> <td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2062mcpsimp"><a name="p2062mcpsimp"></a><a name="p2062mcpsimp"></a>N/A</p>
</td> </td>
</tr> </tr>
<tr id="row2063mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2065mcpsimp"><a name="p2065mcpsimp"></a><a name="p2065mcpsimp"></a>hw ether</p> <tr id="row2063mcpsimp"><td class="cellrowborder" valign="top" width="17.93%" headers="mcps1.2.4.1.1 "><p id="p2065mcpsimp"><a name="p2065mcpsimp"></a><a name="p2065mcpsimp"></a>hw ether</p>
</td> </td>
<td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2067mcpsimp"><a name="p2067mcpsimp"></a><a name="p2067mcpsimp"></a>设置mac地址, 后面是MAC地址,比如</p> <td class="cellrowborder" valign="top" width="53.669999999999995%" headers="mcps1.2.4.1.2 "><p id="p2067mcpsimp"><a name="p2067mcpsimp"></a><a name="p2067mcpsimp"></a>设置mac地址, 后面是MAC地址,比如00:11:22:33:44:55。目前只支持ether硬件类型。</p>
<p id="p2068mcpsimp"><a name="p2068mcpsimp"></a><a name="p2068mcpsimp"></a>00:11:22:33:44:55。目前只支持ether硬件类</p>
<p id="p2069mcpsimp"><a name="p2069mcpsimp"></a><a name="p2069mcpsimp"></a>型。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2071mcpsimp"><a name="p2071mcpsimp"></a><a name="p2071mcpsimp"></a>N/A</p> <td class="cellrowborder" valign="top" width="28.4%" headers="mcps1.2.4.1.3 "><p id="p2071mcpsimp"><a name="p2071mcpsimp"></a><a name="p2071mcpsimp"></a>N/A</p>
</td> </td>
......
# ipdebug<a name="ZH-CN_TOPIC_0000001051690317"></a> # ipdebug<a name="ZH-CN_TOPIC_0000001134006272"></a>
- [命令功能](#section10191115553720) - [命令功能](#section10191115553720)
- [命令格式](#section124061758123713) - [命令格式](#section124061758123713)
......
# netstat<a name="ZH-CN_TOPIC_0000001052370301"></a> # netstat<a name="ZH-CN_TOPIC_0000001179845939"></a>
- [命令功能](#section13469162113816) - [命令功能](#section13469162113816)
- [命令格式](#section795712373812) - [命令格式](#section795712373812)
...@@ -30,7 +30,7 @@ netstat ...@@ -30,7 +30,7 @@ netstat
**图 1** netstat 打印信息<a name="fig51865585412"></a> **图 1** netstat 打印信息<a name="fig51865585412"></a>
![](figure/Snipaste_2021-01-26_10-38-58-18.png) ![](figure/Snipaste_2021-01-26_10-38-58-25.png)
## 输出说明<a name="section1357015107117"></a> ## 输出说明<a name="section1357015107117"></a>
......
# ntpdate<a name="ZH-CN_TOPIC_0000001052170282"></a> # ntpdate<a name="ZH-CN_TOPIC_0000001179965859"></a>
- [命令功能](#section38494293815) - [命令功能](#section38494293815)
- [命令格式](#section5503114413387) - [命令格式](#section5503114413387)
......
# ping<a name="ZH-CN_TOPIC_0000001052810296"></a> # ping<a name="ZH-CN_TOPIC_0000001133846496"></a>
- [命令功能](#section119672573385) - [命令功能](#section119672573385)
- [命令格式](#section869419010390) - [命令格式](#section869419010390)
...@@ -55,16 +55,14 @@ ping _-k_ ...@@ -55,16 +55,14 @@ ping _-k_
</tr> </tr>
<tr id="row2703mcpsimp"><td class="cellrowborder" valign="top" width="21%" headers="mcps1.2.4.1.1 "><p id="p2705mcpsimp"><a name="p2705mcpsimp"></a><a name="p2705mcpsimp"></a>-l data_len</p> <tr id="row2703mcpsimp"><td class="cellrowborder" valign="top" width="21%" headers="mcps1.2.4.1.1 "><p id="p2705mcpsimp"><a name="p2705mcpsimp"></a><a name="p2705mcpsimp"></a>-l data_len</p>
</td> </td>
<td class="cellrowborder" valign="top" width="52%" headers="mcps1.2.4.1.2 "><p id="p2707mcpsimp"><a name="p2707mcpsimp"></a><a name="p2707mcpsimp"></a>ping包,即ICMP echo request报文的数据长</p> <td class="cellrowborder" valign="top" width="52%" headers="mcps1.2.4.1.2 "><p id="p2707mcpsimp"><a name="p2707mcpsimp"></a><a name="p2707mcpsimp"></a>ping包,即ICMP echo request报文的数据长度,不包含ICMP包头。</p>
<p id="p2708mcpsimp"><a name="p2708mcpsimp"></a><a name="p2708mcpsimp"></a>度,不包含ICMP包头。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="27%" headers="mcps1.2.4.1.3 "><p id="p2710mcpsimp"><a name="p2710mcpsimp"></a><a name="p2710mcpsimp"></a>0-65500</p> <td class="cellrowborder" valign="top" width="27%" headers="mcps1.2.4.1.3 "><p id="p2710mcpsimp"><a name="p2710mcpsimp"></a><a name="p2710mcpsimp"></a>0-65500</p>
</td> </td>
</tr> </tr>
<tr id="row2711mcpsimp"><td class="cellrowborder" valign="top" width="21%" headers="mcps1.2.4.1.1 "><p id="p2713mcpsimp"><a name="p2713mcpsimp"></a><a name="p2713mcpsimp"></a>-t</p> <tr id="row2711mcpsimp"><td class="cellrowborder" valign="top" width="21%" headers="mcps1.2.4.1.1 "><p id="p2713mcpsimp"><a name="p2713mcpsimp"></a><a name="p2713mcpsimp"></a>-t</p>
</td> </td>
<td class="cellrowborder" valign="top" width="52%" headers="mcps1.2.4.1.2 "><p id="p2715mcpsimp"><a name="p2715mcpsimp"></a><a name="p2715mcpsimp"></a>表示永久ping,直到使用ping -k杀死ping线</p> <td class="cellrowborder" valign="top" width="52%" headers="mcps1.2.4.1.2 "><p id="p2715mcpsimp"><a name="p2715mcpsimp"></a><a name="p2715mcpsimp"></a>表示永久ping,直到使用ping -k杀死ping线程。</p>
<p id="p2716mcpsimp"><a name="p2716mcpsimp"></a><a name="p2716mcpsimp"></a>程。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="27%" headers="mcps1.2.4.1.3 "><p id="p20501182215720"><a name="p20501182215720"></a><a name="p20501182215720"></a>N/A</p> <td class="cellrowborder" valign="top" width="27%" headers="mcps1.2.4.1.3 "><p id="p20501182215720"><a name="p20501182215720"></a><a name="p20501182215720"></a>N/A</p>
</td> </td>
...@@ -95,5 +93,5 @@ ping _-k_ ...@@ -95,5 +93,5 @@ ping _-k_
**图 1** ping tftp 服务器地址<a name="fig525762695417"></a> **图 1** ping tftp 服务器地址<a name="fig525762695417"></a>
![](figure/Snipaste_2021-01-26_10-38-58-19.png) ![](figure/Snipaste_2021-01-26_10-38-58-26.png)
# ping6<a name="ZH-CN_TOPIC_0000001052451611"></a> # ping6<a name="ZH-CN_TOPIC_0000001134006274"></a>
- [命令功能](#section1057291313393) - [命令功能](#section1057291313393)
- [命令格式](#section199901315123919) - [命令格式](#section199901315123919)
......
# telnet<a name="ZH-CN_TOPIC_0000001051611544"></a> # telnet<a name="ZH-CN_TOPIC_0000001179845941"></a>
- [命令功能](#section3551830123913) - [命令功能](#section3551830123913)
- [命令格式](#section14897133233918) - [命令格式](#section14897133233918)
......
# tftp<a name="ZH-CN_TOPIC_0000001051451597"></a> # tftp<a name="ZH-CN_TOPIC_0000001179965861"></a>
- [命令功能](#section15142134573911) - [命令功能](#section15142134573911)
- [命令格式](#section20958174917394) - [命令格式](#section20958174917394)
......
# 网络命令<a name="ZH-CN_TOPIC_0000001133846492"></a>
- **[arp](kernel-small-debug-shell-net-arp.md)**
- **[dhclient](kernel-small-debug-shell-net-dhclient.md)**
- **[dns](kernel-small-debug-shell-net-dns.md)**
- **[ifconfig](kernel-small-debug-shell-net-ifconfig.md)**
- **[ipdebug](kernel-small-debug-shell-net-ipdebug.md)**
- **[netstat](kernel-small-debug-shell-net-netstat.md)**
- **[ntpdate](kernel-small-debug-shell-net-ntpdate.md)**
- **[ping](kernel-small-debug-shell-net-ping.md)**
- **[ping6](kernel-small-debug-shell-net-ping6.md)**
- **[telnet](kernel-small-debug-shell-net-telnet.md)**
- **[tftp](kernel-small-debug-shell-net-tftp.md)**
# Shell介绍<a name="ZH-CN_TOPIC_0000001053967735"></a> # Shell介绍<a name="ZH-CN_TOPIC_0000001179965829"></a>
- [注意事项](#section12298165312328) - [注意事项](#section12298165312328)
...@@ -10,7 +10,7 @@ OpenHarmony内核提供的Shell支持调试常用的基本功能,包含系统 ...@@ -10,7 +10,7 @@ OpenHarmony内核提供的Shell支持调试常用的基本功能,包含系统
- 网络相关命令:支持查询接到开发板的其他设备的IP、查询本机IP、测试网络连接、设置开发板的AP和station模式等相关功能。 - 网络相关命令:支持查询接到开发板的其他设备的IP、查询本机IP、测试网络连接、设置开发板的AP和station模式等相关功能。
新增命令的详细流程可参见[开发指导](kernel-lite-small-shell-guide.md)和[编程实例](kernel-lite-small-shell-sample.md)。 新增命令的详细流程可参见[Shell命令开发指导](kernel-small-debug-shell-guide.md)和[Shell命令编程实例](kernel-small-debug-shell-build.md)。
## 注意事项<a name="section12298165312328"></a> ## 注意事项<a name="section12298165312328"></a>
......
# Shell<a name="ZH-CN_TOPIC_0000001179845911"></a>
- **[Shell介绍](kernel-small-debug-shell-overview.md)**
- **[Shell命令开发指导](kernel-small-debug-shell-guide.md)**
- **[Shell命令编程实例](kernel-small-debug-shell-build.md)**
- **[Shell命令使用详解](kernel-small-debug-shell-details.md)**
- **[魔法键使用方法](kernel-small-debug-shell-magickey.md)**
- **[用户态异常信息说明](kernel-small-debug-shell-error.md)**
# 常见问题定位方法<a name="ZH-CN_TOPIC_0000001079096842"></a>
- [通过异常信息定位问题](#section695838161711)
- [内存池节点完整性验证](#section362917569179)
- [全局变量踩内存定位方法](#section18971311121816)
## 通过异常信息定位问题<a name="section695838161711"></a>
系统异常被挂起后,会在串口看到一些关键寄存器的信息,如图1所示。可通过这些信息定位到异常所在函数和其调用栈关系,为原因分析提供第一手资料。
图1 异常信息
![](figure/zh-cn_image_0000001173429547.png)
上图中的异常信息主要解释4个标签:
**标签1**:标识异常在内核态;
**标签2**:标识了异常类型(数据异常时,far后的值是系统异常时CPU访问的地址);
**标签3**:pc的值标识系统异常时执行指令的位置,klr的值一般标识pc所在函数执行完后下一条要执行的命令。(**注:标签4处 traceback 0 lr有值时不用关注klr**)。
**标签4**:lr 的值依次标识正常情况下PC要依次执行的指令的位置。
对于内核异常打印信息,确定PC和LR的具体位置的指令需要结合out目录下OHOS\_Image.asm(跟烧写的系统镜像OHOS\_Image.bin对应的汇编文件)查看,根据指令所在的位置可确认使用该指令的函数,依次确定LR位置所在的函数,即得到异常发生时的函数调用关系。
## 内存池节点完整性验证<a name="section362917569179"></a>
仅凭上节异常信息定位的基本方法,常常无法直接定位问题所在。并且常常会因为异常的寄存器值而无法对问题进行定位。若怀疑是堆内存越界导致的问题,可以调用内存池完整性检测函数LOS\_MemIntegrityCheck进行检查。函数LOS\_MemIntegrityCheck将会对系统动态内存池所有的节点进行遍历,如果所有节点正常则函数返回0,不会有任何打印,否则将打印相关的错误信息。该函数的入参使用\(VOID \*\)OS\_SYS\_MEM\_ADDR。
定位堆内存越界踩的问题,一般是在可能存在问题的业务逻辑代码前后使用LOS\_MemIntegrityCheck,如果该业务代码不存在问题,则前后两次LOS\_MemIntegrityCheck调用不会失败,按前述方式逐步缩小问题定位范围。
## 全局变量踩内存定位方法<a name="section18971311121816"></a>
如果已知一个全局变量内存域被踩,可在OHOS\_Image.map文件中找到该全局变量所在的地址,并且特别注意该地址之前最近被使用的变量,有极大概率是前面的变量(尤其数组类型的或会被强转成其他类型的变量)在使用的过程中内存越界,破坏了这个全局变量。
# 临终遗言<a name="ZH-CN_TOPIC_0000001078588210"></a>
- [使用场景](#section158501652121514)
- [功能说明](#section1186411122215)
- [参数说明](#section1083765723015)
- [开发流程](#section783435801510)
## 使用场景<a name="section158501652121514"></a>
在无串口的设备上,将系统异常时打印的信息保存到不丢失的存储介质上,方便对运行时问题进行定位。
## 功能说明<a name="section1186411122215"></a>
该调测功能提供了一种用于保存系统异常时打印信息到不丢失存储介质中的机制,用户可自行注册读写异常时打印信息的钩子函数,实现在不同存储介质上保存异常信息的能力,这样方便无串口的设备的问题定位。接口名为LOS\_ExcInfoRegHook,该函数声明在los\_config.h中,函数原型:
```
typedef VOID (*log_read_write_fn)(UINT32 startAddr, UINT32 space, UINT32 rwFlag, CHAR *buf);
......
VOID LOS_ExcInfoRegHook(UINT32 startAddr, UINT32 space, CHAR *buf, log_read_write_fn hook);
```
## 参数说明<a name="section1083765723015"></a>
**表 1** LOS\_ExcInfoRegHook 参数说明
<a name="table1345253123117"></a>
<table><thead align="left"><tr id="row19452331143115"><th class="cellrowborder" valign="top" width="42.77%" id="mcps1.2.3.1.1"><p id="p1145253110313"><a name="p1145253110313"></a><a name="p1145253110313"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="57.230000000000004%" id="mcps1.2.3.1.2"><p id="p9452153114313"><a name="p9452153114313"></a><a name="p9452153114313"></a>参数说明</p>
</th>
</tr>
</thead>
<tbody><tr id="row5452131123110"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p1245233110317"><a name="p1245233110317"></a><a name="p1245233110317"></a>startAddr</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p1845203116313"><a name="p1845203116313"></a><a name="p1845203116313"></a>存取异常信息的物理介质起始地址</p>
</td>
</tr>
<tr id="row745217316312"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p7452331133118"><a name="p7452331133118"></a><a name="p7452331133118"></a>space</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p9452203117312"><a name="p9452203117312"></a><a name="p9452203117312"></a>存取的空间大小</p>
</td>
</tr>
<tr id="row15578112463216"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p5578202413220"><a name="p5578202413220"></a><a name="p5578202413220"></a>buf</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p1057816247322"><a name="p1057816247322"></a><a name="p1057816247322"></a>存取异常信息的内存缓冲区</p>
</td>
</tr>
<tr id="row0123932163215"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p612320322321"><a name="p612320322321"></a><a name="p612320322321"></a>log_read_write_fn</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p17123143218322"><a name="p17123143218322"></a><a name="p17123143218322"></a>存取异常信息的函数</p>
</td>
</tr>
</tbody>
</table>
**表 2** log\_read\_write\_fn 参数说明
<a name="table1950318463620"></a>
<table><thead align="left"><tr id="row45034463611"><th class="cellrowborder" valign="top" width="42.77%" id="mcps1.2.3.1.1"><p id="p950316412365"><a name="p950316412365"></a><a name="p950316412365"></a>参数</p>
</th>
<th class="cellrowborder" valign="top" width="57.230000000000004%" id="mcps1.2.3.1.2"><p id="p1050304123619"><a name="p1050304123619"></a><a name="p1050304123619"></a>参数说明</p>
</th>
</tr>
</thead>
<tbody><tr id="row1850394153612"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p155039453619"><a name="p155039453619"></a><a name="p155039453619"></a>startAddr</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p18503341366"><a name="p18503341366"></a><a name="p18503341366"></a>存取异常信息的物理介质起始地址</p>
</td>
</tr>
<tr id="row1450354113617"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p115031642363"><a name="p115031642363"></a><a name="p115031642363"></a>space</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p1350354113619"><a name="p1350354113619"></a><a name="p1350354113619"></a>存取的空间大小</p>
</td>
</tr>
<tr id="row750314413361"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p115031241361"><a name="p115031241361"></a><a name="p115031241361"></a>rwFlag</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p8503548362"><a name="p8503548362"></a><a name="p8503548362"></a>读写标记,0为写,1为读</p>
</td>
</tr>
<tr id="row250312420363"><td class="cellrowborder" valign="top" width="42.77%" headers="mcps1.2.3.1.1 "><p id="p850314493611"><a name="p850314493611"></a><a name="p850314493611"></a>buf</p>
</td>
<td class="cellrowborder" valign="top" width="57.230000000000004%" headers="mcps1.2.3.1.2 "><p id="p85033413613"><a name="p85033413613"></a><a name="p85033413613"></a>存取异常信息的内存缓冲区</p>
</td>
</tr>
</tbody>
</table>
## 开发流程<a name="section783435801510"></a>
该功能依赖于宏LOSCFG\_SAVE\_EXCINFO,使用临终遗言功能时,在配置项中开启“ Enable Saving Exception Information ”:Debug-\> Enable Saving Exception Information ;若关闭该选项,则该功能失效。功能开启后,可在SystemInit中调用LOS\_ExcInfoRegHook来注册存取异常信息的位置、大小、内存缓冲区以及存取函数。当系统进入异常时,会将异常时系统各类信息先保存在注册时传入的内存缓冲区中,最后调用注册的存取函数,将异常信息写入到物理存储介质中。
>![](../public_sys-resources/icon-note.gif) **说明:**
>- 注册的存取位置不要跟其他存储重叠。
>- 注册的内存缓冲区不能太小,建议不低于16KiB,否则异常信息会存储不完整。
>- 注册的读写函数对应的具体存储介质的驱动功能正常,才能保证存取功能正常。
# Trace<a name="ZH-CN_TOPIC_0000001123695263"></a>
- [基本概念](#section531482192018)
- [运行机制](#section5125124532010)
- [使用指导](#section1381714413216)
## 基本概念<a name="section531482192018"></a>
Trace是内核提供的一个跟踪模块关键流程的功能框架,各个模块根据机制需要,可以在关键位置通过Trace进行相关信息记录,再通过文件或者其他方式导出,对数据进行分析。
Trace的记录要求:
1. 需要尽快的完成信息记录,对系统时序的影响降低到最小;
2. 需要尽可能的用小的空间存储大的数据量,减少内存消耗。
## 运行机制<a name="section5125124532010"></a>
在内核启动初期完成Trace功能的初始化,并且在支持Trace功能的模块进行初始化时,完成模块相应的Trace类型及回调函数的注册,触发Trace记录的trace point的具体位置可由各模块自行决定。
当系统触发到一个trace point时,Trace模块会对输入信息进行封装,添加Trace帧头信息,包含Trace类型、运行的cpuid、运行的任务id、运行的相对时间戳以及运行的进程id;再将trace frame记录到预先申请好的循环buffer中。
如果循环buffer记录的frame过多则可能出现翻转,会覆盖之前的记录,故保持记录的信息始终是最新的信息。Trace循环buffer的数据可以通过文件dump等形式导出进行详细分析,导出信息已按照时间戳信息完成排序。
![](figure/zh-cn_image_0000001127390512.png)
## 使用指导<a name="section1381714413216"></a>
1. 配置Trace控制宏LOSCFG\_KERNEL\_TRACE,默认关,通过在menuconfig内核配置"Kernel-\>Enable Trace Feature"中打开。
2. 内核启动完成Trace初始化,对应接口OsTraceInit。
3. 统一在los\_trace\_frame.h定义模块内traceframe结构体,并在los\_trace\_frame.c中实现模块Trace回调函数的实现。
4. 需要跟踪的模块在初始化或者更早阶段完成Trace注册,对应接口LOS\_TraceReg。
5. 在需要开始跟踪的位置打开Trace开关进行记录,结束的位置关闭Trace开关停止记录。
6. 通过LOS\_Trace2File接口导出到文件。
7. 根据帧头及帧体数据结构,对数据进行二次分析。
**接口说明**
OpenHarmony LiteOS-A内核的Trace框架提供下面几种功能,接口详细信息可以查看API参考。
**表 1** Trace接口说明
<a name="table818431314338"></a>
<table><thead align="left"><tr id="row151841613163315"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p159375113174"><a name="p159375113174"></a><a name="p159375113174"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p199385118173"><a name="p199385118173"></a><a name="p199385118173"></a>接口<strong id="b197068338312"><a name="b197068338312"></a><a name="b197068338312"></a>名称</strong></p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p18937511175"><a name="p18937511175"></a><a name="p18937511175"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row1918541303315"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p518551319333"><a name="p518551319333"></a><a name="p518551319333"></a>打桩记录</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p19185513103317"><a name="p19185513103317"></a><a name="p19185513103317"></a>LOS_Trace</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1118515135337"><a name="p1118515135337"></a><a name="p1118515135337"></a>Trace信息记录打桩</p>
</td>
</tr>
<tr id="row13185111320331"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p13512294508"><a name="p13512294508"></a><a name="p13512294508"></a>注册解注册</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p151852013203318"><a name="p151852013203318"></a><a name="p151852013203318"></a>LOS_TraceReg</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1318571310338"><a name="p1318571310338"></a><a name="p1318571310338"></a>Trace类型注册</p>
</td>
</tr>
<tr id="row201858136336"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p6185171393311"><a name="p6185171393311"></a><a name="p6185171393311"></a>LOS_TraceUnreg</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1185181363313"><a name="p1185181363313"></a><a name="p1185181363313"></a>Trace类型解注册</p>
</td>
</tr>
<tr id="row1518581363317"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p20974111585115"><a name="p20974111585115"></a><a name="p20974111585115"></a>开关</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p91858132336"><a name="p91858132336"></a><a name="p91858132336"></a>LOS_TraceTypeSwitch</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p11185121313333"><a name="p11185121313333"></a><a name="p11185121313333"></a>Trace分类开关</p>
</td>
</tr>
<tr id="row14185101310339"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1185151323311"><a name="p1185151323311"></a><a name="p1185151323311"></a>LOS_TraceSwitch</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p61852135331"><a name="p61852135331"></a><a name="p61852135331"></a>Trace总开关</p>
</td>
</tr>
<tr id="row71858133339"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p12306322125115"><a name="p12306322125115"></a><a name="p12306322125115"></a>数据导出</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p481141115110"><a name="p481141115110"></a><a name="p481141115110"></a>LOS_TraceBufDataGet</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p131851813173314"><a name="p131851813173314"></a><a name="p131851813173314"></a>Trace数据获取到堆缓存(缓存空间内部申请,使用完需显示释放)</p>
</td>
</tr>
<tr id="row10185131373310"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p31851139333"><a name="p31851139333"></a><a name="p31851139333"></a>LOS_Trace2File</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p121856132333"><a name="p121856132333"></a><a name="p121856132333"></a>Trace数据存储到文件系统(依赖文件系统)</p>
</td>
</tr>
</tbody>
</table>
>![](../public_sys-resources/icon-note.gif) **说明:**
>- frame buffer是个循环buffer,如果记录过长时间会覆盖旧的信息,该buffer的大小可以在los\_config.h中LOS\_TRACE\_BUFFER\_SIZE宏配置,默认配置512KiB。
>- 尽管Trace已经尽快的完成了组装及记录,但是仍旧会对系统整体性能产生不可避免的影响。
>- Trace支持多个模块的Trace同时记录,根据需要开关各个模块的Trace,有助于降低数据分析量。
>- 当前内核的task、memory、liteipc模块支持Trace记录功能。
# 调测与工具<a name="ZH-CN_TOPIC_0000001078652838"></a>
- **[Shell](kernel-small-debug-shell.md)**
- **[Trace](kernel-small-debug-trace.md)**
- **[进程调测](kernel-small-debug-process.md)**
- **[内存调测](kernel-small-debug-memory.md)**
- **[其他内核调测手段](kernel-small-debug-other.md)**
# 内核概述<a name="ZH-CN_TOPIC_0000001122933245"></a>
- [简介](#section6614133913129)
- [内核架构](#section827143517385)
## 简介<a name="section6614133913129"></a>
OpenHarmony 轻量级内核是基于IoT领域轻量级物联网操作系统Huawei LiteOS内核演进发展的新一代内核,包含LiteOS-M和LiteOS-A两类内核。LiteOS-M内核主要应用于轻量系统,面向的MCU一般是百K级内存,可支持MPU隔离,业界类似的内核有FreeRTOS或ThreadX等;LiteOS-A内核主要应用于小型系统,面向设备一般是M级内存,可支持MMU隔离,业界类似的内核有Zircon或Darwin等。本开发指南适用于LiteOS-A内核。
为适应IoT产业的高速发展,OpenHarmony 轻量级内核不断优化和扩展,能够带给应用开发者友好的开发体验和统一开放的生态系统能力。轻量级内核LiteOS-A重要的新特性如下:
- 新增了丰富的内核机制
新增虚拟内存、系统调用、多核、轻量级IPC(Inter-Process Communication,进程间通信)、DAC(Discretionary Access Control,自主访问控制)等机制,丰富了内核能力;为了更好的兼容软件和开发者体验,新增支持多进程,使得应用之间内存隔离、相互不影响,提升系统的健壮性。
- 引入统一驱动框架HDF(Hardware Driver Foundation)
引入统一驱动框架HDF,统一驱动标准,为设备厂商提供了更统一的接入方式,使驱动更加容易移植,力求做到一次开发,多系统部署。
- 支持1200+标准POSIX接口
更加全面的支持POSIX标准接口,使得应用软件易于开发和移植,给应用开发者提供了更友好的开发体验。
- 内核和硬件高解耦
轻量级内核与硬件高度解耦,新增单板,内核代码不用修改。
## 内核架构<a name="section827143517385"></a>
轻量级内核主要由基础内核、扩展组件、HDF框架、POSIX接口组成。轻量级内核的文件系统、网络协议等扩展功能(没有像微内核那样运行在用户态)运行在内核地址空间,主要考虑组件之间直接函数调用比进程间通信或远程过程调用要快得多。
**图 1** OpenHarmony LiteOS-A内核架构图<a name="fig1216111597122"></a>
![](figure/zh-cn_image_0000001179063579.png)
- 基础内核主要包括内核的基础机制,如调度、内存管理、中断异常等
- 扩展组件主要包括文件系统、网络协议和安全等扩展功能
- HDF框架是外设驱动统一标准框架
- POSIX接口是为兼容POSIX标准的应用方便移植到OpenHarmony
**基础内核**
基础内核组件实现精简,主要包括内核的基础机制,如调度、内存管理、中断异常、内核通信等;
- 进程管理:支持进程和线程,基于Task实现进程,进程独立4GB地址空间
- 多核调度:支持任务和中断亲核性设置,支持绑核运行
- 实时调度:支持高优先级抢占,同优先级时间片轮转
- 虚拟内存:支持缺页异常,内核空间静态映射到0-1G地址,用户空间映射到1-4G地址
- 内核通信:事件、信号量、互斥锁、队列
- 时间管理:软件定时器、系统时钟
**文件系统**
轻量级内核支持FAT,JFFS2,NFS,ramfs,procfs等众多文件系统,并对外提供完整的POSIX标准的操作接口,功能非常强大;内部使用VFS层作为统一的适配层框架,方便移植新的文件系统,各个文件系统也能自动利用VFS层提供的丰富的功能。
主要特性有:
- 完整的POSIX接口支持
- 文件级缓存\(pagecache)
- 磁盘级缓存(bcache)
- 目录缓存\(pathcache\)
- DAC能力
- 支持嵌套挂载及文件系统堆叠等
- 支持特性的裁剪和资源占用的灵活配置。
**网络协议**
轻量级内核网络协议基于开源LWIP构建,对LWIP的RAM占用进行优化,同时提高LWIP的传输性能。
- 协议: IP、IPv6、 ICMP、 ND、MLD、 UDP、 TCP、IGMP、ARP、PPPoS、PPPoE
- API:socket API
- 扩展特性:多网络接口IP转发、TCP拥塞控制、RTT估计和快速恢复/快速重传
- 应用程序:HTTP\(S\)服务、SNTP客户端、SMTP\(S\)客户端、ping工具、NetBIOS名称服务、mDNS响应程序、MQTT客户端、TFTP服务、DHCP客户端、DNS客户端、AutoIP/APIPA(零配置)、SNMP代理
**HDF框架**
轻量级内核集成HDF框架,HDF框架旨在为开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
- 支持多内核平台
- 支持用户态驱动
- 可配置组件化驱动模型
- 基于消息的驱动接口模型
- 基于对象的驱动、设备管理
- HDI(Hardware Driver Interface)统一硬件接口
- 支持电源管理、PnP
**扩展组件**
对内核功能进行扩展,可选但很重要的机制。
- 动态链接:支持标准ELF链接执行、加载地址随机化
- 进程通信:支持轻量级LiteIPC,同时也支持标准的Mqueue、Pipe、Fifo、Signal等机制
- 系统调用:支持170+系统调用 ,同时有支持VDSO机制
- 权限管理:支持进程粒度的特权划分和管控,UGO三种权限配置
# 内核态启动<a name="ZH-CN_TOPIC_0000001127506594"></a>
- [内核启动流程](#section9882154318299)
- [编程样例](#section19145114703217)
- [实例描述](#section1045483642518)
## 内核启动流程<a name="section9882154318299"></a>
内核启动流程包含汇编启动阶段和C语言启动阶段2部分,如图1所示。汇编启动阶段完成CPU初始设置,关闭dcache/icache,使能FPU及neon,设置MMU建立虚实地址映射,设置系统栈,清理bss段,调用C语言main函数等。C语言启动阶段包含OsMain函数及开始调度等,其中如上图所示,OsMain函数用于内核基础初始化和架构、板级初始化等,其整体由内核启动框架主导初始化流程,图中右边区域为启动框架中可接受外部模块注册启动的阶段,各个阶段的说明如下表1所示。
**图 1** 内核启动流程图<a name="fig1372861419385"></a>
![](figure/zh-cn_image_0000001178856385.png)
**表 1** 启动框架层级
<a name="table38544719428"></a>
<table><thead align="left"><tr id="row286134714423"><th class="cellrowborder" valign="top" width="35.58%" id="mcps1.2.3.1.1"><p id="p886164717423"><a name="p886164717423"></a><a name="p886164717423"></a>层级</p>
</th>
<th class="cellrowborder" valign="top" width="64.42%" id="mcps1.2.3.1.2"><p id="p586194716421"><a name="p586194716421"></a><a name="p586194716421"></a>说明</p>
</th>
</tr>
</thead>
<tbody><tr id="row48664764218"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p7861447174211"><a name="p7861447174211"></a><a name="p7861447174211"></a>LOS_INIT_LEVEL_EARLIEST</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p1561350125815"><a name="p1561350125815"></a><a name="p1561350125815"></a>最早期初始化</p>
<p id="p13865183210552"><a name="p13865183210552"></a><a name="p13865183210552"></a>说明:不依赖架构,单板以及后续模块会对其有依赖的纯软件模块初始化</p>
<p id="p1686104764216"><a name="p1686104764216"></a><a name="p1686104764216"></a>例如:Trace模块</p>
</td>
</tr>
<tr id="row4861478429"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p1986164710423"><a name="p1986164710423"></a><a name="p1986164710423"></a>LOS_INIT_LEVEL_ARCH_EARLY</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p6864470423"><a name="p6864470423"></a><a name="p6864470423"></a>架构早期初始化</p>
<p id="p118192355598"><a name="p118192355598"></a><a name="p118192355598"></a>说明:架构相关,后续模块会对其有依赖的模块初始化,如启动过程中非必需的功能,建议放到LOS_INIT_LEVEL_ARCH层</p>
</td>
</tr>
<tr id="row98694774219"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p118624714210"><a name="p118624714210"></a><a name="p118624714210"></a>LOS_INIT_LEVEL_PLATFORM_EARLY</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p118531052143510"><a name="p118531052143510"></a><a name="p118531052143510"></a>平台早期初始化</p>
<p id="p666132195816"><a name="p666132195816"></a><a name="p666132195816"></a>说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化,如启动过程中必需的功能,建议放到LOS_INIT_LEVEL_PLATFORM层</p>
<p id="p1986104794218"><a name="p1986104794218"></a><a name="p1986104794218"></a>例如:uart模块</p>
</td>
</tr>
<tr id="row8863470423"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p19861547114214"><a name="p19861547114214"></a><a name="p19861547114214"></a>LOS_INIT_LEVEL_KMOD_PREVM</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p2862471421"><a name="p2862471421"></a><a name="p2862471421"></a>内存初始化前的内核模块初始化</p>
<p id="p989110481520"><a name="p989110481520"></a><a name="p989110481520"></a>说明:在内存初始化之前需要使能的模块初始化</p>
</td>
</tr>
<tr id="row4861147124218"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p16863472426"><a name="p16863472426"></a><a name="p16863472426"></a>LOS_INIT_LEVEL_VM_COMPLETE</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p1186114715427"><a name="p1186114715427"></a><a name="p1186114715427"></a>基础内存就绪后的初始化</p>
<p id="p26441930165910"><a name="p26441930165910"></a><a name="p26441930165910"></a>说明:此时内存初始化完毕,需要进行使能且不依赖进程间通讯机制与系统进程的模块初始化</p>
<p id="p76991543175013"><a name="p76991543175013"></a><a name="p76991543175013"></a>例如:共享内存功能</p>
</td>
</tr>
<tr id="row12869472429"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p178694712429"><a name="p178694712429"></a><a name="p178694712429"></a>LOS_INIT_LEVEL_ARCH</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p1086104719427"><a name="p1086104719427"></a><a name="p1086104719427"></a>架构后期初始化</p>
<p id="p556511281688"><a name="p556511281688"></a><a name="p556511281688"></a>说明:架构拓展功能相关,后续模块会对其有依赖的模块初始化</p>
</td>
</tr>
<tr id="row128624717424"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p198684711427"><a name="p198684711427"></a><a name="p198684711427"></a>LOS_INIT_LEVEL_PLATFORM</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p65519915524"><a name="p65519915524"></a><a name="p65519915524"></a>平台后期初始化</p>
<p id="p187247164213"><a name="p187247164213"></a><a name="p187247164213"></a>说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化</p>
<p id="p138046651010"><a name="p138046651010"></a><a name="p138046651010"></a>例如:驱动内核抽象层初始化(mmc、mtd)</p>
</td>
</tr>
<tr id="row2149155220436"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p8150105215436"><a name="p8150105215436"></a><a name="p8150105215436"></a>LOS_INIT_LEVEL_KMOD_BASIC</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p81509525436"><a name="p81509525436"></a><a name="p81509525436"></a>内核基础模块初始化</p>
<p id="p763134221115"><a name="p763134221115"></a><a name="p763134221115"></a>说明:内核可拆卸的基础模块初始化</p>
<p id="p7781186191213"><a name="p7781186191213"></a><a name="p7781186191213"></a>例如:VFS初始化</p>
</td>
</tr>
<tr id="row19671355174317"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p1596825564317"><a name="p1596825564317"></a><a name="p1596825564317"></a>LOS_INIT_LEVEL_KMOD_EXTENDED</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p6968155513438"><a name="p6968155513438"></a><a name="p6968155513438"></a>内核扩展模块初始化</p>
<p id="p669712304124"><a name="p669712304124"></a><a name="p669712304124"></a>说明:内核可拆卸的扩展模块初始化</p>
<p id="p7600114618125"><a name="p7600114618125"></a><a name="p7600114618125"></a>例如:系统调用初始化、ProcFS初始化、Futex初始化、HiLog初始化、HiEvent初始化、LiteIPC初始化</p>
</td>
</tr>
<tr id="row357517134414"><td class="cellrowborder" valign="top" width="35.58%" headers="mcps1.2.3.1.1 "><p id="p12575676449"><a name="p12575676449"></a><a name="p12575676449"></a>LOS_INIT_LEVEL_KMOD_TASK</p>
</td>
<td class="cellrowborder" valign="top" width="64.42%" headers="mcps1.2.3.1.2 "><p id="p7128122619143"><a name="p7128122619143"></a><a name="p7128122619143"></a>内核任务创建</p>
<p id="p1657587184419"><a name="p1657587184419"></a><a name="p1657587184419"></a>说明:进行内核任务的创建(内核线程,软件定时器任务)</p>
<p id="p55485297219"><a name="p55485297219"></a><a name="p55485297219"></a>例如:资源回收系统常驻任务的创建、SystemInit任务创建、CPU占用率统计任务创建</p>
</td>
</tr>
</tbody>
</table>
## 编程样例<a name="section19145114703217"></a>
### 实例描述<a name="section1045483642518"></a>
新增一个内核模块,需要在内核初始化时进行该模块的初始化,则通过内核启动框架将该模块的初始化函数注册进内核启动流程中。
**示例代码**
```
/* 内核启动框架头文件 */
#include "los_init.h"
......
/* 新增模块的初始化函数 */
unsigned int OsSampleModInit(void)
{
PRINTK("OsSampleModInit SUCCESS!\n");
......
}
......
/* 在启动框架的目标层级中注册新增模块 */
LOS_MODULE_INIT(OsSampleModInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
```
**结果验证**
```
main core booting up...
OsSampleModInit SUCCESS!
releasing 1 secondary cores
cpu 1 entering scheduler
cpu 0 entering scheduler
```
根据上述系统启动阶段的打印可知,内核在启动时进行了该注册模块的初始化函数调用,完成该模块的初始化操作。
>![](../public_sys-resources/icon-note.gif) **说明:**
>启动框架中同一层级内的注册模块不能有依赖关系,建议新增模块按照上述启动阶段进行模块初始化的拆分,按需注册启动。
>可通过查看系统编译生成文件OHOS\_Image.map中.rodata.init.kernel.\*段内的符号表来了解当前已注册进内核启动框架中的各个模块初始化入口,以及检查新注册的模块初始化入口是否生效。
# 用户态启动<a name="ZH-CN_TOPIC_0000001123640059"></a>
- [用户态根进程启动](#section79911135647)
- [根进程的启动过程](#section1184317581349)
- [根进程的职责](#section1590220321759)
- [用户态程序运行](#section194576310611)
## 用户态根进程启动<a name="section79911135647"></a>
根进程是系统第一个用户态进程,进程ID为1,它是所有用户态进程的祖先。
**图 1** 进程树示意图<a name="fig427516409375"></a>
![](figure/进程树示意图.png "进程树示意图")
### 根进程的启动过程<a name="section1184317581349"></a>
使用链接脚本将如下init启动代码放置到系统镜像指定位置。
```
#define LITE_USER_SEC_ENTRY __attribute__((section(".user.entry")))
LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args)
{
#ifdef LOSCFG_KERNEL_DYNLOAD
sys_call3(__NR_execve, (UINTPTR)g_initPath, 0, 0);
#endif
while (true) {
}
}
```
系统启动阶段,OsUserInitProcess启动init进程。具体过程如下:
1. 由内核OsLoadUserInit加载上述代码。
2. 创建新的进程空间,启动/bin/init进程。
### 根进程的职责<a name="section1590220321759"></a>
- 启动关键系统程序或服务,如交互进程shell。
>![](../public_sys-resources/icon-note.gif) **说明:**
>在OpenHarmony 中**init**进程通过读取/etc/init.cfg,根据配置执行指定命令,或启动指定进程(详见:[init启动引导](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/init%E5%90%AF%E5%8A%A8%E5%BC%95%E5%AF%BC%E7%BB%84%E4%BB%B6.md))。
- 监控回收孤儿进程,清理子进程中的僵尸进程。
## 用户态程序运行<a name="section194576310611"></a>
用户态程序常见编译方式有如下两种:
1. [利用框架编译用户态进程](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/%E8%BF%90%E8%A1%8CHello-OHOS.md)
2. 手动编译
实例:
```
clang --target=arm-liteos --sysroot=prebuilts/lite/sysroot -o helloworld helloworld.c
```
**clang**:编译器下载:[llvm安装指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/Ubuntu%E7%BC%96%E8%AF%91%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87.md#section12202192215415)。
**--target**:--target=arm-liteos,指定编译平台为arm-liteos。
**--sysroot**:--sysroot=$\{YOUR\_ROOT\_PATH\}/prebuilts/lite/sysroot,指定头文件以及依赖标准库搜索路径为prebuilts下的指定路径。
用户态程序启动有如下常见方式:
- shell命令启动进程。
```
OHOS $ exec helloworld
OHOS $ ./helloworld
OHOS $ /bin/helloworld
```
- 通过POSIX接口启动新进程。
Fork方法创建一个新的进程,exec类接口执行一个全新的进程。
# 内核启动<a name="ZH-CN_TOPIC_0000001173040439"></a>
- **[内核态启动](kernel-small-start-kernel.md)**
- **[用户态启动](kernel-small-start-user.md)**
# 小型系统内核<a name="ZH-CN_TOPIC_0000001171191693"></a>
- **[内核概述](kernel-small-overview.md)**
- **[内核启动](kernel-small-start.md)**
- **[基础内核](kernel-small-basics.md)**
- **[扩展组件](kernel-small-bundles.md)**
- **[调测与工具](kernel-small-debug.md)**
- **[附录](kernel-small-apx.md)**
# 标准系统内核<a name="ZH-CN_TOPIC_0000001111199444"></a> # 标准系统内核<a name="ZH-CN_TOPIC_0000001111199444"></a>
- **[Linux内核概述](kernel-standard-des.md)** - **[Linux内核概述](kernel-standard-overview.md)**
- **[OpenHarmony开发板Patch使用指导](kernel-standard-patch.md)** - **[OpenHarmony开发板Patch使用指导](kernel-standard-patch.md)**
......
# 内核<a name="ZH-CN_TOPIC_0000001111039554"></a> # 内核<a name="ZH-CN_TOPIC_0000001111039554"></a>
- **[轻量和小型系统内核](kernel-lite.md)** - **[轻量系统内核](kernel-mini.md)**
- **[小型系统内核](kernel-small.md)**
- **[标准系统内核](kernel-standard.md)** - **[标准系统内核](kernel-standard.md)**
......
...@@ -227,7 +227,7 @@ CMake方式可通过指定工具链进行交叉编译,修改并编译该库, ...@@ -227,7 +227,7 @@ CMake方式可通过指定工具链进行交叉编译,修改并编译该库,
1. 搭建OpenHarmony环境 1. 搭建OpenHarmony环境
以hi3518ev300为例,编译出OpenHarmony镜像,烧写到开发板,参考[开发Hi3518第一个示例程序](../quick-start/quickstart-lite-steps-board3518-running.md)。 以hi3518ev300为例,编译出OpenHarmony镜像,烧写到开发板,参考[开发Hi3518第一个示例程序](../quick-start/quickstart-lite-steps-hi3518-running.md)。
进入系统如下所示: 进入系统如下所示:
......
...@@ -2,40 +2,35 @@ ...@@ -2,40 +2,35 @@
- [轻量和小型系统入门](quickstart-lite.md) - [轻量和小型系统入门](quickstart-lite.md)
- [概述](quickstart-lite-overview.md) - [概述](quickstart-lite-overview.md)
- [了解开发板](quickstart-lite-introduction.md) - [入门介绍](quickstart-lite-introduction.md)
- [Hi3861开发板介绍](quickstart-lite-introduction-hi3861.md) - [Hi3861开发板介绍](oem_minitinier_des_3861.md)
- [Hi3516开发板介绍](quickstart-lite-introduction-hi3516.md) - [Hi3516开发板介绍](oem_minitinier_des_3516.md)
- [Hi3518开发板介绍](quickstart-lite-introduction-hi3518.md) - [Hi3518开发板介绍](oem_minitinier_des_3518.md)
- [搭建系统环境](quickstart-lite-env-setup.md) - [搭建系统环境](quickstart-lite-env-setup.md)
- [概述](quickstart-lite-env-setup-des.md) - [概述](quickstart-lite-env-setup-overview.md)
- [Windows开发环境准备](quickstart-lite-env-setup-win.md) - [Windows开发环境准备](quickstart-lite-env-setup-windows.md)
- [Ubuntu编译环境准备](quickstart-lite-env-setup-lin.md) - [获取源码及Ubuntu编译环境准备](quickstart-lite-env-setup-linux.md)
- [常见问题](quickstart-lite-env-setup-faqs.md) - [常见问题](quickstart-lite-env-setup-faqs.md)
- [开发步骤](quickstart-lite-steps.md) - [开发步骤](quickstart-lite-steps.md)
- [Hi3861开发板](quickstart-lite-steps-board3861.md) - [Hi3861开发板](quickstart-lite-steps-hi3861.md)
- [安装开发板环境](quickstart-lite-steps-board3861-setting.md) - [安装开发板环境](quickstart-lite-steps-hi3861-setting.md)
- [WLAN联网](quickstart-lite-steps-board3861-connection.md) - [WLAN联网(编译、烧录)](quickstart-lite-steps-hi3861-connection.md)
- [运行Hello World](quickstart-lite-steps-board3861-running.md) - [运行Hello World](quickstart-lite-steps-hi3861-running.md)
- [常见问题](quickstart-lite-steps-board3861-faqs.md) - [常见问题](quickstart-lite-steps-hi3861-faqs.md)
- [Hi3516开发板](quickstart-lite-steps-hi3516.md)
- [Hi3516开发板](quickstart-lite-steps-board3516.md) - [安装开发板环境](quickstart-lite-steps-hi3516-setting.md)
- [安装开发板环境](quickstart-lite-steps-board3516-setting.md) - [运行Hello OHOS(编译、烧录)](quickstart-lite-steps-hi3516-running.md)
- [运行Hello OHOS](quickstart-lite-steps-board3516-running.md) - [驱动开发示例](quickstart-lite-steps-hi3516-program.md)
- [驱动开发示例](quickstart-lite-steps-board3516-program.md) - [常见问题](quickstart-lite-steps-hi3516-faqs.md)
- [常见问题](quickstart-lite-steps-board3516-faqs.md) - [Hi3518开发板](quickstart-lite-steps-hi3518.md)
- [安装开发板环境](quickstart-lite-steps-hi3518-setting.md)
- [Hi3518开发板](quickstart-lite-steps-board3518.md) - [运行Hello OHOS(编译、烧录)](quickstart-lite-steps-hi3518-running.md)
- [安装开发板环境](quickstart-lite-steps-board3518-setting.md) - [常见问题](quickstart-lite-steps-hi3518-faqs.md)
- [运行Hello OHOS](quickstart-lite-steps-board3518-running.md)
- [常见问题](quickstart-lite-steps-board3518-faqs.md)
- [标准系统入门](quickstart-standard.md) - [标准系统入门](quickstart-standard.md)
- [入门介绍](quickstart-standard-description.md) - [入门介绍](quickstart-standard-overview.md)
- [Windows开发环境准备](quickstart-standard-windows-environment.md) - [搭建Windows开发环境](quickstart-standard-windows-environment.md)
- [搭建Ubuntu环境及编译(Docker方式)](quickstart-standard-docker-environment.md) - [搭建Ubuntu环境\(获取源码及编译,Docker方式\)](quickstart-standard-docker-environment.md)
- [搭建Ubuntu环境及编译(安装包方式)](quickstart-standard-package-environment.md) - [搭建Ubuntu环境\(获取源码及编译,安装包方式\)](quickstart-standard-package-environment.md)
- [镜像烧录](quickstart-standard-burn.md) - [镜像烧录](quickstart-standard-burn.md)
- [常见问题](quickstart-standard-faq.md) - [镜像运行](quickstart-standard-running.md)
- [常见问题](quickstart-standard-faqs.md)
\ No newline at end of file
# Ubuntu编译环境准备<a name="ZH-CN_TOPIC_0000001174350605"></a> # 获取源码及Ubuntu编译环境准备<a name="ZH-CN_TOPIC_0000001174350605"></a>
- [获取软件](#section1897711811517) - [获取软件](#section1897711811517)
- [获取源码](#section1545225464016) - [获取源码](#section1545225464016)
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
6. 安装hb 6. 安装hb
>![](../public_sys-resources/icon-notice.gif) **须知:** >![](../public_sys-resources/icon-notice.gif) **须知:**
>- 针对Ubuntu编译环境我们提供了对应的Docker,该Docker封装了相关编译工具,选择使用Docker的开发者可跳过此章节。Docker使用可参考[Docker方式获取编译环境](../get-code/gettools-acquire.md)。 >- 针对Ubuntu编译环境我们提供了对应的Docker,该Docker封装了相关编译工具,选择使用Docker的开发者可跳过此章节。Docker使用可参考[Docker方式获取编译环境](../get-code/gettools-acquire.md#section107932281315)。
>- 通常系统默认安装samba、vim等常用软件,需要做适当适配以支持Linux服务器与Windows工作台之间的文件共享。 >- 通常系统默认安装samba、vim等常用软件,需要做适当适配以支持Linux服务器与Windows工作台之间的文件共享。
>- 想要详细了解OpenHarmony编译构建模块功能的开发者可参考[编译构建使用指南](../subsystems/subsys-build-mini-lite.md)。 >- 想要详细了解OpenHarmony编译构建模块功能的开发者可参考[编译构建使用指南](../subsystems/subsys-build-mini-lite.md)。
...@@ -160,7 +160,6 @@ Linux服务器通用环境配置需要的工具及其获取途径如下表所示 ...@@ -160,7 +160,6 @@ Linux服务器通用环境配置需要的工具及其获取途径如下表所示
``` ```
3. 设置python和python3软链接为python3.8。 3. 设置python和python3软链接为python3.8。
``` ```
......
# 搭建系统环境<a name="ZH-CN_TOPIC_0000001128311058"></a> # 搭建系统环境<a name="ZH-CN_TOPIC_0000001128311058"></a>
- **[概述](quickstart-lite-env-setup-des.md)** - **[概述](quickstart-lite-env-setup-overview.md)**
- **[Windows开发环境准备](quickstart-lite-env-setup-win.md)** - **[Windows开发环境准备](quickstart-lite-env-setup-windows.md)**
- **[Ubuntu编译环境准备](quickstart-lite-env-setup-lin.md)** - **[获取源码及Ubuntu编译环境准备](quickstart-lite-env-setup-linux.md)**
- **[常见问题](quickstart-lite-env-setup-faqs.md)** - **[常见问题](quickstart-lite-env-setup-faqs.md)**
......
# 了解开发板<a name="ZH-CN_TOPIC_0000001174270687"></a> # 入门介绍<a name="ZH-CN_TOPIC_0000001181550103"></a>
- **[Hi3861开发板介绍](quickstart-lite-introduction-hi3861.md)** - **[Hi3861开发板介绍](oem_minitinier_des_3861.md)**
- **[Hi3516开发板介绍](quickstart-lite-introduction-hi3516.md)** - **[Hi3516开发板介绍](oem_minitinier_des_3516.md)**
- **[Hi3518开发板介绍](quickstart-lite-introduction-hi3518.md)** - **[Hi3518开发板介绍](oem_minitinier_des_3518.md)**
# Hi3516开发板<a name="ZH-CN_TOPIC_0000001128470852"></a>
- **[安装开发板环境](quickstart-lite-steps-board3516-setting.md)**
- **[运行Hello OHOS](quickstart-lite-steps-board3516-running.md)**
- **[驱动开发示例](quickstart-lite-steps-board3516-program.md)**
- **[常见问题](quickstart-lite-steps-board3516-faqs.md)**
# Hi3518开发板<a name="ZH-CN_TOPIC_0000001128311052"></a>
- **[安装开发板环境](quickstart-lite-steps-board3518-setting.md)**
- **[运行Hello OHOS](quickstart-lite-steps-board3518-running.md)**
- **[常见问题](quickstart-lite-steps-board3518-faqs.md)**
# Hi3861开发板<a name="ZH-CN_TOPIC_0000001174350609"></a>
- **[安装开发板环境](quickstart-lite-steps-board3861-setting.md)**
- **[WLAN联网](quickstart-lite-steps-board3861-connection.md)**
- **[运行Hello World](quickstart-lite-steps-board3861-running.md)**
- **[常见问题](quickstart-lite-steps-board3861-faqs.md)**
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
- **解决办法** - **解决办法**
请按照[安装python](quickstart-lite-env-setup-lin.md)。 请按照[安装Python环境](quickstart-lite-env-setup-linux.md#section1238412211211)。
- **可能原因2** - **可能原因2**
......
# 驱动开发示例<a name="ZH-CN_TOPIC_0000001174350613"></a> # 驱动开发示例<a name="ZH-CN_TOPIC_0000001174350613"></a>
- [驱动程序介绍](#s8efc1952ebfe4d1ea717182e108c29bb) - [驱动程序介绍](#s8efc1952ebfe4d1ea717182e108c29bb)
- [编译和烧](#section660016185110) - [编译和烧](#section660016185110)
- [镜像运行](#section333215226219) - [镜像运行](#section333215226219)
- [下一步学习](#section9712145420182) - [下一步学习](#section9712145420182)
...@@ -421,16 +421,16 @@ ...@@ -421,16 +421,16 @@
>示例代码默认不参与编译,需要手动添加到编译脚本中。 >示例代码默认不参与编译,需要手动添加到编译脚本中。
## 编译和烧<a name="section660016185110"></a> ## 编译和烧<a name="section660016185110"></a>
参考《运行Hello OHOS》进行编译和烧写:[编译](quickstart-lite-steps-board3516-running.md#section1077671315253)[烧录](quickstart-lite-steps-board3516-running.md#section1347011412201) 参考《运行Hello OHOS》进行编译和烧录:[编译](quickstart-lite-steps-hi3516-running.md#section1077671315253)[烧录](quickstart-lite-steps-hi3516-running.md#section1347011412201)
## 镜像运行<a name="section333215226219"></a> ## 镜像运行<a name="section333215226219"></a>
1. 连接串口。 1. 连接串口。
>![](../public_sys-resources/icon-notice.gif) **须知:** >![](../public_sys-resources/icon-notice.gif) **须知:**
>若无法连接串口,请参考[常见问题](quickstart-lite-steps-board3516-faqs.md)进行排查。 >若无法连接串口,请参考[常见问题](quickstart-lite-steps-hi3516-faqs.md#section14871149155911)进行排查。
**图 1** 连接串口图<a name="zh-cn_topic_0000001151888681_fig056645018495"></a> **图 1** 连接串口图<a name="zh-cn_topic_0000001151888681_fig056645018495"></a>
...@@ -439,7 +439,7 @@ ...@@ -439,7 +439,7 @@
1. 单击**Monitor**打开串口。 1. 单击**Monitor**打开串口。
2. 连续输入回车直到串口显示"hisilicon"。 2. 连续输入回车直到串口显示"hisilicon"。
3. 单板初次启动或修改启动参数,请进入[步骤2](quickstart-lite-steps-board3516-running.md#l5b42e79a33ea4d35982b78a22913b0b1),否则进入[步骤3](quickstart-lite-steps-board3516-running.md#ld26f18828aa44c36bfa36be150e60e49)。 3. 单板初次启动或修改启动参数,请进入[步骤2](quickstart-lite-steps-hi3516-running.md#l5b42e79a33ea4d35982b78a22913b0b1),否则进入[步骤3](quickstart-lite-steps-hi3516-running.md#ld26f18828aa44c36bfa36be150e60e49)。
2. (单板初次启动必选)修改U-boot的bootcmd及bootargs内容:该步骤为固化操作,若不修改参数只需执行一次。每次复位单板均会自动进入系统。 2. (单板初次启动必选)修改U-boot的bootcmd及bootargs内容:该步骤为固化操作,若不修改参数只需执行一次。每次复位单板均会自动进入系统。
......
# 运行Hello OHOS<a name="ZH-CN_TOPIC_0000001174270695"></a> # 运行Hello OHOS(编译、烧录)<a name="ZH-CN_TOPIC_0000001174270695"></a>
- [新建应用程序](#section204672145202) - [新建应用程序](#section204672145202)
- [编译](#section1077671315253) - [编译](#section1077671315253)
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
## 编译<a name="section1077671315253"></a> ## 编译<a name="section1077671315253"></a>
如果Linux编译环境通过Docker方式安装,具体编译过程请参见[Docker方式获取编译环境](../get-code/gettools-acquire.md)的编译操作。如果Linux编译环境通过软件包方式安装,请进入源码根目录,执行如下命令进行编译: 如果Linux编译环境通过Docker方式安装,具体编译过程请参见[Docker方式获取编译环境](../get-code/gettools-acquire.md#section107932281315)的编译操作。如果Linux编译环境通过软件包方式安装,请进入源码根目录,执行如下命令进行编译:
``` ```
hb set(设置编译路径) hb set(设置编译路径)
...@@ -150,7 +150,7 @@ hb build -f(执行编译) ...@@ -150,7 +150,7 @@ hb build -f(执行编译)
Hi3516开发板的代码烧录支持USB烧录、网口烧录和串口烧录三种方式。此处仅以网口烧录为例进行说明。 Hi3516开发板的代码烧录支持USB烧录、网口烧录和串口烧录三种方式。此处仅以网口烧录为例进行说明。
1. 请连接好电脑和待烧录开发板,以Hi3516DV300为例,需要同时连接串口、网口和电源,具体可参考[Hi3516开发板介绍](quickstart-lite-introduction-hi3516.md) 1. 请连接好电脑和待烧录开发板,以Hi3516DV300为例,需要同时连接串口、网口和电源,具体可参考[Hi3516开发板介绍](oem_minitinier_des_3516.md)
2. <a name="zh-cn_topic_0000001056443961_li142386399535"></a>打开电脑的设备管理器,查看并记录对应的串口号。 2. <a name="zh-cn_topic_0000001056443961_li142386399535"></a>打开电脑的设备管理器,查看并记录对应的串口号。
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
...@@ -200,7 +200,7 @@ Hi3516开发板的代码烧录支持USB烧录、网口烧录和串口烧录三 ...@@ -200,7 +200,7 @@ Hi3516开发板的代码烧录支持USB烧录、网口烧录和串口烧录三
1. 连接串口。 1. 连接串口。
>![](../public_sys-resources/icon-notice.gif) **须知:** >![](../public_sys-resources/icon-notice.gif) **须知:**
>若无法连接串口,请参考[常见问题](quickstart-lite-steps-board3516-faqs.md)进行排查。 >若无法连接串口,请参考[常见问题](quickstart-lite-steps-hi3516-faqs.md)进行排查。
**图 2** 连接串口图<a name="fig056645018495"></a> **图 2** 连接串口图<a name="fig056645018495"></a>
......
# Hi3516开发板<a name="ZH-CN_TOPIC_0000001128470852"></a>
- **[安装开发板环境](quickstart-lite-steps-hi3516-setting.md)**
- **[运行Hello OHOS(编译、烧录)](quickstart-lite-steps-hi3516-running.md)**
- **[驱动开发示例](quickstart-lite-steps-hi3516-program.md)**
- **[常见问题](quickstart-lite-steps-hi3516-faqs.md)**
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
- **解决办法** - **解决办法**
请按照[安装python](quickstart-lite-env-setup-lin.md)。 请按照[安装Python环境](quickstart-lite-env-setup-linux.md#section1238412211211)。
- **可能原因2** - **可能原因2**
...@@ -142,7 +142,7 @@ ...@@ -142,7 +142,7 @@
修改串口号。 修改串口号。
请查看设备管理器,确认连接单板的串口与终端中连接串口是否一致,若不一致,请按镜像运行内[步骤1](quickstart-lite-steps-board3518-running.md)修改串口号。 请查看设备管理器,确认连接单板的串口与终端中连接串口是否一致,若不一致,请按镜像运行内[步骤1](#section1498892119619)修改串口号。
- **可能原因2** - **可能原因2**
......
# 运行Hello OHOS<a name="ZH-CN_TOPIC_0000001174350607"></a> # 运行Hello OHOS(编译、烧录)<a name="ZH-CN_TOPIC_0000001174350607"></a>
- [新建应用程序](#section1550972416485) - [新建应用程序](#section1550972416485)
- [编译](#section234175193114) - [编译](#section234175193114)
...@@ -128,7 +128,7 @@ ...@@ -128,7 +128,7 @@
## 编译<a name="section234175193114"></a> ## 编译<a name="section234175193114"></a>
如果Linux编译环境通过Docker方式安装,具体编译过程请参见[Docker方式获取编译环境](../get-code/gettools-acquire.md)的编译操作。如果Linux编译环境通过软件包方式安装,进入源码根目录,执行如下命令进行编译: 如果Linux编译环境通过Docker方式安装,具体编译过程请参见[Docker方式获取编译环境](../get-code/gettools-acquire.md#section107932281315)的编译操作。如果Linux编译环境通过软件包方式安装,进入源码根目录,执行如下命令进行编译:
``` ```
hb set(设置编译路径) hb set(设置编译路径)
...@@ -149,7 +149,7 @@ hb build -f(执行编译) ...@@ -149,7 +149,7 @@ hb build -f(执行编译)
Hi3518开发板的代码烧录仅支持USB烧录方式。 Hi3518开发板的代码烧录仅支持USB烧录方式。
1. 请连接好电脑和待烧录开发板,以Hi3518EV300为例,需要同时连接串口和USB口,具体可参考[Hi3518开发板介绍](quickstart-lite-introduction-hi3518.md) 1. 请连接好电脑和待烧录开发板,以Hi3518EV300为例,需要同时连接串口和USB口,具体可参考[Hi3518开发板介绍](oem_minitinier_des_3518.md)
2. <a name="zh-cn_topic_0000001057313128_li46411811196"></a>打开电脑的设备管理器,查看并记录对应的串口号。 2. <a name="zh-cn_topic_0000001057313128_li46411811196"></a>打开电脑的设备管理器,查看并记录对应的串口号。
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
...@@ -197,7 +197,7 @@ Hi3518开发板的代码烧录仅支持USB烧录方式。 ...@@ -197,7 +197,7 @@ Hi3518开发板的代码烧录仅支持USB烧录方式。
1. 连接串口。 1. 连接串口。
>![](../public_sys-resources/icon-notice.gif) **须知:** >![](../public_sys-resources/icon-notice.gif) **须知:**
>若无法连接串口,请参考[常见问题](quickstart-lite-steps-board3518-faqs.md)进行排查。 >若无法连接串口,请参考[常见问题](quickstart-lite-steps-hi3518-faqs.md#zh-cn_topic_0000001053466255_section14871149155911)进行排查。
**图 2** 连接串口图<a name="fig056645018495"></a> **图 2** 连接串口图<a name="fig056645018495"></a>
......
# Hi3518开发板<a name="ZH-CN_TOPIC_0000001128311052"></a>
- **[安装开发板环境](quickstart-lite-steps-hi3518-setting.md)**
- **[运行Hello OHOS(编译、烧录)](quickstart-lite-steps-hi3518-running.md)**
- **[常见问题](quickstart-lite-steps-hi3518-faqs.md)**
# WLAN联网<a name="ZH-CN_TOPIC_0000001174350611"></a> # WLAN联网(编译、烧录)<a name="ZH-CN_TOPIC_0000001174350611"></a>
- [源码编译](#section191121332125319) - [编译](#section191121332125319)
- [镜像烧录](#section19458165166) - [镜像烧录](#section19458165166)
- [WLAN模组联网](#section194671619167) - [WLAN模组联网](#section194671619167)
本示例将演示如何通过AT命令完成WLAN模组与网关联网。 本示例将演示如何通过AT命令完成WLAN模组与网关联网。
## 源码编译<a name="section191121332125319"></a> ## 编译<a name="section191121332125319"></a>
本节描述如何在Linux服务器上进行WLAN模组版本的编译。 本节描述如何在Linux服务器上进行WLAN模组版本的编译。
如果Linux编译环境通过Docker方式安装,具体编译过程请参见[Docker方式获取编译环境](../get-code/sourcecode-acquire.md)的编译操作。如果Linux编译环境通过软件包方式安装,请参考如下步骤。 如果Linux编译环境通过Docker方式安装,具体编译过程请参见[Docker方式获取编译环境](../get-code/gettools-acquire.md#section107932281315)的编译操作。如果Linux编译环境通过软件包方式安装,请参考如下步骤。
1. 打开DevEco Device Tool工具,点击“View \> Terminal”,进入终端界面。 1. 打开DevEco Device Tool工具,点击“View \> Terminal”,进入终端界面。
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
Hi3861 WLAN模组的镜像烧录可以通过OpenHarmony IDE工具DevEco完成,工具的基本使用请参考[DevEco Device Tool使用指南](https://device.harmonyos.com/cn/docs/ide/user-guides/service_introduction-0000001050166905),烧录过程包含如下步骤。 Hi3861 WLAN模组的镜像烧录可以通过OpenHarmony IDE工具DevEco完成,工具的基本使用请参考[DevEco Device Tool使用指南](https://device.harmonyos.com/cn/docs/ide/user-guides/service_introduction-0000001050166905),烧录过程包含如下步骤。
1. 请连接好电脑和待烧录开发板,需要连接USB口,具体可参考[Hi3861开发板介绍](quickstart-lite-introduction-hi3861.md) 1. 请连接好电脑和待烧录开发板,需要连接USB口,具体可参考[Hi3861开发板介绍](oem_minitinier_des_3861.md)
2. <a name="zh-cn_topic_0000001056563976_li848662117291"></a>打开电脑的设备管理器,查看并记录对应的串口号。 2. <a name="zh-cn_topic_0000001056563976_li848662117291"></a>打开电脑的设备管理器,查看并记录对应的串口号。
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
......
...@@ -249,7 +249,7 @@ ...@@ -249,7 +249,7 @@
- **解决办法** - **解决办法**
请按照 [安装Python环境](quickstart-lite-env-setup-lin.md) 请按照[安装Python环境](quickstart-lite-env-setup-linux.md#section1238412211211)
- **可能原因2** - **可能原因2**
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
- [修改源码](#section79601457101015) - [修改源码](#section79601457101015)
- [调测验证](#section1621064881419) - [调测验证](#section1621064881419)
- [printf打印](#section1246911301217) - [printf打印](#section5204547123316)
- [根据asm文件进行问题定位](#section199621957141014) - [根据asm文件进行问题定位](#section15919111423416)
- [运行结果](#section18115713118) - [运行结果](#section18115713118)
- [下一步学习](#section9712145420182) - [下一步学习](#section9712145420182)
...@@ -92,7 +93,7 @@ bugfix和新增业务两种情况,涉及源码修改。下面以新增业务 ...@@ -92,7 +93,7 @@ bugfix和新增业务两种情况,涉及源码修改。下面以新增业务
由于本示例业务简单,采用printf打印日志的调试方式即可。下面开始介绍这两种调试手段的使用方法。 由于本示例业务简单,采用printf打印日志的调试方式即可。下面开始介绍这两种调试手段的使用方法。
## printf打印<a name="section1246911301217"></a> ### printf打印<a name="section5204547123316"></a>
代码中增加printf维测,信息会直接打印到串口上。开发者可在业务关键路径或业务异常位置增加日志打印,如下所示。 代码中增加printf维测,信息会直接打印到串口上。开发者可在业务关键路径或业务异常位置增加日志打印,如下所示。
...@@ -103,7 +104,7 @@ void HelloWorld(void) ...@@ -103,7 +104,7 @@ void HelloWorld(void)
} }
``` ```
## 根据asm文件进行问题定位<a name="section199621957141014"></a> ### 根据asm文件进行问题定位<a name="section15919111423416"></a>
系统异常退出时,会在串口上打印异常退出原因调用栈信息,如下文所示。通过解析异常栈信息可以定位异常位置。 系统异常退出时,会在串口上打印异常退出原因调用栈信息,如下文所示。通过解析异常栈信息可以定位异常位置。
...@@ -137,7 +138,7 @@ Call Stack 6 -- 3f5e24 addr:f78fc ...@@ -137,7 +138,7 @@ Call Stack 6 -- 3f5e24 addr:f78fc
3. 根据以上调用栈信息,可以定位WadRecvCB函数中出现了异常。 3. 根据以上调用栈信息,可以定位WadRecvCB函数中出现了异常。
![](figure/zh-cn_image_0000001174270737.png) ![](figure/zh-cn_image_0000001134641222.png)
4. 完成代码排查及修改。 4. 完成代码排查及修改。
......
...@@ -142,13 +142,11 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev ...@@ -142,13 +142,11 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev
sudo pip3 install kconfiglib sudo pip3 install kconfiglib
``` ```
- **安装包方式:** - **安装包方式:**
1. 下载.whl文件(例如:kconfiglib-13.2.0-py2.py3-none-any.whl)。 1. 下载.whl文件(例如:kconfiglib-13.2.0-py2.py3-none-any.whl)。
下载路径:“[https://pypi.org/project/kconfiglib\#files](https://pypi.org/project/kconfiglib#files)” 下载路径:“[https://pypi.org/project/kconfiglib\#files](https://pypi.org/project/kconfiglib#files)”
1. 运行如下命令,安装.whl文件。 1. 运行如下命令,安装.whl文件。
``` ```
...@@ -156,7 +154,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev ...@@ -156,7 +154,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev
``` ```
3. 安装pycryptodome,任选如下一种方式。 3. 安装pycryptodome,任选如下一种方式。
安装升级文件签名依赖的Python组件包,包括:pycryptodome、six、ecdsa。安装ecdsa依赖six,请先安装six,再安装ecdsa。 安装升级文件签名依赖的Python组件包,包括:pycryptodome、six、ecdsa。安装ecdsa依赖six,请先安装six,再安装ecdsa。
...@@ -172,7 +169,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev ...@@ -172,7 +169,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev
下载路径:“[https://pypi.org/project/pycryptodome/\#files](https://pypi.org/project/pycryptodome/#files)”。 下载路径:“[https://pypi.org/project/pycryptodome/\#files](https://pypi.org/project/pycryptodome/#files)”。
1. 运行如下命令,安装.whl文件。 1. 运行如下命令,安装.whl文件。
``` ```
...@@ -180,7 +176,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev ...@@ -180,7 +176,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev
``` ```
4. 安装six,任选如下一种方式。 4. 安装six,任选如下一种方式。
- **命令行方式:** - **命令行方式:**
...@@ -188,13 +183,11 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev ...@@ -188,13 +183,11 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev
sudo pip3 install six --upgrade --ignore-installed six sudo pip3 install six --upgrade --ignore-installed six
``` ```
- **安装包方式:** - **安装包方式:**
1. 下载.whl文件(例如:six-1.12.0-py2.py3-none-any.whl)。 1. 下载.whl文件(例如:six-1.12.0-py2.py3-none-any.whl)。
下载路径:“[https://pypi.org/project/six/\#files](https://pypi.org/project/six/#files)” 下载路径:“[https://pypi.org/project/six/\#files](https://pypi.org/project/six/#files)”
1. 运行如下命令,安装.whl文件。 1. 运行如下命令,安装.whl文件。
``` ```
...@@ -202,7 +195,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev ...@@ -202,7 +195,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev
``` ```
5. 安装ecdsa,任选如下一种方式。 5. 安装ecdsa,任选如下一种方式。
- **命令行方式:** - **命令行方式:**
...@@ -215,7 +207,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev ...@@ -215,7 +207,6 @@ sudo apt-get install build-essential gcc g++ make zlib* libffi-dev
下载路径:“[https://pypi.org/project/ecdsa/\#files](https://pypi.org/project/ecdsa/#files)” 下载路径:“[https://pypi.org/project/ecdsa/\#files](https://pypi.org/project/ecdsa/#files)”
1. 运行如下命令,安装.whl文件。 1. 运行如下命令,安装.whl文件。
``` ```
......
# Hi3861开发板<a name="ZH-CN_TOPIC_0000001174350609"></a>
- **[安装开发板环境](quickstart-lite-steps-hi3861-setting.md)**
- **[WLAN联网(编译、烧录)](quickstart-lite-steps-hi3861-connection.md)**
- **[运行Hello World](quickstart-lite-steps-hi3861-running.md)**
- **[常见问题](quickstart-lite-steps-hi3861-faqs.md)**
# 开发步骤<a name="ZH-CN_TOPIC_0000001128470860"></a> # 开发步骤<a name="ZH-CN_TOPIC_0000001128470860"></a>
- **[Hi3861开发板](quickstart-lite-steps-board3861.md)** - **[Hi3861开发板](quickstart-lite-steps-hi3861.md)**
- **[Hi3516开发板](quickstart-lite-steps-board3516.md)** - **[Hi3516开发板](quickstart-lite-steps-hi3516.md)**
- **[Hi3518开发板](quickstart-lite-steps-board3518.md)** - **[Hi3518开发板](quickstart-lite-steps-hi3518.md)**
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- **[概述](quickstart-lite-overview.md)** - **[概述](quickstart-lite-overview.md)**
- **[了解开发板](quickstart-lite-introduction.md)** - **[入门介绍](quickstart-lite-introduction.md)**
- **[搭建系统环境](quickstart-lite-env-setup.md)** - **[搭建系统环境](quickstart-lite-env-setup.md)**
......
# 镜像烧录<a name="ZH-CN_TOPIC_0000001119964704"></a> # 镜像烧录<a name="ZH-CN_TOPIC_0000001119964704"></a>
- [下一步](#section5600113114323) - [前提条件](#section63941724112115)
- [使用网口烧录](#section112807166589)
标准系统烧录,在V2.2 Beta1及以上版本支持。 标准系统烧录,在V2.2 Beta1及以上版本支持。
Hi3516DV300支持烧录标准系统,其烧录方式包括网口烧录和串口烧录三种方式,其中: Hi3516DV300支持烧录标准系统,其烧录方式包括USB烧录、网口烧录和串口烧录三种方式,其中:
- **Windows系统:支持网口烧录和串口烧录** - **Windows系统:支持USB烧录、网口烧录和串口烧录**
- **Linux系统:支持串口烧录和网口烧录。** - **Linux系统:支持串口烧录和网口烧录。**
同一种烧录方式(如网口烧录),在Windows和Linux环境下的烧录操作完全一致,区别仅在于DevEco Device Tool环境搭建不同。 同一种烧录方式(如网口烧录),在Windows和Linux环境下的烧录操作完全一致,区别仅在于DevEco Device Tool环境搭建不同。
...@@ -14,166 +15,166 @@ Hi3516DV300支持烧录标准系统,其烧录方式包括网口烧录和串口 ...@@ -14,166 +15,166 @@ Hi3516DV300支持烧录标准系统,其烧录方式包括网口烧录和串口
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
>当前Hi3516DV300开发板支持通过网口、USB、串口三种方式烧录OpenHarmony标准系统。本文以网口方式为例讲解烧录操作,其他两种烧录方式请参照[Hi3516DV300烧录指导](https://device.harmonyos.com/cn/docs/ide/user-guides/hi3516_upload-0000001052148681)。 >当前Hi3516DV300开发板支持通过网口、USB、串口三种方式烧录OpenHarmony标准系统。本文以网口方式为例讲解烧录操作,其他两种烧录方式请参照[Hi3516DV300烧录指导](https://device.harmonyos.com/cn/docs/ide/user-guides/hi3516_upload-0000001052148681)。
### 前提条件<a name="section1458192114718"></a> ## 前提条件<a name="section63941724112115"></a>
在DevEco Device Tool中[打开一个工程](https://device.harmonyos.com/cn/docs/ide/user-guides/open_project-0000001071680043),该工程文件夹选择待烧录文件所在文件夹即可。其中开发板类型固定选择Hi3516DV300,Framework选择“Hb”。 在DevEco Device Tool中[打开一个工程](https://device.harmonyos.com/cn/docs/ide/user-guides/open_project-0000001071680043),该工程文件夹选择待烧录文件所在文件夹即可。其中开发板类型固定选择Hi3516DV300,Framework选择“Hb”。
### 使用网口烧录<a name="section134403184287"></a> ## 使用网口烧录<a name="section112807166589"></a>
Hi3516DV300开发板使用网口录方式,支持Windows和Linux系统。 Hi3516DV300开发板使用网口录方式,支持Windows和Linux系统。
1. 请连接好电脑和待烧录开发板,需要同时连接串口、网口和电源,具体可参考[Hi3516DV300开发板介绍](https://device.harmonyos.com/cn/docs/start/introduce/oem_minitinier_des_3516-0000001152041033) 1. 请连接好电脑和待烧录开发板,需要同时连接串口、网口和电源,具体可参考[Hi3516DV300开发板介绍](https://device.harmonyos.com/cn/docs/start/introduce/oem_minitinier_des_3516-0000001152041033)
2. <a name="zh-cn_topic_0000001056443961_li1050616379507"></a>打开电脑的设备管理器,查看并记录对应的串口号。 2. <a name="zh-cn_topic_0000001180633781_li1050616379507"></a>打开电脑的设备管理器,查看并记录对应的串口号。
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
>如果对应的串口异常,请根据[Hi3516DV300/Hi3518EV300开发板串口驱动安装指导](https://device.harmonyos.com/cn/docs/ide/user-guides/hi3516_hi3518-drivers-0000001050743695)安装USB转串口的驱动程序。 >如果对应的串口异常,请根据[Hi3516DV300/Hi3518EV300开发板串口驱动安装指导](https://device.harmonyos.com/cn/docs/ide/user-guides/hi3516_hi3518-drivers-0000001050743695)安装USB转串口的驱动程序。
![](figure/zh-cn_image_0000001114129428.png) ![](figure/zh-cn_image_0000001180513891.png)
3. 打开DevEco Device Tool,在Projects中,点击**Settings**打开工程配置界面。 3. 打开DevEco Device Tool,在Projects中,点击**Settings**打开工程配置界面。
![](figure/2021-01-27_170334-16.png) ![](figure/2021-01-27_170334-17.png)
4.**Partition Configuration**页签中,按照下表内容填写烧录文件信息,包括: 4.**Partition Configuration**页签中,按照下表内容填写烧录文件信息,包括:
<a name="zh-cn_topic_0000001056443961_table18494162555410"></a> <a name="zh-cn_topic_0000001180633781_table18494162555410"></a>
<table><thead align="left"><tr id="zh-cn_topic_0000001056443961_row15492132518545"><th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.1"><p id="zh-cn_topic_0000001056443961_p174911825135413"><a name="zh-cn_topic_0000001056443961_p174911825135413"></a><a name="zh-cn_topic_0000001056443961_p174911825135413"></a>Name</p> <table><thead align="left"><tr id="zh-cn_topic_0000001180633781_row15492132518545"><th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.1"><p id="zh-cn_topic_0000001180633781_p174911825135413"><a name="zh-cn_topic_0000001180633781_p174911825135413"></a><a name="zh-cn_topic_0000001180633781_p174911825135413"></a>Name</p>
</th> </th>
<th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.2"><p id="zh-cn_topic_0000001056443961_p114911625165414"><a name="zh-cn_topic_0000001056443961_p114911625165414"></a><a name="zh-cn_topic_0000001056443961_p114911625165414"></a>Binary</p> <th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.2"><p id="zh-cn_topic_0000001180633781_p114911625165414"><a name="zh-cn_topic_0000001180633781_p114911625165414"></a><a name="zh-cn_topic_0000001180633781_p114911625165414"></a>Binary</p>
</th> </th>
<th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.3"><p id="zh-cn_topic_0000001056443961_p1749112515417"><a name="zh-cn_topic_0000001056443961_p1749112515417"></a><a name="zh-cn_topic_0000001056443961_p1749112515417"></a>Memory</p> <th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.3"><p id="zh-cn_topic_0000001180633781_p1749112515417"><a name="zh-cn_topic_0000001180633781_p1749112515417"></a><a name="zh-cn_topic_0000001180633781_p1749112515417"></a>Memory</p>
</th> </th>
<th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.4"><p id="zh-cn_topic_0000001056443961_p1749182575420"><a name="zh-cn_topic_0000001056443961_p1749182575420"></a><a name="zh-cn_topic_0000001056443961_p1749182575420"></a>System</p> <th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.4"><p id="zh-cn_topic_0000001180633781_p1749182575420"><a name="zh-cn_topic_0000001180633781_p1749182575420"></a><a name="zh-cn_topic_0000001180633781_p1749182575420"></a>System</p>
</th> </th>
<th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.5"><p id="zh-cn_topic_0000001056443961_p174921325135414"><a name="zh-cn_topic_0000001056443961_p174921325135414"></a><a name="zh-cn_topic_0000001056443961_p174921325135414"></a>Address</p> <th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.5"><p id="zh-cn_topic_0000001180633781_p174921325135414"><a name="zh-cn_topic_0000001180633781_p174921325135414"></a><a name="zh-cn_topic_0000001180633781_p174921325135414"></a>Address</p>
</th> </th>
<th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.6"><p id="zh-cn_topic_0000001056443961_p749242515415"><a name="zh-cn_topic_0000001056443961_p749242515415"></a><a name="zh-cn_topic_0000001056443961_p749242515415"></a>Length</p> <th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.6"><p id="zh-cn_topic_0000001180633781_p749242515415"><a name="zh-cn_topic_0000001180633781_p749242515415"></a><a name="zh-cn_topic_0000001180633781_p749242515415"></a>Length</p>
</th> </th>
<th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.7"><p id="zh-cn_topic_0000001056443961_p164921925115416"><a name="zh-cn_topic_0000001056443961_p164921925115416"></a><a name="zh-cn_topic_0000001056443961_p164921925115416"></a>Board</p> <th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.7"><p id="zh-cn_topic_0000001180633781_p164921925115416"><a name="zh-cn_topic_0000001180633781_p164921925115416"></a><a name="zh-cn_topic_0000001180633781_p164921925115416"></a>Board</p>
</th> </th>
<th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.8"><p id="zh-cn_topic_0000001056443961_p0492132595412"><a name="zh-cn_topic_0000001056443961_p0492132595412"></a><a name="zh-cn_topic_0000001056443961_p0492132595412"></a>Type</p> <th class="cellrowborder" valign="top" width="12.5%" id="mcps1.1.9.1.8"><p id="zh-cn_topic_0000001180633781_p0492132595412"><a name="zh-cn_topic_0000001180633781_p0492132595412"></a><a name="zh-cn_topic_0000001180633781_p0492132595412"></a>Type</p>
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody><tr id="zh-cn_topic_0000001056443961_row949214259543"><td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001056443961_p194922259548"><a name="zh-cn_topic_0000001056443961_p194922259548"></a><a name="zh-cn_topic_0000001056443961_p194922259548"></a>fastboot</p> <tbody><tr id="zh-cn_topic_0000001180633781_row949214259543"><td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001180633781_p194922259548"><a name="zh-cn_topic_0000001180633781_p194922259548"></a><a name="zh-cn_topic_0000001180633781_p194922259548"></a>fastboot</p>
</td> </td>
<td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001056443961_p749222515411"><a name="zh-cn_topic_0000001056443961_p749222515411"></a><a name="zh-cn_topic_0000001056443961_p749222515411"></a>选择“u-boot-hi3516dv300_emmc.bin”</p> <td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001180633781_p749222515411"><a name="zh-cn_topic_0000001180633781_p749222515411"></a><a name="zh-cn_topic_0000001180633781_p749222515411"></a>选择“u-boot-hi3516dv300_emmc.bin”</p>
</td> </td>
<td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001056443961_p1749213258540"><a name="zh-cn_topic_0000001056443961_p1749213258540"></a><a name="zh-cn_topic_0000001056443961_p1749213258540"></a>emmc</p> <td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001180633781_p1749213258540"><a name="zh-cn_topic_0000001180633781_p1749213258540"></a><a name="zh-cn_topic_0000001180633781_p1749213258540"></a>emmc</p>
</td> </td>
<td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001056443961_p1749220254548"><a name="zh-cn_topic_0000001056443961_p1749220254548"></a><a name="zh-cn_topic_0000001056443961_p1749220254548"></a>none</p> <td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001180633781_p1749220254548"><a name="zh-cn_topic_0000001180633781_p1749220254548"></a><a name="zh-cn_topic_0000001180633781_p1749220254548"></a>none</p>
</td> </td>
<td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001056443961_p144921825125418"><a name="zh-cn_topic_0000001056443961_p144921825125418"></a><a name="zh-cn_topic_0000001056443961_p144921825125418"></a>0x000000</p> <td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001180633781_p144921825125418"><a name="zh-cn_topic_0000001180633781_p144921825125418"></a><a name="zh-cn_topic_0000001180633781_p144921825125418"></a>0x000000</p>
</td> </td>
<td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001056443961_p549272518547"><a name="zh-cn_topic_0000001056443961_p549272518547"></a><a name="zh-cn_topic_0000001056443961_p549272518547"></a>0x100000</p> <td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001180633781_p549272518547"><a name="zh-cn_topic_0000001180633781_p549272518547"></a><a name="zh-cn_topic_0000001180633781_p549272518547"></a>0x100000</p>
</td> </td>
<td class="cellrowborder" rowspan="7" valign="top" width="12.5%" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001056443961_p9492125205411"><a name="zh-cn_topic_0000001056443961_p9492125205411"></a><a name="zh-cn_topic_0000001056443961_p9492125205411"></a>固定选择“hi3516dv300”</p> <td class="cellrowborder" rowspan="7" valign="top" width="12.5%" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001180633781_p9492125205411"><a name="zh-cn_topic_0000001180633781_p9492125205411"></a><a name="zh-cn_topic_0000001180633781_p9492125205411"></a>固定选择“hi3516dv300”</p>
</td> </td>
<td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.8 "><p id="zh-cn_topic_0000001056443961_p1549282518548"><a name="zh-cn_topic_0000001056443961_p1549282518548"></a><a name="zh-cn_topic_0000001056443961_p1549282518548"></a>NA</p> <td class="cellrowborder" valign="top" width="12.5%" headers="mcps1.1.9.1.8 "><p id="zh-cn_topic_0000001180633781_p1549282518548"><a name="zh-cn_topic_0000001180633781_p1549282518548"></a><a name="zh-cn_topic_0000001180633781_p1549282518548"></a>NA</p>
</td> </td>
</tr> </tr>
<tr id="zh-cn_topic_0000001056443961_row94933253545"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001056443961_p1749311252542"><a name="zh-cn_topic_0000001056443961_p1749311252542"></a><a name="zh-cn_topic_0000001056443961_p1749311252542"></a>boot</p> <tr id="zh-cn_topic_0000001180633781_row94933253545"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001180633781_p1749311252542"><a name="zh-cn_topic_0000001180633781_p1749311252542"></a><a name="zh-cn_topic_0000001180633781_p1749311252542"></a>boot</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001056443961_p18493162515543"><a name="zh-cn_topic_0000001056443961_p18493162515543"></a><a name="zh-cn_topic_0000001056443961_p18493162515543"></a>选择“uImage”</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001180633781_p18493162515543"><a name="zh-cn_topic_0000001180633781_p18493162515543"></a><a name="zh-cn_topic_0000001180633781_p18493162515543"></a>选择“uImage”</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001056443961_p1249332512548"><a name="zh-cn_topic_0000001056443961_p1249332512548"></a><a name="zh-cn_topic_0000001056443961_p1249332512548"></a>emmc</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001180633781_p1249332512548"><a name="zh-cn_topic_0000001180633781_p1249332512548"></a><a name="zh-cn_topic_0000001180633781_p1249332512548"></a>emmc</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001056443961_p114931825155414"><a name="zh-cn_topic_0000001056443961_p114931825155414"></a><a name="zh-cn_topic_0000001056443961_p114931825155414"></a>none</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001180633781_p114931825155414"><a name="zh-cn_topic_0000001180633781_p114931825155414"></a><a name="zh-cn_topic_0000001180633781_p114931825155414"></a>none</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001056443961_p1249392565417"><a name="zh-cn_topic_0000001056443961_p1249392565417"></a><a name="zh-cn_topic_0000001056443961_p1249392565417"></a>0x100000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001180633781_p1249392565417"><a name="zh-cn_topic_0000001180633781_p1249392565417"></a><a name="zh-cn_topic_0000001180633781_p1249392565417"></a>0x100000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001056443961_p84932253541"><a name="zh-cn_topic_0000001056443961_p84932253541"></a><a name="zh-cn_topic_0000001056443961_p84932253541"></a>0xf00000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001180633781_p84932253541"><a name="zh-cn_topic_0000001180633781_p84932253541"></a><a name="zh-cn_topic_0000001180633781_p84932253541"></a>0xf00000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001056443961_p13493142515412"><a name="zh-cn_topic_0000001056443961_p13493142515412"></a><a name="zh-cn_topic_0000001056443961_p13493142515412"></a>NA</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001180633781_p13493142515412"><a name="zh-cn_topic_0000001180633781_p13493142515412"></a><a name="zh-cn_topic_0000001180633781_p13493142515412"></a>NA</p>
</td> </td>
</tr> </tr>
<tr id="zh-cn_topic_0000001056443961_row649362515548"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001056443961_p749317258546"><a name="zh-cn_topic_0000001056443961_p749317258546"></a><a name="zh-cn_topic_0000001056443961_p749317258546"></a>updater</p> <tr id="zh-cn_topic_0000001180633781_row649362515548"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001180633781_p749317258546"><a name="zh-cn_topic_0000001180633781_p749317258546"></a><a name="zh-cn_topic_0000001180633781_p749317258546"></a>updater</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001056443961_p749372519545"><a name="zh-cn_topic_0000001056443961_p749372519545"></a><a name="zh-cn_topic_0000001056443961_p749372519545"></a>选择“updater.img”</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001180633781_p749372519545"><a name="zh-cn_topic_0000001180633781_p749372519545"></a><a name="zh-cn_topic_0000001180633781_p749372519545"></a>选择“updater.img”</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001056443961_p34931825165414"><a name="zh-cn_topic_0000001056443961_p34931825165414"></a><a name="zh-cn_topic_0000001056443961_p34931825165414"></a>emmc</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001180633781_p34931825165414"><a name="zh-cn_topic_0000001180633781_p34931825165414"></a><a name="zh-cn_topic_0000001180633781_p34931825165414"></a>emmc</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001056443961_p104932253549"><a name="zh-cn_topic_0000001056443961_p104932253549"></a><a name="zh-cn_topic_0000001056443961_p104932253549"></a>ext3/4</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001180633781_p104932253549"><a name="zh-cn_topic_0000001180633781_p104932253549"></a><a name="zh-cn_topic_0000001180633781_p104932253549"></a>ext3/4</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001056443961_p1149310255541"><a name="zh-cn_topic_0000001056443961_p1149310255541"></a><a name="zh-cn_topic_0000001056443961_p1149310255541"></a>0x1000000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001180633781_p1149310255541"><a name="zh-cn_topic_0000001180633781_p1149310255541"></a><a name="zh-cn_topic_0000001180633781_p1149310255541"></a>0x1000000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001056443961_p194936251542"><a name="zh-cn_topic_0000001056443961_p194936251542"></a><a name="zh-cn_topic_0000001056443961_p194936251542"></a>0x1400000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001180633781_p194936251542"><a name="zh-cn_topic_0000001180633781_p194936251542"></a><a name="zh-cn_topic_0000001180633781_p194936251542"></a>0x1400000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001056443961_p1849352575412"><a name="zh-cn_topic_0000001056443961_p1849352575412"></a><a name="zh-cn_topic_0000001056443961_p1849352575412"></a>NA</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001180633781_p1849352575412"><a name="zh-cn_topic_0000001180633781_p1849352575412"></a><a name="zh-cn_topic_0000001180633781_p1849352575412"></a>NA</p>
</td> </td>
</tr> </tr>
<tr id="zh-cn_topic_0000001056443961_row1149316252542"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001056443961_p114931925205416"><a name="zh-cn_topic_0000001056443961_p114931925205416"></a><a name="zh-cn_topic_0000001056443961_p114931925205416"></a>misc</p> <tr id="zh-cn_topic_0000001180633781_row1149316252542"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001180633781_p114931925205416"><a name="zh-cn_topic_0000001180633781_p114931925205416"></a><a name="zh-cn_topic_0000001180633781_p114931925205416"></a>misc</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001056443961_p149318253541"><a name="zh-cn_topic_0000001056443961_p149318253541"></a><a name="zh-cn_topic_0000001056443961_p149318253541"></a>空白,不用选择</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001180633781_p149318253541"><a name="zh-cn_topic_0000001180633781_p149318253541"></a><a name="zh-cn_topic_0000001180633781_p149318253541"></a>空白,不用选择</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001056443961_p64931825145418"><a name="zh-cn_topic_0000001056443961_p64931825145418"></a><a name="zh-cn_topic_0000001056443961_p64931825145418"></a>emmc</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001180633781_p64931825145418"><a name="zh-cn_topic_0000001180633781_p64931825145418"></a><a name="zh-cn_topic_0000001180633781_p64931825145418"></a>emmc</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001056443961_p1149372535411"><a name="zh-cn_topic_0000001056443961_p1149372535411"></a><a name="zh-cn_topic_0000001056443961_p1149372535411"></a>none</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001180633781_p1149372535411"><a name="zh-cn_topic_0000001180633781_p1149372535411"></a><a name="zh-cn_topic_0000001180633781_p1149372535411"></a>none</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001056443961_p64931253544"><a name="zh-cn_topic_0000001056443961_p64931253544"></a><a name="zh-cn_topic_0000001056443961_p64931253544"></a>0x2400000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001180633781_p64931253544"><a name="zh-cn_topic_0000001180633781_p64931253544"></a><a name="zh-cn_topic_0000001180633781_p64931253544"></a>0x2400000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001056443961_p194932025195413"><a name="zh-cn_topic_0000001056443961_p194932025195413"></a><a name="zh-cn_topic_0000001056443961_p194932025195413"></a>0x100000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001180633781_p194932025195413"><a name="zh-cn_topic_0000001180633781_p194932025195413"></a><a name="zh-cn_topic_0000001180633781_p194932025195413"></a>0x100000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001056443961_p1649332565414"><a name="zh-cn_topic_0000001056443961_p1649332565414"></a><a name="zh-cn_topic_0000001056443961_p1649332565414"></a>NA</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001180633781_p1649332565414"><a name="zh-cn_topic_0000001180633781_p1649332565414"></a><a name="zh-cn_topic_0000001180633781_p1649332565414"></a>NA</p>
</td> </td>
</tr> </tr>
<tr id="zh-cn_topic_0000001056443961_row16494182510545"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001056443961_p64948251549"><a name="zh-cn_topic_0000001056443961_p64948251549"></a><a name="zh-cn_topic_0000001056443961_p64948251549"></a>system</p> <tr id="zh-cn_topic_0000001180633781_row16494182510545"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001180633781_p64948251549"><a name="zh-cn_topic_0000001180633781_p64948251549"></a><a name="zh-cn_topic_0000001180633781_p64948251549"></a>system</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001056443961_p104948254549"><a name="zh-cn_topic_0000001056443961_p104948254549"></a><a name="zh-cn_topic_0000001056443961_p104948254549"></a>选择“system.img”</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001180633781_p104948254549"><a name="zh-cn_topic_0000001180633781_p104948254549"></a><a name="zh-cn_topic_0000001180633781_p104948254549"></a>选择“system.img”</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001056443961_p5494122517543"><a name="zh-cn_topic_0000001056443961_p5494122517543"></a><a name="zh-cn_topic_0000001056443961_p5494122517543"></a>emmc</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001180633781_p5494122517543"><a name="zh-cn_topic_0000001180633781_p5494122517543"></a><a name="zh-cn_topic_0000001180633781_p5494122517543"></a>emmc</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001056443961_p84948259549"><a name="zh-cn_topic_0000001056443961_p84948259549"></a><a name="zh-cn_topic_0000001056443961_p84948259549"></a>ext3/4</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001180633781_p84948259549"><a name="zh-cn_topic_0000001180633781_p84948259549"></a><a name="zh-cn_topic_0000001180633781_p84948259549"></a>ext3/4</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001056443961_p1249432519541"><a name="zh-cn_topic_0000001056443961_p1249432519541"></a><a name="zh-cn_topic_0000001056443961_p1249432519541"></a>0x2500000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001180633781_p1249432519541"><a name="zh-cn_topic_0000001180633781_p1249432519541"></a><a name="zh-cn_topic_0000001180633781_p1249432519541"></a>0x2500000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001056443961_p154941125205415"><a name="zh-cn_topic_0000001056443961_p154941125205415"></a><a name="zh-cn_topic_0000001056443961_p154941125205415"></a>0xceb00000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001180633781_p154941125205415"><a name="zh-cn_topic_0000001180633781_p154941125205415"></a><a name="zh-cn_topic_0000001180633781_p154941125205415"></a>0xceb00000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001056443961_p24941925205415"><a name="zh-cn_topic_0000001056443961_p24941925205415"></a><a name="zh-cn_topic_0000001056443961_p24941925205415"></a>NA</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001180633781_p24941925205415"><a name="zh-cn_topic_0000001180633781_p24941925205415"></a><a name="zh-cn_topic_0000001180633781_p24941925205415"></a>NA</p>
</td> </td>
</tr> </tr>
<tr id="zh-cn_topic_0000001056443961_row10494202535417"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001056443961_p3494225175414"><a name="zh-cn_topic_0000001056443961_p3494225175414"></a><a name="zh-cn_topic_0000001056443961_p3494225175414"></a>vendor</p> <tr id="zh-cn_topic_0000001180633781_row10494202535417"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001180633781_p3494225175414"><a name="zh-cn_topic_0000001180633781_p3494225175414"></a><a name="zh-cn_topic_0000001180633781_p3494225175414"></a>vendor</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001056443961_p6494192516544"><a name="zh-cn_topic_0000001056443961_p6494192516544"></a><a name="zh-cn_topic_0000001056443961_p6494192516544"></a>选择“vendor.img”</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001180633781_p6494192516544"><a name="zh-cn_topic_0000001180633781_p6494192516544"></a><a name="zh-cn_topic_0000001180633781_p6494192516544"></a>选择“vendor.img”</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001056443961_p549492595415"><a name="zh-cn_topic_0000001056443961_p549492595415"></a><a name="zh-cn_topic_0000001056443961_p549492595415"></a>emmc</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001180633781_p549492595415"><a name="zh-cn_topic_0000001180633781_p549492595415"></a><a name="zh-cn_topic_0000001180633781_p549492595415"></a>emmc</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001056443961_p1494122595420"><a name="zh-cn_topic_0000001056443961_p1494122595420"></a><a name="zh-cn_topic_0000001056443961_p1494122595420"></a>ext3/4</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001180633781_p1494122595420"><a name="zh-cn_topic_0000001180633781_p1494122595420"></a><a name="zh-cn_topic_0000001180633781_p1494122595420"></a>ext3/4</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001056443961_p04941925115412"><a name="zh-cn_topic_0000001056443961_p04941925115412"></a><a name="zh-cn_topic_0000001056443961_p04941925115412"></a>0xd1000000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001180633781_p04941925115412"><a name="zh-cn_topic_0000001180633781_p04941925115412"></a><a name="zh-cn_topic_0000001180633781_p04941925115412"></a>0xd1000000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001056443961_p749416252545"><a name="zh-cn_topic_0000001056443961_p749416252545"></a><a name="zh-cn_topic_0000001056443961_p749416252545"></a>0x10000000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001180633781_p749416252545"><a name="zh-cn_topic_0000001180633781_p749416252545"></a><a name="zh-cn_topic_0000001180633781_p749416252545"></a>0x10000000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001056443961_p134941725175414"><a name="zh-cn_topic_0000001056443961_p134941725175414"></a><a name="zh-cn_topic_0000001056443961_p134941725175414"></a>NA</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001180633781_p134941725175414"><a name="zh-cn_topic_0000001180633781_p134941725175414"></a><a name="zh-cn_topic_0000001180633781_p134941725175414"></a>NA</p>
</td> </td>
</tr> </tr>
<tr id="zh-cn_topic_0000001056443961_row349412251547"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001056443961_p19494122585417"><a name="zh-cn_topic_0000001056443961_p19494122585417"></a><a name="zh-cn_topic_0000001056443961_p19494122585417"></a>userdata</p> <tr id="zh-cn_topic_0000001180633781_row349412251547"><td class="cellrowborder" valign="top" headers="mcps1.1.9.1.1 "><p id="zh-cn_topic_0000001180633781_p19494122585417"><a name="zh-cn_topic_0000001180633781_p19494122585417"></a><a name="zh-cn_topic_0000001180633781_p19494122585417"></a>userdata</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001056443961_p14494192514543"><a name="zh-cn_topic_0000001056443961_p14494192514543"></a><a name="zh-cn_topic_0000001056443961_p14494192514543"></a>选择“userdata.img”</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.2 "><p id="zh-cn_topic_0000001180633781_p14494192514543"><a name="zh-cn_topic_0000001180633781_p14494192514543"></a><a name="zh-cn_topic_0000001180633781_p14494192514543"></a>选择“userdata.img”</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001056443961_p15494725175416"><a name="zh-cn_topic_0000001056443961_p15494725175416"></a><a name="zh-cn_topic_0000001056443961_p15494725175416"></a>emmc</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.3 "><p id="zh-cn_topic_0000001180633781_p15494725175416"><a name="zh-cn_topic_0000001180633781_p15494725175416"></a><a name="zh-cn_topic_0000001180633781_p15494725175416"></a>emmc</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001056443961_p154946254549"><a name="zh-cn_topic_0000001056443961_p154946254549"></a><a name="zh-cn_topic_0000001056443961_p154946254549"></a>ext3/4</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.4 "><p id="zh-cn_topic_0000001180633781_p154946254549"><a name="zh-cn_topic_0000001180633781_p154946254549"></a><a name="zh-cn_topic_0000001180633781_p154946254549"></a>ext3/4</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001056443961_p204941225155420"><a name="zh-cn_topic_0000001056443961_p204941225155420"></a><a name="zh-cn_topic_0000001056443961_p204941225155420"></a>0xe1000000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.5 "><p id="zh-cn_topic_0000001180633781_p204941225155420"><a name="zh-cn_topic_0000001180633781_p204941225155420"></a><a name="zh-cn_topic_0000001180633781_p204941225155420"></a>0xe1000000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001056443961_p1449482515413"><a name="zh-cn_topic_0000001056443961_p1449482515413"></a><a name="zh-cn_topic_0000001056443961_p1449482515413"></a>0x5b800000</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.6 "><p id="zh-cn_topic_0000001180633781_p1449482515413"><a name="zh-cn_topic_0000001180633781_p1449482515413"></a><a name="zh-cn_topic_0000001180633781_p1449482515413"></a>0x5b800000</p>
</td> </td>
<td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001056443961_p0494182535420"><a name="zh-cn_topic_0000001056443961_p0494182535420"></a><a name="zh-cn_topic_0000001056443961_p0494182535420"></a>NA</p> <td class="cellrowborder" valign="top" headers="mcps1.1.9.1.7 "><p id="zh-cn_topic_0000001180633781_p0494182535420"><a name="zh-cn_topic_0000001180633781_p0494182535420"></a><a name="zh-cn_topic_0000001180633781_p0494182535420"></a>NA</p>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
![](figure/zh-cn_image_0000001130584312.png) ![](figure/zh-cn_image_0000001180633813.png)
5. 在“hi3516dv300”页签,设置烧录选项,包括upload\_port、upload\_partitions和upload\_protocol。 5. 在“hi3516dv300”页签,设置烧录选项,包括upload\_port、upload\_partitions和upload\_protocol。
- upload\_port:选择步骤[2](#zh-cn_topic_0000001056443961_li1050616379507)中查询的串口号。 - upload\_port:选择步骤[2](#zh-cn_topic_0000001180633781_li1050616379507)中查询的串口号。
- upload\_protocol:选择烧录协议,固定选择“hiburn-net”。 - upload\_protocol:选择烧录协议,固定选择“hiburn-net”。
- upload\_partitions:选择待烧录的文件,包括fastboot、boot、updater、misc、system、vendor和userdata。 - upload\_partitions:选择待烧录的文件,包括fastboot、boot、updater、misc、system、vendor和userdata。
![](figure/zh-cn_image_0000001117621400.png) ![](figure/zh-cn_image_0000001134474510.png)
6. 检查和设置连接开发板后的网络适配器的IP地址信息,设置方法请参考[设置Hi3516DV300网口烧录的IP地址信息](https://device.harmonyos.com/cn/docs/ide/user-guides/set_ipaddress-0000001141825075) 6. 检查和设置连接开发板后的网络适配器的IP地址信息,设置方法请参考[设置Hi3516DV300网口烧录的IP地址信息](https://device.harmonyos.com/cn/docs/ide/user-guides/set_ipaddress-0000001141825075)
7. 设置网口烧录的IP地址信息,设置如下选项: 7. 设置网口烧录的IP地址信息,设置如下选项:
...@@ -183,19 +184,15 @@ Hi3516DV300开发板使用网口录方式,支持Windows和Linux系统。 ...@@ -183,19 +184,15 @@ Hi3516DV300开发板使用网口录方式,支持Windows和Linux系统。
- upload\_net\_client\_gw:设置开发板的网关,工具会自动根据选择的upload\_net\_server\_ip进行设置。例如192.168.1.1 - upload\_net\_client\_gw:设置开发板的网关,工具会自动根据选择的upload\_net\_server\_ip进行设置。例如192.168.1.1
- upload\_net\_client\_ip:设置开发板的IP地址,工具会自动根据选择的upload\_net\_server\_ip进行设置。例如192.168.1.3 - upload\_net\_client\_ip:设置开发板的IP地址,工具会自动根据选择的upload\_net\_server\_ip进行设置。例如192.168.1.3
![](figure/zh-cn_image_0000001117463460.png) ![](figure/zh-cn_image_0000001180633847.png)
8. 所有的配置都修改完成后,在工程配置页签的顶部,点击**Save**进行保存。 8. 所有的配置都修改完成后,在工程配置页签的顶部,点击**Save**进行保存。
9. 启动烧录后,显示如下提示信息时,请重启开发板(下电再上电)。 9. 启动烧录后,显示如下提示信息时,请重启开发板(下电再上电)。
![](figure/zh-cn_image_0000001114129432.png) ![](figure/zh-cn_image_0000001134634288.png)
10. 重新上电后,启动烧录,界面提示如下信息时,表示烧录成功。 10. 重新上电后,启动烧录,界面提示如下信息时,表示烧录成功。
![](figure/zh-cn_image_0000001113969542.png) ![](figure/zh-cn_image_0000001180513893.png)
## 下一步<a name="section5600113114323"></a>
恭喜!您已经完成了OpenHarmony标准系统的快速入门,接下来可[开发一个小示例](../guide/device-clock-guide.md),进一步熟悉OpenHarmony的开发。
# 搭建Ubuntu环境及编译(Docker方式)<a name="ZH-CN_TOPIC_0000001119805112"></a> # 搭建Ubuntu环境\(获取源码及编译,Docker方式\)<a name="ZH-CN_TOPIC_0000001119805112"></a>
- [获取标准系统源码](#section8761819202511) - [获取标准系统源码](#section8761819202511)
- [前提条件](#section102871547153314) - [前提条件](#section102871547153314)
......
...@@ -22,7 +22,7 @@ Hi3516DV300作为新一代行业专用Smart HD IP摄像机SOC,集成新一代I ...@@ -22,7 +22,7 @@ Hi3516DV300作为新一代行业专用Smart HD IP摄像机SOC,集成新一代I
**图 2** Hi3516单板正面外观图<a name="zh-cn_topic_0000001053666242_fig11402183715219"></a> **图 2** Hi3516单板正面外观图<a name="zh-cn_topic_0000001053666242_fig11402183715219"></a>
![](figure/3516正面.png) ![](figure/3516正面-16.png)
## 开发板规格<a name="zh-cn_topic_0000001053666242_section15192203316533"></a> ## 开发板规格<a name="zh-cn_topic_0000001053666242_section15192203316533"></a>
......
# 搭建Ubuntu环境及编译(安装包方式)<a name="ZH-CN_TOPIC_0000001119804790"></a> # 搭建Ubuntu环境\(获取源码及编译,安装包方式\)<a name="ZH-CN_TOPIC_0000001119804790"></a>
- [安装依赖工具](#section18431165519244) - [安装依赖工具](#section18431165519244)
- [获取标准系统源码](#section113751052102517) - [获取标准系统源码](#section113751052102517)
......
# 镜像运行<a name="ZH-CN_TOPIC_0000001142160948"></a>
- [镜像运行](#section153991115191314)
- [下一步](#section5600113114323)
## 镜像运行<a name="section153991115191314"></a>
烧录完成后通过以下步骤运行系统:
>![](../public_sys-resources/icon-note.gif) **说明:**
>初次烧写标准系统,需要完成以下配置,后续烧写或者启动,可以跳过以下操作。
1. 在DevEco Device Tool中,点击Monitor,打开串口工具。
![](figure/zh-cn_image_0000001142616226.png)
2. 重启开发板,在倒计时结束前,按任意键进入系统。
![](figure/1-18.gif)
3. 通过以下两条命令设置启动参数。
```
setenv bootargs 'mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M clk_ignore_unused androidboot.selinux=permissive skip_initramfs rootdelay=5 init=/init root=/dev/mmcblk0p5 rootfstype=ext4 rw blkdevparts=mmcblk0:1M(boot),15M(kernel),20M(updater),1M(misc),3307M(system),256M(vendor),-(userdata)'
```
```
setenv bootcmd "mmc read 0x0 0x80000000 0x800 0x4800; bootm 0x80000000";
```
![](figure/启动.png)
4. 保存参数设置。
```
save
```
![](figure/启动1.png)
5. 重启开发板,完成系统启动。
```
reset
```
![](figure/启动2.png)
## 下一步<a name="section5600113114323"></a>
恭喜!您已经完成了OpenHarmony标准系统的快速入门,接下来可[开发一个小示例](../guide/device-clock-guide.md),进一步熟悉OpenHarmony的开发。
# Windows开发环境准备<a name="ZH-CN_TOPIC_0000001124187462"></a> # 搭建Windows开发环境<a name="ZH-CN_TOPIC_0000001124187462"></a>
- [获取软件](#zh-cn_topic_0000001058091994_section1483143015558) - [获取软件](#zh-cn_topic_0000001058091994_section1483143015558)
- [安装Visual Studio Code](#zh-cn_topic_0000001058091994_section71401018163318) - [安装Visual Studio Code](#zh-cn_topic_0000001058091994_section71401018163318)
...@@ -34,7 +34,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展 ...@@ -34,7 +34,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展
</td> </td>
<td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p12332194816317"><a name="zh-cn_topic_0000001058091994_p12332194816317"></a><a name="zh-cn_topic_0000001058091994_p12332194816317"></a>代码编辑工具</p> <td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p12332194816317"><a name="zh-cn_topic_0000001058091994_p12332194816317"></a><a name="zh-cn_topic_0000001058091994_p12332194816317"></a>代码编辑工具</p>
</td> </td>
<td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p711918919618"><a name="zh-cn_topic_0000001058091994_p711918919618"></a><a name="zh-cn_topic_0000001058091994_p711918919618"></a>V1.53及以上 64位版本。</p> <td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p711918919618"><a name="zh-cn_topic_0000001058091994_p711918919618"></a><a name="zh-cn_topic_0000001058091994_p711918919618"></a>V1.53及以上64位版本。</p>
</td> </td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p2721438193710"><a name="zh-cn_topic_0000001058091994_p2721438193710"></a><a name="zh-cn_topic_0000001058091994_p2721438193710"></a><a href="https://code.visualstudio.com/Download" target="_blank" rel="noopener noreferrer">https://code.visualstudio.com/Download</a></p> <td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p2721438193710"><a name="zh-cn_topic_0000001058091994_p2721438193710"></a><a name="zh-cn_topic_0000001058091994_p2721438193710"></a><a href="https://code.visualstudio.com/Download" target="_blank" rel="noopener noreferrer">https://code.visualstudio.com/Download</a></p>
</td> </td>
...@@ -43,7 +43,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展 ...@@ -43,7 +43,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展
</td> </td>
<td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p547205817316"><a name="zh-cn_topic_0000001058091994_p547205817316"></a><a name="zh-cn_topic_0000001058091994_p547205817316"></a>编译构建工具</p> <td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p547205817316"><a name="zh-cn_topic_0000001058091994_p547205817316"></a><a name="zh-cn_topic_0000001058091994_p547205817316"></a>编译构建工具</p>
</td> </td>
<td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p1991315166416"><a name="zh-cn_topic_0000001058091994_p1991315166416"></a><a name="zh-cn_topic_0000001058091994_p1991315166416"></a>V3.7.4~V3.8.x 64位版本</p> <td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p1991315166416"><a name="zh-cn_topic_0000001058091994_p1991315166416"></a><a name="zh-cn_topic_0000001058091994_p1991315166416"></a>V3.8及以上64位版本</p>
</td> </td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p108321457411"><a name="zh-cn_topic_0000001058091994_p108321457411"></a><a name="zh-cn_topic_0000001058091994_p108321457411"></a><a href="https://www.python.org/downloads/" target="_blank" rel="noopener noreferrer">https://www.python.org/downloads/</a></p> <td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p108321457411"><a name="zh-cn_topic_0000001058091994_p108321457411"></a><a name="zh-cn_topic_0000001058091994_p108321457411"></a><a href="https://www.python.org/downloads/" target="_blank" rel="noopener noreferrer">https://www.python.org/downloads/</a></p>
</td> </td>
...@@ -52,7 +52,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展 ...@@ -52,7 +52,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展
</td> </td>
<td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p1773185765616"><a name="zh-cn_topic_0000001058091994_p1773185765616"></a><a name="zh-cn_topic_0000001058091994_p1773185765616"></a>提供npm环境</p> <td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p1773185765616"><a name="zh-cn_topic_0000001058091994_p1773185765616"></a><a name="zh-cn_topic_0000001058091994_p1773185765616"></a>提供npm环境</p>
</td> </td>
<td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p573118572567"><a name="zh-cn_topic_0000001058091994_p573118572567"></a><a name="zh-cn_topic_0000001058091994_p573118572567"></a>v12.0.0及以上 64位版本</p> <td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p573118572567"><a name="zh-cn_topic_0000001058091994_p573118572567"></a><a name="zh-cn_topic_0000001058091994_p573118572567"></a>v12.0.0及以上64位版本</p>
</td> </td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p9200911141112"><a name="zh-cn_topic_0000001058091994_p9200911141112"></a><a name="zh-cn_topic_0000001058091994_p9200911141112"></a><a href="https://nodejs.org/zh-cn/download/" target="_blank" rel="noopener noreferrer">https://nodejs.org/zh-cn/download/</a></p> <td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p9200911141112"><a name="zh-cn_topic_0000001058091994_p9200911141112"></a><a name="zh-cn_topic_0000001058091994_p9200911141112"></a><a href="https://nodejs.org/zh-cn/download/" target="_blank" rel="noopener noreferrer">https://nodejs.org/zh-cn/download/</a></p>
</td> </td>
...@@ -70,7 +70,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展 ...@@ -70,7 +70,7 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展
</td> </td>
<td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p1690316506517"><a name="zh-cn_topic_0000001058091994_p1690316506517"></a><a name="zh-cn_topic_0000001058091994_p1690316506517"></a>OpenHarmony源码的编译、烧录、调试插件工具</p> <td class="cellrowborder" valign="top" width="20.5%" headers="mcps1.1.5.1.2 "><p id="zh-cn_topic_0000001058091994_p1690316506517"><a name="zh-cn_topic_0000001058091994_p1690316506517"></a><a name="zh-cn_topic_0000001058091994_p1690316506517"></a>OpenHarmony源码的编译、烧录、调试插件工具</p>
</td> </td>
<td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p113171956185715"><a name="zh-cn_topic_0000001058091994_p113171956185715"></a><a name="zh-cn_topic_0000001058091994_p113171956185715"></a>v2.2 Beta1</p> <td class="cellrowborder" valign="top" width="20.03%" headers="mcps1.1.5.1.3 "><p id="zh-cn_topic_0000001058091994_p113171956185715"><a name="zh-cn_topic_0000001058091994_p113171956185715"></a><a name="zh-cn_topic_0000001058091994_p113171956185715"></a>v2.2 Beta2</p>
</td> </td>
<td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p3503163074720"><a name="zh-cn_topic_0000001058091994_p3503163074720"></a><a name="zh-cn_topic_0000001058091994_p3503163074720"></a><a href="https://device.harmonyos.com/cn/ide#download" target="_blank" rel="noopener noreferrer">https://device.harmonyos.com/cn/ide#download</a></p> <td class="cellrowborder" valign="top" width="39.98%" headers="mcps1.1.5.1.4 "><p id="zh-cn_topic_0000001058091994_p3503163074720"><a name="zh-cn_topic_0000001058091994_p3503163074720"></a><a name="zh-cn_topic_0000001058091994_p3503163074720"></a><a href="https://device.harmonyos.com/cn/ide#download" target="_blank" rel="noopener noreferrer">https://device.harmonyos.com/cn/ide#download</a></p>
<p id="zh-cn_topic_0000001058091994_p23171856135717"><a name="zh-cn_topic_0000001058091994_p23171856135717"></a><a name="zh-cn_topic_0000001058091994_p23171856135717"></a>下载前,请使用华为开发者帐号登录,如未注册,请先<a href="https://developer.huawei.com/consumer/cn/doc/start/registration-and-verification-0000001053628148" target="_blank" rel="noopener noreferrer">注册华为开发者帐号</a></p> <p id="zh-cn_topic_0000001058091994_p23171856135717"><a name="zh-cn_topic_0000001058091994_p23171856135717"></a><a name="zh-cn_topic_0000001058091994_p23171856135717"></a>下载前,请使用华为开发者帐号登录,如未注册,请先<a href="https://developer.huawei.com/consumer/cn/doc/start/registration-and-verification-0000001053628148" target="_blank" rel="noopener noreferrer">注册华为开发者帐号</a></p>
...@@ -92,12 +92,9 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展 ...@@ -92,12 +92,9 @@ DevEco Device Tool以插件方式提供,基于Visual Studio Code进行扩展
## 安装Python<a name="zh-cn_topic_0000001058091994_section16266553175320"></a> ## 安装Python<a name="zh-cn_topic_0000001058091994_section16266553175320"></a>
>![](../public_sys-resources/icon-note.gif) **说明:**
>请注意,Python版本要求为V3.7.4\~V3.8.x 64位版本。
1. 双击Python安装包进行安装,勾选“**Add Python 3.8 to PATH**”,然后点击**Install Now**开始安装。 1. 双击Python安装包进行安装,勾选“**Add Python 3.8 to PATH**”,然后点击**Install Now**开始安装。
![](figure/zh-cn_image_0000001176317561.png) ![](figure/zh-cn_image_0000001138841358.png)
2. 等待安装完成后,点击**Close** 2. 等待安装完成后,点击**Close**
...@@ -164,12 +161,22 @@ DevEco Device Tool正常运行需要依赖于C/C++和CodeLLDB插件,在安装 ...@@ -164,12 +161,22 @@ DevEco Device Tool正常运行需要依赖于C/C++和CodeLLDB插件,在安装
>安装DevEco Device Tool时,请先关闭Visual Studio Code。 >安装DevEco Device Tool时,请先关闭Visual Studio Code。
1. 解压DevEco Device Tool插件压缩包,双击安装包程序进行安装。 1. 解压DevEco Device Tool插件压缩包,双击安装包程序进行安装。
2. 安装过程中,会自动安装DevEco Device Tool所需的依赖文件(如C/C++和CodeLLDB插件)和执行程序。 2. DevEco Device Tool会检测安装依赖的工具包是否符合要求。如果不符合要求,请按照本章节前面的内容进行安装。
>![](../public_sys-resources/icon-note.gif) **说明:**
>如果已经安装Visual Studio Code,但依然检测不到,可重启电脑解决。
![](figure/zh-cn_image_0000001184531449.png)
3. 点击**Install**进行安装。
![](figure/zh-cn_image_0000001137332702.png)
4. 等待安装完成后,点击Close关闭安装界面。
![](figure/zh-cn_image_0000001072468991.png) ![](figure/zh-cn_image_0000001138853234.png)
3. 安装完成后,会自动关闭命令行工具窗口。 5. 启动Visual Studio Code,会自动安装DevEco Device Tool依赖的C/C++、CodeLLDB插件。等待安装完成后,点击Visual Studio Code左侧的![](figure/zh-cn_image_0000001072757874.png)按钮,检查INSTALLED中,是否已成功安装C/C++、CodeLLDB和DevEco Device Tool。
4. 启动Visual Studio Code,点击左侧的![](figure/zh-cn_image_0000001072757874.png)按钮,检查INSTALLED中,是否已成功安装C/C++、CodeLLDB和DevEco Device Tool。
>![](../public_sys-resources/icon-note.gif) **说明:** >![](../public_sys-resources/icon-note.gif) **说明:**
>如果C/C++和CodeLLDB插件安装不成功,则DevEco Device Tool不能正常运行,解决方法,详细请参考:[离线安装C/C++和CodeLLDB插件](https://device.harmonyos.com/cn/docs/ide/user-guides/offline_plugin_install-0000001074376846)。 >如果C/C++和CodeLLDB插件安装不成功,则DevEco Device Tool不能正常运行,解决方法,详细请参考:[离线安装C/C++和CodeLLDB插件](https://device.harmonyos.com/cn/docs/ide/user-guides/offline_plugin_install-0000001074376846)。
......
# 标准系统入门<a name="ZH-CN_TOPIC_0000001111221726"></a> # 标准系统入门<a name="ZH-CN_TOPIC_0000001111221726"></a>
- **[入门介绍](quickstart-standard-description.md)** - **[入门介绍](quickstart-standard-overview.md)**
- **[Windows开发环境准备](quickstart-standard-windows-environment.md)** - **[搭建Windows开发环境](quickstart-standard-windows-environment.md)**
- **[搭建Ubuntu环境及编译(Docker方式)](quickstart-standard-docker-environment.md)** - **[搭建Ubuntu环境\(获取源码及编译,Docker方式\)](quickstart-standard-docker-environment.md)**
- **[搭建Ubuntu环境及编译(安装包方式)](quickstart-standard-package-environment.md)** - **[搭建Ubuntu环境\(获取源码及编译,安装包方式\)](quickstart-standard-package-environment.md)**
- **[镜像烧录](quickstart-standard-burn.md)** - **[镜像烧录](quickstart-standard-burn.md)**
- **[常见问题](quickstart-standard-faq.md)** - **[镜像运行](quickstart-standard-running.md)**
- **[常见问题](quickstart-standard-faqs.md)**
# 导读<a name="ZH-CN_TOPIC_0000001122921792"></a> # 导读<a name="ZH-CN_TOPIC_0000001142413608"></a>
此工程存放OpenHarmony提供的快速入门、开发指南、API参考等开发者文档,欢迎参与OpenHarmony开发者文档开源项目,与我们一起完善开发者文档。 此工程存放OpenHarmony提供的快速入门、开发指南、API参考等开发者文档,欢迎参与OpenHarmony开发者文档开源项目,与我们一起完善开发者文档。
## 文档目录结构<a name="section5508141817255"></a> ## **文档目录结构**<a name="section1976124516374"></a>
- [Openharmony概述](OpenHarmony-Overview_zh.md) - [Openharmony概述](OpenHarmony-Overview_zh.md)
- 轻量和小型系统开发指导(参考内存<128MB) - 轻量和小型系统开发指导(参考内存<128MB)
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
- overview:[设备开发导读](device-dev/Readme-CN.md) - overview:[设备开发导读](device-dev/Readme-CN.md)
- quick-start:[快速入门](device-dev/quick-start/Readme-CN.md)(搭建环境、获取源码、编译、烧录等) - quick-start:[快速入门](device-dev/quick-start/Readme-CN.md)(搭建环境、获取源码、编译、烧录等)
- Basic Capability:开发基础能力 - Basic Capability:开发基础能力
- Kernel:[轻量和小型系统内核](device-dev/kernel/kernel.md) - Kernel:[轻量系统内核](device-dev/kernel/kernel-mini.md)
- Kernel:[小型系统内核](device-dev/kernel/kernel-small.md)
- Drivers:[驱动](device-dev/driver/Readme-CN.md) - Drivers:[驱动](device-dev/driver/Readme-CN.md)
- Subsystems:[子系统](device-dev/subsystems/Readme-CN.md)(编译构建、图形图像、DFX、XTS等子系统) - Subsystems:[子系统](device-dev/subsystems/Readme-CN.md)(编译构建、图形图像、DFX、XTS等子系统)
- Security:[隐私与安全](device-dev/security/Readme-CN.md) - Security:[隐私与安全](device-dev/security/Readme-CN.md)
...@@ -22,11 +23,11 @@ ...@@ -22,11 +23,11 @@
- porting:移植适配 - porting:移植适配
- [三方库移植指导](device-dev/porting/transplant-thirdparty.md) - [三方库移植指导](device-dev/porting/transplant-thirdparty.md)
- [轻量系统芯片移植指导](device-dev/porting/transplant-minichip.md) - [轻量系统芯片移植指导](device-dev/porting/transplant-smallchip.md)
- [小型系统芯片移植指导](device-dev/porting/transplant-smallchip.md) - [小型系统芯片移植指导](device-dev/porting/transplant-smallchip.md)
- bundles:组件开发 - bundles:组件开发
- [组件开发规范](device-dev/bundles/bundles-standard-rules.md) - [组件开发规范](device-dev/bundles/oem_bundle_standard_des.md)
- [组件开发指南](device-dev/bundles/bundles-guide.md) - [组件开发指南](device-dev/bundles/bundles-guide.md)
- [组件开发示例](device-dev/bundles/bundles-demo.md) - [组件开发示例](device-dev/bundles/bundles-demo.md)
...@@ -39,15 +40,18 @@ ...@@ -39,15 +40,18 @@
- Drivers:[驱动](device-dev/driver/Readme-CN.md) - Drivers:[驱动](device-dev/driver/Readme-CN.md)
- Subsystems:[子系统](device-dev/subsystems/Readme-CN.md)(编译构建、图形图像、DFX、XTS等子系统) - Subsystems:[子系统](device-dev/subsystems/Readme-CN.md)(编译构建、图形图像、DFX、XTS等子系统)
- Security:[隐私与安全](device-dev/security/Readme-CN.md) - Security:[隐私与安全](device-dev/security/Readme-CN.md)
- guide:开发示例 - guide:开发示例
- [时钟应用](device-dev/guide/device-clock-guide.md) - [时钟应用](device-dev/guide/device-clock-guide.md)
- [平台驱动](device-dev/guide/device-driver-demo.md) - [平台驱动](device-dev/guide/device-driver-demo.md)
- [外设驱动](device-dev/guide/device-outerdriver-demo.md) - [外设驱动](device-dev/guide/device-outerdriver-demo.md)
- porting:移植适配 - porting:移植适配
- [三方库移植指导](device-dev/porting/transplant-thirdparty.md) - [三方库移植指导](device-dev/porting/transplant-thirdparty.md)
- [标准系统芯片移植指导](device-dev/porting/standard-system-porting-guide.md) - [标准系统芯片移植指导](device-dev/porting/standard-system-porting-guide.md)
- bundles:组件开发 - bundles:组件开发
- [组件开发规范](device-dev/bundles/bundles-standard-rules.md) - [组件开发规范](device-dev/bundles/oem_bundle_standard_des.md)
- [组件开发指南](device-dev/bundles/bundles-guide.md) - [组件开发指南](device-dev/bundles/bundles-guide.md)
- [组件开发示例](device-dev/bundles/bundles-demo.md) - [组件开发示例](device-dev/bundles/bundles-demo.md)
...@@ -59,18 +63,19 @@ ...@@ -59,18 +63,19 @@
- media:[媒体](application-dev/media/Readme-CN.md) - media:[媒体](application-dev/media/Readme-CN.md)
- connectivity:[网络与连接](application-dev/connectivity/Readme-CN.md) - connectivity:[网络与连接](application-dev/connectivity/Readme-CN.md)
- js-reference:[JS参考规范](application-dev/js-reference/Readme-CN.md) - js-reference:[JS参考规范](application-dev/js-reference/Readme-CN.md)
- 许可证及版权信息检查工具:[开源合规审查工具](https://gitee.com/openharmony-sig/tools_oat) - 许可证及版权信息检查工具:[开源合规审查工具](https://gitee.com/openharmony-sig/tools_oat)
- glossary:[术语](device-dev/glossary/glossary.md) - glossary:[术语](device-dev/glossary/glossary.md)
## 版本更新<a name="section8910101119262"></a> ## **版本更新**<a name="section945819377382"></a>
参考[Release Notes](release-notes/OpenHarmony-Release-Notes.md) 参考[Release Notes](release-notes/OpenHarmony-Release-Notes.md)
## 第三方开源软件及许可说明<a name="section0300839202619"></a> ## **第三方开源软件及许可说明**<a name="section840310516385"></a>
3rd-Party-License:[第三方开源软件及许可证说明](contribute/第三方开源软件及许可证说明.md) 3rd-Party-License:[第三方开源软件及许可证说明](contribute/第三方开源软件及许可证说明.md)
## 贡献<a name="section7772211142710"></a> ## **贡献**<a name="section152287615392"></a>
非常欢迎您参与[贡献](contribute/参与贡献.md),我们鼓励开发者以各种方式参与文档反馈和贡献。 非常欢迎您参与[贡献](contribute/参与贡献.md),我们鼓励开发者以各种方式参与文档反馈和贡献。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册