gh-liu / myNote

0 stars 0 forks source link

`go`中的`syscall` #11

Open gh-liu opened 4 months ago

gh-liu commented 4 months ago

go syscall

系统调用描述的是用户程序进入内核后执行的任务。 用户程序利用系统调用能执行许多操作:创建进程、网络、文件以及I/O操作等。

man page for syscalls(2) 列出了全部系统调用。

// syscall/syscall_linux.go

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {}
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {}
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {}
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno){}
// 不带 Raw 函数会在进入/退出系统调用的时候,通知 runtime
// 不通知 runtime,则没有办法通过调度,把这个 G 的 M 的 P 调度走
// runtime/internal/syscall/asm_linux_amd64.s

// func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr)
//
// We need to convert to the syscall ABI.
//
// arg | ABIInternal | Syscall
// ---------------------------
// num | AX          | AX
// a1  | BX          | DI
// a2  | CX          | SI
// a3  | DI          | DX
// a4  | SI          | R10
// a5  | R8          | R8
// a6  | R9          | R9
//
// r1  | AX          | AX
// r2  | BX          | DX
// err | CX          | part of AX
//
// Note that this differs from "standard" ABI convention, which would pass 4th
// arg in CX, not R10.
TEXT ·Syscall6<ABIInternal>(SB),NOSPLIT,$0
    // a6 already in R9.
    // a5 already in R8.
    MOVQ    SI, R10 // a4
    MOVQ    DI, DX  // a3
    MOVQ    CX, SI  // a2
    MOVQ    BX, DI  // a1
    // num already in AX.
    SYSCALL
    CMPQ    AX, $0xfffffffffffff001
    JLS ok
    NEGQ    AX
    MOVQ    AX, CX  // errno
    MOVQ    $-1, AX // r1
    MOVQ    $0, BX  // r2
    RET
ok:
    // r1 already in AX.
    MOVQ    DX, BX // r2
    MOVQ    $0, CX // errno
    RET

以上函数的实现都是汇编,按照linuxsyscall调用规范: 在汇编中把参数依次传入相关寄存器,并调用SYSCALL指令即可进入内核处理逻辑,系统调用执行完毕之后,返回值放在 RAX 中。

RDI RSI RDX R10 R8 R9 RAX
参数1 参数2 参数3 参数4 参数5 参数6 系统调用编号/返回值

SYSCALL 定义

syscall/syscall_linux_amd64.go

阻塞的系统调用,定义成:

//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)

非阻塞的系统调用,定义成:

//sysnb socket(domain int, typ int, proto int) (fd int, err error)

根据这些注释,mksyscall.pl 脚本会生成对应的平台的具体实现: 标记 //sys 的系统调用使用的是 Syscall 或者 Syscall6,因为阻塞调用需要通知runtime调度p 标记 //sysnb 的系统调用使用的是 RawSyscall 或 RawSyscall6

runtime 中的 SYSCALL

提供给用户的 syscall 库,在使用时,会使 G 和 P 分别进入 Gsyscall 和 Psyscall 状态(使用 entersyscall/exitsyscall 与调度交互) 而 runtime 封装的这些 syscall 无论是否阻塞,都不会调用 entersyscall 和 exitsyscall