前言
之前弄个一段时间内核,而最近在应用程序特别是C++ 方面开发多一些。当前日常工作中碰到一些性能分析、不同锁API选择的问题,发现由于对用户态程序API背后的工作原理,特别是它和内核的调用关系、在内核中具体实现过程不甚清楚,导致前期的预期无法进行分析。为此,打算结合工作中碰到的问题,比如:
- 用户态程序如何执行系统调用;
- 用户态锁的底层实现及其和内核态锁的关系如何;
- 用户态不同锁(自旋锁,读写锁,条件锁)和无锁机制的对比该如何做理论分析;
- ?Libaio 异步IO在内核中的具体使怎样实现的;
- ?系统调用、线程调度、中断分别对系统性能、CPU消耗的影响如何;
希望通过理清上面的这些基础问题,打通脑子中相互孤立的知识点,帮助他们建立起比较紧密的联系。
系统调用ABC
系统调用的功能
从操作系统的角度看,系统调用是内核提供用户态程序操作最底层软件或硬件的接口。Linux 系统中每种硬件系统架构都有自己的系统调用表,比如下面mips的系统调用表:
EXPORT(sys_call_table)
PTR sys_read /* 5000 */
PTR sys_write
PTR sys_open
PTR sys_close
....
PTR sys_statx
PTR sys_rseq
PTR sys_io_pgetevents
.size sys_call_table,.-sys_call_table
...
NESTED(handle_sys64, PT_SIZE, sp)
#if !defined(CONFIG_MIPS32_O32) && !defined(CONFIG_MIPS32_N32)
/*
* When 32-bit compatibility is configured scall_o32.S
* already did this.
*/
.set noat
SAVE_SOME
TRACE_IRQS_ON_RELOAD
STI
.set at
.....
syscall_common:
dsubu t2, v0, __NR_64_Linux
sltiu t0, t2, __NR_64_Linux_syscalls + 1
beqz t0, illegal_syscall
dsll t0, t2, 3 # offset into table
dla t2, sys_call_table
daddu t0, t2, t0
ld t2, (t0) # syscall routine
beqz t2, illegal_syscall
jalr t2 # Do The Real Thing (TM)
系统调用的工作过程
从调用者的角度看:
(1)参考系统调用的操作规范,准备参数和数据;
(2)通过系统调用的标准接口模式,调用系统调用的接口;
从被调用者的角度看:
(1)将处理机状态由用户态转为系统态之后,由硬件和内核程序进行系统调用的一般性处理,即首先保护被中断进程的CPU环境;
(2)分析系统调用类型,转入相应的系统调用处理子程序;
(3)在系统调用处理子程序执行完后,恢复被中断的或设置新进程的CPU现场,然后返冋被中断进程或新进程,继续往下执行。
用户态程序快速调用系统调用
当前为了快速开发,也可以通过syscall 快速调用,比如下面Libaio的两个快速调用的实现:
/* Actual syscalls */
int io_setup(int maxevents, io_context_t *ctxp) {
return syscall(_io_setup, maxevents, ctxp);
}
int io_destroy(io_context_t ctx) {
return syscall(__io_destroy, ctx);
}
读者可以根据上面的示例,调用自己的系统调用。
原文地址:https://blog.51cto.com/xiamachao/2434444
时间: 2024-10-13 05:40:24