diff --git a/docs/zh/embedded/_toc.yaml b/docs/zh/embedded/_toc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f0e10eb7fdabc7ae11916e32780ae4d66252e014 --- /dev/null +++ b/docs/zh/embedded/_toc.yaml @@ -0,0 +1,4 @@ +label: 嵌入式 +sections: + - href: ./openEuler_embedded/_toc.yaml + - href: ./uniproton/_toc.yaml diff --git a/docs/zh/embedded/openEuler_embedded/_toc.yaml b/docs/zh/embedded/openEuler_embedded/_toc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2a7ffe74afa66dece19ac0951859b3477b93c4b5 --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/_toc.yaml @@ -0,0 +1,16 @@ +label: openEuler Embedded 用户指南 +isManual: true +description: openEuler Embedded是基于openEuler社区面向嵌入式场景的Linux版本,旨在成为一个高质量的以Linux为中心的嵌入式系统软件平台 +sections: + - label: openEuler Embedded 用户指南 + href: ./openEuler-embedded.md + - label: 基于openEuler Embedded的SDK应用开发 + href: ./application_development_using_sdk.md + - label: 安装与运行 + href: ./installation_and_running.md + - label: openEuler Embedded 22.03发行说明 + href: ./openEuler_embedded_22.03_release_notes.md + - label: openEuler Embedded构建指导 + href: ./openEuler_embedded_build_guide.md + - label: 快速构建指导 + href: ./quick_build_guide.md diff --git a/docs/zh/embedded/openEuler_embedded/application_development_using_sdk.md b/docs/zh/embedded/openEuler_embedded/application_development_using_sdk.md new file mode 100644 index 0000000000000000000000000000000000000000..81a3ab785dfcfcba745d872632f0e6e43e62a033 --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/application_development_using_sdk.md @@ -0,0 +1,189 @@ +# 基于openEuler Embedded的SDK应用开发 + +当前发布的镜像除了体验openEuler Embedded的基本功能外,还可以进行基本的应用开发,也即在openEuler Embedded上运行用户自己的程序。本章主要介绍如何基于openEuler Embedded的SDK进行应用开发。 + +## 安装SDK + +1. **安装依赖软件包** + + 使用SDK开发内核模块需要安装一些必要的软件包,运行如下命令: + + ```sh + 在 openEuler 上安装: + yum install make gcc g++ flex bison gmp-devel libmpc-devel openssl-devel + + 在 Ubuntu 上安装: + apt-get install make gcc g++ flex bison libgmp3-dev libmpc-dev libssl-dev + ``` + +2. **执行SDK自解压安装脚本** + + 运行如下命令: + + ```sh + sh openeuler-glibc-x86_64-openeuler-image-aarch64-qemu-aarch64-toolchain-22.03.sh + ``` + + 根据提示输入工具链的安装路径,默认路径是`/opt/openeuler//`。若不设置,则按默认路径安装,也可以配置相对路径或绝对路径。 + + 举例如下: + + ```sh + sh ./openeuler-glibc-x86_64-openeuler-image-armv7a-qemu-arm-toolchain-22.03.sh + + openEuler embedded(openEuler Embedded Reference Distro) SDK installer version 22.03 + ================================================================ + + Enter target directory for SDK (default: /opt/openeuler/22.03): sdk + You are about to install the SDK to "/usr1/openeuler/sdk". Proceed [Y/n]? y + Extracting SDK...............................................done + Setting it up...SDK has been successfully set up and is ready to be used. + Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g. + $ . /usr1/openeuler/sdk/environment-setup-armv7a-openeuler-linux-gnueabi + ``` + +3. **设置SDK环境变量** + + 运行source命令。第2步执行结束后已打印source命令,直接运行即可。 + + ```sh + . /usr1/openeuler/myfiles/sdk/environment-setup-armv7a-openeuler-linux-gnueabi + ``` + +4. **查看是否安装成功** + + 运行如下命令,查看是否安装成功、环境设置成功。 + + ```sh + arm-openeuler-linux-gnueabi-gcc -v + ``` + +## 使用SDK编译hello world样例 + +1. **准备代码** + + 以构建一个hello world程序为例,运行在openEuler Embedded根文件系统镜像中。 + + 创建一个`hello.c`文件,源码如下: + + ```c + #include + + int main(void) + { + printf("hello world\n"); + } + ``` + + 编写`CMakeLists.txt`,和`hello.c`文件放在同一个目录。 + + ```sh + project(hello C) + + add_executable(hello hello.c) + ``` + +2. **编译生成二进制** + + 进入`hello.c`文件所在目录,使用工具链编译,命令如下: + + ```sh + cmake .. + make + ``` + + 把编译好的hello程序拷贝到openEuler Embedded系统的`/tmp/`某个目录下(例如`/tmp/myfiles/`)。如何拷贝可以参考前文所述[使能共享文件系统场景](./installation_and_running.md#使能共享文件系统场景)。 + +3. **运行用户态程序** + + 在openEuler Embedded系统中运行hello程序。 + + ```sh + cd /tmp/myfiles/ + ./hello + ``` + + 如运行成功,则会输出\"hello world\"。 + +## 使用SDK编译内核模块样例 + +1. **准备环境** + + 在设置好SDK环境的基础之上,编译内核模块还需准备相应环境,但只需要准备一次即可。运行如下命令会创建相应的内核模块编译环境: + + ```sh + cd /sysroots/-openeuler-linux/usr/src/kernel + make modules_prepare + ``` + +2. **准备代码** + + 以编译一个内核模块为例,运行在openEuler Embedded内核中。 + + 创建一个`hello.c`文件,源码如下: + + ```c + #include + #include + + static int hello_init(void) + { + printk("Hello, openEuler Embedded!\r\n"); + return 0; + } + + static void hello_exit(void) + { + printk("Byebye!"); + } + + module_init(hello_init); + module_exit(hello_exit); + + MODULE_LICENSE("GPL"); + ``` + + 编写`Makefile`,和`hello.c`文件放在同一个目录: + + ```c + KERNELDIR := ${KERNEL_SRC_DIR} + CURRENT_PATH := $(shell pwd) + + target := hello + obj-m := $(target).o + + build := kernel_modules + + kernel_modules: + $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules + clean: + $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean + ``` + + ![](./public_sys-resources/icon-note.gif) **说明:** + + - `KERNEL_SRC_DIR` 为SDK中内核源码树的目录,该变量在安装SDK后会被自动设置。 + + - `$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules`和`$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean`代码前均为Tab键,非空格键。 + +3. **编译生成内核模块** + + 进入hello.c文件所在目录,使用工具链编译,命令如下: + + ```sh + make + ``` + + 将编译好的hello.ko拷贝到openEuler Embedded系统的目录下。 + + 如何拷贝可以参考前文所述[使能共享文件系统场景](./installation_and_running.md#使能共享文件系统场景)。 + +4. **插入内核模块** + + 在openEuler Embedded系统中插入内核模块: + + ```sh + insmod hello.ko + ``` + + 如运行成功,则会在内核日志中出现"Hello, openEuler Embedded!"。 diff --git a/docs/zh/embedded/openEuler_embedded/container_build_guide.markdown b/docs/zh/embedded/openEuler_embedded/container_build_guide.markdown new file mode 100644 index 0000000000000000000000000000000000000000..52d120a4846cd8ea0588d48fbd79424644f7bc6e --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/container_build_guide.markdown @@ -0,0 +1,141 @@ +# 容器构建指导 + +============================== + +由于openEuler Embedded构建过程需要基于openEuler操作系统,且需要安装较多系统工具和构建工具。为方便开发人员快速搭建构建环境,我们将构建过程所依赖的操作系统和工具封装到一个容器中,这就使得开发人员可以快速搭建一个构建环境,进而投入到代码开发中去,避免在准备环境阶段消耗大量时间。 + +## 环境准备 + +需要使用docker创建容器环境,为了确保docker成功安装,需满足以下软件硬件要求: + +- 操作系统: 推荐使用openEuler 22.03/22.03、Ubuntu 20.04/22.04、Debian 11、Suse 12.05 +- 内核: 推荐3.8及以上的内核 +- 驱动: 内核必须支持一种合适的存储驱动,例如: Device Mapper、AUFS、vfs、btrfs、ZFS +- 架构: 运行64位架构的计算机(目前只支持x86\_64和amd64) + +### 安装docker + +------------- + +1. 检查当前环境是否已安装docker工具 + + 运行如下命令,可以看到当前docker版本信息,则说明当前环境已安装docker,无需再次安装。 + + ``` sh + docker version + ``` + +2. 如果没有安装,可参考官方链接安装 + +官网地址: ,openEuler环境可参考Centos安装Docker。 + +例如openEuler环境docker安装命令如下: + +``` sh +sudo yum install docker +``` + +### 获取容器镜像 + +------------- + +通过`docker pull`命令拉取华为云中的镜像到宿主机。命令如下: + +``` sh +docker pull swr.cn-north-4.myhuaweicloud.com/openeuler-embedded/openeuler-container:22.03-lts +``` + +### 准备容器构建环境 + +------------- + +#### 1.启动容器 + +可通过`docker run`命令启动容器,为了保证容器启动后可以在后台运行,且可以正常访问网络,建议使用如下命令启动: + +``` bash +docker run -idt --network host swr.cn-north-4.myhuaweicloud.com/openeuler-embedded/openeuler-container:22.03-lts bash +``` + +参数说明: + +- -i 让容器的标准输入保持打开 +- -d 让 Docker 容器在后台以守护态(Daemonized)形式运行 +- -t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上 +- --network 将容器连接到(host)网络 +- swr.cn-north-4.myhuaweicloud.com/openeuler-embedded/openeuler-container 指定镜像名称 +- bash 进入容器的方式 + +#### 2.查看已启动的容器id + +``` sh +docker ps +``` + +#### 3.进入容器 + +``` bash +docker exec -it 容器id bash +``` + +构建环境已准备完成,下面就可以在容器中进行构建了。 + +## 版本构建 + +### 下载源码 + +1. 获取源码下载脚本 + + ```sh + git clone https://gitee.com/openeuler/yocto-meta-openeuler.git -b openEuler-22.03-LTS -v /usr1/openeuler/src/yocto-meta-openeuler + ``` + +2. 通过脚本下载源码 + +```sh +cd /usr1/openeuler/src/yocto-meta-openeuler/scripts +sh download_code.sh /usr1/openeuler/src +``` + +### 编译构建 + +- 编译架构: aarch64-std、aarch64-pro、arm-std、raspberrypi4-64 +- 构建目录: /usr1/build +- 源码目录: /usr1/openeuler/src +- 编译器所在路径: /usr1/openeuler/gcc/openeuler\_gcc\_arm64le + +>![](./public_sys-resources/icon-note.gif) **说明:** +> +>- 不同的编译架构使用不同的编译器,aarch64-std、aarch64-pro、raspberrypi4-64使用openeuler\_gcc\_arm64le编译器,arm-std使用openeuler\_gcc\_arm32le编译器。 +>- 下面以以aarch64-std目标架构编译为例。 + +1. 将/usr1目录所属群组改为openeuler,否则切换至openeuler用户构建会存在权限问题。 + + ``` sh + chown -R openeuler:users /usr1 + ``` + +2. 切换至openeuler用户。 + + ```sh + su openeuler + ``` + +3. 进入构建脚本所在路径,运行编译脚本。 + +```sh +cd /usr1/openeuler/src/yocto-meta-openeuler/scripts +source compile.sh aarch64-std /usr1/build /usr1/openeuler/gcc/openeuler_gcc_arm64le +bitbake openeuler-image +``` + +### 构建结果说明 + +结果件默认生成在构建目录下的output目录下,例如上面aarch64-std的构建结果件生成在/usr1/build/output目录下,如下表: + +| filename | description | +| ---------------------------------------------------------- | ----------------------------------- | +| Image-\* | openEuler Embedded image | +| openeuler-glibc-x86\_64-openeuler-image-\*-toolchain-\*.sh | openEuler Embedded sdk toolchain | +| openeuler-image-qemu-aarch64-\*.rootfs.cpio.gz | openEuler Embedded file system | +| zImage | openEuler Embedded compressed image | diff --git a/docs/zh/embedded/openEuler_embedded/installation_and_running.md b/docs/zh/embedded/openEuler_embedded/installation_and_running.md new file mode 100644 index 0000000000000000000000000000000000000000..4eb92b39c37ecca9cb62821e9a676a5288adb67c --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/installation_and_running.md @@ -0,0 +1,176 @@ +# 安装与运行 + +本章主要介绍如何获取预先构建好的镜像,如何运行镜像。 + +## 获取镜像 + +当前发布的已构建好的镜像,只支持arm和aarch64两种架构,且只支持qemu中ARM virt-4.0平台,您可以通过如下链接获得相应的镜像: + +- [qemu_arm](https://repo.openeuler.org/openEuler-22.03-LTS/embedded_img/arm32/arm-std/):32位arm架构,ARM Cortex A15处理器 +- [qemu_aarch64](https://repo.openeuler.org/openEuler-22.03-LTS/embedded_img/arm64/aarch64-std/):64位aarch64架构,ARM Cortex A57处理器 + +只要相应环境支持qemu仿真器(版本5.0以上),您可以将提供的openEuler Embedded镜像部署在物理裸机、云环境、容器或虚拟机上。 + +## 镜像内容 + +所下载的镜像,由以下几部分组成: + +- 内核镜像**zImage**: 基于openEuler社区Linux 5.10代码构建得到。相应的内核配置可通过如下链接获取: + - [arm(cortex a15)](https://gitee.com/openeuler/yocto-embedded-tools/blob/openEuler-22.03-LTS/config/arm/defconfig-kernel) + - [arm(cortex a57)](https://gitee.com/openeuler/yocto-embedded-tools/blob/openEuler-22.03-LTS/config/arm64/defconfig-kernel),针对aarch64架构,额外增加了镜像自解压功能,可以参见相应的[patch](https://gitee.com/openeuler/yocto-embedded-tools/blob/openEuler-22.03-LTS/patches/arm64/0001-arm64-add-zImage-support-for-arm64.patch) + +- 根文件系统镜像 + + - **openeuler-image-qemu-xxx.cpio.gz**:标准根文件系统镜像,进行了必要安全加固,增加了audit、cracklib、OpenSSH、Linux PAM、shadow、iSula容器所支持的软件包。 + +- SDK(Software Development Kit)工具 + + - **openeuler-glibc-x86_64-xxxxx.sh**:openEuler Embedded SDK自解压安装包,SDK包含了进行开发(用户态程序、内核模块等)所必需的工具、库和头文件等。 + +## 运行镜像 + +通过运行镜像,一方面您可以体验openEuler Embedded的功能,一方面也可以完成基本的嵌入式Linux开发。 + +![](./public_sys-resources/icon-note.gif) **说明:** + +- 建议使用QEMU 5.0以上版本运行镜像,由于一些额外功能(网络、共享文件系统)需要依赖QEMU的virtio-net, virtio-fs等特性,如未在QEMU中使能,则运行时可能会产生错误,此时可能需要从源码重新编译QEMU。 +- 运行镜像时,建议把内核镜像和根文件系统镜像放在同一目录下。 + +QEMU的下载与安装可以参考[QEMU官方网站](https://www.qemu.org/download/#linux) , 或者下载[源码](https://www.qemu.org/download/#source)单独编译安装。安装好后可以运行如下命令确认: + +```sh +qemu-system-aarch64 --version +``` + +### 极简运行场景 + +该场景下,QEMU未使能网络和共享文件系统,适合快速的功能体验。 + +1. **启动QEMU** + + 针对arm(ARM Cortex A15),运行如下命令: + + ```sh + qemu-system-arm -M virt-4.0 -m 1G -cpu cortex-a15 -nographic -kernel zImage -initrd + ``` + + 针对aarch64(ARM Cortex A57),运行如下命令: + + ```sh + qemu-system-aarch64 -M virt-4.0 -m 1G -cpu cortex-a57 -nographic -kernel zImage -initrd + ``` + + >![](./public_sys-resources/icon-note.gif) **说明:** + > + >由于标准根文件系统镜像进行了安全加固,因此第一次启动时,需要为登录用户名root设置密码,且密码强度有相应要求: + > + >- 至少8个字符。 + >- 必须包含数字,字母和特殊字符。 + > + > @#$%^&*+|\\=~`!?,.:;-_'"(){}[]/>< + > + >例如openEuler@2021。 + +2. **检查运行是否成功** + + QEMU运行成功并登录后,将会呈现openEuler Embedded的Shell。 + +### 使能共享文件系统场景 + +通过共享文件系统,可以使得运行QEMU仿真器的宿主机和openEuler Embedded共享文件,这样在宿主机上交叉编译的程序,拷贝到共享目录中,即可在openEuler Embedded上运行。 + +假设将宿主机的`/tmp`目录作为共享目录,并事先在其中创建了名为`hello_openeuler.txt`的文件,使能共享文件系统功能的操作指导如下: + +1. **启动QEMU** + + 针对arm(ARM Cortex A15),运行如下命令: + + ```sh + qemu-system-arm -M virt-4.0 -m 1G -cpu cortex-a15 -nographic -kernel zImage -initrd -device virtio-9p-device,fsdev=fs1,mount_tag=host -fsdev local,security_model=passthrough,id=fs1,path=/tmp + ``` + + 针对aarch64(ARM Cortex A57),运行如下命令: + + ```sh + qemu-system-aarch64 -M virt-4.0 -m 1G -cpu cortex-a57 -nographic -kernel zImage -initrd -device virtio-9p-device,fsdev=fs1,mount_tag=host -fsdev local,security_model=passthrough,id=fs1,path=/tmp + ``` + +2. **映射文件系统** + + 在openEuler Embedded启动并登录之后,需要运行如下命令,映射共享文件系统 + + ```sh + cd /tmp + mkdir host + mount -t 9p -o trans=virtio,version=9p2000.L host /tmp/host + ``` + + 即把9p文件系统挂载到到openEuler Embedded的`/tmp/host`目录下,实现共享映射。 + +3. **检查共享是否成功** + + 在openEuler Embedded中,运行如下命令: + + ```sh + cd /tmp/host + ls + ``` + + 如能发现`hello_openeuler.txt`,则共享成功。 + +### 使能网络场景 + +通过QEMU的virtio-net和宿主机上的虚拟网卡,可以实现宿主机和openEuler Embedded之间的网络通信。除了通过virtio-fs实现文件共享外,还可以通过网络的方式,例如**scp**命令,实现宿主机和 openEuler Embedded传输文件。 + +1. **启动QEMU** + + 针对arm(ARM Cortex A15),运行如下命令: + + ```sh + qemu-system-arm -M virt-4.0 -m 1G -cpu cortex-a15 -nographic -kernel zImage -initrd -device virtio-net-device,netdev=tap0 -netdev tap,id=tap0,script=/etc/qemu-ifup + ``` + + 针对aarch64(ARM Cortex A57),运行如下命令: + + ```sh + qemu-system-aarch64 -M virt-4.0 -m 1G -cpu cortex-a57 -nographic -kernel zImage -initrd -device virtio-net-device,netdev=tap0 -netdev tap,id=tap0,script=/etc/qemu-ifup + ``` + +2. **宿主上建立虚拟网卡** + + 在宿主机上需要建立名为tap0的虚拟网卡,可以借助脚本实现,创建`qemu-ifup`脚本,放在`/etc/`下,具体内容如下: + + ```sh + #!/bin/bash + ifconfig $1 192.168.10.1 up + ``` + + 其执行需要root权限: + + ```sh + chmod a+x qemu-ifup + ``` + + 通过`qemu-ifup`脚本,宿主机上将创建名为tap0的虚拟网卡,地址为192.168.10.1。 + +3. **配置openEuler Embedded网卡** + + openEuler Embedded登录后,执行如下命令: + + ```sh + ifconfig eth0 192.168.10.2 + ``` + +4. **确认网络连通** + + 在openEuler Embedded中,执行如下命令: + + ```sh + ping 192.168.10.1 + ``` + + 如能ping通,则宿主机和openEuler Embedded之间的网络是连通的。 + + >![](./public_sys-resources/icon-note.gif) **说明:** + > + >如需openEuler Embedded借助宿主机访问互联网,则需要在宿主机上建立网桥,此处不详述,如有需要,请自行查阅相关资料。 diff --git a/docs/zh/embedded/openEuler_embedded/openEuler-embedded.md b/docs/zh/embedded/openEuler_embedded/openEuler-embedded.md new file mode 100644 index 0000000000000000000000000000000000000000..732600e24a452fe3bdec89e172e14f2587af4fb3 --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/openEuler-embedded.md @@ -0,0 +1,5 @@ +# openEuler Embedded 用户指南 + +openEuler Embedded是基于openEuler社区面向嵌入式场景的Linux版本,旨在成为一个高质量的以Linux为中心的嵌入式系统软件平台。openEuler Embedded在内核版本、软件包版本等代码层面会与openEuler其他场景的Linux保持一致,共同演进,不同之处在于针对嵌入场景的内核配置、软件包的组合与配置、代码特性补丁的不同。 + +本文档主要用于介绍如何获取预先构建好的镜像,如何运行镜像,如何基于镜像完成基本的嵌入式Linux应用开发以及如何构建openEuler Embedded。使用人员需要具备基本的Linux操作系统知识。 diff --git a/docs/zh/embedded/openEuler_embedded/openEuler_embedded_22.03_release_notes.md b/docs/zh/embedded/openEuler_embedded/openEuler_embedded_22.03_release_notes.md new file mode 100644 index 0000000000000000000000000000000000000000..4cbd32235a334135899e857707273fd0f8ba5a32 --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/openEuler_embedded_22.03_release_notes.md @@ -0,0 +1,32 @@ +# openEuler Embedded 22.03发行说明 + +openEuler Embedded 22.03是openEuler Embedded第一次正式发布,包含的内容大概如下: + +## 内核 + +- 内核升级到 5.10.0-60.17.0 + +- 内核支持Preempt-RT补丁 + +- 内核支持树莓派4B相关补丁 + +## 软件包 + +- 支持80+软件包,详见[当前所支持的软件包](https://openeuler.gitee.io/yocto-meta-openeuler/features/software_package_description.html) + +## 亮点特性 + +- 多OS混合部署框架的初步实现,支持openEuler Embedded和Zephyr的混合部署,详见[多OS混合部署框架](https://openeuler.gitee.io/yocto-meta-openeuler/features/mcs.html) +- 分布式软总线的初步集成,详见[分布式软总线](https://openeuler.gitee.io/yocto-meta-openeuler/features/distributed_soft_bus.html) + +- 安全加固指导,详见[安全加固说明](https://openeuler.gitee.io/yocto-meta-openeuler/security_hardening/index.html) +- 基于Preempt-RT的软实时,详见[软实时系统介绍](https://openeuler.gitee.io/yocto-meta-openeuler/features/preempt_rt.html) + +## 南向生态 + +- 新增树莓派4B支持,详见[树莓派4B的支持](https://openeuler.gitee.io/yocto-meta-openeuler/features/raspberrypi.html) + +## 构建系统 + +- 初步的openEuler Embedded构建体系, 详见[快速构建指导](./quick_build_guide.md) +- 容器化构建,详见[容器构建指导](./container_build_guide.markdown) diff --git a/docs/zh/embedded/openEuler_embedded/openEuler_embedded_build_guide.md b/docs/zh/embedded/openEuler_embedded/openEuler_embedded_build_guide.md new file mode 100644 index 0000000000000000000000000000000000000000..68d6e1d8431247b1d033d71af2ec38421065823a --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/openEuler_embedded_build_guide.md @@ -0,0 +1,8 @@ +# openEuler Embedded构建指导 + +===================== + +本文档主要提供了两种方式准备构建环境,并描述了详细的构建流程。用户根据需要选择一种方式即可。 + +- 初步的openEuler Embedded构建体系, 详见[快速构建指导](./quick_build_guide.md) +- 容器化构建,详见[容器构建指导](./container_build_guide.markdown) diff --git a/docs/zh/embedded/openEuler_embedded/public_sys-resources/hosttools.png b/docs/zh/embedded/openEuler_embedded/public_sys-resources/hosttools.png new file mode 100644 index 0000000000000000000000000000000000000000..83bb076a7763d522dde36168b1f713e524141531 Binary files /dev/null and b/docs/zh/embedded/openEuler_embedded/public_sys-resources/hosttools.png differ diff --git a/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-caution.gif b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-caution.gif differ diff --git a/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-danger.gif b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-danger.gif differ diff --git a/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-note.gif b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-note.gif differ diff --git a/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-notice.gif b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-notice.gif differ diff --git a/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-tip.gif b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-tip.gif differ diff --git a/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-warning.gif b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/docs/zh/embedded/openEuler_embedded/public_sys-resources/icon-warning.gif differ diff --git a/docs/zh/embedded/openEuler_embedded/quick_build_guide.md b/docs/zh/embedded/openEuler_embedded/quick_build_guide.md new file mode 100644 index 0000000000000000000000000000000000000000..c2f52cde9281959f30bc2c6ca8b1ece76780ed91 --- /dev/null +++ b/docs/zh/embedded/openEuler_embedded/quick_build_guide.md @@ -0,0 +1,135 @@ +# 快速构建指导 + +===================== + +本章主要介绍如何构建openEuler Embedded。 + +## 环境准备 + +-------------- + +### Yocto中主机端命令使用 + +Yocto或者说Bitbake本质上是一组python程序,其最小运行环境要求如下: + +- Python3 \> 3.6.0 +- Git \> 1.8.3.1 +- Tar \> 1.28 + +在构建过程中所需要的其他工具,Yocto都可以根据相应的软件包配方自行构建出来,从而达到自包含的效果。在这个过程中,Yocto还会依据自身需要,对相应的工具打上yocto专属补丁(如dnf,rpm等)。这些主机工具会在第一次的构建中从源码开始构建,因此Yocto第一次构建比较费时。 + +为了加速构建特别是第一次构建,openEuler Embedded采取了"能用原生工具就用原生工具,能不构建就不构建"的策略,尽可能使用主机上预编译的原生的工具。这就需要依赖主机上软件包管理工具(apt, dnf, yum, zypper等)事先安装好。 + +Yocto是通过HOSTTOOLS变量来实现主机工具的引入,为每个在HOSTTOOLS中列出的工具建立相应的软链接。为了避免来自主机对构建环境的污染,Yocto会重新准备不同于主机的环境,例如PATH变量等,因此如果新增依赖主机上的某个命令,需显示在Yocto的HOSTTOOLS变量中增加,否则即使主机上存在,Yocto构建时也会报错找不到相应的工具。相应流程如下图所示: + +![](./public_sys-resources/hosttools.png) + +当前openEuler Embedded所需要主机工具已经默认在local.conf.sample中的HOSTTOOLS定义,主要工具描述如下: + +| 工具名 | 用途 | +| ------ | ------------- | +| cmake | cmake构建工具 | +| ninjia | ninja构建系统 | + +### openEuler Embedded所需构建工具 + +- 构建OS + + [操作系统:openEuler-22.03-LTS-SP4](https://repo.openeuler.org/openEuler-22.03-LTS-SP4/docker_img/x86_64/openEuler-docker.x86_64.tar.xz) + +- 安装系统额外工具 + +```sh +yum -y install tar cmake gperf sqlite-devel chrpath gcc-c++ patch rpm-build flex autoconf automake m4 bison bc libtool gettext-devel createrepo\_c rpcgen texinfo hostname python meson dosfstools mtools parted ninja-build autoconf-archive libmpc-devel gmp-devel +``` + +- 预编译的交叉工具链和库 + + Yocto可以构建出交叉编译所需的交叉工具链和C库,但整个流程复杂且耗时,不亚于内核乃至镜像的构建,而且除了第一次构建,后面很少会再涉及。同时,绝大部分开发者都不会直接与工具链和C库构建打交道。所以为了简化该流程,openEuler Embedded采取的策略是采用预编译的交叉工具链和库,会专门维护和发布相应的带有C库的工具链。 + + 目前我们提供了对arm32位和aarch64位两种架构的工具链支持,通过如下方式可以获得: + + - 下载rpm包: `wget https://repo.openeuler.org/openEuler-22.03-LTS/EPOL/main/x86_64/Packages/gcc-cross-1.0-0.oe2203.x86_64.rpm` + - 解压rpm包: `rpm2cpio gcc-cross-1.0-0.oe2203.x86_64.rpm | cpio -id` + - 解压后可以看到当前路径下会有tmp目录,编译链存放于该目录下 + - ARM 32位工具链: openeuler_gcc_arm32le.tar.xz + - ARM 64位工具链: openeuler_gcc_arm64le.tar.xz + +### 已安装好工具的构建容器 + +openEuler Embedded的构建过程中会使用到大量的各式各样的主机工具。如前文所述,为了加速构建,openEuler Embedded依赖主机事先安装好相应的工具,但这也会带来不同主机环境会有不同的工具版本的问题,例如构建需要cmake高于1.9版本,但主机上最高只有cmake 1.8。为了解决这一问题,openEuler Embedded提供了专门的构建容器,提供统一的构建环境。 + +使用者可以通过如下链接获得容器镜像直接用于编译: + +​ [openEuler Embedded构建容器的基础镜像](https://repo.openeuler.org/openEuler-21.03/docker_img/x86_64/openEuler-docker.x86_64.tar.xz) + +具体构建指导请参考[容器构建指导](./container_build_guide.markdown)。 + +## 版本构建 + +### 构建代码下载 + +openEuler Embedded整个构建工程的文件布局如下,假设openeuler\_embedded为顶层目录: + +>\<顶层目录openeuler_embedded> +>├── src 源代码目录,包含所有软件包代码、内核代码和Yocto构建代码 +>├── build openEuler Embedded的构建目录,生成的各种镜像放在此目录下 + +1. 获取源码下载脚本 + + 将脚本下载到指定目录,例如下载到src/yocto-meta-openeuler目录下: + + ```sh + git clone https://gitee.com/openeuler/yocto-meta-openeuler.git -b openEuler-22.03-LTS -v src/yocto-meta-openeuler + ``` + + 脚本为src/yocto-meta-openeuler/scripts/download\_code.sh,此脚本有3个参数: + + - 参数1:下载的源码路径,默认相对脚本位置下载,例如前面样例,代码仓会下到src/下 + - 参数2:下载的分支,默认值见脚本,不同分支按版本确定 + - 参数3:下代码的xml文件,标准manifest格式,按xml配置下代码 + +2. 通过脚本下载源码 + + - 下载最新代码: + + ```sh + sh src/yocto-meta-openeuler/scripts/download_code.sh + ``` + + - 下载指定版本代码: + + ```sh + sh src/yocto-meta-openeuler/scripts/download_code.sh "" "" "manifest.xml" + ``` + + 指定openEuler Embedded版本的代码的manifest.xml文件从openEuler Embedded发布件目录embedded\_img/source-list/下获取。 + +### 编译构建 + +一键式构建脚本:src/yocto-meta-openeuler/scripts/compile.sh, 具体细节可以参考该脚本。 + +编译脚本的主要流程说明: + +1. 设置PATH增加额外工具路径 +2. TEMPLATECONF指定local.conf.sample等配置文件路径 +3. 调用poky仓的oe-init-build-env进行初始化配置 +4. 在编译目录的conf/local.conf中配置MACHINE,按需增加额外新增的层 +5. 在编译目录执行bitbake openeuler-image编译openEuler Embedded的image和sdk +6. 执行完发布件在编译目录的output目录下 + +运行编译脚本,以编译标准arm架构为例,编译方法如下: + +source src/yocto-meta-openeuler/scripts/compile.sh arm-std +bitbake openeuler-image #执行第一条source后,会提示出bitbake命令 + +### 构建结果说明 + +结果件默认生成在构建目录下的output目录下,例如上面arm的构建结果件生成在/usr1/build/output目录下,如下表: + +| filename | description | +| ---------------------------------------------------------- | ----------------------------------- | +| Image-\* | openEuler Embedded image | +| openeuler-glibc-x86\_64-openeuler-image-\*-toolchain-\*.sh | openEuler Embedded sdk toolchain | +| openeuler-image-qemu-aarch64-\*.rootfs.cpio.gz | openEuler Embedded file system | +| zImage | openEuler Embedded compressed image | diff --git a/docs/zh/embedded/uniproton/_toc.yaml b/docs/zh/embedded/uniproton/_toc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..44a46ce762dd3e07f16a1acce52f627ede2f7092 --- /dev/null +++ b/docs/zh/embedded/uniproton/_toc.yaml @@ -0,0 +1,10 @@ +label: UniProton用户指南 +isManual: true +description: UniProton是面向嵌入式场景的操作系统,支持任务和内存管理、中断处理,提供强大调试能力 +sections: + - label: 概述 + href: ./overview.md + - label: UniProton功能设计 + href: ./uniproton_functions.md + - label: UniProton接口说明 + href: ./uniproton_apis.md diff --git a/docs/zh/embedded/uniproton/figures/FCS.png b/docs/zh/embedded/uniproton/figures/FCS.png new file mode 100644 index 0000000000000000000000000000000000000000..afb47c557755c10a3f0b196b7080b16a0f86ab6a Binary files /dev/null and b/docs/zh/embedded/uniproton/figures/FCS.png differ diff --git a/docs/zh/embedded/uniproton/figures/MemoryApplication.png b/docs/zh/embedded/uniproton/figures/MemoryApplication.png new file mode 100644 index 0000000000000000000000000000000000000000..de46581c40122a82b92db8a67ae3fcd76a97041a Binary files /dev/null and b/docs/zh/embedded/uniproton/figures/MemoryApplication.png differ diff --git a/docs/zh/embedded/uniproton/figures/MemoryRelease.png b/docs/zh/embedded/uniproton/figures/MemoryRelease.png new file mode 100644 index 0000000000000000000000000000000000000000..f91c89bb02311f104949e2af42cddc4a3faaaca3 Binary files /dev/null and b/docs/zh/embedded/uniproton/figures/MemoryRelease.png differ diff --git a/docs/zh/embedded/uniproton/figures/pend_semaphore.png b/docs/zh/embedded/uniproton/figures/pend_semaphore.png new file mode 100644 index 0000000000000000000000000000000000000000..59d8159d1ff1cecb43f59cc5d7c5a9900db8e767 Binary files /dev/null and b/docs/zh/embedded/uniproton/figures/pend_semaphore.png differ diff --git a/docs/zh/embedded/uniproton/figures/post_semaphore.png b/docs/zh/embedded/uniproton/figures/post_semaphore.png new file mode 100644 index 0000000000000000000000000000000000000000..fa08d76dafd335b60838dda08db61ccadd8c6b8d Binary files /dev/null and b/docs/zh/embedded/uniproton/figures/post_semaphore.png differ diff --git a/docs/zh/embedded/uniproton/overview.md b/docs/zh/embedded/uniproton/overview.md new file mode 100644 index 0000000000000000000000000000000000000000..79ecdf23c70904b152181c164a0e4f4543c5d881 --- /dev/null +++ b/docs/zh/embedded/uniproton/overview.md @@ -0,0 +1,11 @@ +# UniProton用户指南 + +## 介绍 + +UniProton是基于openEuler社区面向嵌入式场景的操作系统,旨在成为一个高质量的为上层业务软件屏蔽底层硬件差异,并提供强大的调试功能的操作系统平台。使业务软件可以在不同的硬件平台之间快速移植,方便产品芯片选型,降低硬件采购成本和软件维护成本。 + +本文档主要用于介绍UniProton的基本功能和接口说明,便于开发人员了解基本的UniProton操作系统知识。 + +## 编译教程 + +相关编译教程,可参考:[https://gitee.com/openeuler/UniProton/blob/master/doc/UniProton_build.md](https://gitee.com/openeuler/UniProton/blob/master/doc/UniProton_build.md/)。 diff --git a/docs/zh/embedded/uniproton/uniproton_apis.md b/docs/zh/embedded/uniproton/uniproton_apis.md new file mode 100644 index 0000000000000000000000000000000000000000..4de2c836197577fa852adf9caad78389332f8ec9 --- /dev/null +++ b/docs/zh/embedded/uniproton/uniproton_apis.md @@ -0,0 +1,4214 @@ +# UniProton接口说明 + +## 任务 + +### 创建并激活任务 + +在OS启动之前(比如在uniAppInit)中创建的任务,只是简单地加入就绪队列。 OS启动后创建的任务,如果优先级高于当前任务且未锁任务,则立即发生任务调度并被运行,否则加入就绪队列,等待执行。 + +**输入**: 任务创建参数,包括任务名、任务栈大小、任务优先级、任务处理函数等。 + +**处理**: + +1. 申请任务栈空间,初始化任务栈,置栈顶魔术字。 +2. 初始化任务上下文。 +3. 初始化任务控制块。 +4. 激活任务,任务是否马上能得到执行,取决于OS是否已经启动、优先级是否高于当前任务且没有锁任务调度、当前线程是否为硬中断。 + +**输出** : + +- 成功:任务ID,若任务具备执行条件,则直接运行任务,否则将任务挂入就绪队列。 + +- 失败:提示错误码。 + +### 删除任务 + + 删除任务并释放任务资源。 + +**输入**:任务ID。 + +**处理**: + +1. 检查任务是否具备删除条件,如锁任务调度情况下不允许删除任务。 +2. 如果任务处于阻塞状态,从对应的阻塞队列中摘除。 +3. 释放任务控制块。 +4. 释放任务栈空间。 +5. 从就绪队列中载入最高优先级的任务,若具备调度条件,则执行。 + +**输出**: + +- 成功:若具备调度条件,则执行就绪队列中的最高任务; + +- 失败:返回错误码。 + +### 挂起任务 + + 挂起任务。 + +**输入**:任务ID。 + +**处理**:将指定任务从就绪队列中摘除,若指定任务处于Running态,则会触发任务切换。 + +**输出**: + +- 成功:挂起指定任务。 + +- 失败:返回错误码。 + +### 恢复任务 + +恢复挂起的任务。 + +**输入**:任务ID。 + +**处理**:恢复挂起的任务,若任务仍处于延时、阻塞态,则只是取消挂起态,并不加入就绪队列。 + +**输出**: + +- 成功:取消任务挂起状态。 +- 失败:返回错误码。 + +### 任务延时 + +将当前任务延时指定时间。 + +**输入**:延时时间。 + +**处理**: + +1. 延时时间转换成OS的Tick数。 +2. 将当前任务从就绪队列中摘除,置成延时态。 +3. 从就绪队列中载入最高优先级的任务,并执行。 +4. Tick中断处理函数中判断任务的延时时间是否已经足够,如果足够,将任务加入就绪队列。 + +**输出**: + +- 成功:当前任务切出,就绪队列中的最高优先级任务切入。 +- 失败:返回错误码。 + +### 锁任务调度 + +禁止任务之间的切换。 + +**输入**:锁任务调度请求。 + +**处理**: + +1. 若有任务切换请求,将其清除。 +2. 锁任务调度次数依次递增。 + +**输出**: 任务之间无法切换。 + +### 恢复任务调度的锁/解锁状态 + +与锁任务调度配对使用,是否解锁任务调度,取决于最近一次锁任务调度前,是否允许任务调度。 + +**输入**:恢复任务调度的锁/解锁状态请求。 + +**处理**: + +1. 锁任务调度次数依次递减。 +2. 若锁任务调度次数等于0,则发起任务调度。 + +**输出**:若最近一次锁任务调度前,允许任务调度,则从就绪队列中载入最高优先级任务,并执行。否则,维持原状,不能发生任务切换。 + +### 任务PID合法性检查 + +检查指定任务PID是否合法。 + +**输入**:任务PID。 + +**处理**:判断输入的任务PID是否超过最大任务PID号或是否已创建。 + +**输出**: + +- TRUE :任务PID有效。 +- FALSE:任务PID无效。 + +### 任务私有数据获取 + +获取当前任务的私有数据。 + +**输入**:无。 + +**处理**:将任务TCB中记录的任务私有数据返回。 + +**输出**:任务私有数据。 + +### 查询本核指定任务正在PEND的信号量 + +查询指定任务正在PEND的信号量ID。 + +**输入**:任务PID。 + +**处理**: 根据任务状态和任务控制块,判断任务是否PEND在某个信号量上,以及PEND的信号量ID。 + +**输出**: + +- 成功:返回信号量ID。 +- 失败:返回错误码。 + +### 查询任务状态 + +获取指定任务的状态。 + +**输入**:任务PID。 + +**处理**:将指定任务的TCB中记录的任务状态字段返回。 + +**输出**: + +- 成功:返回任务状态信息。 +- 失败:返回错误码。 + +### 查询任务上下文信息 + +获取指定任务的上下文信息。 + +**输入**:任务PID。 + +**处理**: 将指定任务的TCB中记录的任务上下文信息返回。 + +**输出**: + +- 成功:返回任务上下文信息。 +- 失败:返回错误码。 + +### 查询任务基本信息 + +获取任务基本信息,包括任务切换时的PC,SP、任务状态、优先级、任务栈大小、栈顶值,任务名等。 + +**输入**:任务PID,用于存放任务基本信息查询结果的缓冲区 + +**处理**: 将指定任务的TCB中记录的任务基本信息返回。 + +**输出**: + +- 成功:返回任务基本信息。 +- 失败:返回错误码。 + +### 任务优先级获取 + +获取指定任务的优先级。 + +**输入**:任务PID + +**处理**:将指定任务的TCB中记录的优先级字段返回。 + +**输出**: + +- 成功:返回任务优先级信息。 +- 失败:返回错误码。 + +### 任务优先级设定 + +设置指定任务的优先级。 + +**输入**:任务PID、优先级值 + +**处理**:将输入的任务优先级信息存入指定任务TCB中优先级字段 + +**输出**: + +- 成功:指定任务的优先级被修改。 +- 失败:返回错误码。 + +### 调整指定优先级的任务调度顺序 + +设置指定任务的优先级以及调整调度顺序。 + +**输入**:指定的优先级、指定需要调整调度顺序的任务,用于保存被调整到队首的任务ID的缓冲。 + +**处理**:若指定要调整调度顺序的任务为TASK_NULL_ID,则优先级队列中的第一个就绪任务调整至队尾;否则,将指定要调整调度顺序的任务调整至优先级队列的队首。 + +**输出**: + +- 成功:指定优先级的任务调度顺序被修改。 +- 失败:返回错误码。 + +## 事件 + +### 写事件 + +写事件操作实现对指定任务写入指定类型的事件,可以一次同时写多个事件。 + +**输入**:任务ID、事件号。 + +**处理**: + +1. 对指定任务事件类型写上输入事件。 +2. 判断目的任务是否正在接收等待事件,且其等待的事件是否已经符合唤醒条件(唤醒条件即读取的事件已经发生)。 +3. 如果符合唤醒条件,则需清除任务读事件状态。 +4. 如果符合唤醒条件,则需清除任务读事件状态。 +5. 清除任务超时状态。 +6. 在任务没有被挂起的情况下,需要将任务加入就绪队列并尝试任务调度。 + +**输出**: + +- 成功:事件写入成功。 +- 失败:错误码。 + +### 读事件 + +读事件操作可以根据入参事件掩码类型读取单个或者多个事件。 + +**输入**:要读取的事件掩码、读取事件所采取的策略、超时时间、接收事件的指针。 + +**处理**: + +1. 根据入参事件掩码类型对自身任务输入读取事件类型。 +2. 判断事件读取模式,是读取输入的所有事件还是其中的任意一种事件。 +3. 根据读取模式,判断期望的事件是否满足读取情况。 +4. 判断事件等待模式:如果为等待事件模式则根据模式来设置相应的超时时间;如果为非等待模式则事件读取失败。 +5. 如果需要等待阻塞读取,则需要将自己的任务从就绪列表中删除,并进行任务调度。 +6. 读取成功后,清除读取的事件类型,并且把事件类型返回。 + +**输出**: + +- 成功:读事件成功,事件指针赋值。 +- 失败:错误码 + +## 队列 + +### 创建队列 + +创建一个队列,创建时可以设定队列长度和队列结点大小。 + +**输入**: 队列节点个数、每个队列节点大小、队列ID指针。 + +**处理**: + +1. 申请一个空闲的队列资源。 +2. 申请队列所需内存。 +3. 初始化队列配置。 + +**输出**: + +- 成功:队列ID。 +- 失败:错误码。 + +### 读队列 + +读指定队列的数据。 + +**输入**:队列ID、缓冲区指针、长度指针、超时时间。 + +**处理**: + +1. 获取指定队列控制块。 +2. 读队列PEND标志,根据缓冲区大小填入队列数据。 +3. 修改队列头指针。 + +**输出**: + +- 成功:缓冲区内填入队列数据。 +- 失败:错误码。 + +### 写队列 + +写数据到指定队列。 + +**输入**: 队列ID、缓冲区指针、缓冲区长度、超时时间、优先级。 + +**处理**: + +1. 获取指定队列控制块。 +2. 读队列PEND标志,选取消息节点,初始化消息节点并拷贝数据。 +3. 队列读资源计数器加一。 + +**输出**: + +- 成功:写入队列数据成功。 +- 失败:错误码。 + +### 删除队列 + +删除一个消息队列,删除后队列资源被回收。 + +**输入**:队列ID。 + +**处理**: + +1. 获取指定队列控制块,确保队列未在使用中。 +2. 释放队列内存。 + +**输出**: + +- 成功:删除队列成功。 +- 失败:错误码 + +### 查询队列的历史最大使用长度 + +获取从队列创建到删除前的历史最大使用长度。 + +**输入**:队列ID、队列节点使用峰值指针。 + +**处理**: + +1. 获取指定队列控制块。 +2. 将队列节点使用峰值赋值到指针参数。 + +**输出**: + +- 成功:获取峰值成功。 +- 失败:错误码 + +### 查询指定源PID的待处理消息个数 + +从指定队列中,获取指定源PID的待处理消息个数。 + +**输入**:队列ID、线程PID、待处理的消息个数指针。 + +**处理**: + +1. 获取指定队列控制块。 +2. 遍历队列查询待处理的消息个数,赋值到指针变量。 + +**输出**: + +- 成功:获取待处理的消息个数成功。 +- 失败:错误码。 + +## 中断 + +### 创建硬中断 + +硬中断在使用前,必须先创建。 + +**输入**:硬中断的创建参数,如:硬中断号(与芯片相关)、硬中断优先级、硬中断处理函数等。 + +**处理**:根据硬中断号设置硬中断优先级、处理函数。 + +**输出**: + +- 成功:硬中断触发后,CPU能够响应该硬中断,并回调硬中断处理函数。 +- 失败:返回错误码。 + +### 硬中断属性设置 + +在创建硬中断前,需要设置硬中断的模式,包括独立型(#OS_HWI_MODE_ENGROSS)和组合型(#OS_HWI_MODE_COMBINE)两种配置模式。 + +**输入**:硬中断号、硬中断模式。 + +**处理**:根据硬中断号设置硬中断的模式; + +**输出**: + +- 成功:指定的硬中断号被设置好硬中断模式。 +- 失败:返回错误码。 + +### 删除硬中断 + +删除相应硬中断或事件,取消硬中断处理函数的注册。 + +**输入**:硬中断号。 + +**处理**:取消指定硬中断的处理函数与中断号的绑定关系。 + +**输出**:硬中断被删除,当硬中断信号触发后,CPU不会响应该中断。 + +### 使能硬中断 + +使能指定的硬中断。 + +**输入**:硬中断号。 + +**处理**:将指定硬中断的使能位置位。 + +**输出**:指定的硬中断被使能,当硬中断信号触发后,CPU会响应该中断。 + +### 屏蔽硬中断 + +屏蔽指定的硬中断。 + +**输入**:硬中断号。 + +**处理**:清除指定硬中断的使能位。 + +**输出**:指定的硬中断被屏蔽,当硬中断信号触发后,CPU不会响应该中断。 + +### 恢复指定硬中断 + +恢复指定的硬中断。 + +**输入**:硬中断号、中断使能寄存器的保存值。 + +**处理**:还原指定硬中断的使能位。 + +**输出**:指定中断的使能位恢复为指定状态。 + +### 禁止硬中断 + +禁止响应所有可屏蔽硬中断。 + +**输入**:禁止硬中断请求。 + +**处理**: + +1. 记录系统状态,用于后续返回。 +2. 禁止响应所有可屏蔽硬中断。 + +**输出**: + +- 所有可屏蔽硬中断都不能响应。 +- 禁止硬中断响应前的系统状态。 + +### 恢复硬中断 + +恢复硬中断的禁止或允许响应状态,与禁止硬中断配对使用。是否允许响应硬中断,取决于最近一次禁止硬中断前,系统是否允许响应硬中断。 + +**输入**:最近一次禁止硬中断前的系统状态。 + +**处理**:将系统状态恢复到最近一次禁止硬中断前。 + +**输出**:系统状态恢复到最近一次禁止硬中断前。 + +### 响应硬中断 + +硬中断触发后,CPU会响应硬中断。 + +**输入**:硬件触发的硬中断信号,且系统没有禁止硬中断。 + +**处理**: + +1. 保存当前上下文。 +2. 调用硬中断处理函数。 +3. 若任务被打断,则恢复最高优先级任务的上下文,该任务不一定是被中断打断的任务。 +4. 若低优先级中断被打断,则直接恢复低先级中断的上下文。 + +**输出**:硬中断被响应。 + +### 触发硬中断 + +触发指定核号的指定硬中断。 + +**输入**:核号、硬中断号。 + +**处理**: + +1. 目前只支持触发本核的硬中断,若指定的核号不为本核,则做报错处理。 +2. 目前只支持触发软件可触发的硬中断,若指定的中断无法进行软件触发,则做报错处理。 +3. 当以前两个条件都满足,则设置对应的中断触发寄存器,软件触发中断。 + +**输出**: + +- 成功:响应的硬中断被触发。 +- 失败:返回错误码。 + +### 清除中断位 + +清除所有的中断请求位或指定的中断请求位。 + +**输入**:硬中断号。 + +**处理**:清除所有的中断请求位或指定的中断请求位。 + +**输出**:所有的中断请求位或指定的中断请求位被清除 + +## 定时器 + +### 定时器创建 + +根据定时器类型,触发模式,定时时长,处理函数等创建一个定时器。 + +**输入**: + +1. 创建参数结构体(包括定时器类型,触发模式,定时时长,处理函数等)。 +2. 用于保存输出的定时器句柄的指针。 + +**处理**:根据入参找到空闲控制块,将入参内容填入控制块中相应的字段中。 + +**输出**: + +- 成功:定时器创建成功,后续可根据得到的定时器句柄做启动、删除等操作。 +- 失败:返回错误码。 + +### 定时器删除 + +删除指定的定时器。 + +**输入**: 定时器句柄 + +**处理**:根据传入的定时器句柄,找到定时器控制块,将其内容清空并将控制块挂接到相应的空闲链表中。 + +**输出**: + +- 成功:定时器被删除。 +- 失败:返回错误码。 + +### 定时器启动 + +指定的定时器开始计时。 + +**输入**: 定时器句柄 + +**处理**:对于软件定时器,根据当前Tick计数以及定时器周期,计算结束时间,将此定时器控制块挂入定时器SortLink。 + +**输出**: + +- 成功:定时器开始计时。 +- 失败:返回错误码。 + +### 定时器停止 + +指定的定时器停止计时。 + +**输入**:定时器句柄。 + +**处理**:对于软件定时器,计算剩余时间并将其保存后,将此定时器控制块从定时器SortLink中摘除。 + +**输出**: + +- 成功:指定任务的信号量计数值被修改。 +- 失败:返回错误码。 + +### 定时器重启 + +指定的定时器重新开始计时。 + +**输入**:定时器句柄 + +**处理**:对于软件定时器,根据当前Tick计数以及定时器周期,计算结束时间,将此定时器控制块挂入定时器SortLink。 + +**输出**: + +- 成功:指定任务的信号量计数值被修改。 +- 失败:返回错误码。 + +### 软件定时器组创建 + +创建一个软件定时器组,后续的软件定时器创建时需要以此为基础。 + +**输入**: + +1. 软件定时器组创建参数(主要关注时钟源类型及最大支持的定时器个数)。 +2. 用于保存输出的定时器组号的地址。 + +**处理**:根据传入的最大支持的定时器个数申请定时器控制块内存,并完成其初始化操作。 + +**输出**: + +- 成功:基于Tick的软件定时器组被成功创建。 +- 失败:返回错误码。 + +## 信号量 + +### 信号量创建 + +创建一个信号量,并设置其初始计数器数值。 + +**输入**:信号量初始计数值、用于保存创建得到句柄的地址。 + +**处理**:找到一个空闲信号量控制块,将输入的初始计数值填入后将信号量ID当做句柄返回。 + +**输出**: + +- 成功:信号量被创建。 +- 失败:返回错误码。 + +### 信号量删除 + +删除指定信号量,若有任务阻塞于该信号量,则删除失败。 + +**输入**:信号量句柄 + +**处理**:对于核内信号量,根据输入的信号量句柄找到信号量控制块,通过查看控制块中任务阻塞链表是否为空来判断是否有任务阻塞于该信号量,若有则删除失败返回,否则释放该信号量控制块。 + +**输出**: + +- 成功:信号量被删除。 +- 失败:返回错误码。 + +### Pend信号量 + +申请指定的信号量,若其计数值大于0,则直接将计数值减1返回,否则发生任务阻塞,等待时间可通过入参设定。 + +**输入**:信号量句柄、等待时间 + +**处理**: + +![](./figures/pend_semaphore.png) + +**输出**: + +- 成功:返回0。 +- 失败:返回错误码。 + +### Post信号量 + +发布信号量,将该信号量计数值+1,若有任务阻塞于该信号量,则将其唤醒。 + +**输入**:信号量句柄。 + +**处理**: + +![](./figures/post_semaphore.png) + +**输出**: + +- 成功:信号量发布成功。 +- 失败:返回错误码。 + +### 信号量计数值重置 + +设置指定信号量计数值,如果有任务阻塞于该信号量,则设置失败。 + +**输入**:信号量句柄、信号量计数值。 + +**处理**:根据输入的信号量句柄,找到相应的信号量控制块,查看控制块中任务阻塞链表,若其不为空,则返回错误,否则将控制块中信号量计数值设为输入的计数值。 + +**输出**: + +- 成功:指定信号量的计数值被修改; +- 失败:返回错误码。 + +### 信号量计数值获取 + + 获取指定信号量计数值。 + +**输入**: 信号量句柄 + +**处理**:根据输入的信号量句柄,找到相应的信号量控制块,将控制块中记录的信号量计数值返回。 + +**输出**: + +- 成功:返回信号量计数值。 +- 失败:返回错误计数值标记。 + +### 信号量阻塞任务PID获取 + +获取阻塞在指定信号量上的任务个数及任务PID列表。 + +**输入**: + +1. 信号量句柄。 +2. 用于存放输出的阻塞任务个数的地址。 +3. 用于存放输出的阻塞任务PID的缓冲区首地址。 +4. 用于存放输出的阻塞任务PID的缓冲区长度。 + +**处理**:若有任务阻塞于指定信号量,则输出阻塞任务的个数及任务PID清单;否则,将阻塞任务个数置为0。 + +**输出**: + +- 成功:输出阻塞于该信号量的任务个数及任务PID清单。 +- 失败:返回错误码。 + +## 异常 + +### 用户注册异常处理钩子 + +用户注册异常处理函数类型定义的异常处理函数钩子,记录异常信息。 + +**输入**:类型为ExcProcFunc的钩子函数。 + +**处理**:将用户注册的钩子函数注册到OS框架里,发生异常时调用。 + +**输出**: + +- 成功:注册成功。 +- 失败:返回错误码。 + +## CPU占用率 + +### 获取当前cpu占用率 + +通过本接口获取当前cpu占用率。 + +**输入**:无。 + +**处理**:采用基于IDLE计数的统计算法,统计结果会有一定误差,误差不超过百分之五。 + +**输出**: + +- 成功:返回当前的cpu占用率[0,10000]。 +- 失败:返回错误码。 + +### 获取指定个数的线程的CPU占用率 + +根据用户输入的线程个数,获取指定个数的线程CPU占用率。 + +**输入**: 线程个数、缓冲区指针、实际线程个数指针。 + +**处理**: + +1. 采用基于 IDLE 计数的统计算法,统计结果会有一定误差,误差不超过百分之五。 +2. 当配置项中的采样周期值等于0时,线程级CPUP采样周期为两次调用该接口或者PRT_CpupNow之间的间隔。否则,线程级CPUP采样周期为配置项中的OS_CPUP_SAMPLE_INTERVAL大小。 +3. 输出的实际线程个数不大于系统中实际的线程个数(任务个数和一个中断线程)。 +4. 若在一个采样周期内有任务被删除,则统计的任务线程和中断线程CPUP总和小于10000。 + +**输出**: + +- 成功:在缓冲区写入cpu占用率。 +- 失败:返回错误码。 + +### 设置CPU占用率告警阈值 + +根据用户配置的 CPU 占用率告警阈值 warn 和告警恢复阈值 resume,设置告警和恢复阈值。 + +**输入**:告警阈值、恢复阈值。 + +**处理**:设置 CPUP 告警阈值和恢复阈值 + +**输出**: + +- 成功:设置成功。 +- 失败:返回错误码。 + +### 查询CPUP告警阈值和告警恢复阈值 + +根据用户配置的告警阈值指针 warn 和告警恢复阈值指针 resume,查询告警阈值和告警恢复阈值。 + +**输入**:告警阈值指针、恢复阈值指针。 + +**处理**:获取 CPUP 告警阈值和恢复阈值,赋值指针变量。 + +**输出**: + +- 成功:获取成功。 +- 失败:返回错误码。 + +### 注册CPUP告警回调函数 + +根据用户配置的回调函数 hook,注册 CPUP 告警回调函数。 + +**输入**:类型为 CpupHookFunc 的 CPU 告警回调函数。 + +**处理**:将用户的钩子函数注册到 OS 框架。 + +**输出**: + +- 成功:注册成功。 +- 失败:错误码 + +## OS启动 + +### main函数入口 + +二进制执行文件函数入口。 + +**输入**:无 + +**输出**: + +- 成功:返回OK。 +- 失败:错误码 + +### 用户业务入口 + +PRT_AppInit 用户业务函数入口,在 main 函数后调用,在此函数中添加业务功能代码。 + +**输入**:无 + +**输出**: + +- 成功:返回OK。 +- 失败:错误码 + +### 硬件驱动初始化入口 + +PRT_HardDrvInit 硬件驱动初始化函数入口,在 main 函数后调用,在此函数中添加板级驱动初始化功能代码。 + +**输入**:无 + +**输出**: + +- 成功:返回OK。 +- 失败:错误码 + +### 硬件启动流程入口 + +PRT_HardBootInit 在 OS 启动时调用,在main函数前被调用,可以用于 BSS 初始化、随机值设置等。 + +**输入**:无 + +**输出**: + +- 成功:返回OK。 +- 失败:错误码。 + +## openamp + +### 初始化openamp资源函数 + +初始化保留内存,初始化 remoteproc、virtio、rpmsg,建立 Uniproton 与 Linux 两端配对的 endpoint,供消息收发使用。 + +**输入**:无。 + +**输出**: + +- 成功:初始化成功。 +- 失败:错误码。 + +### 消息接收函数 + +接收消息,并触发SGI中断 + +**输入**: + +1. 类型为 unsigned char * 的存储消息的缓冲区。 +2. 类型为 int 的消息预期长度。 +3. 类型为 int *,用于获取消息实际长度。 + +**输出**: + +- 成功:消息接收成功。 +- 失败:错误码。 + +### 消息发送函数 + +发送消息和SGI中断 + +**输入**:类型为 unsigned char * 的存储消息的缓冲区、类型为 int 的消息长度。 + +**输出**: + +- 成功:消息发送成功。 +- 失败:错误码。 + +### 释放openamp资源 + +用于释放openamp资源。 + +**输入**:无 + +**输出**: + +- 成功:资源释放成功。 +- 失败:错误码。 + +## POSIX接口 + +| 接口名 | 适配情况 | +| :---: | :-----: | +| [pthread_atfork](#pthread_atfork) | 不支持 | +| [pthread_attr_destroy](#pthread_attr_destroy) | 支持 | +| [pthread_attr_getdetachstate](#pthread_attr_getdetachstate) | 支持 | +| [pthread_attr_getguardsize](#pthread_attr_getguardsize) | 不支持 | +| [pthread_attr_getinheritsched](#pthread_attr_getinheritsched) | 支持 | +| [pthread_attr_getschedparam](#pthread_attr_getschedparam) | 支持 | +| [pthread_attr_getschedpolicy](#pthread_attr_getschedpolicy) | 支持 | +| [pthread_attr_getscope](#pthread_attr_getscope) | 支持 | +| [pthread_attr_getstack](#pthread_attr_getstack) | 支持 | +| [pthread_attr_getstackaddr](#pthread_attr_getstackaddr) | 支持 | +| [pthread_attr_getstacksize](#pthread_attr_getstacksize) | 支持 | +| [pthread_attr_init](#pthread_attr_init) | 支持 | +| [pthread_attr_setdetachstate](#pthread_attr_setdetachstate) | 支持 | +| [pthread_attr_setguardsize](#pthread_attr_setguardsize) | 不支持 | +| [pthread_attr_setinheritsched](#pthread_attr_setinheritsched) | 支持 | +| [pthread_attr_setschedparam](#pthread_attr_setschedparam) | 部分支持 | +| [pthread_attr_setschedpolicy](#pthread_attr_setschedpolicy) | 部分支持 | +| [pthread_attr_setscope](#pthread_attr_setscope) | 部分支持 | +| [pthread_attr_setstack](#pthread_attr_setstack) | 支持 | +| [pthread_attr_setstackaddr](#pthread_attr_setstackaddr) | 支持 | +| [pthread_attr_setstacksize](#pthread_attr_setstacksize) | 支持 | +| [pthread_barrier_destroy](#pthread_barrier_destroy) | 支持 | +| [pthread_barrier_init](#pthread_barrier_init) | 部分支持 | +| [pthread_barrier_wait](#pthread_barrier_wait) | 支持 | +| [pthread_barrierattr_getpshared](#pthread_barrierattr_getpshared) | 支持 | +| [pthread_barrierattr_setpshared](#pthread_barrierattr_setpshared) | 部分支持 | +| [pthread_cancel](#pthread_cancel) | 支持 | +| [pthread_cond_broadcast](#pthread_cond_broadcast) | 支持 | +| [pthread_cond_destroy](#pthread_cond_destroy) | 支持 | +| [pthread_cond_init](#pthread_cond_init) | 支持 | +| [pthread_cond_signal](#pthread_cond_signal) | 支持 | +| [pthread_cond_timedwait](#pthread_cond_timedwait) | 支持 | +| [pthread_cond_wait](#pthread_cond_wait) | 支持 | +| [pthread_condattr_destroy](#pthread_condattr_destroy) | 支持 | +| [pthread_condattr_getclock](#pthread_condattr_getclock) | 支持 | +| [pthread_condattr_getpshared](#pthread_condattr_getpshared) | 支持 | +| [pthread_condattr_init](#pthread_condattr_init) | 支持 | +| [pthread_condattr_setclock](#pthread_condattr_setclock) | 部分支持 | +| [pthread_condattr_setpshared](#pthread_condattr_setpshared) | 部分支持 | +| [pthread_create](#pthread_create) | 支持 | +| [pthread_detach](#pthread_detach) | 支持 | +| [pthread_equal](#pthread_equal) | 支持 | +| [pthread_exit](#pthread_exit) | 支持 | +| [pthread_getcpuclockid](#pthread_getcpuclockid) | 不支持 | +| [pthread_getschedparam](#pthread_getschedparam) | 支持 | +| [pthread_getspecific](#pthread_getspecific) | 支持 | +| [pthread_join](#pthread_join) | 支持 | +| [pthread_key_create](#pthread_key_create) | 支持 | +| [pthread_key_delete](#pthread_key_delete) | 支持 | +| [pthread_kill](#pthread_kill) | 不支持 | +| [pthread_mutex_consistent](#pthread_mutex_consistent) | 不支持 | +| [pthread_mutex_destroy](#pthread_mutex_destroy) | 支持 | +| [pthread_mutex_getprioceiling](#pthread_mutex_getprioceiling) | 不支持 | +| [pthread_mutex_init](#pthread_mutex_init) | 支持 | +| [pthread_mutex_lock](#pthread_mutex_lock) | 支持 | +| [pthread_mutex_setprioceiling](#pthread_mutex_setprioceiling) | 不支持 | +| [pthread_mutex_timedlock](#pthread_mutex_timedlock) | 支持 | +| [pthread_mutex_trylock](#pthread_mutex_trylock) | 支持 | +| [pthread_mutex_unlock](#pthread_mutex_unlock) | 支持 | +| [pthread_mutexattr_destroy](#pthread_mutexattr_destroy) | 支持 | +| [pthread_mutexattr_getprioceiling](#pthread_mutexattr_getprioceiling) | 不支持 | +| [pthread_mutexattr_getprotocol](#pthread_mutexattr_getprotocol) | 支持 | +| [pthread_mutexattr_getpshared](#pthread_mutexattr_getpshared) | 部分支持 | +| [pthread_mutexattr_getrobust](#pthread_mutexattr_getrobust) | 部分支持 | +| [pthread_mutexattr_gettype](#pthread_mutexattr_gettype) | 支持 | +| [pthread_mutexattr_init](#pthread_mutexattr_init) | 支持 | +| [pthread_mutexattr_setprioceiling](#pthread_mutexattr_setprioceiling) | 不支持 | +| [pthread_mutexattr_setprotocol](#pthread_mutexattr_setprotocol) | 部分支持 | +| [pthread_mutexattr_setpshared](#pthread_mutexattr_setpshared) | 不支持 | +| [pthread_mutexattr_setrobust](#pthread_mutexattr_setrobust) | 部分支持 | +| [pthread_mutexattr_settype](#pthread_mutexattr_settype) | 支持 | +| [pthread_once](#pthread_once) | 部分支持 | +| [pthread_rwlock_destroy](#pthread_rwlock_destroy) | 支持 | +| [pthread_rwlock_init](#pthread_rwlock_init) | 支持 | +| [pthread_rwlock_rdlock](#pthread_rwlock_rdlock) | 支持 | +| [pthread_rwlock_timedrdlock](#pthread_rwlock_timedrdlock) | 支持 | +| [pthread_rwlock_timedwrlock](#pthread_rwlock_timedwrlock) | 支持 | +| [pthread_rwlock_tryrdlock](#pthread_rwlock_tryrdlock) | 支持 | +| [pthread_rwlock_trywrlock](#pthread_rwlock_trywrlock) | 支持 | +| [pthread_rwlock_unlock](#pthread_rwlock_unlock) | 支持 | +| [pthread_rwlock_wrlock](#pthread_rwlock_wrlock) | 支持 | +| [pthread_rwlockattr_destroy](#pthread_rwlockattr_destroy) | 不支持 | +| [pthread_rwlockattr_getpshared](#pthread_rwlockattr_getpshared) | 部分支持 | +| [pthread_rwlockattr_init](#pthread_rwlockattr_init) | 不支持 | +| [pthread_rwlockattr_setpshared](#pthread_rwlockattr_setpshared) | 部分支持 | +| [pthread_self](#pthread_self) | 支持 | +| [pthread_setcancelstate](#pthread_setcancelstate) | 支持 | +| [pthread_setcanceltype](#pthread_setcanceltype) | 支持 | +| [pthread_setschedparam](#pthread_setschedparam) | 部分支持 | +| [pthread_setschedprio](#pthread_setschedprio) | 支持 | +| [pthread_setspecific](#pthread_setspecific) | 支持 | +| [pthread_sigmask](#pthread_sigmask) | 不支持 | +| [pthread_spin_init](#pthread_spin_init) | 不支持 | +| [pthread_spin_destory](#pthread_spin_destory) | 不支持 | +| [pthread_spin_lock](#pthread_spin_lock) | 不支持 | +| [pthread_spin_trylock](#pthread_spin_trylock) | 不支持 | +| [pthread_spin_unlock](#pthread_spin_unlock) | 不支持 | +| [pthread_testcancel](#pthread_testcancel) | 支持 | +| [sem_close](#sem_close) | 支持 | +| [sem_destroy](#sem_destroy) | 支持 | +| [sem_getvalue](#sem_getvalue) | 支持 | +| [sem_init](#sem_init) | 支持 | +| [sem_open](#sem_open) | 支持 | +| [sem_post](#sem_post) | 支持 | +| [sem_timedwait](#sem_timedwait) | 支持 | +| [sem_trywait](#sem_trywait) | 支持 | +| [sem_unlink](#sem_unlink) | 部分支持 | +| [sem_wait](#sem_wait) | 支持 | +| [sched_yield](#sched_yield) | 支持 | +| [sched_get_priority_max](#sched_get_priority_max) | 支持 | +| [sched_get_priority_min](#sched_get_priority_min) | 支持 | +| [asctime](#asctime) | 支持 | +| [asctime_r](#asctime_r) | 支持 | +| [clock](#clock) | 支持 | +| [clock_getcpuclockid](#clock_getcpuclockid) | 部分支持 | +| [clock_getres](#clock_getres) | 部分支持 | +| [clock_gettime](#clock_gettime) | 支持 | +| [clock_nanosleep](#clock_nanosleep) | 部分支持 | +| [clock_settime](#clock_settime) | 支持 | +| [ctime](#ctime) | 支持 | +| [ctime_r](#ctime_r) | 支持 | +| [difftime](#difftime) | 支持 | +| [getdate](#getdate) | 不支持 | +| [gettimeofday](#gettimeofday) | 支持 | +| [gmtime](#gmtime) | 支持 | +| [gmtime_r](#gmtime_r) | 支持 | +| [localtime](#localtime) | 支持 | +| [localtime_r](#localtime_r) | 支持 | +| [mktime](#mktime) | 支持 | +| [nanosleep](#nanosleep) | 支持 | +| [strftime](#strftime) | 不支持 | +| [strftime_l](#strftime_l) | 不支持 | +| [strptime](#strptime) | 支持 | +| [time](#time) | 支持 | +| [timer_create](#timer_create) | 支持 | +| [timer_delete](#timer_delete) | 支持 | +| [timer_getoverrun](#timer_getoverrun) | 支持 | +| [timer_gettime](#timer_gettime) | 支持 | +| [timer_settime](#timer_settime) | 支持 | +| [times](#times) | 支持 | +| [timespec_get](#timespec_get) | 支持 | +| [utime](#utime) | 不支持 | +| [wcsftime](#wcsftime) | 不支持 | +| [wcsftime_l](#wcsftime_l) | 不支持 | +| [malloc](#malloc) | 支持 | +| [free](#free) | 支持 | +| [memalign](#memalign) | 支持 | +| [realloc](#realloc) | 支持 | +| [malloc_usable_size](#malloc_usable_size) | 支持 | +| [aligned_alloc](#aligned_alloc) | 支持 | +| [reallocarray](#reallocarray) | 支持 | +| [calloc](#calloc) | 支持 | +| [posix_memalign](#posix_memalign) | 支持 | +| [abort](#abort) | 支持 | +| [_Exit](#_Exit) | 支持 | +| [atexit](#atexit) | 支持 | +| [quick_exit](#quick_exit) | 支持 | +| [at_quick_exit](#at_quick_exit) | 支持 | +| [assert](#assert) | 支持 | +| [div](#div) | 支持 | +| [ldiv](#ldiv) | 支持 | +| [lldiv](#lldiv) | 支持 | +| [imaxdiv](#imaxdiv) | 支持 | +| [wcstol](#wcstol) | 支持 | +| [wcstod](#wcstod) | 支持 | +| [fcvt](#fcvt) | 支持 | +| [ecvt](#ecvt) | 支持 | +| [gcvt](#gcvt) | 支持 | +| [qsort](#qsort) | 支持 | +| [abs](#abs) | 支持 | +| [labs](#labs) | 支持 | +| [llabs](#llabs) | 支持 | +| [imaxabs](#imaxabs) | 支持 | +| [strtol](#strtol) | 支持 | +| [strtod](#strtod) | 支持 | +| [atoi](#atoi) | 支持 | +| [atol](#atol) | 支持 | +| [atoll](#atoll) | 支持 | +| [atof](#atof) | 支持 | +| [bsearch](#bsearch) | 支持 | +| [semget](#semget) | 支持 | +| [semctl](#semctl) | 部分支持 | +| [semop](#semop) | 部分支持 | +| [semtimedop](#semtimedop) | 部分支持 | +| [msgget](#msgget) | 支持 | +| [msgctl](#msgctl) | 部分支持 | +| [msgsnd](#msgsnd) | 部分支持 | +| [msgrcv](#msgrcv) | 部分支持 | +| [shmget](#shmget) | 不支持 | +| [shmctl](#shmctl) | 不支持 | +| [shmat](#shmat) | 不支持 | +| [shmdt](#shmdt) | 不支持 | +| [ftok](#ftok) | 不支持 | + +### 任务管理 + +#### pthread_attr_init + +pthread_attr_init() 函数初始化一个线程对象的属性,需要用 pthread_attr_destroy() 函数对其去除初始化。 + +**参数**:指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr,结构中的元素分别对应着新线程的运行属性。 + +**输出**: + +- 0:初始化成功。 +- ENOMEM:内存不足,无法初始化线程属性对象。 +- EBUSY:attr是以前初始化但未销毁的线程属性。 + +#### pthread_attr_destroy + +pthread_attr_destroy()函数应销毁线程属性对象。被销毁的attr属性对象可以使用pthread_attr_init()重新初始化;在对象被销毁后引用该对象的结果是未定义的。 + +**参数**:指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 + +**输出**: + +- 0:函数销毁对象成功。 +- EINVAL:attr指向的是未初始化的线程属性对象。 + +#### pthread_attr_setstackaddr + +pthread_attr_setstackaddr()函数设置attr对象中的线程创建堆栈addr属性。堆栈addr属性指定用于创建线程堆栈的存储位置。 + +**输入**:指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr、 栈地址stackaddr。 + +**输出**: + +- 0:设置成功。 +- EINVAL:attr指向的是未初始化的线程属性对象。 + +#### pthread_attr_getstackaddr + +pthread_attr_getstackaddr()如果成功,函数将堆栈地址属性值存储在堆栈地址中。 + +**参数**:指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr、栈地址stackaddr. + +**输出**: + +- 0:获取成功。 +- EINVAL:attr指向的是未初始化的线程属性对象。 + +#### pthread_attr_getstacksize + +pthread_attr_getstacksize()和pthread_attr_setstacksize()函数分别应获取和设置 attr 对象中的线程创建堆栈大小属性(以字节为单位)。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr. +2. 栈大小指针stacksize,指向设置或获取的堆栈大小。 + +**输出**: + +- 0:获取成功。 +- EINVAL:attr指向的是未初始化的线程属性对象。 + +#### pthread_attr_setstacksize + +设置attr对象中的线程创建堆栈大小属性。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 栈大小指针stacksize,指向设置或获取的堆栈大小。 + +**输出**: + +- 0:设置成功。 +- EINVAL:堆栈size小于最小值或超过限制。 + +#### pthread_attr_getinheritsched + +获取线程的继承属性。 + +**参数**: + +- 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +- 线程的继承性指针inheritsched。 + +**输出**: + +- 0:获取成功。 +- EINVAL:attr指向的是未初始化的线程属性对象。 + +#### pthread_attr_setinheritsched + +设置线程的继承属性。可设置如下参数: + +- PTHREAD_INHERIT_SCHED:指定线程调度属性应继承自创建线程,并且应忽略此attr参数中的调度属性。 +- PTHREAD_EXPLICIT_SCHED:指定线程调度属性应设置为此属性对象中的相应值。 + +**参数**: + +- 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +- 线程的继承性inheritsched。 + +**输出**: + +- 0:设置成功。 +- EINVAL:继承的值无效,或attr指向的是未初始化的线程属性对象。 +- ENOTSUP:试图将属性设置为不支持的值。 + +#### pthread_attr_getschedpolicy + +获取调度策略属性,策略支持SCHED_FIFO。当使用调度策略SCHED_FIFO执行的线程正在等待互斥体时,互斥体解锁,它们应按优先级顺序获取互斥体。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 线程的调度策略指针policy。 + +**输出**: + +- 0:获取成功。 +- EINVAL:attr指向的是未初始化的线程属性对象。 + +#### pthread_attr_setschedpolicy + +设置调度策略属性,策略支持SCHED_FIFO。当使用调度策略SCHED_FIFO执行的线程正在等待互斥体时,互斥体解锁时,它们应按优先级顺序获取互斥体。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 线程的调度策略policy。 + +**输出**: + +- 0:设置成功。 +- EINVAL:policy的值无效,或者attr指向没有初始化的线程对象。 +- ENOTSUP:试图将属性设置为不支持的值。 + +#### pthread_attr_getdetachstate + +获取线程分离属性,分离状态应设置为PTHREAD_CREATE_DETAED或PTHREAD_CREATE_JOI无BLE。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 分离属性指针detachstate。 + +**输出**: + +- 0:获取成功。 +- EINVAL:attr指向没有初始化的线程对象。 + +#### pthread_attr_setdetachstate + +设置线程分离属性。分离状态应设置为PTHREAD_CREATE_DETAED或PTHREAD_CREATE_JOINABLE。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 分离属性detachstate。 + +**输出**: + +- 0:设置成功。 +- EINVAL:attr指向没有初始化的线程对象或分离状态的值无效。 + +#### pthread_attr_setschedparam + +pthread_attr_setschedparam() 可用来设置线程属性对象的优先级属性。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 调度属性指针schedparam。 + +**输出**: + +- 0:操作成功。 +- EINVAL:参数不合法或attr未初始化。 +- ENOTSUP:schedparam的优先级属性不支持。 + +#### pthread_attr_getschedparam + +pthread_attr_getschedparam() 可用来获取线程属性对象的优先级属性。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 调度属性指针schedparam。 + +**输出**: + +- 0:操作成功。 +- EINVAL:参数不合法或attr未初始化。 + +#### pthread_attr_getscope + +pthread_attr_getscope() 可用来获取线程属性对象的作用域属性。 + +**参数**: + +- 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +- 线程的作用域属性指针scope。 + +**输出**: + +- 0:获取成功。 +- EINVAL:指针未初始化。 + +#### pthread_attr_setscope + +设置线程的作用域,支持PTHREAD_SCOPE_SYSTEM,控制线程在系统级竞争资源。 + +**参数**: + +1. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +2. 作用域scope。 + +**输出**: + +- 0:设置成功。 +- EINVAL:scope的值无效,或者attr指向没有初始化的线程对象。 +- ENOTSUP:试图将属性设置为不支持的值。 + +#### pthread_attr_getstack + +pthread_attr_getstack() 可用来获取线程属性对象的栈信息。 + +**参数**: + +- 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +- 线程的栈地址指针stackAddr。 +- 线程的栈大小指针stackSize。 + +**输出**: + +- 0:获取成功。 +- EINVAL:指针未初始化。 + +#### pthread_attr_setstack + +pthread_attr_setstack() 可用来设置线程属性对象的栈地址和栈大小。 + +**参数**: + +- 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +- 线程的栈地址stackAddr。 +- 线程的栈大小stackSize。 + +**输出**: + +- 0:获取成功。 +- EINVAL:指针未初始化或值无效。 + +#### pthread_attr_getguardsize + +暂不支持。 + +#### pthread_attr_setguardsize + +暂不支持。 + +#### pthread_atfork + +暂不支持。 + +#### pthread_create + +pthread_create()函数创建一个新线程,其属性由 attr 指定。如果 attr 为 NULL,则使用默认属性。创建成功后,pthread_create()应将创建的线程的ID存储在参数 thread 的位置。 + +**参数**: + +1. 指向线程[标识符](https://baike.baidu.com/item/标识符?fromModule=lemma_inlink)的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)thread。 +2. 指向一个线程属性结构的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)attr。 +3. 线程处理函数的起始地址 start_routine。 +4. 运行函数的参数 arg。 + +**输出**: + +- 0:创建成功。 +- EINVAL:attr指定的属性无效。 +- EAGAIN:系统缺少创建新线程所需的资源,或者将超过系统对线程总数施加的限制。 +- EPERM:调用者没有权限。 + +#### pthread_cancel + +取消线程的执行。pthread_cancel()函数应请求取消线程。目标线程的可取消状态和类型决定取消何时生效。当取消被操作时,应调用线程的取消处理程序。 + +**参数**:线程的ID thread。 + +**输出**: + +- 0:取消成功。 +- ESRCH:找不到与给定线程ID相对应的线程。 + +#### pthread_testcancel + +设置可取消状态。pthread_testcancel()函数应在调用线程中创建一个取消点。如果禁用了可取消性,pthread_testcancel()函数将无效。 + +**参数**:无 + +**输出**:无 + +#### pthread_setcancelstate + +pthread_setcancelstate() 将调用线程的可取消性状态设置为 state 中给出的值。线程以前的可取消性状态返回到oldstate所指向的缓冲区中。state状态的合法值为PTHREAD_CANCEL_E无BLE和PTHREAD_CANCEL_DISABLE。 + +**参数**: + +- 线程的可取消性状态 state。 +- 之前的可取消状态 oldstate。 + +**输出**: + +- 0:设置成功。 +- EINVAL:指定的状态不是 PTHREAD_CANCEL_E无BLE 或 PTHREAD_CANCEL_DISABLE。 + +#### pthread_setcanceltype + +pthread_setcanceltype()函数应原子地将调用线程的可取消类型设置为指定的类型,并在oldtype引用的位置返回上一个可取消类型。类型的合法值为PTHREAD_CANCEL_DEFERRED和PTHREAD_CANCEL_ASYNCHRONOUS。 + +**输入**: + +- 线程的可取消类型type。 +- 之前的可取消类型oldtype。 + +**输出**: + +- 0:设置成功。 +- EINVAL:指定的类型不是PTHREAD_CANCEL_DEFERRED或PTHREAD_CANCEL_ASYNCHRONOUS。 + +#### pthread_exit + +线程的终止可以是调用 pthread_exit 或者该线程的例程结束。由此可看出,一个线程可以隐式退出,也可以显式调用 pthread_exit 函数来退出。pthread_exit 函数唯一的参数 value_ptr 是函数的返回代码,只要 pthread_join 中的第二个参数 value_ptr 不是NULL,这个值将被传递给 value_ptr。 + +**参数**:线程退出状态value_ptr,通常传NULL。 + +**输出**:无 + +#### pthread_cleanup_push + +pthread_cleanup_push() 函数应将指定的取消处理程序推送到调用线程的取消堆栈上。pthread_cleanup_push必须和pthread_cleanup_pop同时使用。当push后,在线程退出前使用pop,便会调用清理函数。 + +**参数**: + +1. 取消处理程序入口地址 routine。 +2. 传递给处理函数的参数 arg。 + +**输出**:无 + +#### pthread_cleanup_pop + +pthread_cleanup_pop()应删除调用线程取消处理程序,并可选择调用它(如果execute非零)。 + +**参数**:执行参数execute。 + +**输出**:无 + +#### pthread_setschedprio + +pthread_setschedprio()函数应将线程 ID 指定的调度优先级设置为 prio 给出的值。如果 pthread_setschedprio()函数失败,则目标线程的调度优先级不应更改。 + +**参数**: + +1. 线程ID:thread。 +2. 优先级:prio。 + +**输出**: + +- 0,设置成功。 +- EINVAL:prio对指定线程的调度策略无效。 +- ENOTSUP:试图将优先级设置为不支持的值。 +- EPERM:调用者没有设置指定线程的调度策略的权限。 +- EPERM:不允许将优先级修改为指定的值。 +- ESRCH:thread指定的线程不存在。 + +#### pthread_self + +pthread_self()函数应返回调用线程的线程ID。 + +**参数**:无 + +**输出**:返回调用线程的线程ID。 + +#### pthread_equal + +此函数应比较线程ID t1和t2。 + +**参数**: + +1. 线程ID t1。 +2. 线程ID t2。 + +**输出**: + +- 如果t1和t2相等,pthread_equal()函数应返回非零值。 +- 如果t1和t2不相等,应返回零。 +- 如果t1或t2不是有效的线程ID,则行为未定义。 + +#### sched_yield + +sched_yield()函数应强制正在运行的线程放弃处理器,并触发线程调度。 + +**参数**:无 + +**输出**:输出0时,成功完成;否则应返回值-1。 + +#### sched_get_priority_max + +sched_get_priority_max()和 sched_get_priority_min()函数应分别返回指定调度策略的优先级最大值或最小值。 + +**参数**:调度策略policy。 + +**输出**: + +返回值: + +- -1:失败。 +- 返回优先级最大值。 + +errno: + +- EINVAL:调度策略非法。 + +#### sched_get_priority_min + +返回指定调度策略的优先级最小值 + +**参数**:调度策略policy。 + +**输出**: + +返回值: + +- -1:失败。 +- 返回优先级最小值。 + +errno: + +- EINVAL:调度策略非法。 + +#### pthread_join + +pthread_join() 函数,以阻塞的方式等待 thread 指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且 thread 指定的线程必须是 joi无ble 的。当 pthread_join()成功返回时,目标线程已终止。对指定同一目标线程的pthread_join()的多个同时调用的结果未定义。如果调用pthread_join()的线程被取消,则目标线程不应被分离 + +**参数**: + +1. 线程ID:thread。 +2. 退出线程:返回值value_ptr。 + +**输出**: + +- 0:成功完成。 +- ESRCH:找不到与给定ID相对应的线程。 +- EDEADLK:检测到死锁或thread的值指定调用线程。 +- EINVAL:thread指定的线程不是joinable的。 + +#### pthread_detach + +实现线程分离,即主线程与子线程分离,子线程结束后,资源自动回收。 + +**参数**:线程ID:thread。 + +**输出**: + +- 0:成功完成。 +- EINVAL:thread是分离线程。 +- ESRCH:给定线程ID指定的线程不存在。 + +#### pthread_key_create + +分配用于标识线程特定数据的键。pthread_key_create 第一个参数为指向一个键值的[指针](https://baike.baidu.com/item/指针/2878304?fromModule=lemma_inlink),第二个参数指明了一个 destructor 函数,如果这个参数不为空,那么当每个线程结束时,系统将调用这个函数来释放绑定在这个键上的内存块。 + +**参数**: + +1. 键值的[指针](https://baike.baidu.com/item/指针/2878304?fromModule=lemma_inlink)key。 +2. destructor 函数入口 destructor。 + +**输出**: + +- 0:创建成功。 +- EAGAIN:系统缺乏创建另一个特定于线程的数据密钥所需的资源,或者已超过系统对每个进程的密钥总数施加的限制。 +- ENOMEM:内存不足,无法创建密钥。 + +#### pthread_setspecific + +pthread_setspecific() 函数应将线程特定的 value 与通过先前调用 pthread_key_create()获得的 key 关联起来。不同的线程可能会将不同的值绑定到相同的键上。这些值通常是指向已保留供调用线程使用的动态分配内存块的指针。 + +**参数**: + +1. 键值key。 +2. 指针value + +**输出**: + +- 0:设置成功。 +- ENOMEM:内存不足,无法将非NULL值与键关联。 +- EINVAL:key的值不合法。 + +#### pthread_getspecific + +将与key关联的数据读出来,返回数据类型为 void *,可以指向任何类型的数据。需要注意的是,在使用此返回的指针时,需满足是 void 类型,虽指向关联的数据地址处,但并不知道指向的数据类型,所以在具体使用时,要对其进行强制类型转换。 + +**参数**:键值key。 + +**输出**: + +- 返回与给定 key 关联的线程特定数据值。 +- NULL:没有线程特定的数据值与键关联。 + +#### pthread_key_delete + +销毁线程特定数据键。 + +**参数**:需要删除的键key。 + +**输出**: + +- 0:删除成功。 +- EINVAL:key值无效。 + +#### pthread_getcpuclockid + +暂不支持。 + +#### pthread_getschedparam + +获取线程调度策略和优先级属性。 + +**参数**: + +1. 线程对象指针thread。 +2. 调度策略指针policy。 +3. 调度属性对象指针param。 + +**输出**: + +- 0:删除成功。 +- EINVAL:指针未初始化。 + +#### pthread_setschedparam + +设置线程调度策略和优先级属性。调度策略仅支持SCHED_FIFO。 + +**参数**: + +1. 线程对象指针thread。 +2. 调度策略指针policy。 +3. 调度属性对象指针param。 + +**输出**: + +- 0:删除成功。 +- EINVAL:指针未初始化。 +- ENOTSUP:设置不支持的值。 + +#### pthread_kill + +暂不支持。 + +#### pthread_once + +pthread_once() 函数使用指定once_contol变量会保证init_routine函数只执行一次。当前init_routine函数不支持被取消。 + +**参数**: + +1. 控制变量control。 +2. 执行函数init_routine。 + +**输出**: + +- 0:删除成功。 +- EINVAL:指针未初始化。 + +#### pthread_sigmask + +暂不支持。 + +#### pthread_spin_init + +暂不支持。 + +#### pthread_spin_destory + +暂不支持。 + +#### pthread_spin_lock + +暂不支持。 + +#### pthread_spin_trylock + +暂不支持。 + +#### pthread_spin_unlock + +暂不支持。 + +### 信号量管理 + +#### sem_init + +sem_init()函数应初始化 sem 引用的匿名信号量。初始化信号量的值应为 value。在成功调用 sem_init()后,信号量可用于后续调用 sem_wait()、sem_timedwait()、sem_trywait()、sem_post()和sem_destroy()。此信号量应保持可用,直到信号量被销毁。 + +**参数**: + +1. 指向信号量指针sem。 +2. 指明信号量的类型pshared。 +3. 信号量值的大小value。 + +**输出**: + +- 0:初始化成功。 +- EINVAL:值参数超过{SEM_VALUE_MAX}。 +- ENOSPC:初始化信号量所需的资源已耗尽,或已达到信号量的限制。 +- EPERM:缺乏初始化信号量的权限。 + +#### sem_destroy + +sem_destroy()函数销毁 sem 指示的匿名信号量。只有使用 sem_init()创建的信号量才能使用 sem_destroy()销毁;使用命名信号量调用 sem_destroy()的效果未定义。在 sem 被另一个对 sem_init()的调用重新初始化之前,后续使用信号量 sem 的效果是未定义的。 + +**参数**:指向信号量指针sem。 + +**输出**: + +- 0:销毁成功。 +- EINVAL:sem不是有效的信号量。 +- EBUSY:信号量上当前有线程被阻止。 + +#### sem_open + +创建并初始化有名信号量。此信号量可用于后续对 sem_wait()、sem_timedwait()、sem_trywait()、sem_post()和sem_close() 的调用。 + +**参数**: + +1. 信号量名无me指针。 + +2. oflag参数控制信号量是创建还是仅通过调用sem_open()访问。以下标志位可以在oflag中设置: + + - O_CREAT:如果信号量不存在,则此标志用于创建信号量。 + + - O_EXCL:如果设置了O_EXCL和O_CREAT,且信号量名称存在,sem_open()将失败。如果设置了O_EXCL而未设置O_CREAT,则效果未定义。 + +3. 如果在oflag参数中指定了O_CREAT和O_EXCL以外的标志,则效果未指定。 + +**输出**: + +- 创建并初始化成功,返回信号量地址。 +- EACCES:创建命名信号量的权限被拒绝。 +- EEXIST:已设置O_CREAT和O_EXCL,且命名信号量已存在。 +- EINTR:sem_open()操作被信号中断。 +- EINVAL:给定名称不支持sem_open(),或在oflag中指定了O_CREAT,并且值大于最大值。 +- EMFILE:当前使用的信号量描述符或文件描述符太多。 +- ENAMETOOLONG:name参数的长度超过{PATH_MAX},或者路径名组件的长度超过{NAME_MAX}。 +- ENFILE:系统中当前打开的信号量太多。 +- ENOENT:未设置O_CREAT且命名信号量不存在。 +- ENOSPC:没有足够的空间来创建新的命名信号量。 + +#### sem_close + +关闭一个命名信号量。未命名的信号量(由sem_init() 创建的信号量)调用 sem_close() 的效果未定义。sem_close() 函数应解除系统分配给此信号量的任何系统资源。此过程后续使用sem指示的信号量的影响未定义。 + +**参数**:信号量指针sem。 + +**输出**: + +- 0: 销毁成功。 +- EINVAL:sem参数不是有效的信号量描述符。 + +#### sem_wait + +sem_wait()函数通过对 sem 引用的信号量执行信号量锁定操作来锁定该信号量。如果信号量值当前为零,则调用线程在锁定信号量或调用被信号中断之前,不会从对 sem_wait()的调用返回。 + +**参数**:信号量指针sem。 + +**输出**: + +- 0:操作成功。 +- EAGAIN:信号量已被锁定,无法立即被 sem_trywait()操作。 +- EDEADLK:检测到死锁条件。 +- EINTR:信号中断了此功能。 +- EINVAL:sem参数未引用有效的信号量。 + +#### sem_trywait + +只有当信号量当前未锁定时,即信号量值当前为正值,sem_trywait()函数才应锁定 sem 引用的信号量。否则它不应锁定信号量。 + +**参数**:信号量指针sem。 + +**输出**: + +- 0:操作成功。 +- EAGAIN:信号量已被锁定,无法立即被sem_trywait()操作。 +- EDEADLK:检测到死锁条件。 +- EINTR:信号中断了此功能。 +- EINVAL:sem参数未引用有效的信号量。 + +#### sem_timedwait + +sem_timedwait()函数应锁定 sem 引用的信号量,就像 sem_wait()函数一样。如果在不等待另一个线程执行sem_post()解锁信号量的情况下无法锁定信号量,则在指定的超时到期时,此等待将终止。 + +**参数**: + +1. 信号量指针sem。 +2. 阻塞时间指针abs_timeout。 + +**输出**: + +- 0:操作成功。 +- EINVAL:线程可能会阻塞,abs_timeout 指定的纳秒值小于0或大于等于1000 million。 +- ETIMEDOUT:在指定的超时到期之前,无法锁定信号量。 +- EDEADLK:检测到死锁条件。 +- EINTR:信号中断了此功能。 +- EINVAL:sem参数未引用有效的信号量。 + +#### sem_post + +sem_post()函数应通过对 sem 引用的信号量执行信号量解锁操作,当有线程阻塞在这个信号量上时,调用这个函数会使其中一个线程不在阻塞,选择机制是由线程的调度策略决定的。 + +**参数**:信号量指针sem。 + +**输出**: + +- 0:操作成功。 +- EINVAL:sem参数未引用有效的信号量。 + +#### sem_getvalue + +sem_getvalue()函数获取 sem 引用的信号量的值,而不影响信号量的状态。获取的 sval 值表示在调用期间某个未指定时间发生的实际信号量值。 + +**参数**: + +1. 信号量指针sem。 +2. 信号量计数值指针sval。 + +**输出**: + +- 0:操作成功。 +- EINVAL:sem参数未引用有效的信号量。 + +#### sem_unlink + +sem_unlink() 函数将删除由字符串名称命名的信号量。如果信号量当前被其他进程引用,那么sem_unlink() 将不会影响信号量的状态。如果在调用sem_unlink() 时一个或多个进程打开了信号量,则信号量的销毁将被推迟,直到信号量的所有引用都被销毁了。 + +**参数**:信号量名称name。 + +**输出**: + +- 0:操作成功。 +- -1:name参数未引用有效的信号量。 + +### 互斥量管理 + +#### pthread_mutexattr_init + +pthread_mutexattr_init()函数初始化互斥锁。如果调用 pthread_mutexattr_init()指定已初始化的attr属性对象行为未定义。 + +**参数**:互斥锁属性对象指针attr。 + +**输出**: + +- 0:操作成功。 +- ENOMEM:内存不足,无法初始化互斥属性对象。 + +#### pthread_mutexattr_destroy + + 注销一个互斥锁。销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。 + +**参数**:互斥锁属性对象指针attr。 + +**输出**: + +- 0:操作成功。 +- EINVAL:attr指定的值无效。 + +#### pthread_mutexattr_settype + +pthread_mutexattr_settype()函数设置互斥 type 属性。默认值为 PTHREAD_MUTEX_DEFAULT。有效的互斥类型包括: + +PTHREAD_MUTEX_NORMAL:此类型的互斥锁不会检测死锁。 + +- 如果线程在不解除互斥锁的情况下尝试重新锁定该互斥锁,则会产生死锁。 +- 如果尝试解除由其他线程锁定的互斥锁,会产生不确定的行为。 +- 如果尝试解除锁定的互斥锁未锁定,则会产生不确定的行为。 + +PTHREAD_MUTEX_ERRORCHECK:此类型的互斥锁可提供错误检查。 + +- 如果线程在不解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则会返回错误。 +- 如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。 +- 如果线程尝试解除锁定的互斥锁未锁定,则会返回错误。 + +PTHREAD_MUTEX_RECURSIVE: + +- 如果线程在不解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则可成功锁定该互斥锁。 与 PTHREAD_MUTEX_NORMAL 类型的互斥锁不同,对此类型互斥锁进行重新锁定时不会产生死锁情况。多次锁定互斥锁需要进行相同次数的解除锁定才可以释放该锁,然后其他线程才能获取该互斥锁。 +- 如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。 +- 如果线程尝试解除锁定的互斥锁未锁定,则会返回错误。 + +PTHREAD_MUTEX_DEFAULT: + +- 如果尝试以[递归](https://baike.baidu.com/item/递归?fromModule=lemma_inlink)方式锁定此类型的互斥锁,则会产生不确定的行为。 +- 对于不是由调用线程锁定的此类型互斥锁,如果尝试对它解除锁定,则会产生不确定的行为。 +- 对于尚未锁定的此类型互斥锁,如果尝试对它解除锁定,也会产生不确定的行为。 + +**参数**: + +1. 互斥锁属性对象指针attr。 +2. 互斥锁类型type。 + +**输出**: + +- 0:操作成功。 +- EINVAL:attr指定的值无效,或type无效。 + +#### pthread_mutexattr_gettype + +pthread_mutexattr_gettype() 可用来获取由 pthread_mutexattr_settype() 设置的互斥锁的 type 属性。 + +**参数**: + +1. 互斥锁属性对象指针attr。 +2. 互斥锁类型指针type。 + +**输出**: + +- 0:操作成功。 +- EINVAL:attr指定的值无效。 + +#### pthread_mutexattr_setprotocol + +pthread_mutexattr_setprotocol() 可用来设置互斥锁属性对象的协议属性。定义的 protocol 可以为以下值之一: + +- PTHREAD_PRIO_NONE +- PTHREAD_PRIO_INHERIT +- PTHREAD_PRIO_PROTECT(当前版本暂不支持) + +**参数**: + +1. 互斥锁属性对象指针 attr。 +2. 互斥锁属性对象的协议 protocol。 + +**输出**: + +- 0:操作成功。 +- ENOTSUP:协议指定的值不支持。 +- EINVAL:attr指定的值无效。 +- EPERM:调用者没有权限。 + +#### pthread_mutexattr_getprotocol + +pthread_mutexattr_getprotocol() 获取互斥锁属性对象的协议属性。 + +**参数**: + +1. 互斥锁属性对象指针attr。 +2. 互斥锁属性对象的协议指针protocol。 + +**输出**: + +- 0:操作成功。 +- EINVAL:attr指定的值无效。 +- EPERM:调用者没有权限。 + +#### pthread_mutexattr_getprioceiling + +暂不支持。 + +#### pthread_mutexattr_setprioceiling + +暂不支持。 + +#### pthread_mutexattr_getpshared + +获取互斥锁属性对象的共享属性。当前支持PTHREAD_PROCESS_PRIVATE,互斥锁为进程内私有。 + +**参数**: + +1. 互斥锁属性对象指针attr。 +2. 共享属性指针pshared。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_mutexattr_setpshared + +暂不支持。 + +#### pthread_mutexattr_getrobust + +获取互斥锁属性对象的健壮属性。当前支持PTHREAD_MUTEX_STALLED,如果互斥锁的所有者在持有互斥锁时终止,则不会执行特殊操作。 + +**参数**: + +1. 互斥锁属性对象指针attr。 +2. 健壮属性指针robust。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_mutexattr_setrobust + +设置互斥锁属性对象的健壮属性。当前支持PTHREAD_MUTEX_STALLED。 + +**参数**: + +1. 互斥锁属性对象指针attr。 +2. 健壮属性robust。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- ENOTSUP:设置不支持的值。 + +#### pthread_mutex_init + +pthread_mutex_init()函数初始化互斥锁,属性由 attr 指定。如果 attr 为NULL,则使用默认互斥属性。 + +**参数**: + +1. 互斥锁指针mutex。 +2. 互斥锁属性对象指针attr。 + +**输出**: + +- 0:操作成功。 +- EAGAIN:缺少初始化互斥锁所需的资源(内存除外)。 +- ENOMEM:内存不足,无法初始化互斥体。 +- EPERM:没有执行操作的权限。 +- EBUSY:互斥锁已经初始化但尚未销毁。 +- EINVAL:attr指定的值无效。 + +#### pthread_mutex_destroy + +pthread_mutex_destroy() 用于注销一个互斥锁。销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。 + +**参数**:互斥锁指针mutex。 + +**输出**: + +- 0:操作成功。 +- EBUSY:锁当前未处于开放状态。 +- EINVAL:mutex指定的值无效。 + +#### pthread_mutex_lock + +当pthread_mutex_lock() 返回时,该[互斥锁](https://baike.baidu.com/item/互斥锁/841823?fromModule=lemma_inlink)已被锁定。[线程](https://baike.baidu.com/item/线程/103101?fromModule=lemma_inlink)调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。 + +**参数**:互斥锁指针mutex。 + +**输出**: + +- 0:操作成功。 +- EINVAL:mutex指定的值未初始化。 +- EAGAIN:无法获取互斥锁。 +- EDEADLK:当前线程已经拥有互斥锁。 + +#### pthread_mutex_trylock + +pthread_mutex_trylock() 语义与 pthread_mutex_lock() 类似,不同点在于锁已经被占据时返回 EBUSY, 而非挂起等待。 + +**参数**:互斥锁指针mutex。 + +**输出**: + +- 0,操作成功。 +- EBUSY:mutex指定的锁已经被占据。 +- EINVAL:mutex指定的值未初始化。 +- EAGAIN:无法获取互斥锁。 +- EDEADLK:当前线程已经拥有互斥锁。 + +#### pthread_mutex_timedlock + +pthread_mutex_timedlock() 语义与pthread_mutex_lock() 类似,不同点在于锁已经被占据时增加一个超时时间,等待超时返回错误码。 + +**参数**: + +1. 互斥锁指针mutex。 +2. 超时时间指针abs_timeout。 + +**输出**: + +- 0:操作成功。 +- EINVAL:mutex指定的值未初始化,abs_timeout指定的纳秒值小于0或大于等于1000 million。 +- ETIMEDOUT:等待超时。 +- EAGAIN:无法获取互斥锁。 +- EDEADLK:当前线程已经拥有互斥锁。 + +#### pthread_mutex_unlock + +释放互斥锁。 + +**参数**:互斥锁指针mutex。 + +**输出**: + +- 0:操作成功。 +- EINVAL:mutex指定的值未初始化。 +- EPERM:当前线程不拥有互斥锁。 + +#### pthread_mutex_consistent + +暂不支持。 + +#### pthread_mutex_getprioceiling + +暂不支持。 + +#### pthread_mutex_setprioceiling + +暂不支持。 + +### 读写锁编程 + +#### pthread_rwlock_init + +pthread_rwlock_init()初始化读写锁。如果 attr 为 NULL,则使用默认的读写锁属性。一旦初始化,锁可以使用任何次数,而无需重新初始化。调用 pthread_rwlock_init()指定已初始化的读写锁行为未定义。如果在没有初始化的情况下使用读写锁,则结果是未定义的。 + +**参数**: + +1. 读写锁指针rwlock。 +2. 读写锁属性指针attr。 + +**输出**: + +- 0:操作成功。 +- EAGAIN:系统缺少初始化读写锁所需的资源(内存除外)。 +- ENOMEM:内存不足,无法初始化读写锁。 +- EPERM:没有执行操作的权限。 +- EBUSY:rwlock是以已初始化但尚未销毁的读写锁。 +- EINVAL:attr指定的值无效。 + +#### pthread_rwlock_destroy + +pthread_rwlock_destroy()函数应销毁 rwlock 引用的读写锁,并释放锁使用的资源。在再次调用pthread_rwlock_init()重新初始化锁之前,后续使用锁的行为未定义。如果在任何线程持有 rwlock 时调用pthread_rwlock_destroy()行为未定义。尝试销毁未初始化的读写锁行为未定义。 + +**参数**:读写锁指针rwlock。 + +**输出**: + +- 0:操作成功。 +- EBUSY: rwlock引用的对象被锁定时销毁该对象。 +- EINVAL:attr指定的值无效。 + +#### pthread_rwlock_rdlock + +pthread_rwlock_rdlock()函数应将读锁应用于rwlock引用的读写锁。 + +**参数**:读写锁指针rwlock。 + +**输出**: + +- 0:操作成功。 +- EINVAL:rwlock是未初始化的读写锁。 +- EAGAIN:无法获取读锁,因为已超过rwlock的最大读锁数。 +- EDEADLK:检测到死锁条件或当前线程已拥有写锁。 + +#### pthread_rwlock_tryrdlock + +pthread_rwlock_tryrdlock()函数语义与pthread_rwlock_rdlock()类似。在任何情况下,pthread_rwlock_tryrdlock()函数都不会阻塞;它会一直获取锁,或者失败并立即返回。 + +**参数**:读写锁指针rwlock。 + +**输出**: + +- 0:操作成功。 +- EINVAL:rwlock是未初始化的读写锁。 +- EAGAIN:无法获取读锁,因为已超过rwlock的最大读锁数。 +- EBUSY:无法获取读写锁以进行读取,因为写入程序持有该锁。 + +#### pthread_rwlock_timedrdlock + +pthread_rwlock_timedrdlock()语义与pthread_rwlock_rdlock()类似,不同的是在锁已经被占据时增加一个超时时间,等待超时返回错误码。 + +**参数**: + +1. 读写锁指针rwlock。 +2. 超时时间指针abs_timeout。 + +**输出**: + +- 0:操作成功。 +- ETIMEDOUT:在指定的超时到期之前,无法获取锁。 +- EAGAIN:无法获取读锁,超过锁的最大读锁数量。 +- EDEADLK:检测到死锁条件或调用线程已在rwlock上持有写锁。 +- EINVAL:rwlock指定的锁未初始化,或者abs_timeout纳秒值小于0或大于等于1000 million。 + +#### pthread_rwlock_wrlock + +pthread_rwlock_wrlock()函数将写锁应用于 rwlock 引用的读写锁。如果没有其他线程持有读写锁 rwlock,调用线程将获得写锁。否则,线程应阻塞,直到它能够获得锁。如果调用线程在调用时持有读写锁(无论是读锁还是写锁),则调用线程可能会死锁。 + +**参数**:读写锁指针rwlock。 + +**输出**: + +- 0:操作成功。 +- EINVAL:rwlock指定的值未初始化。 +- EDEADLK:检测到死锁情况,或者当前线程已经拥有用于写入或读取的读写锁。 + +#### pthread_rwlock_trywrlock + +pthread_rwlock_trywrlock()函数类似 pthread_rwlock_wrlock(),但如果任何线程当前持有rwlock(用于读取或写入,该函数将失败)。 + +**参数**:读写锁指针rwlock。 + +**输出**: + +- 0:操作成功。 +- EBUSY:无法获取读写锁以进行写入,因为它已被锁定以进行读取或写入。 +- EINVAL:rwlock指定的值未初始化。 + +#### pthread_rwlock_timedwrlock + +pthread_rwlock_timedwrlock()语义与pthread_rwlock_wrlock()类似,不同的是在锁已经被占据时增加一个超时时间,等待超时返回错误码。 + +**参数**: + +1. 读写锁指针rwlock。 +2. 超时时间指针abs_timeout。 + +**输出**: + +- 0:操作成功。 +- ETIMEDOUT:在指定的超时到期之前,无法获取锁。 +- EAGAIN:无法获取读锁,超过锁的最大读锁数量。 +- EDEADLK:检测到死锁条件或调用线程已在rwlock上持有写锁。 +- EINVAL;rwlock指定的锁未初始化,或者abs_timeout纳秒值小于0或大于等于1000 million。 + +#### pthread_rwlock_unlock + +pthread_rwlock_unlock()函数释放rwlock引用的读写锁上持有的锁。如果读写锁rwlock未被调用线程持有,则结果未定义。 + +**参数**:读写锁指针rwlock。 + +**输出**: + +- 0:操作成功。 +- EINVAL:rwlock指定的锁未初始化。 +- EPERM:当前线程不持有读写锁。 + +#### pthread_rwlockattr_init + +暂不支持 + +#### pthread_rwlockattr_destroy + +暂不支持 + +#### pthread_rwlockattr_getpshared + +pthread_rwlockattr_getpshared() 函数从attr引用的读写锁属性对象中获取进程共享属性的值。 + +**参数**: + +1. 读写锁属性指针attr。 +2. 共享属性指针pshared。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +### pthread_rwlockattr_setpshared + +设置读写锁属性对象中进程共享属性的值。当前支持PTHREAD_PROCESS_PRIVATE,读写锁为进程私有。 + +**参数**: + +1. 读写锁属性指针attr。 +2. 共享属性指针pshared。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- ENOTSUP:设置不支持的值。 + +### 线程屏障管理 + +#### pthread_barrier_destroy + +销毁线程屏障变量,并释放该屏障使用的任何资源。 + +**参数**:屏障变量指针b。 + +**输出**: + +- 0:操作成功。 +- EBUSY:另一个线程在使用该变量。 + +#### pthread_barrier_init + +分配线程屏障变量所需的资源,并使用attr的属性初始化屏障。如果attr为NULL,则使用默认的屏障属性。 + +**参数**: + +1. 屏障变量指针b。 +2. 屏障属性指针attr。 +3. 等待线程个数count。 + +**输出**: + +- 0:操作成功。 +- EINVAL:count为0。 +- ENOTSUP:attr指定的屏障属性不支持。 +- EAGAIN:系统缺乏初始化一个屏障所需的资源。 + +#### pthread_barrier_wait + +pthread_barrier_wait() 阻塞调用线程,直到等待的线程达到了预定的数量。 + +**参数**:屏障变量指针b。 + +**输出**: + +- 0:操作成功。 +- -1:第一个线程成功返回。 + +#### pthread_barrierattr_getpshared + +获取屏障属性的共享属性值。 + +**参数**: + +1. 屏障属性指针a。 +2. 共享属性值指针pshared。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_barrierattr_setpshared + +设置屏障属性的共享属性值。支持PTHREAD_PROCESS_PRIVATE,该屏障为进程私有的,不允许不同进程的线程访问该屏障。 + +**参数**: + +1. 屏障属性指针a。 +2. 共享属性值pshared。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- ENOTSUP:试图将属性设置为不支持的值。 + +### 条件变量管理 + +#### pthread_cond_init + +使用attr引用的属性初始化cond引用的条件变量。如果attr为NULL,则使用默认条件变量属性。 + +**参数** + +1. 条件变量指针cond。 +2. 条件变量属性指针attr。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- EAGAIN:系统缺乏初始化一个条件变量所需的资源。 + +#### pthread_cond_destroy + +销毁指定条件变量,使得该条件变量未初始化,可以使用pthread_cond_init() 重新初始化。 + +**参数**:条件变量指针cond。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- EBUSY:另一个线程在使用该变量。 + +#### pthread_cond_broadcast + +pthread_cond_broadcast()函数取消阻塞指定条件变量cond上当前阻塞的所有线程。 + +**参数**:条件变量指针cond。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_cond_signal + +pthread_cond_signal() 函数取消阻塞在指定的条件变量cond上阻塞的线程中的至少一个(如果有任何线程在cond上被阻塞)。 + +**参数**:条件变量指针cond。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_cond_timedwait + +pthread_cond_timedwait() 函数阻塞当前线程等待cond指定的条件变量,并释放互斥体指定的互斥体。只有在另一个线程使用相同的条件变量调用pthread_cond_signal() 或pthread_cond_broadcast() 后,或者如果系统时间达到指定的时间,并且当前线程重新获得互斥锁时,等待线程才会解锁。 + +**参数**: + +1. 条件变量指针cond。 +2. 互斥锁指针m。 +3. 超时时间指针ts。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- ETIMEDOUT:阻塞超时 + +#### pthread_cond_wait + +pthread_cond_wait() 函数与pthread_cond_timedwait() 类似,阻塞当前线程等待cond指定的条件变量,并释放互斥体指定的互斥体。只有在另一个线程使用相同的条件变量调用pthread_cond_signal() 或pthread_cond_broadcast() 后,并且当前线程重新获得互斥锁时,等待线程才会解锁。 + +**参数**: + +1. 条件变量指针cond。 +2. 互斥锁指针m。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_condattr_init + +使用属性的默认值初始化条件变量属性对象attr。 + +**参数**: 条件变量属性对象指针attr。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_condattr_destroy + +pthread_condattr_destroy)函数销毁条件变量属性对象,使对象变得未初始化,可以使用pthread_condattr_init() 重新初始化。 + +**参数**:条件变量属性对象指针attr。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_condattr_getclock + +从attr引用的属性对象中获取时钟属性的值。 + +**参数**: + +1. 条件变量属性对象指针attr。 +2. 时钟属性指针clk。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_condattr_setclock + +设置attr引用的属性对象中时钟属性的值。当前支持CLOCK_REALTIME,采用系统时间。 + +**参数**: + +1. 条件变量属性对象指针attr。 +2. 时钟属性clock。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- ENOTSUP:设置不支持的值。 + +#### pthread_condattr_getpshared + +从attr引用的属性对象中获取共享属性的值。 + +**参数**: + +1. 条件变量属性对象指针attr。 +2. 共享属性指针pshared。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_condattr_setpshared + +设置attr引用的属性对象中共享属性属性的值。当前支持PTHREAD_PROCESS_PRIVATE,该条件变量为进程私有的,不允许不同进程的线程访问。 + +**参数**: + +1. 条件变量属性对象指针attr。 +2. 共享属性pshared。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- ENOTSUP:设置不支持的值。 + +### 时钟管理 + +#### asctime + +asctime() 函数将timeptr指向的tm结构体对象转换为的字符串。 + +**参数**: tm结构体指针timeptr。 + +**输出**: + +- 成功则返回字符串指针。 +- 失败返回NULL。 + +#### asctime_r + +与asctime() 函数类似,将timeptr指向的tm结构体对象转换为的字符串。不同的是该字符串放置在用户提供的缓冲区buf(至少包含26字节)中,然后返回buf。 + +**参数**: + +1. tm结构体指针timeptr。 +2. 字符串缓冲区buf。 + +**输出**: + +- 成功则返回字符串指针。 +- 失败返回NULL。 + +#### clock + +返回该进程使用等处理器时间的最佳近似值。 + +**参数**:无 + +**输出**: + +- 成功则返回时间。 +- -1:失败。 + +#### clock_gettime + +clock_gettime()函数应返回指定时钟的当前值tp。 + +**参数**: + +1. 时钟类型clock_id。 +2. timespec结构体指针tp。 + +**输出**: + +返回值: + +- 0:操作成功。 +- -1:操作失败。 + +errno: + +- EINVAL:clock_id不合法。 +- ENOTSUP:clock_id不支持。 + +#### clock_settime + +clock_settime()函数应将指定的clock_id设置为tp指定的值。 + +**参数**: + +1. 时钟类型clock_id。 +2. timespec结构体指针tp。 + +**输出**: + +返回值: + +- 0:操作成功。 +- -1:操作失败。 + +errno: + +- EINVAL:clock_id不合法,或tp参数指定的纳秒值小于0或大于等于1000 million。 +- ENOTSUP:clock_id不支持。 + +#### clock_getres + +clock_getres()返回时钟的分辨率。如果参数res不为NULL,则指定时钟的分辨率应存储在res指向的位置。如果res为NULL,则不返回时钟分辨率。如果clock_settime()的时间参数不是res的倍数,则该值将被截断为res的倍数。 + +**参数**: + +1. 时钟类型clock_id。 +2. timespec结构体指针res。 + +**输出**: + +返回值: + +- 0:操作成功。 +- -1:操作失败。 + +errno: + +- EINVAL:clock_id不合法。 +- ENOTSUP:clock_id不支持。 + +#### clock_getcpuclockid + +clock_getcpuclockid函数获取CPU时间时钟的ID,当前进程只有一个,因此无论传入的pid是什么,都返回CLOCK_PROCESS_CPUTIME_ID。 + +**参数**: + +1. 进程ID:pid。 +2. 时钟指针:clk。 + +**输出**: + +- 0:操作成功。 + +#### clock_nanosleep + +与nanosleep类似,clock_nanosleep() 允许调用线程在以纳秒精度指定的时间间隔内休眠,并可以将睡眠间隔指定为绝对值或相对值。当前支持CLOCK_REALTIME。 + +**参数**: + +1. 时钟ID:clk。 +2. 是否为绝对值:flag。 +3. 指定的时间间隔值eq。 +4. 剩余时间值:rem。 + +**输出**: + +- 0:操作成功。 +- -1:操作失败。 +- EINVAL:时钟ID错误。 +- ENOTSUP:不支持的时钟ID。 + +#### nanosleep + +nanosleep()函数应导致当前线程暂停执行,直到rqtp参数指定的时间间隔过去或信号传递到调用线程。挂起时间可能比请求的长,因为参数值被四舍五入到睡眠分辨率的整数倍,或者因为系统调度了其他活动。但是,除被信号中断外,暂停时间不得小于rqtp规定的时间。 + +如果rmtp参数是非NULL,则更新其为剩余的时间量(请求的时间减去实际睡眠时间)。如果rmtp参数为NULL,则不返回剩余时间。 + +**参数**: + +1. timespec结构体指针rqtp。 +2. timespec结构体指针rmtp。 + +**输出**: + +返回值: + +- 0:操作成功。 +- -1:操作失败。 + +errno: + +- EINVAL:rqtp参数指定的纳秒值小于0或大于等于1000 million。 +- EINTR:信号中断。 + +#### sleep + +sleep()函数应导致调用线程暂停执行,直到参数seconds指定的实时秒数过去或信号被传递到调用线程。由于系统安排了其他活动,暂停时间可能比请求的要长。 + +**参数**: 秒数seconds。 + +**输出**: + +- 0:操作成功。 +- 如果由于信号的传递而返回,则返回值应为“未睡眠”量,以秒为单位。 + +#### timer_create + +timer_create()函数使用指定的时钟clock_id作为时序基创建计时器,在timerid引用的位置返回计时器ID,用于标识计时器。在删除计时器之前,此计时器ID在调用过程中应是唯一的。 + +**参数**: + +1. 时钟类型clock_id。 +2. sigevent结构体指针evp。(仅支持SIGEV_THREAD) +3. 定时器ID指针timerid。 + +**输出**: + +- 0:操作成功。 +- EINVAL:clock_id不合法。 +- EAGAIN:系统缺少足够的资源来满足请求。 +- EINVAL:指定的时钟ID未定义。 +- ENOTSUP:不支持创建附加到clock_id时钟上的计时器。 + +#### timer_delete + +删除定时器。 + +**参数**:定时器ID指针timerid。 + +**输出**: + +- 0:操作成功。 +- EINVAL:timerid不合法。 + +#### timer_settime + +如果value的it_value成员非0,timer_settime()函数从value参数的it_value成员设置timerid指定的计时器的到期时间。如果在调用timer_settime()时指定的计时器已启用,则此调用应将下次到期的时间重置为指定的值。如果value的it_value成员为0,则应解除计时器。 + +**参数**: + +1. 定时器ID timerid。 +2. 计时器的特征flag。 +3. itimerspec结构体指针value。 +4. itimerspec结构体指针ovalue。返回上一次计时器设置超时时间。 + +**输出**: + +- 0:操作成功。 +- EINVAL:timerid不合法。 + +#### timer_gettime + +timer_gettime() 函数存储定时器 timerid 的剩余时间以及间隔。value 的 it_value 成员包含计时器到期前的时间量,如果计时器已解除,则为零。value 的 it_interval 成员将包含 timer_settime() 上次设置的间隔时间。 + +**参数**: + +1. 定时器ID timerid。 +2. itimerspec结构体指针value。 + +**输出**: + +- 0:操作成功。 +- EINVAL:timerid不合法。 + +#### timer_getoverrun + +根据指定的定时器ID,获取定时器的超时次数。 + +**参数**: + +1. 定时器ID timerid。 +2. itimerspec结构体指针value。 + +**输出**: + +- 非负数:超时次数。 +- -1:操作失败。 + +errno: + +- EINVAL:无效ID或定时器未初始化。 + +#### times + +获取进程的执行时间。由于UniProton无用户模式/内核模式且无子进程概念,出参和返回值均为进程执行总时间。 + +**参数**: + +1. tms结构体指针ts。 + +**输出**: + +- 非负数:进程的执行时间。 + +#### ctime + +ctime() 函数将tp指向的time_t结构体对象转换为的字符串。效果等同于asctime(localtime(t))。 + +**参数**: time_t结构体指针tp。 + +**输出**: + +- 成功则返回字符串指针。 +- 失败返回NULL。 + +#### ctime_r + +ctime_r() 函数将tp指向的time_t结构体对象转换为的字符串,并将字符串放入buf指向的数组中(其大小应至少为26字节)并返回buf。 + +**参数**: + +1. tm结构体指针timeptr。 +2. 字符串缓冲区buf。 + +**输出**: + +- 成功则返回字符串指针。 +- 失败返回NULL。 + +#### difftime + +计算两个日历时间之间的差值(由第一个参数减去第二个参数)。 + +**参数**: + +1. 第一个时间值t1。 +2. 第二个时间值t0。 + +**输出**: + +- 返回时间差值。 + +#### getdate + +暂不支持 + +#### gettimeofday + +gettimeofday() 函数应获取当前时间,并将其存储在tp指向的timeval结构中。如果时区结果tz不是空指针,则行为未指定。 + +**参数**: + +1. timeval结构体指针tp。 +2. 时区指针tz。 + +**输出**: + +- 返回0。 + +#### gmtime + +将time_t结构表示的日历时间转换为tm结构表示的时间,无时区转换。 + +**参数**:time_t结构体指针。 + +**输出**: + +返回值: + +- tm结构体指针。 + +errno: + +- EOVERFLOW:转换溢出。 + +#### gmtime_r + +与gmtime函数类似,不同的是gmtime_r会将结果放入在用户提供的tm结构体中。 + +**参数**: + +1. time_t结构体指针。 +2. tm结构体指针。 + +**输出**: + +返回值: + +- tm结构体指针。 + +errno: + +- EOVERFLOW:转换溢出。 + +#### localtime + +将time_t结构表示的日历时间转换为tm结构表示的本地时间,受时区的影响。 + +**参数**:time_t结构体指针。 + +**输出**: + +返回值: + +- tm结构体指针。 + +errno: + +- EOVERFLOW:转换溢出。 + +#### localtime_r + +与localtime函数类似,不同的是localtime_r会将结果放入在用户提供的tm结构体中。 + +**参数**: + +1. time_t结构体指针。 +2. tm结构体指针。 + +**输出**: + +返回值: + +- tm结构体指针。 + +errno: + +- EOVERFLOW:转换溢出。 + +#### mktime + +将已经根据时区信息计算好的tm结构表示的时间转换为time_t结构表示的时间戳,受时区的影响。 + +**参数**:tm结构体指针。 + +**输出**: + +返回值: + +- time_t结构体指针。 + +errno: + +- EOVERFLOW:转换溢出。 + +#### strftime + +暂不支持 + +#### strftime_l + +暂不支持 + +#### strptime + +使用format指定的格式,将buf指向的字符串解析转换为tm结构体的时间值。 + +**参数**: + +1. 时间字符串buf。 +2. 格式字符串format。 +3. tm结构体指针tp。 + +**输出**: + +- 成功则返回指针,指向解析的最后一个字符后面的字符。 +- 失败返回NULL。 + +#### time + +获取当前的日历时间,即从一个标准时间点到此时的时间经过的秒数。 + +**参数**:time_t结构体指针t。 + +**输出**:time_t结构体指针t。 + +#### timespec_get + +返回基于给定时基base的时间,由timespec结构体保存。时基通常为TIME_UTC。 + +**参数**: + +1. timespec结构体指针ts。 +2. 时基base + +**输出**: + +- 成功则返回时基的值。 +- 失败则返回0。 + +#### utime + +暂不支持。 + +#### wcsftime + +暂不支持 + +#### wcsftime_l + +暂不支持 + +### 内存管理 + +#### malloc + +malloc()分配大小(以字节为单位)size 的未使用的空间。 + +**参数**:大小size。 + +**输出**:分配成功时,返回指向分配空间的指针。 + +- 如果size 为0,则返回空指针或可以成功传递给 free()的唯一指针。 +- 否则它将返回一个空指针,并设置 errno 来指示错误:ENOMEM 存储空间不足。 + +#### free + +Free()函数释放ptr指向的空间,即可供进一步分配。如果ptr是空指针,则不发生任何操作。如果空间已被对free()或realloc()的调用释放,则行为未定义。 + +**参数**:指针ptr。 + +**输出**:无 + +#### memalign + +memalign()函数将分配按align大小字节对齐,大小为len的内存空间指针。 + +**参数**:align是对齐字节数,len指定分配内存的字节大小。 + +**输出**:成功完成后,空间大小为len的指针。 + +#### realloc + +realloc()函数将释放ptr所指向的旧对象,并返回一个指向新对象的指针,该对象的大小由size指定。并拷贝旧指针指向的内容到新指针,然后释放旧指针指向的空间。如果ptr是空指针,则realloc()对于指定的大小应等同于malloc()。 + +**参数**:旧指针地址;新指针的目标分配空间大小。 + +**输出**:在成功完成后,realloc()将返回一个指向分配空间的指针。如果size为0,则行为不可预测。 + +#### malloc_usable_size + +malloc_usable_size()函数返回ptr所指向的块中的可用字节数。 + +**参数**:待计算内存块大小的指针。 + +**输出**:返回ptr指向的已分配内存块中的可用字节数。如果ptr为NULL,则返回0。 + +#### aligned_alloc + +aligned_alloc()函数分配size字节未初始化的存储空间,按照alignment指定对齐。 + +**参数**:alignment指定对齐;size是分配的字节数。 + +**输出**:返回指向新分配内存的指针。 + +#### reallocarray + +reallocarray()函数将释放ptr所指向的旧对象,并返回一个指向新对象的指针,该对象的大小由size由入参m和n决定。等同于realloc(ptr, m * n); + +**参数**:ptr待释放的指针内容,m和n代表数组的长度和单个元素的字节数。 + +**输出**:在成功完成后返回一个指向分配空间的指针。如果size为0,则行为不可预测。 + +#### calloc + +calloc()函数将为一个数组分配未使用的空间,并将该空间应初始化为所有位0。 + +**参数**:m和n分别代表数组的元素个数或单个元素的大小。 + +**输出**:分配成功时,返回指向分配空间的指针。失败时则行为不可预测。 + +#### posix_memalign + +posix_memalign()函数将分配按align指定的边界对齐的大小字节,并返回指向在memptr中分配的内存的指针。对齐的值应该是sizeof(void *)的2倍幂。 + +**参数**:res分配好的内存空间的首地址,align是对齐字节数,len指定分配内存的字节大小。 + +**输出**:成功完成后,posix_memalign()将返回零;否则,将返回一个错误号来表示错误,并且不修改memptr的内容,或者将其设置为空指针。 + +### 退出管理 + +#### abort + +abort()函数触发程序的异常终止,除了信号SIGABRT没有被捕获或者返回。 + +**参数**:无 + +**输出**:无 + +#### _Exit + +_Exit()函数终止程序。 + +**参数**:入参是0,EXIT_SUCCESS, EXIT_FAILURE或任何其他值。wait()和waitpid()只能获得最低有效的8位(即status & 0377);完整的值应该可以从waitid()和siginfo_t中获得,SIGCHLD传递给信号处理程序。 + +**输出**:无 + +#### atexit + +atexit()注册一个在程终止时运行的函数。在正常的程序终止时,所有由atexit()函数注册的函数都应该按照其注册的相反顺序被调用,除非一个函数在之前注册的函数之后被调用,而这些函数在注册时已经被调用了。正常的终止发生在调用exit()或从main()返回时。 + +**参数**:函数指针,该入参函数不带参数。 + +**输出**:成功返回0;失败返回非0。 + +#### quick_exit + +quick_exit()函数触发快速程序终止,并以后进先出(LIFO)的顺序调用由at_quick_exit注册的函数。 + +**参数**:程序退出的状态码。 + +**输出**:无 + +#### at_quick_exit + +at_quick_exit()函数注册由func指向的函数,在快速程序终止时(通过quick_exit)调用。最多能注册32个函数。 + +**参数**:指向快速程序退出时要调用的函数的指针。 + +**输出**:注册成功返回0,否则为非零值。 + +#### assert + +assert()宏将在程序中插入断言,它将扩展为一个void表达式。当它被执行时,如果判断条件失败。assert()将写失败特定的调用信息,并将调用abort()退出程序。 + +**参数**:判断表达式。 + +**输出**:无 + +### stdlib接口 + +#### div + +div()函数计算int型除法的商和余数。如果余数或商不能表示,结果是未知的。 + +**参数**:int numer(分子), int denom(分母)。 + +**输出**:结构体div_t,int型的商和余数。 + +#### ldiv + +ldiv()函数将计算long型除法的商和余数。如果余数或商不能表示,结果是未知的。 + +**参数**:long numer(分子), long denom(分母)。 + +**输出**:结构体ldiv_t,long型的商和余数。 + +#### lldiv + +lldiv()函数将计算long long型除法的商和余数。如果余数或商不能表示,结果是未知的。 + +**参数**:long long numer(分子), long long denom(分母)。 + +**输出**:结构体lldiv_t,long long型的商和余数。 + +#### imaxdiv + +imaxdiv()函数将计算intmax_t型除法的商和余数。如果余数或商不能表示,结果是未知的。 + +**参数**:intmax_t numer(分子), intmax_t denom(分母)。 + +**输出**:结构体imaxdiv_t,intmax_t型的商和余数。 + +#### wcstol + +wcstol()将宽字符串转换为long型正数。输入字符串分解为三部分。 + +1. 初始的(可能为空的)空白宽字符代码序列(由iswspace()指定)。 +2. long型整数,进制的类型由base入参决定。 +3. 由一个或多个无法识别的宽字符代码组成的最终宽字符串。 + +**参数**:指向要解释的以空字符结尾的宽字符串的指针;指向宽字符的指针;解释的整数值的基数。 + +**输出**:转换后的long型数值。如果无法进行转换,则返回0,并设置errno表示错误。如果正确值在可表示的值范围之外,则返回LONG_MIN,LONG_MAX,LLONG_MIN或LLONG_MAX,并将errno设置为ERANGE。 + +#### wcstod + +wcstod()将宽字符串转换为double型浮点数。输入字符串分解为三部分。 + +1. 初始的(可能为空的)空白宽字符代码序列(由iswspace()指定)。 +2. double型浮点数、无穷大或者NaN。 +3. 由一个或多个无法识别的宽字符代码组成的最终宽字符串。 + +**参数**:指向要解释的以空字符结尾的宽字符串的指针;指向宽字符的指针; + +**输出**:转换后的double型浮点数。如果越界,则可能返回±HUGE_VAL, ±HUGE_VALF或±HUGE_VALL,并将errno设置为ERANGE。 + +#### fcvt + +fcvt()将浮点数转换为要求长度的字符串,没有小数点,如果超过value的数字长度将补零。 + +**参数**:待转换的浮点数、转换后字符串的长度、小数点所在位指针、符号位指针。 + +**输出**:转换后字符串指针。 + +#### ecvt + +ecvt()函数将浮点数转换为要求长度的字符串,没有小数点,如果超过value的数字长度不补零(与fcvt的区别)。 + +**参数**:待转换的浮点数、转换后字符串的长度、小数点所在位指针、符号位指针。 + +**输出**:转换后字符串指针。 + +#### gcvt + +gcvt()函数将double类型的值转换为要求长度的字符串,包含小数点。 + +**参数**:待转换的浮点数,转换后字符串的长度、转换后字符串指针。 + +**输出**:转换后字符串指针(等于函数成功调用后第三个入参的指针)。 + +#### qsort + +qsort()函数对数据表进行排序。 + +**参数**:qsort()函数将对nel对象数组进行排序,该数组的初始元素由base指向。每个对象的大小(以字节为单位)由width参数指定。如果nel参数的值为0,则不会调用comp所指向的比较函数,也不会进行重排。应用程序应确保compar所指向的比较函数不会改变数组的内容。实现可以在调用比较函数之间对数组元素重新排序,但不能改变任何单个元素的内容。 + +**输出**:无 + +#### abs + +abs()函数计算并返回int型数值的绝对值。 + +**参数**:int整型数值。 + +**输出**:int整型数值的绝对值。 + +#### labs + +labs()函数计算并返回long型数值的绝对值。 + +**参数**:long型数值。 + +**输出**:long型数值的绝对值。 + +#### llabs + +llabs()函数计算并返回long long型数值的绝对值。 + +**参数**:long long型数值。 + +**输出**:long long型数值的绝对值。 + +#### imaxabs + +imaxabs()函数计算并返回intmax_t型的绝对值。 + +**参数**:intmax_t型数值。 + +**输出**:intmax_t型数值的绝对值。 + +#### strtol + +strtol()函数转换字符串到long型数值。这将nptr所指向的字符串的初始部分转换为long类型的表示形式。首先,它们将输入字符串分解为三部分。 + +1. 一个初始的、可能为空的空白字符序列(由isspace()函数判断)。 +2. long型整数,进制的类型由base入参决定。 +3. 由一个或多个不可识别字符组成的最后字符串,包括输入字符串的终止NUL字符。 + +**参数**:待转换的字符串的指针;指向字符的指针;解释的整数值的基数。 + +**输出**:转换后的long型。如果无法进行转换,则返回0,并设置errno表示错误。如果正确值在可表示的值范围之外,则返回LONG_MIN, LONG_MAX, LLONG_MIN或LLONG_MAX,并将errno设置为EINVAL。 + +#### strtod + +strtod()函数将字符串转换为double型。输入字符串分解为三部分。 + +1. 初始的(可能为空的)空白字符代码序列(由isspace()指定)。 +2. double型浮点数、无穷大或者NaN。 +3. 由一个或多个无法识别的字符代码组成的最终字符串。 + +**参数**:待转换的字符串的指针;指向字符的指针; + +**输出**:转换后的double型浮点数。如果越界,则可能返回±HUGE_VAL, ±HUGE_VALF或±HUGE_VALL,并将errno设置为EINVAL。 + +#### atoi + +atoi()函数将字符串转换为int型整数。 + +**参数**:待转换的字符串的指针。 + +**输出**:转换后的int型数值。如果是无法显示数值,返回值不可预测。 + +#### atol + +atol()函数将字符串转换为long型整数。 + +**参数**:待转换的字符串的指针。 + +**输出**:转换后的long型数值。如果是无法显示数值,返回值不可预测。 + +#### atoll + +atoll()函数将字符串转换为long long型整数。 + +**参数**:待转换的字符串的指针。 + +**输出**:转换后的long long型数值。如果是无法显示数值,返回值不可预测。 + +#### atof + +atof()函数将字符串转换为double型浮点数。 + +**参数**:待转换的字符串的指针。 + +**输出**:转换后的double型数值。如果是无法显示数值,返回值不可预测。 + +#### bsearch + +bsearch()函数二分查找一个已排序表.将搜索一个nel对象数组,该数组的初始元素由base指向,以查找与key指向的对象匹配的元素。数组中每个元素的大小由width指定。如果nel参数的值为0,则不会调用compar所指向的比较函数,也不会找到匹配项。 + +**参数**:依次为目标查找的元素,待查找的数组的指针,数组的元素个数,数组每个元素的size大小,两个元素的比较函数。 + +**输出**:指向数组中匹配成员的指针,如果没找到则返回空指针。 + +### SystemV IPC + +#### semget + +semget()函数返回与参数key相关联的SystemV信号量集的标识符。它可用于获得先前创建的信号量集合的标识符(当flag为0且key不为IPC_PRIVATE时)或来创建一个新的集合。最多可以支持创建SEMSET_MAX_SYS_LIMIT个信号量集合,每个集合最多支持SEMSET_MAX_SEM_NUM个信号量。 + +**参数**: + +1. 键值key。 +2. 信号量的个数nsems。 +3. 信号量的创建方式和权限flag。 + +**输出**: + +- 非负数:信号量集的标识符。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- ENOENT:信号量集不存在。 +- ENOSPC:超出最大信号量集合的限制。 +- EEXIST:flag包含了IPC_CREAT和IPC_EXCL但标识符已存在。 + +#### semctl + +semctl()函数在由semid标识的SystemV信号量集合中的第semnum个信号量上执行由cmd指定的控制操作。集合中的信号量从0开始编号。当前支持的cmd包括IPC_STAT(支持获取信号量集合中的个数)、GETALL(获取信号量集合中所有信号量的值)、GETVAL(获取单个信号量的值)和IPC_RMID(根据标识符删除信号量集合)。 + +**参数**: + +1. 信号量集合标识符semid。 +2. 信号量中的编号semnum。 +3. 要执行的操作命令cmd。 +4. 可选参数union semun结构体arg。 + +**输出**: + +- 0:操作成功。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- EIDRM:信号量集合已删除。 +- EFAULT:arg中的buf或array指针为空。 + +#### semop + +semop()函数对semid关联的信号量集合中选定的信号量进行操作,也就是使用资源或者释放资源。具体操作由struct sembuf结构体来决定。结构体包括数组索引semnum,信号量操作(支持+1或-1,表示释放资源和使用资源)op,操作方式flag(支持IPC_NOWAIT,不阻塞操作)。当前只支持单个信号量的操作。 + +**参数**: + +1. 信号量集合标识符semid。 +2. 指向struct sembuf结构体的数组sops。 +3. 数组个数nsops。 + +**输出**: + +- 0:操作成功。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- ENOTSUP:操作不支持。 +- EFAULT:数组指针sops为空。 +- E2BIG:数组个数nsops超过限制。 +- EIDRM;信号量集合已删除。 +- EFBIG:某个信号量索引超过限制。 +- EAGAIN:操作无法立即进行,如flag包含了IPC_NOWAIT或超时。 + +#### semtimedop + +semtimedop()的行为与semop()相同,不同点在于增加一个超时时间,等待超时返回错误码。 + +**参数**: + +1. 信号量集合标识符semid。 +2. 指向struct sembuf结构体的数组sops。 +3. 数组个数nsops。 +4. timespec结构体指针timeout。 + +**输出**: + +- 0:操作成功。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- ENOTSUP:操作不支持。 +- EFAULT:数组指针sops为空。 +- E2BIG:数组个数nsops超过限制。 +- EIDRM;信号量集合已删除。 +- EFBIG:某个信号量索引超过限制。 +- EAGAIN:操作无法立即进行,如flag包含了IPC_NOWAIT或超时。 + +#### msgget + +msgget()返回与参数key相关联的SystemV消息队列的标识符。它可用于获得先前创建的消息队列的标识符(当flag为0且key不为IPC_PRIVATE时)或来创建一个新的消息队列。最多支持创建MSGQUE_MAX_SYS_LIMIT个消息队列,消息队列默认大小为MSGQUE_MAX_MSG_NUM,消息大小默认为MSGQUE_MAX_MSG_SIZE。 + +**参数**: + +1. 键值key。 +2. 消息队列的创建方式和权限flag。 + +**输出**: + +- 非负数:消息队列的标识符。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- ENOENT:消息队列不存在。 +- ENOSPC:超出最大消息队列的限制。 +- EEXIST:flag包含了IPC_CREAT和IPC_EXCL但标识符已存在。 +- ENOMEM:内存不足。 + +#### msgctl + +msgctl()在标识为msgqid的SystemV消息队列上执行cmd指定的控制操作。当前支持IPC_STAT(支持获取消息队列中的消息个数和大小)、IPC_RMID(删除消息队列)。 + +**参数**: + +1. 消息队列标识符msgqid。 +2. 消息队列控制命令cmd。 +3. 消息队列信息msqid_ds结构体buf。 + +**输出**: + +- 0:操作成功。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- EFAULT:msqid_ds结构体指针为空。 +- EIDRM:消息队列已删除。 +- ENOTSUP:不支持的命令。 + +#### msgsnd + +msgsnd()将msgp指向的消息追加到msgqid指定的SystemV消息队列中,如果队列有足够空间,msgsnd立即执行。消息大小不超过MSGQUE_MAX_MSG_SIZE。当前flag支持IPC_NOWAIT,表示操作不等待。 + +**参数**: + +1. 消息队列标识符msgqid。 +2. 需要发送的消息msgp。 +3. 发送消息的大小msgsz。 +4. 发送方式flag。 + +**输出**: + +- 0:操作成功。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- EFAULT:msgp指针为空。 +- EIDRM:消息队列已删除。 +- ENOTSUP:不支持的命令。 + +#### msgrcv + +msgrcv()函数将消息从msgqid指定的消息队列中移除,并放入msgp指向的缓冲区中。参数msgsz指定了缓冲区buf的大小。当前msgtype支持的值为0,flag支持IPC_NOWAIT,表示操作不等待。 + +**参数**: + +1. 消息队列标识符msgqid。 +2. 需要接受消息的缓冲区msgp。 +3. 接受消息的大小msgsz。 +4. 接受消息的类型msgtype。 +5. 发送方式flag。 + +**输出**: + +- 0:操作成功。 +- -1: 操作失败。 + +errno: + +- EINVAL:参数错误。 +- EFAULT:msgp指针为空。 +- EIDRM:消息队列已删除。 +- ENOTSUP:不支持的命令。 +- ENOMSG:消息队列中没有请求类型的消息。 + +#### shmget + +暂不支持 + +#### shmctl + +暂不支持 + +#### shmat + +暂不支持 + +#### shmdt + +暂不支持 + +#### ftok + +暂不支持 + +## C11接口 + +| 接口名 | 适配情况 | +| :---: | :-----: | +| [cnd_broadcast](#cnd_broadcast) | 支持 | +| [cnd_destroy](#cnd_destroy) | 支持 | +| [cnd_init](#cnd_init) | 支持 | +| [cnd_signal](#cnd_signal) | 支持 | +| [cnd_timedwait](#cnd_timedwait) | 支持 | +| [cnd_wait](#cnd_wait) | 支持 | +| [mtx_destroy](#mtx_destroy) | 支持 | +| [mtx_init](#mtx_init) | 支持 | +| [mtx_lock](#mtx_lock) | 支持 | +| [mtx_timedlock](#mtx_timedlock) | 支持 | +| [mtx_trylock](#mtx_trylock) | 支持 | +| [thrd_create](#thrd_create) | 支持 | +| [thrd_current](#thrd_current) | 支持 | +| [thrd_detach](#thrd_detach) | 支持 | +| [thrd_equal](#thrd_equal) | 支持 | +| [thrd_exit](#thrd_exit) | 支持 | +| [thrd_join](#thrd_join) | 支持 | +| [thrd_sleep](#thrd_sleep) | 支持 | +| [thrd_yield](#thrd_yield) | 支持 | +| [tss_create](#tss_create) | 支持 | +| [tss_delete](#tss_delete) | 支持 | +| [tss_get](#tss_get) | 支持 | +| [tss_set](#tss_set) | 支持 | + +### 条件变量管理 + +#### cnd_init + +初始化条件变量cond。同使用条件变量属性为NULL的pthread_cond_init()。 + +**参数** + +1. 条件变量指针cond。 +2. 条件变量属性指针attr。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 + +#### cnd_destroy + +销毁指定条件变量,使得该条件变量未初始化,可以使用cnd_init() 重新初始化。同pthread_cond_destory()。 + +**参数**:条件变量指针cond。 + +**输出**:无。 + +#### cnd_broadcast + +取消阻止当前等待cond所指向的条件变量的所有线程。如果没有线程被阻塞,则不执行任何操作并返回thrd_success。 + +**参数**:条件变量指针cond。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 + +#### cnd_signal + +取消阻塞在指定的条件变量cond上阻塞的线程中的至少一个(如果有任何线程在cond上被阻塞)。 + +**参数**:条件变量指针cond。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 + +#### cnd_timedwait + +阻塞当前线程等待cond指定的条件变量,并释放互斥体指定的互斥体。只有在另一个线程使用相同的条件变量调用cnd_signal() 或cnd_broadcast() 后,或者如果系统时间达到指定的时间,并且当前线程重新获得互斥锁时,等待线程才会解锁。 + +**参数**: + +1. 条件变量指针cond。 +2. 互斥锁指针m。 +3. 超时时间指针ts。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 +- thrd_timedout:阻塞超时 + +#### cnd_wait + +cnd_wait() 函数与cnd_timedwait() 类似,阻塞当前线程等待cond指定的条件变量,并释放互斥体指定的互斥体。只有在另一个线程使用相同的条件变量调用cnd_signal() 或cnd_broadcast() 后,并且当前线程重新获得互斥锁时,等待线程才会解锁。 + +**参数**: + +1. 条件变量指针cond。 +2. 互斥锁指针m。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 + +### 互斥锁管理 + +#### mtx_init + +mtx_init()函数根据属性type初始化互斥锁。 + +**参数**: + +1. 互斥锁指针mutex。 +2. 互斥锁属性type。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 + +#### mtx_destroy + +mtx_destroy() 用于注销一个互斥锁。销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。 + +**参数**:互斥锁指针mutex。 + +**输出**:无。 + +#### mtx_lock + +当pthread_mutex_lock() 返回时,该[互斥锁](https://baike.baidu.com/item/互斥锁/841823?fromModule=lemma_inlink)已被锁定。[线程](https://baike.baidu.com/item/线程/103101?fromModule=lemma_inlink)调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。 + +**参数**:互斥锁指针mutex。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 + +#### mtx_timedlock + +mtx_timedlock() 语义与mtx_lock() 类似,不同点在于锁已经被占据时增加一个超时时间,等待超时返回错误码。 + +**参数**: + +1. 互斥锁指针mutex。 +2. 超时时间指针ts。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 +- thrd_timedout:等待超时。 + +#### mtx_trylock + +mtx_trylock() 语义与 mtx_lock() 类似,不同点在于锁已经被占据时返回 thrd_busy, 而非挂起等待。 + +**参数**:互斥锁指针mutex。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_busy:mutex指定的锁已经被占据。 +- thrd_error:操作失败。 + +### 任务管理 + +#### thrd_create + +thrd_create()函数创建一个执行函数为func的新线程,创建成功后,将创建的线程的ID存储在参数 thread 的位置。 + +**参数**: + +1. 指向线程[标识符](https://baike.baidu.com/item/标识符?fromModule=lemma_inlink)的[指针](https://baike.baidu.com/item/指针?fromModule=lemma_inlink)thread。 +2. 线程处理函数的起始地址 func。 +3. 运行函数的参数 arg。 + +**输出**: + +- thrd_success:创建成功。 +- thrd_error:attr指定的属性无效。 +- thrd_nomem:系统缺少创建新线程所需的资源。 + +#### thrd_current + +返回调用线程的线程ID。 + +**参数**:无 + +**输出**:返回调用线程的线程ID。 + +#### thrd_detach + +实现线程分离,即主线程与子线程分离,子线程结束后,资源自动回收。 + +**参数**:线程ID:thread。 + +**输出**: + +- 0:成功完成。 +- EINVAL:thread是分离线程。 +- ESRCH:给定线程ID指定的线程不存在。 + +#### thrd_equal + +此函数应比较线程ID t1和t2。 + +**参数**: + +1. 线程ID t1。 +2. 线程ID t2。 + +**输出**: + +- 如果t1和t2相等,pthread_equal()函数应返回非零值。 +- 如果t1和t2不相等,应返回零。 +- 如果t1或t2不是有效的线程ID,则行为未定义。 + +#### thrd_exit + +线程的终止可以是调用 thrd_exit 或者该线程的例程结束。由此可看出,一个线程可以隐式退出,也可以显式调用 thrd_exit 函数来退出。thrd_exit 函数唯一的参数 value_ptr 是函数的返回代码,只要 thrd_join 中的第二个参数 value_ptr 不是NULL,这个值将被传递给 value_ptr。 + +**参数**:线程退出状态value_ptr,通常传NULL。 + +**输出**:无 + +#### thrd_join + +thrd_join() 函数,以阻塞的方式等待 thread 指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且 thread 指定的线程必须是 joinable 的。当 thrd_join()成功返回时,目标线程已终止。对指定同一目标线程的thrd_join()的多个同时调用的结果未定义。如果调用thrd_join()的线程被取消,则目标线程不应被分离。 + +**参数**: + +1. 线程ID:thread。 +2. 退出线程:返回值value_ptr。 + +**输出**: + +- thrd_success:操作成功。 + +#### thrd_sleep + +至少在达到time_point指向的基于TIME_UTC的时间点之前,阻塞当前线程的执行。如果收到未被忽略的信号,睡眠可能会恢复。 + +**参数**: + +1. 应等待时间:req。 +2. 实际等待时间:rem。 + +**输出**: + +- 0:操作成功。 +- -2: 操作失败。 + +#### thrd_yield + +thrd_yield()函数应强制正在运行的线程放弃处理器,并触发线程调度。 + +**参数**:无 + +**输出**:输出0时,成功完成;否则应返回值-1。 + +#### tss_create + +分配用于标识线程特定数据的键。tss_create 第一个参数为指向一个键值的[指针](https://baike.baidu.com/item/指针/2878304?fromModule=lemma_inlink),第二个参数指明了一个 destructor 函数,如果这个参数不为空,那么当每个线程结束时,系统将调用这个函数来释放绑定在这个键上的内存块。 + +**参数**: + +1. 键值的[指针](https://baike.baidu.com/item/指针/2878304?fromModule=lemma_inlink)tss。 +2. destructor 函数入口 destructor。 + +**输出**: + +- thrd_success:操作成功。 +- thrd_error:操作失败。 + +#### tss_delete + +销毁线程特定数据键。 + +**参数**:需要删除的键key。 + +**输出**:无 + +#### tss_get + +将与key关联的数据读出来,返回数据类型为 void *,可以指向任何类型的数据。需要注意的是,在使用此返回的指针时,需满足是 void 类型,虽指向关联的数据地址处,但并不知道指向的数据类型,所以在具体使用时,要对其进行强制类型转换。 + +**参数**:键值key。 + +**输出**: + +- 返回与给定 key 关联的线程特定数据值。 +- NULL:没有线程特定的数据值与键关联。 + +#### tss_set + +tss_set() 函数应将线程特定的 value 与通过先前调用 tss_create()获得的 key 关联起来。不同的线程可能会将不同的值绑定到相同的键上。这些值通常是指向已保留供调用线程使用的动态分配内存块的指针。 + +**参数**: + +1. 键值key。 +2. 指针value + +**输出**: + +- 0:设置成功。 + +## 其他接口 + +| 接口名 | 适配情况 | +| :---: | :-----: | +| [pthread_getattr_default_np](#pthread_getattr_default_np) | 支持 | +| [pthread_getattr_np](#pthread_getattr_np) | 支持 | +| [pthread_getname_np](#pthread_getattr_np) | 支持 | +| [pthread_setattr_default_np](#pthread_setattr_default_np) | 支持 | +| [pthread_setname_np](#pthread_setname_np) | 支持 | +| [pthread_timedjoin_np](#pthread_timedjoin_np) | 支持 | +| [pthread_tryjoin_np](#pthread_tryjoin_np) | 支持 | +| [ftime](#ftime) | 支持 | +| [timegm](#timegm) | 支持 | + +### pthread_getattr_default_np + +pthread_getattr_default_np() 函数初始化attr引用的线程属性对象,使其包含用于创建线程的默认属性。 + +**参数**:线程属性对象attr。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +### pthread_setattr_default_np + +pthread_setattr_default_np() 函数用于设置创建新线程的默认属性,即当使用NULL的第二个参数调用pthread_create时使用的属性。 + +**参数**:线程属性对象attr。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +### pthread_getattr_np + +pthread_getattr_np() 函数初始化attr引用的线程属性对象,使其包含描述正在运行的线程线程的实际属性值。 + +**参数**: + +1. 线程ID值thread。 +2. 线程属性对象attr。 + +**输出**: + +- 0:操作成功。 +- 非0值:操作失败。 + +### pthread_getname_np + +pthread_getname_np() 函数可用于检索线程的名称。thread参数指定要检索其名称的线程。 + +**参数**: + +1. 线程ID值thread。 +2. 线程名字符串name。 +3. 字符串大小len。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +### pthread_setname_np + +pthread_setname_np() 函数可用于设置线程的名称。 + +**参数**: + +1. 线程ID值thread。 +2. 线程名字符串name。 +3. 字符串大小len。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 + +#### pthread_timedjoin_np + +类似pthread_join,如果线程尚未终止,则调用将阻塞直到abstime中指定的最大时间。如果超时在线程终止之前到期,则调用将返回错误。 + +**参数**: + +1. 线程ID值thread。 +2. 线程退出状态status。 +3. 阻塞时间指针ts。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- ETIMEDOUT:阻塞超时。 + +### pthread_tryjoin_np + +类似pthread_join,但如果线程尚未终止,将立即返回EBUSY。 + +**参数**: + +1. 线程ID值thread。 +2. 线程退出状态status。 + +**输出**: + +- 0:操作成功。 +- EINVAL:指针未初始化。 +- EBUSY:调用时线程尚未终止。 + +### ftime + +取得当前的时间和日期,由一个timeb结构体返回。 + +**参数**: + +1. timeb结构体指针tp。 + +**输出**:无 + +### timegm + +将tm结构体表示的时间转换为自一个标准时间点以来的时间,不受本地时区的影响。 + +**参数**: + +1. tm结构体指针tp。 + +**输出**: + +返回值: + +- time_t结构体表示的时间值。 +- -1: 转换失败。 + +errno: + +- EOVERFLOW:转换溢出。 + +## math数学库 + +| 接口名 | 描述 | 输入参数 | 适配情况 | +| :---: | :-----: | :-----: | :-----: | +| [acos](#acos) | 计算参数x的反余弦值,参数x的取值范围[-1, +1],返回类型double | double类型的浮点数x | 支持 | +| [acosf](#acosf) | 计算参数x的反余弦值,参数x的取值范围[-1, +1],返回类型float | float类型的浮点数x | 支持 | +| [acosl](#acosl) | 计算参数x的反余弦值,参数x的取值范围[-1, +1],返回类型long double | long double类型的浮点数x | 支持 | +| [acosh](#acosh) | 计算参数x的反双曲余弦值,返回类型double | double类型的浮点数x | 支持 | +| [acoshf](#acoshf) | 计算参数x的反双曲余弦值,返回类型float | float类型的浮点数x | 支持 | +| [acoshl](#acoshl) | 计算参数x的反双曲余弦值,返回类型long double | long double类型的浮点数x | 支持 | +| [asin](#asin) | 计算参数x的反正弦值,参数x的取值范围为[-1, +1] | duoble类型的浮点数x | 支持 | +| [asinf](#asinf) | 计算参数x的反正弦值,参数x的取值范围为[-1, +1] | float类型的浮点数x | 支持 | +| [asinl](#asinl) | 计算参数x的反正弦值,参数x的取值范围为[-1, +1] | long double类型的浮点数x | 支持 | +| [asinh](#asinh) | 计算参数x的反双曲正弦值,返回类型double | double类型的浮点数x | 支持 | +| [asinhf](#asinhf) | 计算参数x的反双曲正弦值,返回类型float | float类型的浮点数x | 支持 | +| [asinhl](#asinhl) | 计算参数x的反双曲正弦值,返回类型long double | long double类型的浮点数x | 支持 | +| [atan](#atan) | 计算参数x的反正切值,返回类型double | double类型的浮点数x | 支持 | +| [atanf](#atanf) | 计算参数x的反正切值,返回类型float | float类型的浮点数x | 支持 | +| [atanl](#atanl) | 计算参数x的反正切值,返回类型long double | long double类型的浮点数x | 支持 | +| [atan2](#atan2) | 计算参数y除以x的反正切值,使用两个参数的符号确定返回值的象限 | double类型的浮点数y
double类型的浮点数x | 支持 | +| [atan2f](#atan2f) | 计算参数y除以x的反正切值,使用两个参数的符号确定返回值的象限 | float类型的浮点数y
float类型的浮点数x | 支持 | +| [atan2l](#atan2l) | 计算参数y除以x的反正切值,使用两个参数的符号确定返回值的象限 | long double类型的浮点数y
long double类型的浮点数x | 支持 | +| [atanh](#atanh) | 计算参数x的反双曲正切值,返回类型double | double类型的浮点数x | 支持 | +| [atanhf](#atanhf) | 计算参数x的反双曲正切值,返回类型float | float类型的浮点数x | 支持 | +| [atanhl](#atanhl) | 计算参数x的反双曲正切值,返回类型long double | long double类型的浮点数x | 支持 | +| [cbrt](#cbrt) | 计算参数x的立方根,返回类型double | double类型的浮点数x | 支持 | +| [cbrtf](#cbrtf) | 计算参数x的立方根,返回类型float | float类型的浮点数x | 支持 | +| [cbrtl](#cbrtl) | 计算参数x的立方根,返回类型long double | long double类型的浮点数x | 支持 | +| [ceil](#ceil) | 计算不小于参数x的最小整数值,返回类型double | duoble类型的浮点数x | 支持 | +| [ceilf](#ceilf) | 计算不小于参数x的最小整数值,返回类型float | float类型的浮点数x | 支持 | +| [ceill](#ceill) | 计算不小于参数x的最小整数值,返回类型long double | long duoble类型的浮点数x | 支持 | +| [copysign](#copysign) | 生成一个值,该值具有参数x的大小和参数y的符号 | duoble类型的浮点数x
double类型的浮点数y | 支持 | +| [copysignf](#copysignf) | 生成一个值,该值具有参数x的大小和参数y的符号 | float类型的浮点数x
float类型的浮点数y | 支持 | +| [copysignl](#copysignl) | 生成一个值,该值具有参数x的大小和参数y的符号 | long duoble类型的浮点数x
long double类型的浮点数y | 支持 | +| [cos](#cos) | 计算参数x的余弦值,参数应为弧度值,返回类型double | duoble类型的浮点数x | 支持 | +| [cosf](#cosf) | 计算参数x的余弦值,参数应为弧度值,返回类型float | float类型的浮点数x | 支持 | +| [cosl](#cosl) | 计算参数x的余弦值,参数应为弧度值,返回类型long double | long double类型的浮点数x | 支持 | +| [cosh](#cosh) | 计算参数x的双曲余弦值,返回类型double | double类型的浮点数x | 支持 | +| [coshf](#coshf) | 计算参数x的双曲余弦值,返回类型float | float类型的浮点数x | 支持 | +| [coshl](#coshl) | 计算参数x的双曲余弦值,返回类型long double | long double类型的浮点数x | 支持 | +| [erf](#erf) | 计算参数x的高斯误差函数的值 | double类型的浮点数x | 支持 | +| [erff](#erff) | 计算参数x的高斯误差函数的值 | float类型的浮点数x | 支持 | +| [erfl](#erfl) | 计算参数x的高斯误差函数的值 | long double类型的浮点数x | 支持 | +| [erfc](#erfc) | 计算参数x的高斯误差函数的值 | double类型的浮点数x | 支持 | +| [erfcf](#erfcf) | 计算参数x的互补误差函数的值 | float类型的浮点数x | 支持 | +| [erfcl](#erfcl) | 计算参数x的互补误差函数的值 | long double类型的浮点数x | 支持 | +| [exp](#exp) | 以e为基数的指数,即$e^x$的值,返回类型double | double类型的浮点数x | 支持 | +| [expf](#expf) | 以e为基数的指数,即$e^x$的值,返回类型float | float类型的浮点数x | 支持 | +| [expl](#expl) | 以e为基数的指数,即$e^x$的值,返回类型long double | long double类型的浮点数x | 支持 | +| [exp10](#exp10) | 以10为基数的指数,即$10^x$的值,返回类型double | double类型的浮点数x | 支持 | +| [exp10f](#exp10f) | 以10为基数的指数,即$10^x$的值,返回类型float | float类型的浮点数x | 支持 | +| [exp10l](#exp10l) | 以10为基数的指数,即$10^x$的值,返回类型long double | long double类型的浮点数x | 支持 | +| [exp2](#exp2) | 以2为基数的指数函数,返回类型double | double类型的浮点数x | 支持 | +| [exp2f](#exp2f) | 以2为基数的指数函数,返回类型float | float类型的浮点数x | 支持 | +| [exp2l](#exp2l) | 以2为基数的指数函数,返回类型long double | long double类型的浮点数x | 支持 | +| [expm1](#expm1) | 计算$e^x - 1$的值。如果参数x是个小值,expm1(x)函数的值比表达式$e^x - 1$更准确 | double类型的浮点数x | 支持 | +| [expm1f](#expm1f) | 计算$e^x - 1$的值。如果参数x是个小值,expm1(x)函数的值比表达式$e^x - 1$更准确 | float类型的浮点数x | 支持 | +| [expm1l](#expm1l) | 计算$e^x - 1$的值。如果参数x是个小值,expm1(x)函数的值比表达式$e^x - 1$更准确 | long double类型的浮点数x | 支持 | +| [fabs](#fabs) | 计算参数x的绝对值,返回类型double | double类型的浮点数x | 支持 | +| [fabsf](#fabsf) | 计算参数x的绝对值,返回类型float | float类型的浮点数x | 支持 | +| [fabsl](#fabsl) | 计算参数x的绝对值,返回类型long double | long double类型的浮点数x | 支持 | +| [fdim](#fdim) | 计算参数x和参数y之间的正差值 | double类型的浮点数x
double类型的浮点数y | 支持 | +| [fdimf](#fdimf) | 计算参数x和参数y之间的正差值 | float类型的浮点数x
float类型的浮点数y | 支持 | +| [fdiml](#fdiml) | 计算参数x和参数y之间的正差值 | long double类型的浮点数x
long double类型的浮点数y | 支持 | +| [finite](#finite) | 如果参数x既不是无限值也不是NaN,则返回一个非零值,否则返回0 | double类型的浮点数x | 支持 | +| [finitef](#finitef) | 如果参数x既不是无限值也不是NaN,则返回一个非零值,否则返回0 | float类型的浮点数x| 支持 | +| [floor](#floor) | 计算不大于参数x到最大整数值,返回类型double | double类型的浮点数x | 支持 | +| [floorf](#floorf) | 计算不大于参数x到最大整数值,返回类型float | float类型的浮点数x | 支持 | +| [floorl](#floorl) | 计算不大于参数x到最大整数值,返回类型long double | long double类型的浮点数x | 支持 | +| [fma](#fma) | 计算表达式$(x * y) + z$的值,返回double类型 | double类型的浮点数x
double类型的浮点数y
double类型的浮点数z | 支持 | +| [fmaf](#fmaf) | 计算表达式$(x * y) + z$的值,返回float类型 | float类型的浮点数x
float类型的浮点数y
float类型的浮点数z | 支持 | +| [fmal](#fmal) | 计算表达式$(x * y) + z$的值,返回long double类型 | long double类型的浮点数x
long double类型的浮点数y
long double类型的浮点数z | 支持 | +| [fmax](#fmax) | 确定其参数的最大数值。如果一个参数是非数值(NaN),另一个参数是数值,fmax函数将选择数值 | double类型的浮点数x
double类型的浮点数y | 支持 | +| [fmaxf](#fmaxf) | 确定其参数的最大数值。如果一个参数是非数值(NaN),另一个参数是数值,fmax函数将选择数值 | float类型的浮点数x
float类型的浮点数y | 支持 | +| [fmaxl](#fmaxl) | 确定其参数的最大数值。如果一个参数是非数值(NaN),另一个参数是数值,fmax函数将选择数值 | long double类型的浮点数x
long double类型的浮点数y | 支持 | +| [fmin](#fmin) | 返回其参数的最小数值。非数值NaN参数视为缺失数据。如果一个参数是非数值,另一个参数是数值,fmin函数将选择数值 | double类型的浮点数x
double类型的浮点数y | 支持 | +| [fminf](#fminf) | 返回其参数的最小数值。非数值NaN参数视为缺失数据。如果一个参数是非数值,另一个参数是数值,fmin函数将选择数值 | float类型的浮点数x
float类型的浮点数y | 支持 | +| [fminl](#fminl) | 返回其参数的最小数值。非数值NaN参数视为缺失数据。如果一个参数是非数值,另一个参数是数值,fmin函数将选择数值 | long double类型的浮点数x
long double类型的浮点数y | 支持 | +| [fmod](#fmod) | 计算表达式x/y的浮点余数,返回double类型 | double类型的浮点数x
double类型的浮点数y | 支持 | +| [fmodf](#fmodf) | 计算表达式x/y的浮点余数,返回float类型 | float类型的浮点数x
float类型的浮点数y | 支持 | +| [fmodl](#fmodl) | 计算表达式x/y的浮点余数,返回long double类型 | long double类型的浮点数x
long double类型的浮点数y | 支持 | +| [frexp](#frexp) | 将浮点数分解为规格化小数和2的整数幂,并将整数存入参数exp指向的对象中 | double类型的浮点数x
int *类型的浮点数y | 支持 | +| [frexpf](#frexpf) | 将浮点数分解为规格化小数和2的整数幂,并将整数存入参数exp指向的对象中 | float类型的浮点数x
int *类型的浮点数y | 支持 | +| [frexpl](#frexpl) | 将浮点数分解为规格化小数和2的整数幂,并将整数存入参数exp指向的对象中 | long double类型的浮点数x
int *类型的浮点数y | 支持 | +| [hypot](#hypot) | 计算表达式$(x^2 + y^2)^{1/2}$的值 | double类型的浮点数x
double类型的浮点数y | 支持 | +| [hypotf](#hypotf) | 计算表达式$(x^2 + y^2)^{1/2}$的值 | float类型的浮点数x
float类型的浮点数y | 支持 | +| [hypotl](#hypotl) | 计算表达式$(x^2 + y^2)^{1/2}$的值 | long double类型的浮点数x
long double类型的浮点数y | 支持 | +| [ilogb](#ilogb) | 以FLT_RADIX作为对数的底数,返回double类型x的对数的整数部分 | double类型的浮点数x | 支持 | +| [ilogbf](#ilogbf) | 以FLT_RADIX作为对数的底数,返回float类型x的对数的整数部分 | float类型的浮点数x | 支持 | +| [ilogbl](#ilogbl) | 以FLT_RADIX作为对数的底数,返回long double类型x的对数的整数部分 | long double类型的浮点数x | 支持 | +| [j0](#j0) | 计算参数x的第一类0阶贝塞尔函数 | double类型浮点数x | 支持 | +| [j0f](#j0f) | 计算参数x的第一类0阶贝塞尔函数 | float类型浮点数x | 支持 | +| [j1](#j1) | 计算参数x的第一类1阶贝塞尔函数 | double类型浮点数x | 支持 | +| [j1f](#j1f) | 计算参数x的第一类1阶贝塞尔函数 | float类型浮点数x | 支持 | +| [jn](#jn) | 计算参数x的第一类n阶贝塞尔函数 | int类型阶数
double类型浮点数x | 支持 | +| [jnf](#jnf) | 计算参数x的第一类n阶贝塞尔函数 | int类型阶数
float类型浮点数x | 支持 | +| [ldexp](#ldexp) | 计算参数x与2的exp次幂的乘积,即返回$x * 2^{exp}$的double类型值。 | double类型的浮点数x
int类型的指数exp | 支持 | +| [ldexpf](#ldexpf) | 计算参数x与2的exp次幂的乘积,即返回$x * 2^{exp}$的float类型值。 | float类型的浮点数x
int类型的指数exp | 支持 | +| [ldexpl](#ldexpl) | 计算参数x与2的exp次幂的乘积,即返回$x * 2^{exp}$的long double类型值。 | long double类型的浮点数x
int类型的指数exp | 支持 | +| [lgamma](#lgamma) | 计算参数x伽玛绝对值的自然对数,返回double类型 | double类型的浮点数x | 支持 | +| [lgammaf](#lgammaf) | 计算参数x伽玛绝对值的自然对数,返回float类型 | float类型的浮点数x | 支持 | +| [lgammal](#lgammal) | 计算参数x伽玛绝对值的自然对数,返回long double类型 | long double类型的浮点数x | 支持 | +| [lgamma_r](#lgamma_r) | 计算参数x伽玛绝对值的自然对数,与lgamma不同在于是线程安全的 | double类型的浮点数x
int *类型符号参数 | 支持 | +| [lgamma_r](#lgamma_r) | 计算参数x伽玛绝对值的自然对数,与lgamma不同在于是线程安全的 | float类型的浮点数x
int *类型符号参数 | 支持 | +| [llrint](#llrint) | 根据当前舍入模式,将参数舍入为long long int类型的最接近整数值 | double类型的浮点数x | 支持 | +| [llrintf](#llrintf) | 根据当前舍入模式,将参数舍入为long long int类型的最接近整数值 | float类型的浮点数x | 支持 | +| [llrintl](#llrintl) | 根据当前舍入模式,将参数舍入为long long int类型的最接近整数值 | long double类型的浮点数x | 支持 | +| [llround](#llround) | 将double类型x舍入为浮点形式表示的long long int型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | double类型的浮点数x | 支持 | +| [llroundf](#llroundf) | 将float类型x舍入为浮点形式表示的long long int型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | float类型的浮点数x | 支持 | +| [llroundl](#llroundl) | 将long double类型x舍入为浮点形式表示的long long int型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | long double类型的浮点数x | 支持 | +| [log](#log) | double类型x的自然对数函数 | double类型的浮点数x | 支持 | +| [logf](#logf) | float类型x的自然对数函数 | float类型的浮点数x | 支持 | +| [logl](#logl) | long double类型x的自然对数函数 | long double类型的浮点数x | 支持 | +| [log10](#log10) | double类型x以10为底数的对数函数 | double类型的浮点数x | 支持 | +| [log10f](#log10f) | float类型x以10为底数的对数函数 | float类型的浮点数x | 支持 | +| [log10l](#log10l) | long double类型x以10为底数的对数函数 | long double类型的浮点数x | 支持 | +| [log1p](#log1p) | 以e为底数的对数函数,计算$log_e(1 + x)$的值。如果参数x是个小值,表达式log1p(x)比表达式log(1 + x)更准确 | double类型的浮点数x | 支持 | +| [log1pf](#log1pf) | 以e为底数的对数函数,计算$log_e(1 + x)$的值。如果参数x是个小值,表达式log1p(x)比表达式log(1 + x)更准确 | float类型的浮点数x | 支持 | +| [log1pl](#log1pl) | 以e为底数的对数函数,计算$log_e(1 + x)$的值。如果参数x是个小值,表达式log1p(x)比表达式log(1 + x)更准确 | long double类型的浮点数x | 支持 | +| [log2](#log2) | double类型x以2为底数的对数函数 | double类型的浮点数x | 支持 | +| [log2f](#log2f) | float类型x以2为底数的对数函数 | flaot类型的浮点数x | 支持 | +| [log2l](#log2l) | long double类型x以2为底数的对数函数 | long double类型的浮点数x | 支持 | +| [logb](#logb) | double类型x以FLT_RADIX为的底数到对数函数 | double类型的浮点数x | 支持 | +| [logbf](#logbf) | float类型x以FLT_RADIX为的底数到对数函数 | float类型的浮点数x | 支持 | +| [logbl](#logbl) | double类型x以FLT_RADIX为的底数到对数函数 | double类型的浮点数x | 支持 | +| [lrint](#lrint) | 根据当前舍入模式,将参数舍入为long int类型的最接近整数值 | double类型的浮点数x | 支持 | +| [lrintf](#lrintf) | 根据当前舍入模式,将参数舍入为long int类型的最接近整数值 | float类型的浮点数x | 支持 | +| [lrintl](#lrintl) | 根据当前舍入模式,将参数舍入为long int类型的最接近整数值 | long double类型的浮点数x | 支持 | +| [lround](#lround) | 将double类型x舍入为浮点形式表示的long int型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | double类型的浮点数x | 支持 | +| [lroundf](#lroundf) | 将float类型x舍入为浮点形式表示的long int型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | float类型的浮点数x | 支持 | +| [lroundl](#lroundl) | 将long double类型x舍入为浮点形式表示的long int型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | long double类型的浮点数x | 支持 | +| [modf](#modf) | 将double类型的参数value分成整数部分和小数部分,两部分与参数value具有相同的类型和符号。整数部分以浮点形式存入参数iptr指向的对象中 | double类型的浮点数value
double *类型的指数iptr | 支持 | +| [modff](#modff) | 将float类型的参数value分成整数部分和小数部分,两部分与参数value具有相同的类型和符号。整数部分以浮点形式存入参数iptr指向的对象中 | float类型的浮点数value
float *类型的指数iptr | 支持 | +| [modfl](#modfl) | 将long double类型的参数value分成整数部分和小数部分,两部分与参数value具有相同的类型和符号。整数部分以浮点形式存入参数iptr指向的对象中 | long double类型的浮点数value
long double *类型的指数iptr | 支持 | +| [nan](#nan) | 返回一个double类型的非数值NaN,内容由参数tagp确定 | const char*类型tagp | 支持 | +| [nanf](#nanf) | 返回一个float类型的非数值NaN,内容由参数tagp确定 | const char*类型tagp | 支持 | +| [nanl](#nanl) | 返回一个long double类型的非数值NaN,内容由参数tagp确定 | const char*类型tagp | 支持 | +| [nearbyint](#nearbyint) | 根据当前舍入模式,将double型参数x舍入为浮点格式的double型整数值 | double类型x | 支持 | +| [nearbyintf](#nearbyintf) | 根据当前舍入模式,将float型参数x舍入为浮点格式的float型整数值 | float类型x | 支持 | +| [nearbyintl](#nearbyintl) | 根据当前舍入模式,将long double型参数x舍入为浮点格式的double型整数值 | long double类型x | 支持 | +| [nextafter](#nextafter) | 返回double类型参数x沿参数y方向的下一个可表示值 | double类型x
double类型y | 支持 | +| [nextafterf](#nextafterf) | 返回double类型参数x沿参数y方向的下一个可表示值 | float类型x
flaot类型y | 支持 | +| [nextafterl](#nextafterl) | 返回double类型参数x沿参数y方向的下一个可表示值 | long double类型x
long double类型y | 支持 | +| [nexttoward](#nexttoward) | 返回double类型参数x沿参数y方向的下一个可表示值,等价于nextafter,区别在于参数y为long double | double类型浮点数x
long double类型浮点数y | 支持 | +| [nexttowardf](#nexttowardf) | 返回double类型参数x沿参数y方向的下一个可表示值,等价于nextafter,区别在于参数y为long double | float类型浮点数x
long double类型浮点数y | 支持 | +| [nexttowardl](#nexttowardl) | 返回double类型参数x沿参数y方向的下一个可表示值,等价于nextafter,区别在于参数y为long double | long double类型浮点数x
long double类型浮点数y | 支持 | +| [pow](#pow) | 计算表达式$x^y$的值 | double类型浮点数x
double类型浮点数y | 支持 | +| [powf](#powf) | 计算表达式$x^y$的值 | float类型浮点数x
float类型浮点数y | 支持 | +| [powl](#powl) | 计算表达式$x^y$的值 | long double类型浮点数x
long double类型浮点数y | 支持 | +| [pow10](#pow10) | 计算表达式$10^x$的值 | double类型浮点数x | 支持 | +| [pow10f](#pow10f) | 计算表达式$10^x$的值 | float类型浮点数x| 支持 | +| [pow10l](#pow10l) | 计算表达式$10^x$的值 | long double类型浮点数x | 支持 | +| [remainder](#remainder) | 计算参数x除以y的余数,等同于drem | double类型浮点数x
double类型浮点数y | 支持 | +| [remainderf](#remainderf) | 计算参数x除以y的余数,等同于dremf | float类型浮点数x
float类型浮点数y | 支持 | +| [remainderl](#remainderl) | 计算参数x除以y的余数 | long double类型浮点数x
long double类型浮点数y | 支持 | +| [remquo](#remquo) | 计算参数x和参数y的浮点余数,并将商保存在传递的参数指针quo中 | double类型浮点数x
double类型浮点数y
int *类型商que | 支持 | +| [remquof](#remquof) | 计算参数x和参数y的浮点余数,并将商保存在传递的参数指针quo中 | float类型浮点数x
float类型浮点数y
int *类型商que | 支持 | +| [remquol](#remquol) | 计算参数x和参数y的浮点余数,并将商保存在传递的参数指针quo中 | long double类型浮点数x
long double类型浮点数y
int *类型商que | 支持 | +| [rint](#rint) | 根据当前舍入模式,将参数x舍入为浮点个数的整数值 | double类型的浮点数x | 支持 | +| [rintf](#rintf) | 根据当前舍入模式,将参数x舍入为浮点个数的整数值 | float类型的浮点数x | 支持 | +| [rintl](#rintl) | 根据当前舍入模式,将参数x舍入为浮点个数的整数值 | long double类型的浮点数x | 支持 | +| [round](#round) | 将double类型x舍入为浮点形式表示的double型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | double类型的浮点数x | 支持 | +| [roundf](#roundf) | 将float类型x舍入为浮点形式表示的float型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | float类型的浮点数x | 支持 | +| [roundl](#roundl) | 将long double类型x舍入为浮点形式表示的long double型最近整数值。如果x位于两个整数中心,将向远离0的方向舍入。 | long double类型的浮点数x | 支持 | +| [scalb](#scalb) | 计算$x * FLT\_RADIX^{exp}$的double类型值 | double类型的浮点数x
double类型的指数exp | 支持 | +| [scalbf](#scalbf) | 计算$x * FLT\_RADIX^{exp}$的float类型值 | float类型的浮点数x
float类型的指数exp | 支持 | +| [scalbln](#scalbln) | 计算$x * FLT\_RADIX^{exp}$的double类型值 | double类型的浮点数x
long类型的指数exp | 支持 | +| [scalblnf](#scalblnf) | 计算$x * FLT\_RADIX^{exp}$的float类型值 | float类型的浮点数x
long类型的指数exp | 支持 | +| [scalblnl](#scalblnl) | 计算$x * FLT\_RADIX^{exp}$的long double类型值 | long double类型的浮点数x
long类型的指数exp | 支持 | +| [scalbn](#scalbn) | 计算$x * FLT\_RADIX^{exp}$的double类型值 | double类型的浮点数x
int类型的指数exp | 支持 | +| [scalbnf](#scalbnf) | 计算$x * FLT\_RADIX^{exp}$的float类型值 | float类型的浮点数x
int类型的指数exp | 支持 | +| [scalbnl](#scalbnl) | 计算$x * FLT\_RADIX^{exp}$的long double类型值 | long double类型的浮点数x
int类型的指数exp | 支持 | +| [significand](#significand) | 用于分离浮点数x的尾数部分,返回double类型 | double类型的浮点数x | 支持 | +| [significandf](#significandf) | 用于分离浮点数x的尾数部分,返回double类型 | double类型的浮点数x | 支持 | +| [sin](#sin) | 计算参数x的正弦值,参数应为弧度值,返回double类型 | double类型的浮点数x | 支持 | +| [sinf](#sinf) | 计算参数x的正弦值,参数应为弧度值,返回float类型 | float类型的浮点数x | 支持 | +| [sinl](#sinl) | 计算参数x的正弦值,参数应为弧度值,返回long double类型 | long double类型的浮点数x | 支持 | +| [sincos](#sincos) | 同时计算参数x的正弦值和余弦值,并将结果存储在*sin和*cos,比单独调用sin和cos效率更高 | double类型的浮点数x
double*类型的浮点数sin
double*类型的浮点数cos | 支持 | +| [sincosf](#sincosf) | 同时计算参数x的正弦值和余弦值,并将结果存储在*sin和*cos,比单独调用sin和cos效率更高 | float类型的浮点数x
float*类型的浮点数sin
float*类型的浮点数cos | 支持 | +| [sincosl](#sincosl) | 同时计算参数x的正弦值和余弦值,并将结果存储在*sin和*cos,比单独调用sin和cos效率更高 | long double类型的浮点数x
long double*类型的浮点数sin
long double*类型的浮点数cos | 支持 | +| [sinh](#sinh) | 计算参数x的双曲正弦值,返回double类型 | double类型的浮点数x | 支持 | +| [sinhf](#sinhf) | 计算参数x的双曲正弦值,返回float类型 | float类型的浮点数x | 支持 | +| [sinhl](#sinhl) | 计算参数x的双曲正弦值,返回long double类型 | long double类型的浮点数x | 支持 | +| [sqrt](#sqrt) | 计算参数x的平方根,返回类型double | double类型的浮点数x | 支持 | +| [sqrtf](#sqrtf) | 计算参数x的平方根,返回类型float | float类型的浮点数x | 支持 | +| [sqrtl](#sqrtl) | 计算参数x的平方根,返回类型long double | long double类型的浮点数x | 支持 | +| [tan](#tan) | 计算参数x的正切值,参数应为弧度值,返回double类型 | double类型的浮点数x | 支持 | +| [tanf](#tanf) | 计算参数x的正切值,参数应为弧度值,返回float类型 | float类型的浮点数x | 支持 | +| [tanl](#tanl) | 计算参数x的正切值,参数应为弧度值,返回long double类型 | long double类型的浮点数x | 支持 | +| [tanh](#tanh) | 计算参数x的双曲正切值,返回double类型 | double类型的浮点数x | 支持 | +| [tanhf](#tanhf) | 计算参数x的双曲正切值,返回float类型 | float类型的浮点数x | 支持 | +| [tanhl](#tanhl) | 计算参数x的双曲正切值,返回long double类型 | long double类型的浮点数x | 支持 | +| [tgamma](#tgamma) | 计算参数x的伽马函数,返回double类型 | double类型的浮点数x | 支持 | +| [tgammaf](#tgammaf) | 计算参数x的伽马函数,返回float类型 | float类型的浮点数x | 支持 | +| [tgammal](#tgammal) | 计算参数x的伽马函数,返回long double类型 | long double类型的浮点数x | 支持 | +| [trunc](#trunc) | 截取参数x的整数部分,并将整数部分以浮点形式表示 | double类型的浮点数x | 支持 | +| [truncf](#truncf) | 截取参数x的整数部分,并将整数部分以浮点形式表示 | float类型的浮点数x | 支持 | +| [truncl](#truncl) | 截取参数x的整数部分,并将整数部分以浮点形式表示 | long double类型的浮点数x | 支持 | +| [y0](#y0) | 计算参数x的第二类0阶贝塞尔函数 | double类型的浮点数x | 支持 | +| [y0f](#y0f) | 计算参数x的第二类0阶贝塞尔函数 | float类型的浮点数x | 支持 | +| [y1](#y1) | 计算参数x的第二类1阶贝塞尔函数 | double类型的浮点数x | 支持 | +| [y1f](#y1f) | 计算参数x的第二类1阶贝塞尔函数 | float类型的浮点数x | 支持 | +| [yn](#yn) | 计算参数x的第二类n阶贝塞尔函数 | int类型阶数n
double类型的浮点数x | 支持 | +| [ynf](#ynf) | 计算参数x的第二类n阶贝塞尔函数 | int类型阶数n
float类型的浮点数x | 支持 | + +## 设备驱动 + +### register_driver + +在文件系统中注册一个字符设备驱动程序。 + +**参数**: + +1. 要创建的索引节点的路径path。 +2. file_operations结构体指针fops。 +3. 访问权限mode。 +4. 将与inode关联的私有用户数据priv。 + +**输出**: + +- 0:操作成功。 +- 负数值:操作失败。 + +#### unregister_driver + +从文件系统中删除“path”处的字符驱动程序。 + +**参数**: + +1. 要删除的索引节点的路径path。 + +**输出**: + +- 0:操作成功。 +- -EINVAL:无效的path路径。 +- -EEXIST:path中已存在inode。 +- -ENOMEM:内存不足。 + +#### register_blockdriver + +在文件系统中注册一个块设备驱动程序。 + +**参数**: + +1. 要创建的索引节点的路径path。 +2. block_operations结构体指针bops。 +3. 访问权限mode。 +4. 将与inode关联的私有用户数据priv。 + +**输出**: + +- 0:操作成功。 +- -EINVAL:无效的path路径。 +- -EEXIST:path中已存在inode。 +- -ENOMEM:内存不足。 + +#### unregister_blockdriver + +从文件系统中删除“path”处的块设备驱动程序。 + +**参数**: + +1. 要删除的索引节点的路径path。 + +**输出**: + +- 0:操作成功。 +- -EINVAL:无效的path路径。 +- -EEXIST:path中已存在inode。 +- -ENOMEM:内存不足。 + +## Shell模块 + +### SHELLCMD_ENTRY + +向Shell模块静态注册命令。 + +**参数**: + +1. 命令变量名name。 +2. 命令类型cmdType。 +3. 命令关键字cmdKey。 +4. 处理函数的入参最大个数paraNum。 +5. 命令处理函数回调cmdHook。 + +**输出**:无 + +### osCmdReg + +向Shell模块动态注册命令。 + +**参数**: + +1. 命令类型cmdType。 +2. 命令关键字cmdKey。 +3. 处理函数的入参最大个数paraNum。 +4. 命令处理函数回调cmdHook。 + +**输出**: + +- 0:操作成功。 +- OS_ERRNO_SHELL_NOT_INIT:shell模块未初始化。 +- OS_ERRNO_SHELL_CMDREG_PARA_ERROR:无效的输入参数。 +- OS_ERRNO_SHELL_CMDREG_CMD_ERROR:无效的字符串关键字。 +- OS_ERRNO_SHELL_CMDREG_CMD_EXIST:关键字已存在。 +- OS_ERRNO_SHELL_CMDREG_MEMALLOC_ERROR:内存不足。 diff --git a/docs/zh/embedded/uniproton/uniproton_functions.md b/docs/zh/embedded/uniproton/uniproton_functions.md new file mode 100644 index 0000000000000000000000000000000000000000..f716755bd8f8baf7b0e9d29342c5a7033f4290f6 --- /dev/null +++ b/docs/zh/embedded/uniproton/uniproton_functions.md @@ -0,0 +1,160 @@ +# UniProton 功能设计 + +## 支持任务管理 + +UniProton 是一个单进程支持多线程的操作系统。在 UniProton 中,一个任务表示一个线程。UniProton 中的任务为抢占式调度机制,而非时间片轮转调度方式。高优先级的任务可打断低优先级任务,低优先级任务必须在高优先级任务挂起或阻塞后才能得到调度。 + +UniProton 的任务一共有32个优先级(0-31),最高优先级为0,最低优先级为31。每个优先级可以创建多个任务。 + +UniProton 任务管理模块提供任务创建、任务删除、任务挂起、任务恢复、任务延时、锁任务调度、解锁任务调度、当前任务ID获取、任务私有数据获取与设置、查询指定任务正在 Pending 的信号量 ID、查询指定任务状态、上下文信息、任务通用信息、任务优先级设定与获取、调整指定优先级的任务调度顺序、注册及取消任务创建钩子、任务删除钩子、任务切换钩子等功能。UniProton 在初始化阶段,默认会创建一个最低优先级的 IDLE 任务,用户在没有处于运行态的任务时,IDLE 任务被运行。 + +## 支持事件管理 + +事件机制可以实现线程之间的通讯。事件通讯只能是事件类型的通讯,无数据传输。 + +UniProton 事件作为任务的扩展,实现任务之间的通讯。每个任务支持32种类型事件(32个 bit 位,每 bit 代表一种事件类型)。 + +UniProton 提供读取本任务事件和写指定任务事件的功能。读事件时可以同时读取多种事件,也可以只读取一种事件,写事件时也可以同时写一种或多种类型事件。 + +## 支持队列管理 + +队列(Queue),又称消息队列,是线程间实现通信的一种方式,实现了数据的存储和传递功能。根据优先级可以将数据写入到队列头或队列尾,但只能从队列的头处读取数据。 + +UniProton 创建队列时,根据用户传入队列长度和消息单元大小来开辟相应的内存空间以供该队列使用。在队列控制块中维护一个头指针 Head 和一个尾指针 Tail 来表示当前队列中数据存储情况。头指针 Head 表示队列中被占用消息的起始地址,尾指针 Tail 表示队列中空闲消息的起始地址。 + +## 支持硬中断管理 + +硬中断是由硬件触发的会改变系统运行轨迹的一个电平信号,硬中断用于通知 CPU 某个硬件事件的发生。硬中断一般分为可屏蔽中断和不可屏蔽中断(NMI)两种。 + +硬中断的优先级高于所有任务,其内部也有不同的优先级,当同时有多个硬中断被触发时,最高优先级的硬中断总是优先得到响应。高优先级硬中断是否能打断正在执行的低优先级硬中断(即中断嵌套),视不同芯片平台而异。 + +出于任务延时、软件定时器等需要,OS 会在初始化阶段,创建1个 Tick 硬中断,其实质是一个周期性的硬件定时器。 + +## 支持内存管理 + +内存管理主要工作是动态的划分并管理用户分配好的大片内存区间。当程序某一部分需要使用内存,可以通过操作系统的内存申请函数索取指定大小内存块,一旦使用完毕,通过内存释放函数归还所占用内存,使之可以重复使用。 + +目前 UniProton 提供了 FSC 内存算法,该算法优缺点及应用场景如下表所示: + +| 内存算法 | 优点 | 缺点 | 应用场景 | +| :----------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------ | ------------------------------------ | +| 类型私有 FSC 算法 | 内存控制块信息占用内存较少,支持最小4字节对齐的内存块大小申请;支持相邻内存块的快速分割合并,无内存碎片。 | 内存申请和内存释放的效率较低。 | 能够灵活适应各种产品的场景。 | + +如下简要描述一下FSC内存算法: + +### FSC内存算法 + +#### 核心思想 + +对于申请的内存大小为 uwSize,如果用二进制,则表示为 0b{0}1xxx,{0}表示1前面可能有0个或多个零。无论1后面xxx为何内容,如果将1变成10,xxx 则全部变成0,则总会出现 10yyy > 1xxx(此处yyy表示xxx的对应位全部变成0)。 + +我们可以直接得到最左边的1的下标。下标值或者从高位到低位依次为0-31(BitMap),或者从低位到高位依次为0-31(uwSize)。如果32位寄存器从高位到低位的bit位的下标依次为0-31,则 0x80004000 的最左边1的下标为0。于是我们可以维护一个空闲链表头数组(元素数不超过31),以内存块大小最左边的1的下标做为链表头的数组索引,即将所有最左边的1的下标相同的内存块挂接在同一个空闲链表中。 + +如:索引为2的链表可挂接的空闲块大小为4、5、6、7;索引为N的链表可挂接的空闲块大小为2^N到2^(N+1)-1。 + +![](./figures/FCS.png) + +#### 内存申请 + +当申请 uwSize 大小的内存时,首先利用汇编指令得到最左边的1的下标,假定为n。为确保空闲链表中的第一个空闲内存块满足 uwSize,从索引为 n+1 开始搜索。若 n+1 所属空闲链表不为空,则取该链表中的第一个空闲块。若 n+1 链表为空,则判断 n+2 链表,依次类推,直到找到非空链表或索引达到31。 + +为避免 for 循环逐级判断空闲链表是否为空,定义一个32位的 BitMap 全局变量。若索引n的空闲链表非空,则 BitMap 的下标为n的位置1,否则清0。BitMap 的下标为31的位在初始化时直接置1。于是查找从 n+1 开始的第一个非空闲链表,可以首先将 BitMap 复本的0到n位清零,然后获取复本的最左边的1的下标,若不等于31,即为第一个空闲链表非空的数组索引。 + +所有的空闲块都以双向链表形式,串接在空闲链表中。若从链表中获取的第一个空闲块比较大,即分割出一个 usSiz e的内存块后,剩下的空间至少可做一次最小分配。则将剩余的空闲块调整到对应的空闲链表中。 + + ![](./figures/MemoryApplication.png) + +内存控制头中记录有空闲内存块的大小(包括控制头本身)。内存控制头中有一个复用成员,位于最首部时。当内存块空闲时,作为指向后一个空闲内存块的指针;当内存块占用时,存放魔术字,表示该内存块非空闲。为避免魔术字与指针冲突(与地址值相同),高低4位均为0xf。因为已分配的内存块起始地址需按4字节对齐,所以不存在冲突。 + +#### 内存释放 + +当释放内存时,需要将前后相邻的空闲块进行合并。首先,通过判断控制头中的魔术字,确认地址参数(pAddr)的合法性。通过首地址加偏移值的方式,得到后邻的内存块控制头的起始地址。若后邻内存块是空闲的,则将后邻内存块从所属空闲链表中删除,调整当前内存块的大小。 + +为了使内存释放时能迅速找到前邻的内存块控制头,及判断前邻的内存块是否空闲。内存控制头中增加一个成员,标记前邻的内存块是否空闲。可在内存申请的时,将后邻的该标记设置为占用态(若空闲内存块被分割成两块,前一块为空闲,将当前内存块的该标记设置为空闲态);在内存释放时,将后邻的该标记设置为空闲态。释放当前内存时,若前邻的内存块标记为使用,则不需要合并前邻的内存块;若前邻的内存块标记为空闲,则需要进行合并。若某个内存块为空闲时,则将其后邻控制块的标记设为到本控制块的距离值。 + + ![](./figures/MemoryRelease.png) + +## 支持定时器管理 + +定时器管理是为满足产品定时业务需要,UniProton 提供了软件定时器功能。 + +对于软件定时器,是基于 Tick 实现,所以定时周期必须为 Tick 的整数倍,在 Tick 处理函数中进行软件定时器的超时扫描。 + +目前提供的软件定时器接口,可以完成定时器创建,启动,停止,重启,删除操作。 + +## 支持信号量管理 + +信号量(Semaphore)常用于协助一组互相竞争的任务来访问临界资源,在需要互斥的场合作为临界资源计数使用,根据临界资源使用场景分为核内信号量和核间信号量。 + +信号量对象有一个内部计数器,它支持如下两种操作: + +- 申请(Pend):Pend 操作等待指定的信号量,若其计数器值大于0,则直接减1返回成功。否则任务阻塞,等待其他线程发布该信号量,等待的容忍时间可设定。 + +- 释放(Post):Post 操作发布指定的信号量,若无任务等待该信号量,则直接将计数器加1返回。否则唤醒为此信号量挂起的任务列表中的第一个任务(最早阻塞的)。 + +通常一个信号量的计数值用于对应有效的资源数,表示剩余可被占用的互斥资源数。其值的含义如下有两种情况: + +- 为0值:表示没有积累下来的Post操作,且有可能有在此信号量上阻塞的任务。 + +- 为正值:表示有一个或多个Post下来的发布操作。 + +## 支持异常管理 + +UniProton 中的异常接管属于维测特性,其主要目的是在系统出现异常后,记录尽可能多的异常现场信息,便于后续问题定位。同时提供异常时的钩子函数,便于用户能够在异常发生时做一些用户化的特殊处理。其主要功能是接管内部异常处理或者外部硬件异常。 + +## 支持 CPU 占用率统计 + +UniProton 中的系统 CPU 占用率(CPU Percent)是指周期时间内系统的 CPU 占用率,用于表示系统一段时间内的闲忙程度,也表示 CPU 的负载情况。系统CPU占用率的有效表示范围为 0~10000,其精度为万分比。10000 表示系统满负荷运转。 + +UniProton 中的线程 CPU 占用率指单个线程的 CPU 占用率,用于表示单个线程在一段时间内的闲忙程度。线程 CPU 占用率的有效表示范围为 0~10000,其精度为万分比。10000 表示在一段时间内系统一直在运行该线程。单核系统所有线程(包括中断和空闲任务)的 CPU 之和为 10000。 + +UniProton 的系统级 CPU 占用率依赖于 Tick 模块,通过 Tick 采样 IDLE 任务或 IDLE 软中断计数来实现。 + +## 支持 STM32F407ZGT6 开发板 + +支持开发板主要涉及 OS 内核外围的启动流程和单板驱动,目录结构如下: + +├─apps # 基于 UniProton 实时 OS 编程的 demo 程序。 + +│ └─hello_world # hello_world 示例程序。 + +├─bsp # 提供的板级驱动与 OS 对接。 + +├─build # 提供编译脚本编译出最终镜像。 + +├─config # 配置选项,供用户调整运行时参数。 + +├─include # UniProton 实时部分提供的编程接口 API。 + +└─libs # UniProton 实时部分的静态库,build 目录中的 makefile 示例已经将头文件和静态库的引用准备好,应用可直接使用。 + +## 支持 OpenAMP 混合部署 + +OpenAMP 是一个开源软件框架,旨在通过非对称多处理器的开源解决方案,来标准化异构嵌入式系统中操作环境之间的交互。OpenAMP 包括如下四大组件: + +1. remoteproc:管理从核的生命周期,管理共享内存、通信使用的buffer、vring等资源,初始化rpmsg和virtio。 + +2. rpmsg:实现多核通信的通道,基于virtio实现。 + +3. virtio:通过一套虚拟IO实现主从核的驱动程序通信,是一种半虚拟化技术。 + +4. libmetal:屏蔽操作系统实现细节,提供通用用户API访问设备,处理设备中断、内存请求。 + +## 支持POSIX标准接口 + +[UniProton支持posix标准接口](./uniproton_apis.md) + +## 支持设备驱动 + +UniProton 的驱动结构、风格与 linux 类似,将驱动设备文件化,即 VFS 系统,通过驱动注册接口,将驱动注册到文件系统中,应用层只需要通过标准系统调用,即可调用底层驱动。整个驱动框架代码适配自开源 RTOS 系统 Nuttx 的驱动模块,因此接口调用也与 Nuttx 基本一致。struct file_operations 结构体保存设备文件操作的方法,定义在 fs.h 头文件中,通过 register_driver 接口将驱动设备挂到对应的 struct inode 节点中,struct inode 描述了每个设备节点的位置和数据。当系统调用操作设备文件时,根据对应文件的 inode 就能索引到对应的函数。接口详细信息可以查看[UniProton接口说明](./uniproton_apis.md)。 + +## 支持 Shell 命令行 + +UniProton 提供 shell 命令行,它能够以命令行交互的方式访问操作系统的功能或服务:它接受并解析用户输入的命令,并处理操作系统的输出结果。UniProton 的 shell 模块代码适配自开源 ROTS 系统 LiteOS 的 shell 模块。因此与 LiteOS 一致,用户可以新增定制的命令,新增命令需重新编译烧录后才能执行。当前 UniProton 只支持了 help 命令,其他命令将在后续的版本中进行完善。Shell 模块为用户提供下面几个接口。 + +| 接口名 | 描述 | +| :---: | :--: | +| SHELLCMD_ENTRY | 静态注册命令 | +| osCmdReg | 动态注册命令 | + +通常静态注册命令方式一般用于注册系统常用命令,动态注册命令方式一般用于注册用户命令。静态注册命令有5个入参,动态注册命令有4个入参。下面除去第一个入参是静态注册独有的,剩余的四个入参两个注册命令是一致的。接口详细信息可以查看[UniProton接口说明](./uniproton_apis.md)。