打通用户态程序和内核系列之一:用户态程序如何执行系统调用

前言

以前弄个一段时间内核,而最近在应用程序特别是C++ 方面开发多一些。当前平常工做中碰到一些性能分析、不一样锁API选择的问题,发现因为对用户态程序API背后的工做原理,特别是它和内核的调用关系、在内核中具体实现过程不甚清楚,致使前期的预期没法进行分析。为此,打算结合工做中碰到的问题,好比:架构

  1. 用户态程序如何执行系统调用;
  2. 用户态锁的底层实现及其和内核态锁的关系如何;
  3. 用户态不一样锁(自旋锁,读写锁,条件锁)和无锁机制的对比该如何作理论分析;
  4.  Libaio 异步IO在内核中的具体使怎样实现的;
  5.  系统调用、线程调度、中断分别对系统性能、CPU消耗的影响如何;

但愿经过理清上面的这些基础问题,打通脑子中相互孤立的知识点,帮助他们创建起比较紧密的联系。异步

系统调用ABC

系统调用的功能

从操做系统的角度看,系统调用是内核提供用户态程序操做最底层软件或硬件的接口。Linux 系统中每种硬件系统架构都有本身的系统调用表,好比下面mips的系统调用表:ide

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环境;this

(2)分析系统调用类型,转入相应的系统调用处理子程序;操作系统

(3)在系统调用处理子程序执行完后,恢复被中断的或设置新进程的CPU现场,而后返冋被中断进程或新进程,继续往下执行。线程

用户态程序快速调用系统调用

当前为了快速开发,也能够经过syscall 快速调用,好比下面Libaio的两个快速调用的实现:code

/* 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);
}

读者能够根据上面的示例,调用本身的系统调用。接口

相关文章
相关标签/搜索