前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go语言调度器源代码情景分析之八:系统调用

go语言调度器源代码情景分析之八:系统调用

作者头像
阿波张
发布2019-06-24 15:38:17
6480
发布2019-06-24 15:38:17
举报

我们将在最后一章讨论有关系统调用方面的抢占调度,所以这里有必要对系统调用有个基本的了解。

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

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

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

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

代码语言:javascript
复制
package main

import (
"os"
)

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

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

代码语言:javascript
复制
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这个系统调用的编号267保存在了对应的寄存器中,然后使用syscall指令进入内核执行打开文件的功能。


最后,如果你觉得本文对你有帮助的话,麻烦帮忙点一下文末右下角的 在看 或转发到朋友圈,非常感谢!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 go语言核心编程技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档