github.com/primecitizens/pcz/std@v0.2.1/builtin/go/g.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright 2023 The Prime Citizens
     3  //
     4  // Copyright 2009 The Go Authors. All rights reserved.
     5  // Use of this source code is governed by a BSD-style
     6  // license that can be found in the LICENSE file.
     7  
     8  package stdgo
     9  
    10  import (
    11  	"unsafe"
    12  
    13  	stdtype "github.com/primecitizens/pcz/std/builtin/type"
    14  	"github.com/primecitizens/pcz/std/core/abi"
    15  	"github.com/primecitizens/pcz/std/core/alloc"
    16  	"github.com/primecitizens/pcz/std/core/mark"
    17  )
    18  
    19  // G defines required methods for a goroutine implementation.
    20  type G interface {
    21  	ID() uint64
    22  	Rand32() uint32
    23  	Rand64() uint64
    24  
    25  	// Status returns the status of this goroutine.
    26  	Status() Status
    27  
    28  	// DefaultAlloc returns the default allocator in this goroutine.
    29  	DefaultAlloc() alloc.M
    30  
    31  	// PersistantAlloc returns the persistant allocator in this goroutine.
    32  	PersistantAlloc() alloc.P
    33  
    34  	// TODO:
    35  	// StackAllocator() alloc.S
    36  	// HeapAllocator() alloc.H
    37  	// ArenaAllocator() alloc.A
    38  
    39  	// // Park puts the current goroutine into a waiting state and calls unlockf
    40  	// // on the system stack.
    41  	// //
    42  	// // If unlockf returns false, the goroutine is resumed.
    43  	// //
    44  	// // unlockf must not access this G's stack, as it may be moved between
    45  	// // the call to gopark and the call to unlockf.
    46  	// //
    47  	// // Note that because unlockf is called after putting the G into a waiting
    48  	// // state, the G may have already been readied by the time unlockf is called
    49  	// // unless there is external synchronization preventing the G from being
    50  	// // readied. If unlockf returns false, it must guarantee that the G cannot be
    51  	// // externally readied.
    52  	// //
    53  	// // Reason explains why the goroutine has been parked. It is displayed in stack
    54  	// // traces and heap dumps. Reasons should be unique and descriptive. Do not
    55  	// // re-use reasons, add new ones.
    56  	// Park(unlockf func(g G, lock unsafe.Pointer) bool, lock unsafe.Pointer, reason WaitReason, traceReason trace.BlockReason)
    57  }
    58  
    59  // GHead contains required per-G data.
    60  //
    61  // See ${GOROOT}/src/runtime/runtime2.go#type:g
    62  //
    63  // NOTE:
    64  //   - unsafe.Offsetof(T.GHead.Stack) MUST be 0.
    65  //   - (dev) MUST be kept as non-generic struct type.
    66  type GHead struct {
    67  	// Stack parameters.
    68  	//
    69  	// Stack describes the actual Stack memory: [Stack.lo, Stack.hi).
    70  	// stackguard0 is the Stack pointer compared in the Go Stack growth prologue.
    71  	// It is Stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
    72  	// stackguard1 is the Stack pointer compared in the C Stack growth prologue.
    73  	// It is Stack.lo+StackGuard on g0 and gsignal stacks.
    74  	// It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
    75  	Stack       Stack   // offset known to runtime/cgo
    76  	Stackguard0 uintptr // offset known to liblink
    77  	Stackguard1 uintptr // offset known to liblink
    78  
    79  	Panic      *Panic         // innermost panic - offset known to liblink
    80  	Defer      *Defer         // innermost defer
    81  	M          unsafe.Pointer // current m; offset known to arm liblink
    82  	Sched      Gobuf
    83  	SyscallSP  uintptr // if status==Gsyscall, syscallsp = Sched.sp to use during gc
    84  	SyscallPC  uintptr // if status==Gsyscall, syscallpc = Sched.pc to use during gc
    85  	StacktopSP uintptr // expected sp at top of stack, to check in traceback
    86  
    87  	// NOTE(pcz): following fields are not known to compiler/link
    88  
    89  	ID_ uint64
    90  
    91  	// Itab for the G interface value.
    92  	Itab *abi.Itab
    93  }
    94  
    95  func (gp *GHead) Guintptr() Guintptr { return Guintptr(unsafe.Pointer(gp)) }
    96  
    97  // G returns the G implementation
    98  //
    99  //go:nosplit
   100  func (gp *GHead) G() G {
   101  	var g G
   102  	iface := stdtype.IfaceOf(mark.NoEscape(&g))
   103  	iface.Itab, iface.Data = mark.NoEscape(gp.Itab), unsafe.Pointer(mark.NoEscape(gp))
   104  	return g
   105  }
   106  
   107  func (gp *GHead) ID() uint64 { return gp.ID_ }
   108  
   109  // Stack describes a Go execution Stack.
   110  // The bounds of the Stack are exactly [lo, hi),
   111  // with no implicit data structures on either side.
   112  type Stack struct {
   113  	Lo uintptr
   114  	Hi uintptr
   115  }
   116  
   117  func (stk Stack) PointerOnStack(ptr uintptr) bool {
   118  	return stk.Lo <= ptr && ptr < stk.Hi
   119  }
   120  
   121  // A Guintptr holds a goroutine pointer, but typed as a uintptr
   122  // to bypass write barriers. It is used in the Gobuf goroutine state
   123  // and in scheduling lists that are manipulated without a P.
   124  //
   125  // The Gobuf.G goroutine pointer is almost always updated by assembly code.
   126  // In one of the few places it is updated by Go code - func save - it must be
   127  // treated as a uintptr to avoid a write barrier being emitted at a bad time.
   128  // Instead of figuring out how to emit the write barriers missing in the
   129  // assembly manipulation, we change the type of the field to uintptr,
   130  // so that it does not require write barriers at all.
   131  //
   132  // Goroutine structs are published in the allg list and never freed.
   133  // That will keep the goroutine structs from being collected.
   134  // There is never a time that Gobuf.g's contain the only references
   135  // to a goroutine: the publishing of the goroutine in allg comes first.
   136  // Goroutine pointers are also kept in non-GC-visible places like TLS,
   137  // so I can't see them ever moving. If we did want to start moving data
   138  // in the GC, we'd need to allocate the goroutine structs from an
   139  // alternate arena. Using Guintptr doesn't make that problem any worse.
   140  // Note that pollDesc.rg, pollDesc.wg also store g in uintptr form,
   141  // so they would need to be updated too if g's start moving.
   142  type Guintptr uintptr
   143  
   144  //go:nosplit
   145  func (gp Guintptr) Ptr() *GHead { return (*GHead)(unsafe.Pointer(gp)) }
   146  
   147  //go:nosplit
   148  func (gp *Guintptr) Set(g *GHead) { *gp = Guintptr(unsafe.Pointer(g)) }
   149  
   150  // See ${GOROOT}/src/runtime/runtime2.go#type:gobuf
   151  type Gobuf struct {
   152  	// The offsets of SP, PC, and G are known to (hard-coded in) libmach.
   153  	//
   154  	// Ctxt is unusual with respect to GC: it may be a
   155  	// heap-allocated funcval, so GC needs to track it, but it
   156  	// needs to be set and cleared from assembly, where it's
   157  	// difficult to have write barriers. However, ctxt is really a
   158  	// saved, live register, and we only ever exchange it between
   159  	// the real register and the gobuf. Hence, we treat it as a
   160  	// root during stack scanning, which means assembly that saves
   161  	// and restores it doesn't need write barriers. It's still
   162  	// typed as a pointer so that any other writes from Go get
   163  	// write barriers.
   164  	SP   uintptr
   165  	PC   uintptr
   166  	G    Guintptr
   167  	Ctxt unsafe.Pointer
   168  	Ret  uintptr
   169  	LR   uintptr
   170  	BP   uintptr // for framepointer-enabled architectures
   171  }
   172  
   173  // Sudog represents a g in a wait list, such as for sending/receiving
   174  // on a channel.
   175  //
   176  // Sudog is necessary because the g ↔ synchronization object relation
   177  // is many-to-many. A g can be on many wait lists, so there may be
   178  // many sudogs for one g; and many gs may be waiting on the same
   179  // synchronization object, so there may be many sudogs for one object.
   180  //
   181  // sudogs are allocated from a special pool. Use acquireSudog and
   182  // releaseSudog to allocate and free them.
   183  //
   184  // See ${GOROOT}/src/runtime/runtime2.go#type:sudog
   185  type Sudog struct {
   186  
   187  	// The following fields are protected by the hchan.lock of the
   188  	// channel this sudog is blocking on. shrinkstack depends on
   189  	// this for sudogs involved in channel ops.
   190  
   191  	g *GHead
   192  
   193  	next *Sudog
   194  	prev *Sudog
   195  
   196  	// NOTE: linker checks `elem` field for dwarf
   197  	// 		DO NOT CHANGE THESE NAMES
   198  	elem unsafe.Pointer // data element (may point to stack)
   199  
   200  	// The following fields are never accessed concurrently.
   201  	// For channels, waitlink is only accessed by g.
   202  	// For semaphores, all fields (including the ones above)
   203  	// are only accessed when holding a semaRoot lock.
   204  
   205  	acquiretime int64
   206  	releasetime int64
   207  	ticket      uint32
   208  
   209  	// isSelect indicates g is participating in a select, so
   210  	// g.selectDone must be CAS'd to win the wake-up race.
   211  	isSelect bool
   212  
   213  	// success indicates whether communication over channel c
   214  	// succeeded. It is true if the goroutine was awoken because a
   215  	// value was delivered over channel c, and false if awoken
   216  	// because c was closed.
   217  	success bool
   218  
   219  	parent   *Sudog // semaRoot binary tree
   220  	waitlink *Sudog // g.waiting list or semaRoot
   221  	waittail *Sudog // semaRoot
   222  	c        *hchan // channel
   223  }
   224  
   225  // G status
   226  //
   227  // Beyond indicating the general state of a G, the G status
   228  // acts like a lock on the goroutine's stack (and hence its
   229  // ability to execute user code).
   230  //
   231  // If you add to this list, add to the list
   232  // of "okay during garbage collection" status
   233  // in mgcmark.go too.
   234  //
   235  // TODO(austin): The StatusGscan bit could be much lighter-weight.
   236  // For example, we could choose not to run StatusGscanrunnable
   237  // goroutines found in the run queue, rather than CAS-looping
   238  // until they become StatusGrunnable. And transitions like
   239  // StatusGscanwaiting -> StatusGscanrunnable are actually okay because
   240  // they don't affect stack ownership.
   241  type Status = uint32
   242  
   243  const (
   244  	// StatusGidle means this goroutine was just allocated and has not
   245  	// yet been initialized.
   246  	StatusGidle Status = iota // 0
   247  
   248  	// StatusGrunnable means this goroutine is on a run queue. It is
   249  	// not currently executing user code. The stack is not owned.
   250  	StatusGrunnable // 1
   251  
   252  	// StatusGrunning means this goroutine may execute user code. The
   253  	// stack is owned by this goroutine. It is not on a run queue.
   254  	// It is assigned an M and a P (g.m and g.m.p are valid).
   255  	StatusGrunning // 2
   256  
   257  	// StatusGsyscall means this goroutine is executing a system call.
   258  	// It is not executing user code. The stack is owned by this
   259  	// goroutine. It is not on a run queue. It is assigned an M.
   260  	StatusGsyscall // 3
   261  
   262  	// StatusGwaiting means this goroutine is blocked in the runtime.
   263  	// It is not executing user code. It is not on a run queue,
   264  	// but should be recorded somewhere (e.g., a channel wait
   265  	// queue) so it can be ready()d when necessary. The stack is
   266  	// not owned *except* that a channel operation may read or
   267  	// write parts of the stack under the appropriate channel
   268  	// lock. Otherwise, it is not safe to access the stack after a
   269  	// goroutine enters StatusGwaiting (e.g., it may get moved).
   270  	StatusGwaiting // 4
   271  
   272  	// StatusGmoribund_unused is currently unused, but hardcoded in gdb
   273  	// scripts.
   274  	StatusGmoribund_unused // 5
   275  
   276  	// StatusGdead means this goroutine is currently unused. It may be
   277  	// just exited, on a free list, or just being initialized. It
   278  	// is not executing user code. It may or may not have a stack
   279  	// allocated. The G and its stack (if any) are owned by the M
   280  	// that is exiting the G or that obtained the G from the free
   281  	// list.
   282  	StatusGdead // 6
   283  
   284  	// StatusGenqueue_unused is currently unused.
   285  	StatusGenqueue_unused // 7
   286  
   287  	// StatusGcopystack means this goroutine's stack is being moved. It
   288  	// is not executing user code and is not on a run queue. The
   289  	// stack is owned by the goroutine that put it in StatusGcopystack.
   290  	StatusGcopystack // 8
   291  
   292  	// StatusGpreempted means this goroutine stopped itself for a
   293  	// suspendG preemption. It is like StatusGwaiting, but nothing is
   294  	// yet responsible for ready()ing it. Some suspendG must CAS
   295  	// the status to StatusGwaiting to take responsibility for
   296  	// ready()ing this G.
   297  	StatusGpreempted // 9
   298  
   299  	// StatusGscan combined with one of the above states other than
   300  	// StatusGrunning indicates that GC is scanning the stack. The
   301  	// goroutine is not executing user code and the stack is owned
   302  	// by the goroutine that set the StatusGscan bit.
   303  	//
   304  	// StatusGscanrunning is different: it is used to briefly block
   305  	// state transitions while GC signals the G to scan its own
   306  	// stack. This is otherwise like StatusGrunning.
   307  	//
   308  	// atomicstatus&~Gscan gives the state the goroutine will
   309  	// return to when the scan completes.
   310  	StatusGscan          Status = 0x1000
   311  	StatusGscanrunnable  Status = StatusGscan + StatusGrunnable  // 0x1001
   312  	StatusGscanrunning   Status = StatusGscan + StatusGrunning   // 0x1002
   313  	StatusGscansyscall   Status = StatusGscan + StatusGsyscall   // 0x1003
   314  	StatusGscanwaiting   Status = StatusGscan + StatusGwaiting   // 0x1004
   315  	StatusGscanpreempted Status = StatusGscan + StatusGpreempted // 0x1009
   316  )
   317  
   318  // A WaitReason explains why a goroutine has been stopped.
   319  // See gopark. Do not re-use waitReasons, add new ones.
   320  type WaitReason uint8
   321  
   322  const (
   323  	WaitReasonZero                  WaitReason = iota // ""
   324  	WaitReasonGCAssistMarking                         // "GC assist marking"
   325  	WaitReasonIOWait                                  // "IO wait"
   326  	WaitReasonChanReceiveNilChan                      // "chan receive (nil chan)"
   327  	WaitReasonChanSendNilChan                         // "chan send (nil chan)"
   328  	WaitReasonDumpingHeap                             // "dumping heap"
   329  	WaitReasonGarbageCollection                       // "garbage collection"
   330  	WaitReasonGarbageCollectionScan                   // "garbage collection scan"
   331  	WaitReasonPanicWait                               // "panicwait"
   332  	WaitReasonSelect                                  // "select"
   333  	WaitReasonSelectNoCases                           // "select (no cases)"
   334  	WaitReasonGCAssistWait                            // "GC assist wait"
   335  	WaitReasonGCSweepWait                             // "GC sweep wait"
   336  	WaitReasonGCScavengeWait                          // "GC scavenge wait"
   337  	WaitReasonChanReceive                             // "chan receive"
   338  	WaitReasonChanSend                                // "chan send"
   339  	WaitReasonFinalizerWait                           // "finalizer wait"
   340  	WaitReasonForceGCIdle                             // "force gc (idle)"
   341  	WaitReasonSemacquire                              // "semacquire"
   342  	WaitReasonSleep                                   // "sleep"
   343  	WaitReasonSyncCondWait                            // "sync.Cond.Wait"
   344  	WaitReasonSyncMutexLock                           // "sync.Mutex.Lock"
   345  	WaitReasonSyncRWMutexRLock                        // "sync.RWMutex.RLock"
   346  	WaitReasonSyncRWMutexLock                         // "sync.RWMutex.Lock"
   347  	WaitReasonTraceReaderBlocked                      // "trace reader (blocked)"
   348  	WaitReasonWaitForGCCycle                          // "wait for GC cycle"
   349  	WaitReasonGCWorkerIdle                            // "GC worker (idle)"
   350  	WaitReasonGCWorkerActive                          // "GC worker (active)"
   351  	WaitReasonPreempted                               // "preempted"
   352  	WaitReasonDebugCall                               // "debug call"
   353  	WaitReasonGCMarkTermination                       // "GC mark termination"
   354  	WaitReasonStoppingTheWorld                        // "stopping the world"
   355  )
   356  
   357  func (w WaitReason) IsMutexWait() bool {
   358  	return w == WaitReasonSyncMutexLock ||
   359  		w == WaitReasonSyncRWMutexRLock ||
   360  		w == WaitReasonSyncRWMutexLock
   361  }