From: Austin Clements Date: Mon, 18 Apr 2022 17:20:54 +0000 (-0400) Subject: runtime: add HACKING section on nosplit functions X-Git-Tag: go1.19rc1~129 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c29be2d41c6c3ed78a76b4d8d8c1c22d7e0ad5b7;p=gostls13.git runtime: add HACKING section on nosplit functions Change-Id: I247874d5c49d2c0d8db2a3d227aa848093551d9b Reviewed-on: https://go-review.googlesource.com/c/go/+/401759 Reviewed-by: Michael Pratt --- diff --git a/src/runtime/HACKING.md b/src/runtime/HACKING.md index af9fe288aa..61b5a51959 100644 --- a/src/runtime/HACKING.md +++ b/src/runtime/HACKING.md @@ -41,8 +41,20 @@ All `g`, `m`, and `p` objects are heap allocated, but are never freed, so their memory remains type stable. As a result, the runtime can avoid write barriers in the depths of the scheduler. -User stacks and system stacks ------------------------------ +`getg()` and `getg().m.curg` +---------------------------- + +To get the current user `g`, use `getg().m.curg`. + +`getg()` alone returns the current `g`, but when executing on the +system or signal stacks, this will return the current M's "g0" or +"gsignal", respectively. This is usually not what you want. + +To determine if you're running on the user stack or the system stack, +use `getg() == getg().m.curg`. + +Stacks +====== Every non-dead G has a *user stack* associated with it, which is what user Go code executes on. User stacks start small (e.g., 2K) and grow @@ -63,17 +75,33 @@ non-preemptible and the garbage collector does not scan system stacks. While running on the system stack, the current user stack is not used for execution. -`getg()` and `getg().m.curg` ----------------------------- +nosplit functions +----------------- -To get the current user `g`, use `getg().m.curg`. +Most functions start with a prologue that inspects the stack pointer +and the current G's stack bound and calls `morestack` if the stack +needs to grow. -`getg()` alone returns the current `g`, but when executing on the -system or signal stacks, this will return the current M's "g0" or -"gsignal", respectively. This is usually not what you want. +Functions can be marked `//go:nosplit` (or `NOSPLIT` in assembly) to +indicate that they should not get this prologue. This has several +uses: -To determine if you're running on the user stack or the system stack, -use `getg() == getg().m.curg`. +- Functions that must run on the user stack, but must not call into + stack growth, for example because this would cause a deadlock, or + because they have untyped words on the stack. + +- Functions that must not be preempted on entry. + +- Functions that may run without a valid G. For example, functions + that run in early runtime start-up, or that may be entered from C + code such as cgo callbacks or the signal handler. + +Splittable functions ensure there's some amount of space on the stack +for nosplit functions to run in and the linker checks that any static +chain of nosplit function calls cannot exceed this bound. + +Any function with a `//go:nosplit` annotation should explain why it is +nosplit in its documentation comment. Error handling and reporting ============================