Fundamentals 17 min read

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.

Didi Tech
Didi Tech
Didi Tech
Understanding Go's Syscall Mechanism and Runtime Interaction

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.

ConcurrencyGoSchedulerRuntimelow-levelsyscall
Didi Tech
Written by

Didi Tech

Official Didi technology account

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.