开源鸿蒙内核源码分析系列 | POSIX | 操作系统界的话事人(转载)
原文来自鸿蒙研究站:http://weharmonyos.com/blog/05.html
鸿蒙研究站网址:http://weharmonyos.com
几个概念
您肯定听过 API,POSIX,C语言库函数,系统调用这些概念,但之间有什么区别和联系,估计一些人没弄明白,本篇重点把它们整明白了。
API :搞应用开发的同学不会陌生,应用编程接口的缩写 ,它是对函数的定义,规定了这个函数的功能。任何公司,个人都可以定义自有特色的API。可以称之为 私有标准 。打个比方就相当于是地方方言,十里不同音,只有这个地方的人能搞懂,对外会带来极高的沟通成本。
POSIX:Unix开源后很多公司都推出了不同的版本的Unix系统。他们的API各不相同。这给软件的移植带来了很大的困难。于是IEEE制定了基于Unix的可移植操作系统接口,目的是为了统一这些 私有标准,可以称之为公共的类Unix接口标准。POSIX是可移植操作系统接口Portable Operating System Interface的英文首字母缩写,是IEEE为要在各种UNIX操作系统上运行软件,而定义API的一系列互相关联的标准的总称。所以POSIX标准也是一种API,IEEE这个协会很牛,制定过很多标准,涵盖太空、计算机、电信、生物医学、电力及消费性电子产品等领域,可以说是科技界标准话事人。对应地方方言,它就相当于是普通话,其实呢它也是一种方言。
C语言库函数:是基于POSIX标准的具体实现, 相当于中国人说的普通话。
系统调用:是内核对外提供的服务总称, 它一般被C语言库函数所调用, 相当于政府对老百姓的办事窗口, 想访问内部资源就需要填表格, 走流程。
POSIX简介
当前的POSIX主要分为四个部分:
XBD(Base Definitions):包含一些通用的术语、概念、接口以及工具函数(cd,mkdir, cp,mv等)和头文件定义(stdio.h, stdlib.h,pthread.h等)。
XSH(System Interfaces):包含系统服务函数的定义,例如线程、套接字、标准IO、信号处理、错误处理等。
XCU(Shell and Utilities):包含shell脚本书写的语法、关键字以及工具函数(break,cd,cp,continue,pwd,return)的定义。
XRAT(Rationale):包含与本标准有关的历史信息以及采用或舍弃某功能的扩展基本原理。具体查看 >> 官方网站 | opengroup 目前单一UNIX规范第4版中定义了 1447 个接口。
XBD | XSH | XCU | 全部的 |
---|---|---|---|
82 | 1191 | 174 | 1447 |
开源鸿蒙支持部分标准POSIX接口 ,并不是很多 >> 可查看源码 compat/posix:https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/compat/posix
compat/posix/src
├── map_error.c //错误码映射 例如: ENOERR EINTR ESRCH
├── malloc.c //内存分配 例如: malloc zalloc r
├── misc.c //系统信息
├── mqueue.c //消息队列
├── posix_memalign.c //内存对齐分配
├── pprivate.h //描述 _pthread_data 结构体
├── pthread.c //线程
├── pthread_attr.c //线程属性
├── pthread_cond.c //线程条件
├── pthread_mutex.c //线程互斥
├── sched.c //任务调度
├── semaphore.c //信号量
├── socket.c //网络
└── time.c //时间
系统调用的实现函数 OsArmA32SyscallHandle实现过程在后续 开源鸿蒙内核源码分析系列 | 系统调用 | 开发者永远的口头禅 中详细说明。进程控制类系统调用,主要有:
- 创建和终止进程的系统调用。
- 获得和设置进程属性的系统调用。
- 等待某事件出现的系统调用。
- SysFork,SysWait,SysSetProcessGroupID,SysGetUserID,SysSchedYield,SysThreadJoin,SysIoctl
文件操纵类系统调用,主要有:
- 创建和删除文件。
- 打开和关闭文件的系统调用。
- 读和写文件的系统调用。
- SysPipe,SysOpen,SysStat,SysRead,SysWrite,SysCreat,SysIoctl
进程通讯类系统调用,主要有:
- SysMqOpen,SysSigAction,SysKill,SysMqNotify,SysMqTimedSend
- 网络类系统调用,主要有:
- SysSocket,SysBind,SysConnect,SysListen,SysAccept,SysRecv
信息配置类系统调用,主要有:
- SysReboot,SysInfo,SysGetrusage,SysSysconf
- 时间类系统调用,主要有:
- SysTimerCreate,SysTimerDelete,SysClockGettime,SysSetiTimer
内存类系统调用,主要有:
- SysMmap,SysMunmap,SysBrk,SysMremap,SysShmGet,SysShmAt,SysShmCtl,SysShmDt
musl | C标准库函数
>> 可查看源码 syscall:https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/syscallmusl,一种C标准库,官方网站 ,主要使用于以Linux内核为主的操作系统上,开源鸿蒙内核也使用了它,目标为嵌入式系统与移动设备,采用MIT许可证发布。作者为瑞奇·费尔克(Rich Felker)。开发此库的目的是写一份干净、高效、符合标准的C标准库。Musl声称与POSIX 2008标准和C11标准兼容。musl是一个非常庞大提供给应用程序使用的工具库,例如: 学习C语言的第一段代码中的printf就是由stdio.h提供,由标准库实现的。这是个可变参数实现函数。
#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}
int printf(const char *restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf(stdout, fmt, ap);
va_end(ap);
return ret;
}
如果你一直往下追,你会追到系统调用 write
ssize_t write(int fd, const void *buf, size_t count)
{
return syscall_cp(SYS_write, fd, buf, count);
}
void SyscallHandleInit(void)
{
#define SYSCALL_HAND_DEF(id, fun, rType, nArg) \
if ((id) < SYS_CALL_NUM) { \
g_syscallHandle[(id)] = (UINTPTR)(fun); \
g_syscallNArgs[(id) / NARG_PER_BYTE] |= ((id) & 1) ? (nArg) << NARG_BITS : (nArg); \
} \
#include "syscall_lookup.h"
#undef SYSCALL_HAND_DEF
}
\code-v1.1.1-LTS\prebuilts\lite\sysroot\usr\include\arm-liteos\bits\syscall.h
#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_creat 8
#define __NR_link 9
#define SYS_restart_syscall 0
#define SYS_exit 1
#define SYS_fork 2
#define SYS_read 3
#define SYS_write 4
#define SYS_open 5
#define SYS_close 6
#define SYS_creat 8
#define SYS_link 9
ssize_t read(int fd, void *buf, size_t count)
{
return syscall_cp(SYS_read, fd, buf, count);
}
#define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)
#define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__))
\code-v1.1.1-LTS\third_party\musl\src\thread\arm\syscall_cp.s
__syscall_cp_asm:
mov ip,sp
stmfd sp!,{r4,r5,r6,r7}
__cp_begin:
ldr r0,[r0]
cmp r0,#0
bne __cp_cancel
mov r7,r1 //R7寄存器保存软中断号
mov r0,r2
mov r1,r3
ldmfd ip,{r2,r3,r4,r5,r6}
svc 0 //原 SWI 指令, 软中断指令
__cp_end:
ldmfd sp!,{r4,r5,r6,r7}
bx lr
__cp_cancel:
ldmfd sp!,{r4,r5,r6,r7}
b __cancel
- 其中最重要的命令就是 svc 0,通过这条指令切换到 svc 模式(svc 替代了以前的 swi 指令,是 arm 提供的系统调用指令),进入到软件中断处理函数( SWI handler )。
问题
那可能有人会问了,操作系统有抽象层,那硬件有没有抽象层,规定处理器内核与外设的接口,统一了内核访问外设寄存器的方法,从而简化了软件的开发,提高重用度,降低软硬件接口开发成本。有的,就是CMSIS( Cortex Microcontroller Software Interface Standard)缩写,中文为Cortex系列微控制器软件接口标准。此标准是ARM公司,芯片供应商以及软件供应商共同制定的,包含以下组件:
- CMSIS-CORE:提供与 Cortex-M0、Cortex-M3、Cortex-M4、SC000 和 SC300 处理器与外围寄存器之间的接口
- CMSIS-DSP:包含以定点(分数 q7、q15、q31)和单精度浮点(32 位)实现的 60 多种函数的 DSP 库
- CMSIS-RTOS API:用于线程控制、资源和时间管理的实时操作系统的标准化编程接口
- CMSIS-SVD:包含完整微控制器系统(包括外设)的程序员视图的系统视图描述 XML 文件 此标准可进行全面扩展,以确保适用于所有 Cortex-M 处理器系列微控制器。其中包括所有设备:从最小的 8 KB 设备,直至带有精密通信外设(例如以太网或 USB)的设备。(内核外设功能的内存要求小于 1 KB 代码,低于 10 字节 RAM)。
百文说内核 | 抓住主脉络
子曰:“诗三百,一言以蔽之,曰‘思无邪’。”——《论语》:为政篇。
百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在开源鸿蒙内核源码加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了。
百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。
与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。百篇博客系列思维导图结构如下:
根据上图的思维导图,我们未来将要和大家一一分享以上大部分关键技术点的博客文章。
百万汉字注解.精读内核源码
如果大家觉得看文章不过瘾,想直接撸代码的话,可以去下面四大码仓围观同步注释内核源码:
gitee仓:
https://gitee.com/weharmony/kernel_liteos_a_note
github仓 :
https://github.com/kuangyufei/kernel_liteos_a_note
codechina仓:
https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note
coding仓:
https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files
写在最后
我们最近正带着大家玩嗨OpenHarmony。如果你有用OpenHarmony开发的好玩的东东,或者有对OpenHarmony的深度技术剖析,想通过我们平台让更多的小伙伴知道和分享的,欢迎投稿,让我们一起嗨起来!有点子,有想法,有Demo,立刻联系我们:
合作邮箱:zzliang@atomsource.org