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

前言

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

  1. 用户态程序如何执行系统调用;
  2. 用户态锁的底层实现及其和内核态锁的关系如何;
  3. 用户态不同锁(自旋锁,读写锁,条件锁)和无锁机制的对比该如何做理论分析;
  4. ?Libaio 异步IO在内核中的具体使怎样实现的;
  5. ?系统调用、线程调度、中断分别对系统性能、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-08-13 21:54:13

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

liunx内核移植(三)——内核、驱动、应用程序、根文件系统的关系

一:驱动属于内核的一部分 (1)驱动就是内核中的硬件设备管理模块 (2)驱动工作在内核态. (3)驱动程序故障可能导致整个内核崩溃 (4)驱动程序漏洞会使内核不安全 二:应用程序和内核的关系 (1)应用程序不属于内核,而是在内核之上的 (2)应用程序工作在用户态,是受限制的. (3)应用程序故障不会导致内核崩溃 (4)应用程序通过内核定义的API接口来调用内核工作,也就是说应 用程序依赖于内核,比如C语言的标准库就属于一个应用程序,所以在 内核当中不能使用C标准库,而是要使用liunx内核中的库

操作系统--用户空间和内核空间,用户态和内核态

内核空间和用户空间,内核态和用户态(转载) 内核空间和用户空间Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟地址空间也为0-4G.Linux内核将这4G字节的空间分为两部分.将最高的1G字节(从虚拟地址 0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”.而将较低的 3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间).因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有

call_usermodehelper内核中运行用户应用程序

init是用户空间第一个程序,在调用init前程序都运行在内核态,之后运行init时程序运行到用户态. 操作系统上,一些内核线程在内核态运行,它们永远不会进入用户态.它们也根本没有用户态的内存空间.它的线性地址空间就是共享内核的线性地址空间.一些用户进程通常在用户态运行.有时因为系统调用而进入内核态,调用内核提供的系统调用处理函数. 但有时,我们的内核模块或者内核线程希望能够调用用户空间的进程,就像系统启动之初init_post函数做的那样. 如,一个驱动从内核得到了主从设备号,然后需要使用mk

内核态和用户态,内核空间和用户空间

内核态与用户态是操作系统的两种运行级别,intel cpu提供Ring0-Ring3三种级别的运行模式.Ring0级别最高,Ring3最低 内核态可以拥有比用户态更大的权限 处于内核态的进程,可以访问用户进程空间(是虚拟地址空间),就是通过进程的页表(进程本身就是一个4G虚拟地址空间.其中用户空间的3G是独立的,内核空间是共享的)来访问用户地址空间对应的物理地址,从而访问用户空间 相反用户态的进程,只能访问用户地址空间(虚拟地址空间) 在内核态下,利用内核地址空间中的高端内存地址空间,来映射高端

Linux 5.3内核系列已终止支持 建议用户升级至Linux Kernel 5.4

上周,Linux 内核开发人员 Greg Kroah-Hartman 宣布了 Linux 5.3 内核系列的第 18 个维护更新(5.3.18).该版本共更改了 59 个文件,插入 369 项 / 移除 329 项.此外开发者指出,这将是 Linux 5.3 内核系列的最后一个维护更新.随着 Linux Kernel 5.3 抵达 EoL,官方建议用户及时更新至 Linux Kernel 5.4,以获得全面的支持与保障. Greg Kroah-Hartman 在<a href="http:

windbg 如何再内核模式调试用户空间的程序

1:使用!process 0 0 获取用户空间的所有的进程的信息 !process 0 0 **** NT ACTIVE PROCESS DUMP ****    PROCESS 80a02a60  Cid: 0002    Peb: 00000000  ParentCid: 0000    DirBase: 00006e05  ObjectTable: 80a03788  TableSize: 150.    Image: System ..... 2:使用.process /p + 你需要断

内核空间与用户空间的通信方式

内核空间与用户空间的通信方式 下面总结了7种方式,主要对以前不是很熟悉的方式做了编程实现,以便加深印象. 1.使用API:这是最常使用的一种方式了 A.get_user(x,ptr):在内核中被调用,获取用户空间指定地址的数值并保存到内核变量x中. B.put_user(x,ptr):在内核中被调用,将内核空间的变量x的数值保存到到用户空间指定地址处. C.Copy_from_user()/copy_to_user():主要应用于设备驱动读写函数中,通过系统调用触发. 2.使用proc文件系统:

(转)内核线程和用户线程的区别

内核级线程切换由内核控制,当线程进行切换的时候,由用户态转化为内核态.切换完毕要从内核态返回用户态:可以很好的利用smp,即利用多核cpu.windows线程就是这样的. 用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的. 线程的实现可以分为两类:用户级线程(User-Level Thread)和内核线线程(Kernel-Level Thread),后者又称为内核支持的线程或轻量级进程

操作系统--用户级线程和内核级线程

在多线程操作系统中,各个系统的实现方式并不相同.在有的系统中实现了用户级线程,有的系统中实现了内核级线程 1.内核级线程: (1)线程的创建.撤销和切换等,都需要内核直接实现,即内核了解每一个作为可调度实体的线程. (2)这些线程可以在全系统内进行资源的竞争. (3)内核空间内为每一个内核支持线程设置了一个线程控制块(TCB),内核根据该控制块,感知线程的存在,并进行控制. 在一定程度上类似于进程,只是创建.调度的开销要比进程小.有的统计是1:10 2.用户级线程: (1)用户级线程仅存在于用户