Understanding Go's Syscall Mechanism and Runtime Interaction
Go’s syscall mechanism uses assembly‑implemented entry functions like Syscall and Syscall6 to invoke the kernel, while the runtime’s entersyscall and exitsyscall hooks notify the scheduler, allowing P resources to be released during blocking calls and handling privileged low‑level syscalls separately.
This article explains how the Go language interacts with the operating system through system calls (syscall) and how the Go runtime optimizes these calls.
Concept : In Go, syscall is the only way for user code to communicate with the kernel. The article introduces the main entry functions defined in syscall/asm_linux_amd64.s such as Syscall , Syscall6 , RawSyscall , and RawSyscall6 .
Entry functions (excerpt):
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)These functions are implemented in assembly; they load arguments into registers and invoke the SYSCALL instruction. The return value is placed in RAX .
Difference between Syscall and Syscall6 : The only difference is the number of arguments passed to the kernel.
Runtime interaction : When user code calls a syscall, the runtime is notified via entersyscall before the kernel call and exitsyscall after it returns. This allows the scheduler to potentially release the current P (processor) so other goroutines can run while the syscall blocks.
Key runtime functions (excerpt):
//go:nosplit
func entersyscall() {
reentersyscall(getcallerpc(), getcallersp())
}
//go:nosplit
func exitsyscall(dummy int32) {
g := getg()
g.m.locks++
// ... checks and restores state ...
if exitsyscallfast() {
// fast path: re‑acquire P and continue
return
}
// slow path: schedule the goroutine
mcall(exitsyscall0)
}The entersyscall function disables preemption, saves the current PC/SP, marks the goroutine as _Gsyscall , and increments the syscall tick of the current P. The exitsyscall function restores the goroutine state, tries to reacquire a P quickly via exitsyscallfast , and if it fails, puts the goroutine back into the run queue and invokes the scheduler.
Special low‑level syscalls : The runtime also defines its own low‑level syscalls (e.g., runtime·write , runtime·read ) that do not go through the normal entersyscall/exitsyscall path, ensuring they are never preempted.
Summary : User‑visible syscalls in Go always notify the runtime, allowing it to manage P resources during blocking operations. The runtime also keeps privileged low‑level syscalls that bypass this mechanism, guaranteeing immediate handling after they return.
Didi Tech
Official Didi technology account
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.