runtime: add HACKING section on nosplit functions

Change-Id: I247874d5c49d2c0d8db2a3d227aa848093551d9b
Reviewed-on: https://go-review.googlesource.com/c/go/+/401759
Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
Austin Clements 2022-04-18 13:20:54 -04:00
parent c5be77b687
commit c29be2d41c

View file

@ -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
============================