github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/runtime/HACKING.md (about) 1 This is a living document and at times it will be out of date. It is 2 intended to articulate how programming in the Go runtime differs from 3 writing normal Go. It focuses on pervasive concepts rather than 4 details of particular interfaces. 5 6 Scheduler structures 7 ==================== 8 9 The scheduler manages three types of resources that pervade(遍布) the 10 runtime: Gs, Ms, and Ps. It's important to understand these even if 11 you're not working on the scheduler. 12 13 Gs, Ms, Ps 14 ---------- 15 16 A "G" is simply a goroutine. It's represented by type `g`. When a 17 goroutine exits, its `g` object is returned to a pool of free `g`s and 18 can later be reused for some other goroutine. 19 一个G代表一个goroutine, 使用类型g表示, 当一个goroutine退出, 其g对象返回 20 free g列表,并且之后可重用. 推论1: goroutine新建和毁灭的开销低 21 22 An "M" is an OS thread that can be executing user Go code, runtime 23 code, a system call, or be idle. It's represented by type `m`. There 24 can be any number of Ms at a time since any number of threads may be 25 blocked in system calls. 26 M代表一个OS thread, 有几种状态: 执行Go代码, 执行runtime代码, 系统调用或者空闲 27 任意时间可以有任意多的M, 因为可以有任意多个线程阻塞在系统调用 28 29 Finally, a "P" represents the resources required to execute user Go 30 code, such as scheduler and memory allocator state. It's represented 31 by type `p`. There are exactly `GOMAXPROCS` Ps. A P can be thought of 32 like a CPU in the OS scheduler and the contents of the `p` type like 33 per-CPU state. This is a good place to put state that needs to be 34 sharded for efficiency, but doesn't need to be per-thread or 35 per-goroutine. 36 P代表需要执行Go代码的资源, 比如调度器和内存分配状态. 恰好有GOMAXPROCS个P 37 38 The scheduler's job is to match up a G (the code to execute), an M 39 (where to execute it), and a P (the rights and resources to execute 40 it). When an M stops executing user Go code, for example by entering a 41 system call, it returns its P to the idle P pool. In order to resume 42 executing user Go code, for example on return from a system call, it 43 must acquire a P from the idle pool. 44 调度器的任务是配对G, M和P. 当M停止执行用户Go代码(比如系统调用阻塞), 其会将其P返回 45 闲置的P池, 使得这个P能被其他M获得, 这个P上的其他goroutine可以被执行. 要恢复执行 46 用户Go代码, 比如从系统调用返回, 其必须从空闲P池中获取一个P. 47 48 All `g`, `m`, and `p` objects are heap allocated, but are never freed, 49 so their memory remains type stable. As a result, the runtime can 50 avoid write barriers in the depths of the scheduler. 51 所有的`g`, `m`, `p`对象都是在堆上分配的, 永远不会被释放, 所以其内存是稳定的. 52 这导致runtime可以在调度器的层级避免写屏障 53 54 User stacks and system stacks 55 ----------------------------- 56 57 Every non-dead G has a *user stack* associated with it, which is what 58 user Go code executes on. User stacks start small (e.g., 2K) and grow 59 or shrink dynamically. 60 每个未死亡的G都有一个用户栈, 用户Go代码在其上执行. 用户栈开始时从2K开始动态增长和缩小 61 62 Every M has a *system stack* associated with it (also known as the M's 63 "g0" stack because it's implemented as a stub G) and, on Unix 64 platforms, a *signal stack* (also known as the M's "gsignal" stack). 65 System and signal stacks cannot grow, but are large enough to execute 66 runtime and cgo code (8K in a pure Go binary; system-allocated in a 67 cgo binary). 68 每个M有个系统栈(也被称为g0栈因为其以一个stub G实现)和一个信号栈(Unix平台下). 69 这两个栈不能增长, 但已经足够大到执行运行时和cgo代码(纯Go二进制有8K, cgo二进制里是系统分配的) 70 71 Runtime code often temporarily switches to the system stack using 72 `systemstack`, `mcall`, or `asmcgocall` to perform tasks that must not 73 be preempted, that must not grow the user stack, or that switch user 74 goroutines. Code running on the system stack is implicitly 75 non-preemptible and the garbage collector does not scan system stacks. 76 While running on the system stack, the current user stack is not used 77 for execution. 78 runtime代码经常切换到系统栈执行不可被抢占的任务,不能增长用户栈的任务或切换用户goroutine的任务(?), 79 使用`systemstack`, `mcall`, `asmcgocall`. 80 运行在系统栈上的代码隐式不可被抢占,并且垃圾回收不扫描系统栈. 81 当运行在系统栈时, 当前用户栈不用来执行. 82 83 `getg()` and `getg().m.curg` 84 ---------------------------- 85 86 To get the current user `g`, use `getg().m.curg`. 87 要获取当前用户`g`, 使用`getg().m.curg`. 88 89 `getg()` alone returns the current `g`, but when executing on the 90 system or signal stacks, this will return the current M's "g0" or 91 "gsignal", respectively. This is usually not what you want. 92 单独的`getg()`会返回当前`g`, 但当在系统栈或信号栈上执行时,这会返回当前M的g0 93 或gsinal. 94 95 To determine if you're running on the user stack or the system stack, 96 use `getg() == getg().m.curg`. 97 使用`getg() == getg().m.curg`可以判断当前是否执行在系统或信号栈上 98 99 Error handling and reporting 100 ============================ 101 102 Errors that can reasonably be recovered from in user code should use 103 `panic` like usual. However, there are some situations where `panic` 104 will cause an immediate fatal error, such as when called on the system 105 stack or when called during `mallocgc`. 106 107 Most errors in the runtime are not recoverable. For these, use 108 `throw`, which dumps the traceback and immediately terminates the 109 process. In general, `throw` should be passed a string constant to 110 avoid allocating in perilous situations. By convention, additional 111 details are printed before `throw` using `print` or `println` and the 112 messages are prefixed with "runtime:". 113 114 For runtime error debugging, it's useful to run with 115 `GOTRACEBACK=system` or `GOTRACEBACK=crash`. 116 117 Synchronization 118 =============== 119 120 The runtime has multiple synchronization mechanisms. They differ in 121 semantics and, in particular, in whether they interact with the 122 goroutine scheduler or the OS scheduler. 123 runtime有多种同步机制. 其语义和是否与goroutine调度器和OS调度器有所区别. 124 125 The simplest is `mutex`, which is manipulated using `lock` and 126 `unlock`. This should be used to protect shared structures for short 127 periods. Blocking on a `mutex` directly blocks the M, without 128 interacting with the Go scheduler. This means it is safe to use from 129 the lowest levels of the runtime, but also prevents any associated G 130 and P from being rescheduled. `rwmutex` is similar. 131 最简单的是`mutex`. 这用来在短时间内保护共享数据结构. 阻塞`mutex`不直接与Go调度器 132 交流, 直接阻塞M. 这意味着runtime最底层使用是安全的, 使用这个也避免和关联的G和P被 133 重新调度. 134 135 For one-shot notifications, use `note`, which provides `notesleep` and 136 `notewakeup`. Unlike traditional UNIX `sleep`/`wakeup`, `note`s are 137 race-free, so `notesleep` returns immediately if the `notewakeup` has 138 already happened. A `note` can be reset after use with `noteclear`, 139 which must not race with a sleep or wakeup. Like `mutex`, blocking on 140 a `note` blocks the M. However, there are different ways to sleep on a 141 `note`:`notesleep` also prevents rescheduling of any associated G and 142 P, while `notetsleepg` acts like a blocking system call that allows 143 the P to be reused to run another G. This is still less efficient than 144 blocking the G directly since it consumes an M. 145 对于一次性的提醒, 使用`note`. `note`也会阻塞M. 但其仍有两种情况, notesleep 146 阻止关联的G和P重调度. `notetsleepg`运行P不被阻塞,继续被重用来执行其他G. 147 这仍然不够高效,因为阻塞了一个M. 148 149 To interact directly with the goroutine scheduler, use `gopark` and 150 `goready`. `gopark` parks the current goroutine—putting it in the 151 "waiting" state and removing it from the scheduler's run queue—and 152 schedules another goroutine on the current M/P. `goready` puts a 153 parked goroutine back in the "runnable" state and adds it to the run 154 queue. 155 为了直接与goroutine调度器直接交流, 使用`gopark`和`goready`. `gopark`停止当前 156 goroutine, 将其放入等待状态,将其从调度器的运行队列中移除,然后调度另一个goroutine 157 在当前M/P上执行. 158 159 In summary, 160 161 <table> 162 <tr><th></th><th colspan="3">Blocks</th></tr> 163 <tr><th>Interface</th><th>G</th><th>M</th><th>P</th></tr> 164 <tr><td>(rw)mutex</td><td>Y</td><td>Y</td><td>Y</td></tr> 165 <tr><td>note</td><td>Y</td><td>Y</td><td>Y/N</td></tr> 166 <tr><td>park</td><td>Y</td><td>N</td><td>N</td></tr> 167 </table> 168 169 Unmanaged memory 170 ================ 171 172 In general, the runtime tries to use regular heap allocation. However, 173 in some cases the runtime must allocate objects outside of the garbage 174 collected heap, in *unmanaged memory*. This is necessary if the 175 objects are part of the memory manager itself or if they must be 176 allocated in situations where the caller may not have a P. 177 178 There are three mechanisms for allocating unmanaged memory: 179 180 * sysAlloc obtains memory directly from the OS. This comes in whole 181 multiples of the system page size, but it can be freed with sysFree. 182 183 * persistentalloc combines multiple smaller allocations into a single 184 sysAlloc to avoid fragmentation. However, there is no way to free 185 persistentalloced objects (hence the name). 186 187 * fixalloc is a SLAB-style allocator that allocates objects of a fixed 188 size. fixalloced objects can be freed, but this memory can only be 189 reused by the same fixalloc pool, so it can only be reused for 190 objects of the same type. 191 192 In general, types that are allocated using any of these should be 193 marked `//go:notinheap` (see below). 194 195 Objects that are allocated in unmanaged memory **must not** contain 196 heap pointers unless the following rules are also obeyed: 197 198 1. Any pointers from unmanaged memory to the heap must be added as 199 explicit garbage collection roots in `runtime.markroot`. 200 201 2. If the memory is reused, the heap pointers must be zero-initialized 202 before they become visible as GC roots. Otherwise, the GC may 203 observe stale heap pointers. See "Zero-initialization versus 204 zeroing". 205 206 Zero-initialization versus zeroing 207 ================================== 208 209 There are two types of zeroing in the runtime, depending on whether 210 the memory is already initialized to a type-safe state. 211 212 If memory is not in a type-safe state, meaning it potentially contains 213 "garbage" because it was just allocated and it is being initialized 214 for first use, then it must be *zero-initialized* using 215 `memclrNoHeapPointers` or non-pointer writes. This does not perform 216 write barriers. 217 218 If memory is already in a type-safe state and is simply being set to 219 the zero value, this must be done using regular writes, `typedmemclr`, 220 or `memclrHasPointers`. This performs write barriers. 221 222 Runtime-only compiler directives 223 ================================ 224 225 In addition to the "//go:" directives documented in "go doc compile", 226 the compiler supports additional directives only in the runtime. 227 228 go:systemstack 229 -------------- 230 231 `go:systemstack` indicates that a function must run on the system 232 stack. This is checked dynamically by a special function prologue. 233 234 go:nowritebarrier 235 ----------------- 236 237 `go:nowritebarrier` directs the compiler to emit an error if the 238 following function contains any write barriers. (It *does not* 239 suppress the generation of write barriers; it is simply an assertion.) 240 241 Usually you want `go:nowritebarrierrec`. `go:nowritebarrier` is 242 primarily useful in situations where it's "nice" not to have write 243 barriers, but not required for correctness. 244 245 go:nowritebarrierrec and go:yeswritebarrierrec 246 ---------------------------------------------- 247 248 `go:nowritebarrierrec` directs the compiler to emit an error if the 249 following function or any function it calls recursively, up to a 250 `go:yeswritebarrierrec`, contains a write barrier. 251 252 Logically, the compiler floods the call graph starting from each 253 `go:nowritebarrierrec` function and produces an error if it encounters 254 a function containing a write barrier. This flood stops at 255 `go:yeswritebarrierrec` functions. 256 257 `go:nowritebarrierrec` is used in the implementation of the write 258 barrier to prevent infinite loops. 259 260 Both directives are used in the scheduler. The write barrier requires 261 an active P (`getg().m.p != nil`) and scheduler code often runs 262 without an active P. In this case, `go:nowritebarrierrec` is used on 263 functions that release the P or may run without a P and 264 `go:yeswritebarrierrec` is used when code re-acquires an active P. 265 Since these are function-level annotations, code that releases or 266 acquires a P may need to be split across two functions. 267 268 go:notinheap 269 ------------ 270 271 `go:notinheap` applies to type declarations. It indicates that a type 272 must never be allocated from the GC'd heap. Specifically, pointers to 273 this type must always fail the `runtime.inheap` check. The type may be 274 used for global variables, for stack variables, or for objects in 275 unmanaged memory (e.g., allocated with `sysAlloc`, `persistentalloc`, 276 `fixalloc`, or from a manually-managed span). Specifically: 277 278 1. `new(T)`, `make([]T)`, `append([]T, ...)` and implicit heap 279 allocation of T are disallowed. (Though implicit allocations are 280 disallowed in the runtime anyway.) 281 282 2. A pointer to a regular type (other than `unsafe.Pointer`) cannot be 283 converted to a pointer to a `go:notinheap` type, even if they have 284 the same underlying type. 285 286 3. Any type that contains a `go:notinheap` type is itself 287 `go:notinheap`. Structs and arrays are `go:notinheap` if their 288 elements are. Maps and channels of `go:notinheap` types are 289 disallowed. To keep things explicit, any type declaration where the 290 type is implicitly `go:notinheap` must be explicitly marked 291 `go:notinheap` as well. 292 293 4. Write barriers on pointers to `go:notinheap` types can be omitted. 294 295 The last point is the real benefit of `go:notinheap`. The runtime uses 296 it for low-level internal structures to avoid memory barriers in the 297 scheduler and the memory allocator where they are illegal or simply 298 inefficient. This mechanism is reasonably safe and does not compromise 299 the readability of the runtime.