zoukankan      html  css  js  c++  java
  • 系统调用

    本文是《go调度器源代码情景分析》系列 第一章 预备知识的第7小节。

    我们将在最后一章讨论goroutine的有关系统调用方面的抢占调度,所以这里先对系统调用做个基本的介绍。

    系统调用是指使用类似函数调用的方式调用操作系统提供的API。

    虽然从概念上来说系统调用和函数调用差不多,但本质上它们有很大的不同,操作系统的代码位于内核地址空间,而CPU在执行用户代码时特权等级很低,无权访问需要最高优先级才能访问的内核地址空间的代码和数据,所以不能通过简单的call指令直接调用操作系统提供的函数,而需要使用特殊的指令进入操作系统内核完成指定的功能。

    另外,用户代码调用操作系统API也不是根据函数名直接调用,而是需要根据操作系统为每个API提供的一个整型编号来调用,AMD64 Linux平台约定在进行系统调用时使用rax寄存器存放系统调用编号,同时约定使用rdi, rsi, rdx, r10, r8和r9来传递前6个系统调用参数。

    可能有读者会说,我们平时编程也没有用到系统调用啊?!其实并不是没有用到,而是我们没有感觉到它的存在,比如最简单的向屏幕输出字符串,打开文件,读写文件以及网络编程中的创建socket等等都使用了系统调用,我们没有感觉到系统调用的存在主要是因为我们使用的函数库或package把它们封装成了函数,我们只需要直接调用这些函数就可以了。比如有下面一段go代码:

    package main
    
    import(
            "os"
    )
    
    funcmain() {
            fd, err:=os.Open("./syscall.go")  // 将会使用系统调用打开文件
            ......
            fd.Close()  // 将会使用系统调用关闭文件
    }
    

     

    这里的os.Open()和fd.Close()函数最终都会通过系统调用进入操作系统内核完成相应的功能。以os.Open为例,在Go语言的实现中它最终会执行下面这段汇编代码来通过openat系统调用打开文件:

    mov   0x10(%rsp),%rdi #第1个参数
    mov   0x18(%rsp),%rsi #第2个参数
    mov   0x20(%rsp),%rdx #第3个参数
    mov   0x28(%rsp),%r10 #第4个参数
    mov   0x30(%rsp),%r8  #第5个参数
    mov   0x38(%rsp),%r9  #第6个参数
    mov   0x8(%rsp),%rax  #系统调用编号 rax = 267,表示调用openat系统调用
    syscall               #系统调用指令,进入Linux内核

    这里,代码首先把6个参数(openat系统调用其实没有这么多参数,这是Go的底层实现,内核并不会使用多余无用的参数)以及openat这个系统调用的编号267保存在了对应的寄存器中,然后使用syscall指令进入内核执行打开文件的功能。

  • 相关阅读:
    将同一个应用程序同时作为 http 和 https
    将数组元素划分为等长的块(二维数组)
    将数组中的空元素转为 undefined
    将某个类型断言为另一个与之毫无关系的类型
    将前端代码放入 Egg 项目中
    将根组件挂载到 DOM 节点上
    将类数组对象转换成数组
    将 ts 代码转成 js 代码
    将代码推迟到系统资源空闲时执行
    React 将 state 传给子组件用
  • 原文地址:https://www.cnblogs.com/abozhang/p/10795259.html
Copyright © 2011-2022 走看看