diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..24a9221 --- /dev/null +++ b/LICENSE @@ -0,0 +1,53 @@ +Copyright for package goroutine. +===================================================================== +Copyright (c) 2015 Huan Du + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +===================================================================== + +Copyright notice for golang source code. +===================================================================== +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +===================================================================== diff --git a/README.md b/README.md new file mode 100644 index 0000000..0492e41 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# Hacking goroutine # + +Package goroutine is merely a hack. +It exports goroutine id to outside so that you can use it for whatever purpose. +However, it's highly recommended to not use this package in your daily life. +It may be broken at any go release as it's a hack. + +## Usage ## + +Get the latest version through `go get -u github.com/huandu/goroutine`. + +Get current goroutine id with `goroutine.GoroutineId()`. + +```go +// Get id of current goroutine. +var id int64 = goroutine.GoroutineId() +println(id) +``` + +See [godoc](https://godoc.org/github.com/huandu/goroutine) for more details. + +## Caveats ## + +Package goroutine is not well tested due to lack of test machines. + +Tested platforms. +* go1.5.1 + Darwin (Mac OSX 10.11.1) + amd64 CPU + +## License ## + +This package is licensed under MIT license. See LICENSE for details. diff --git a/arch_386.go b/arch_386.go new file mode 100644 index 0000000..8dab3eb --- /dev/null +++ b/arch_386.go @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +type uintreg uint32 +type intptr int32 // TODO(rsc): remove diff --git a/arch_amd64.go b/arch_amd64.go new file mode 100644 index 0000000..58b788f --- /dev/null +++ b/arch_amd64.go @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +type uintreg uint64 +type intptr int64 // TODO(rsc): remove diff --git a/arch_amd64p32.go b/arch_amd64p32.go new file mode 100644 index 0000000..a61f307 --- /dev/null +++ b/arch_amd64p32.go @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +type uintreg uint64 +type intptr int32 // TODO(rsc): remove diff --git a/arch_arm.go b/arch_arm.go new file mode 100644 index 0000000..8dab3eb --- /dev/null +++ b/arch_arm.go @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +type uintreg uint32 +type intptr int32 // TODO(rsc): remove diff --git a/arch_arm64.go b/arch_arm64.go new file mode 100644 index 0000000..58b788f --- /dev/null +++ b/arch_arm64.go @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +type uintreg uint64 +type intptr int64 // TODO(rsc): remove diff --git a/arch_ppc64.go b/arch_ppc64.go new file mode 100644 index 0000000..58b788f --- /dev/null +++ b/arch_ppc64.go @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +type uintreg uint64 +type intptr int64 // TODO(rsc): remove diff --git a/arch_ppc64le.go b/arch_ppc64le.go new file mode 100644 index 0000000..58b788f --- /dev/null +++ b/arch_ppc64le.go @@ -0,0 +1,8 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +type uintreg uint64 +type intptr int64 // TODO(rsc): remove diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..1845ef1 --- /dev/null +++ b/doc.go @@ -0,0 +1,8 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +// Package goroutine is merely a hack. Don't use it if you can. +// +// Package goroutine exports goroutine id. Do whatever you want with care. +package goroutine diff --git a/go_tls.h b/go_tls.h new file mode 100644 index 0000000..6a707cf --- /dev/null +++ b/go_tls.h @@ -0,0 +1,22 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifdef GOARCH_arm +#define LR R14 +#endif + +#ifdef GOARCH_amd64 +#define get_tls(r) MOVQ TLS, r +#define g(r) 0(r)(TLS*1) +#endif + +#ifdef GOARCH_amd64p32 +#define get_tls(r) MOVL TLS, r +#define g(r) 0(r)(TLS*1) +#endif + +#ifdef GOARCH_386 +#define get_tls(r) MOVL TLS, r +#define g(r) 0(r)(TLS*1) +#endif diff --git a/info.go b/info.go new file mode 100644 index 0000000..0fae335 --- /dev/null +++ b/info.go @@ -0,0 +1,14 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +package goroutine + +func getg() *g + +// GoroutineId return id of current goroutine. +// It's guaranteed to be unique globally during app's life time. +func GoroutineId() int64 { + gp := getg() + return gp.goid +} diff --git a/info_386.s b/info_386.s new file mode 100644 index 0000000..603b5c4 --- /dev/null +++ b/info_386.s @@ -0,0 +1,13 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "go_tls.h" +#include "textflag.h" + +TEXT ·getg(SB), NOSPLIT, $0-4 + get_tls(CX) + MOVL g(CX), AX + MOVL AX, ret+0(FP) + RET diff --git a/info_amd64.s b/info_amd64.s new file mode 100644 index 0000000..86c3361 --- /dev/null +++ b/info_amd64.s @@ -0,0 +1,13 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "go_tls.h" +#include "textflag.h" + +TEXT ·getg(SB), NOSPLIT, $0-8 + get_tls(CX) + MOVQ g(CX), AX + MOVQ AX, ret+0(FP) + RET diff --git a/info_amd64p32.s b/info_amd64p32.s new file mode 100644 index 0000000..a50c333 --- /dev/null +++ b/info_amd64p32.s @@ -0,0 +1,5 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +#include "info_amd64.s" diff --git a/info_arm.s b/info_arm.s new file mode 100644 index 0000000..552d7ce --- /dev/null +++ b/info_arm.s @@ -0,0 +1,10 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "textflag.h" + +TEXT ·getg(SB), NOSPLIT, $0-4 + MOVW g, ret+0(FP) + RET diff --git a/info_arm64.s b/info_arm64.s new file mode 100644 index 0000000..2d0feb0 --- /dev/null +++ b/info_arm64.s @@ -0,0 +1,12 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +#include "go_asm.h" +#include "go_tls.h" +#include "textflag.h" + +TEXT ·getg(SB), NOSPLIT, $0-8 + get_tls(R0) + MOVQ R0, ret+0(FP) + RET diff --git a/info_test.go b/info_test.go new file mode 100644 index 0000000..16f34ee --- /dev/null +++ b/info_test.go @@ -0,0 +1,47 @@ +// Copyright 2015 Huan Du. All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +package goroutine + +import ( + "testing" + "time" + "fmt" + "math/rand" +) + +func TestGoroutineIdConsistency(t *testing.T) { + cnt := 10 + exit := make(chan error) + + for i := 0; i < cnt; i++ { + go func(n int) { + id1 := GoroutineId() + time.Sleep(time.Duration(rand.Int63n(100)) * time.Millisecond) + id2 := GoroutineId() + + if id1 != id2 { + exit <- fmt.Errorf("Inconsistent goroutine id. [old:%v] [new:%v]", id1, id2) + return + } + + exit <- nil + }(i) + } + + failed := false + + for i := 0; i < cnt; i++ { + err := <-exit + + if err != nil { + t.Logf("Found error. [err:%v]", err) + failed = true + } + } + + if failed { + t.Fatalf("Test failed.") + } +} diff --git a/opaque.go b/opaque.go new file mode 100644 index 0000000..8b79a1f --- /dev/null +++ b/opaque.go @@ -0,0 +1,75 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +import "unsafe" + +const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const +const regSize = 4 << (^uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const + +type mcache struct {} +type typeAlg struct {} +type traceBuf struct {} + +type gcMarkWorkerMode int + +type persistentAlloc struct { + base unsafe.Pointer + off uintptr +} + +// A wbufptr holds a workbuf*, but protects it from write barriers. +// workbufs never live on the heap, so write barriers are unnecessary. +// Write barriers on workbuf pointers may also be dangerous in the GC. +type wbufptr uintptr + +// A gcWork provides the interface to produce and consume work for the +// garbage collector. +// +// A gcWork can be used on the stack as follows: +// +// var gcw gcWork +// disable preemption +// .. call gcw.put() to produce and gcw.get() to consume .. +// gcw.dispose() +// enable preemption +// +// Or from the per-P gcWork cache: +// +// (preemption must be disabled) +// gcw := &getg().m.p.ptr().gcw +// .. call gcw.put() to produce and gcw.get() to consume .. +// if gcphase == _GCmarktermination { +// gcw.dispose() +// } +// +// It's important that any use of gcWork during the mark phase prevent +// the garbage collector from transitioning to mark termination since +// gcWork may locally hold GC work buffers. This can be done by +// disabling preemption (systemstack or acquirem). +type gcWork struct { + // Invariant: wbuf is never full or empty + wbuf wbufptr + + // Bytes marked (blackened) on this gcWork. This is aggregated + // into work.bytesMarked by dispose. + bytesMarked uint64 + + // Scan work performed on this gcWork. This is aggregated into + // gcController by dispose. + scanWork int64 +} + +// Information from the compiler about the layout of stack frames. +type bitvector struct { + n int32 // # of bits + bytedata *uint8 +} + +type slice struct { + array unsafe.Pointer + len int + cap int +} diff --git a/runtime2.go b/runtime2.go new file mode 100644 index 0000000..736bedc --- /dev/null +++ b/runtime2.go @@ -0,0 +1,699 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goroutine + +import "unsafe" + +/* + * defined constants + */ +const ( + // G status + // + // If you add to this list, add to the list + // of "okay during garbage collection" status + // in mgcmark.go too. + _Gidle = iota // 0 + _Grunnable // 1 runnable and on a run queue + _Grunning // 2 + _Gsyscall // 3 + _Gwaiting // 4 + _Gmoribund_unused // 5 currently unused, but hardcoded in gdb scripts + _Gdead // 6 + _Genqueue // 7 Only the Gscanenqueue is used. + _Gcopystack // 8 in this state when newstack is moving the stack + // the following encode that the GC is scanning the stack and what to do when it is done + _Gscan = 0x1000 // atomicstatus&~Gscan = the non-scan state, + // _Gscanidle = _Gscan + _Gidle, // Not used. Gidle only used with newly malloced gs + _Gscanrunnable = _Gscan + _Grunnable // 0x1001 When scanning completes make Grunnable (it is already on run queue) + _Gscanrunning = _Gscan + _Grunning // 0x1002 Used to tell preemption newstack routine to scan preempted stack. + _Gscansyscall = _Gscan + _Gsyscall // 0x1003 When scanning completes make it Gsyscall + _Gscanwaiting = _Gscan + _Gwaiting // 0x1004 When scanning completes make it Gwaiting + // _Gscanmoribund_unused, // not possible + // _Gscandead, // not possible + _Gscanenqueue = _Gscan + _Genqueue // When scanning completes make it Grunnable and put on runqueue +) + +const ( + // P status + _Pidle = iota + _Prunning // Only this P is allowed to change from _Prunning. + _Psyscall + _Pgcstop + _Pdead +) + +// The next line makes 'go generate' write the zgen_*.go files with +// per-OS and per-arch information, including constants +// named goos_$GOOS and goarch_$GOARCH for every +// known GOOS and GOARCH. The constant is 1 on the +// current system, 0 otherwise; multiplying by them is +// useful for defining GOOS- or GOARCH-specific constants. +//go:generate go run gengoos.go + +type mutex struct { + // Futex-based impl treats it as uint32 key, + // while sema-based impl as M* waitm. + // Used to be a union, but unions break precise GC. + key uintptr +} + +type note struct { + // Futex-based impl treats it as uint32 key, + // while sema-based impl as M* waitm. + // Used to be a union, but unions break precise GC. + key uintptr +} + +type _string struct { + str *byte + len int +} + +type funcval struct { + fn uintptr + // variable-size, fn-specific data here +} + +type iface struct { + tab *itab + data unsafe.Pointer +} + +type eface struct { + _type *_type + data unsafe.Pointer +} + +// The guintptr, muintptr, and puintptr are all used to bypass write barriers. +// It is particularly important to avoid write barriers when the current P has +// been released, because the GC thinks the world is stopped, and an +// unexpected write barrier would not be synchronized with the GC, +// which can lead to a half-executed write barrier that has marked the object +// but not queued it. If the GC skips the object and completes before the +// queuing can occur, it will incorrectly free the object. +// +// We tried using special assignment functions invoked only when not +// holding a running P, but then some updates to a particular memory +// word went through write barriers and some did not. This breaks the +// write barrier shadow checking mode, and it is also scary: better to have +// a word that is completely ignored by the GC than to have one for which +// only a few updates are ignored. +// +// Gs, Ms, and Ps are always reachable via true pointers in the +// allgs, allm, and allp lists or (during allocation before they reach those lists) +// from stack variables. + +// A guintptr holds a goroutine pointer, but typed as a uintptr +// to bypass write barriers. It is used in the Gobuf goroutine state +// and in scheduling lists that are manipulated without a P. +// +// The Gobuf.g goroutine pointer is almost always updated by assembly code. +// In one of the few places it is updated by Go code - func save - it must be +// treated as a uintptr to avoid a write barrier being emitted at a bad time. +// Instead of figuring out how to emit the write barriers missing in the +// assembly manipulation, we change the type of the field to uintptr, +// so that it does not require write barriers at all. +// +// Goroutine structs are published in the allg list and never freed. +// That will keep the goroutine structs from being collected. +// There is never a time that Gobuf.g's contain the only references +// to a goroutine: the publishing of the goroutine in allg comes first. +// Goroutine pointers are also kept in non-GC-visible places like TLS, +// so I can't see them ever moving. If we did want to start moving data +// in the GC, we'd need to allocate the goroutine structs from an +// alternate arena. Using guintptr doesn't make that problem any worse. +type guintptr uintptr + +func (gp guintptr) ptr() *g { return (*g)(unsafe.Pointer(gp)) } +func (gp *guintptr) set(g *g) { *gp = guintptr(unsafe.Pointer(g)) } +// func (gp *guintptr) cas(old, new guintptr) bool { +// return casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new)) +// } + +type puintptr uintptr + +func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) } +func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) } + +type muintptr uintptr + +func (mp muintptr) ptr() *m { return (*m)(unsafe.Pointer(mp)) } +func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) } + +type gobuf struct { + // The offsets of sp, pc, and g are known to (hard-coded in) libmach. + sp uintptr + pc uintptr + g guintptr + ctxt unsafe.Pointer // this has to be a pointer so that gc scans it + ret uintreg + lr uintptr + bp uintptr // for GOEXPERIMENT=framepointer +} + +// Known to compiler. +// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. +type sudog struct { + g *g + selectdone *uint32 + next *sudog + prev *sudog + elem unsafe.Pointer // data element + releasetime int64 + nrelease int32 // -1 for acquire + waitlink *sudog // g.waiting list +} + +type gcstats struct { + // the struct must consist of only uint64's, + // because it is casted to uint64[]. + nhandoff uint64 + nhandoffcnt uint64 + nprocyield uint64 + nosyield uint64 + nsleep uint64 +} + +type libcall struct { + fn uintptr + n uintptr // number of parameters + args uintptr // parameters + r1 uintptr // return values + r2 uintptr + err uintptr // error number +} + +// describes how to handle callback +type wincallbackcontext struct { + gobody unsafe.Pointer // go function to call + argsize uintptr // callback arguments size (in bytes) + restorestack uintptr // adjust stack on return by (in bytes) (386 only) + cleanstack bool +} + +// Stack describes a Go execution stack. +// The bounds of the stack are exactly [lo, hi), +// with no implicit data structures on either side. +type stack struct { + lo uintptr + hi uintptr +} + +// stkbar records the state of a G's stack barrier. +type stkbar struct { + savedLRPtr uintptr // location overwritten by stack barrier PC + savedLRVal uintptr // value overwritten at savedLRPtr +} + +type g struct { + // Stack parameters. + // stack describes the actual stack memory: [stack.lo, stack.hi). + // stackguard0 is the stack pointer compared in the Go stack growth prologue. + // It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption. + // stackguard1 is the stack pointer compared in the C stack growth prologue. + // It is stack.lo+StackGuard on g0 and gsignal stacks. + // It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash). + stack stack // offset known to runtime/cgo + stackguard0 uintptr // offset known to liblink + stackguard1 uintptr // offset known to liblink + + _panic *_panic // innermost panic - offset known to liblink + _defer *_defer // innermost defer + m *m // current m; offset known to arm liblink + stackAlloc uintptr // stack allocation is [stack.lo,stack.lo+stackAlloc) + sched gobuf + syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc + syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc + stkbar []stkbar // stack barriers, from low to high + stkbarPos uintptr // index of lowest stack barrier not hit + param unsafe.Pointer // passed parameter on wakeup + atomicstatus uint32 + stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus + goid int64 + waitsince int64 // approx time when the g become blocked + waitreason string // if status==Gwaiting + schedlink guintptr + preempt bool // preemption signal, duplicates stackguard0 = stackpreempt + paniconfault bool // panic (instead of crash) on unexpected fault address + preemptscan bool // preempted g does scan for gc + gcscandone bool // g has scanned stack; protected by _Gscan bit in status + gcscanvalid bool // false at start of gc cycle, true if G has not run since last scan + throwsplit bool // must not split stack + raceignore int8 // ignore race detection events + sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine + sysexitticks int64 // cputicks when syscall has returned (for tracing) + sysexitseq uint64 // trace seq when syscall has returned (for tracing) + lockedm *m + sig uint32 + writebuf []byte + sigcode0 uintptr + sigcode1 uintptr + sigpc uintptr + gopc uintptr // pc of go statement that created this goroutine + startpc uintptr // pc of goroutine function + racectx uintptr + waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr) + readyg *g // scratch for readyExecute + + // Per-G gcController state + gcalloc uintptr // bytes allocated during this GC cycle + gcscanwork int64 // scan work done (or stolen) this GC cycle +} + +type mts struct { + tv_sec int64 + tv_nsec int64 +} + +type mscratch struct { + v [6]uintptr +} + +type m struct { + g0 *g // goroutine with scheduling stack + morebuf gobuf // gobuf arg to morestack + divmod uint32 // div/mod denominator for arm - known to liblink + + // Fields not known to debuggers. + procid uint64 // for debuggers, but offset not hard-coded + gsignal *g // signal-handling g + sigmask [4]uintptr // storage for saved signal mask + tls [4]uintptr // thread-local storage (for x86 extern register) + mstartfn func() + curg *g // current running goroutine + caughtsig guintptr // goroutine running during fatal signal + p puintptr // attached p for executing go code (nil if not executing go code) + nextp puintptr + id int32 + mallocing int32 + throwing int32 + preemptoff string // if != "", keep curg running on this m + locks int32 + softfloat int32 + dying int32 + profilehz int32 + helpgc int32 + spinning bool // m is out of work and is actively looking for work + blocked bool // m is blocked on a note + inwb bool // m is executing a write barrier + printlock int8 + fastrand uint32 + ncgocall uint64 // number of cgo calls in total + ncgo int32 // number of cgo calls currently in progress + park note + alllink *m // on allm + schedlink muintptr + machport uint32 // return address for mach ipc (os x) + mcache *mcache + lockedg *g + createstack [32]uintptr // stack that created this thread. + freglo [16]uint32 // d[i] lsb and f[i] + freghi [16]uint32 // d[i] msb and f[i+16] + fflag uint32 // floating point compare flags + locked uint32 // tracking for lockosthread + nextwaitm uintptr // next m waiting for lock + waitsema uintptr // semaphore for parking on locks + waitsemacount uint32 + waitsemalock uint32 + gcstats gcstats + needextram bool + traceback uint8 + waitunlockf unsafe.Pointer // todo go func(*g, unsafe.pointer) bool + waitlock unsafe.Pointer + waittraceev byte + waittraceskip int + startingtrace bool + syscalltick uint32 + //#ifdef GOOS_windows + thread uintptr // thread handle + // these are here because they are too large to be on the stack + // of low-level NOSPLIT functions. + libcall libcall + libcallpc uintptr // for cpu profiler + libcallsp uintptr + libcallg guintptr + syscall libcall // stores syscall parameters on windows + //#endif + //#ifdef GOOS_solaris + perrno *int32 // pointer to tls errno + // these are here because they are too large to be on the stack + // of low-level NOSPLIT functions. + //LibCall libcall; + ts mts + scratch mscratch + //#endif + //#ifdef GOOS_plan9 + notesig *int8 + errstr *byte + //#endif +} + +type p struct { + lock mutex + + id int32 + status uint32 // one of pidle/prunning/... + link puintptr + schedtick uint32 // incremented on every scheduler call + syscalltick uint32 // incremented on every system call + m muintptr // back-link to associated m (nil if idle) + mcache *mcache + + deferpool [5][]*_defer // pool of available defer structs of different sizes (see panic.go) + deferpoolbuf [5][32]*_defer + + // Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen. + goidcache uint64 + goidcacheend uint64 + + // Queue of runnable goroutines. Accessed without lock. + runqhead uint32 + runqtail uint32 + runq [256]*g + // runnext, if non-nil, is a runnable G that was ready'd by + // the current G and should be run next instead of what's in + // runq if there's time remaining in the running G's time + // slice. It will inherit the time left in the current time + // slice. If a set of goroutines is locked in a + // communicate-and-wait pattern, this schedules that set as a + // unit and eliminates the (potentially large) scheduling + // latency that otherwise arises from adding the ready'd + // goroutines to the end of the run queue. + runnext guintptr + + // Available G's (status == Gdead) + gfree *g + gfreecnt int32 + + sudogcache []*sudog + sudogbuf [128]*sudog + + tracebuf *traceBuf + + palloc persistentAlloc // per-P to avoid mutex + + // Per-P GC state + gcAssistTime int64 // Nanoseconds in assistAlloc + gcBgMarkWorker *g + gcMarkWorkerMode gcMarkWorkerMode + + // gcw is this P's GC work buffer cache. The work buffer is + // filled by write barriers, drained by mutator assists, and + // disposed on certain GC state transitions. + gcw gcWork + + runSafePointFn uint32 // if 1, run sched.safePointFn at next safe point + + pad [64]byte +} + +const ( + // The max value of GOMAXPROCS. + // There are no fundamental restrictions on the value. + _MaxGomaxprocs = 1 << 8 +) + +type schedt struct { + lock mutex + + goidgen uint64 + + midle muintptr // idle m's waiting for work + nmidle int32 // number of idle m's waiting for work + nmidlelocked int32 // number of locked m's waiting for work + mcount int32 // number of m's that have been created + maxmcount int32 // maximum number of m's allowed (or die) + + pidle puintptr // idle p's + npidle uint32 + nmspinning uint32 + + // Global runnable queue. + runqhead guintptr + runqtail guintptr + runqsize int32 + + // Global cache of dead G's. + gflock mutex + gfree *g + ngfree int32 + + // Central cache of sudog structs. + sudoglock mutex + sudogcache *sudog + + // Central pool of available defer structs of different sizes. + deferlock mutex + deferpool [5]*_defer + + gcwaiting uint32 // gc is waiting to run + stopwait int32 + stopnote note + sysmonwait uint32 + sysmonnote note + lastpoll uint64 + + // safepointFn should be called on each P at the next GC + // safepoint if p.runSafePointFn is set. + safePointFn func(*p) + safePointWait int32 + safePointNote note + + profilehz int32 // cpu profiling rate + + procresizetime int64 // nanotime() of last change to gomaxprocs + totaltime int64 // ∫gomaxprocs dt up to procresizetime +} + +// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread. +// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active. +// External locks are not recursive; a second lock is silently ignored. +// The upper bits of m->locked record the nesting depth of calls to lockOSThread +// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal). +// Internal locks can be recursive. For instance, a lock for cgo can occur while the main +// goroutine is holding the lock during the initialization phase. +const ( + _LockExternal = 1 + _LockInternal = 2 +) + +type sigtabtt struct { + flags int32 + name *int8 +} + +const ( + _SigNotify = 1 << iota // let signal.Notify have signal, even if from kernel + _SigKill // if signal.Notify doesn't take it, exit quietly + _SigThrow // if signal.Notify doesn't take it, exit loudly + _SigPanic // if the signal is from the kernel, panic + _SigDefault // if the signal isn't explicitly requested, don't monitor it + _SigHandling // our signal handler is registered + _SigIgnored // the signal was ignored before we registered for it + _SigGoExit // cause all runtime procs to exit (only used on Plan 9). + _SigSetStack // add SA_ONSTACK to libc handler + _SigUnblock // unblocked in minit +) + +// Layout of in-memory per-function information prepared by linker +// See https://golang.org/s/go12symtab. +// Keep in sync with linker +// and with package debug/gosym and with symtab.go in package runtime. +type _func struct { + entry uintptr // start pc + nameoff int32 // function name + + args int32 // in/out args size + frame int32 // legacy frame size; use pcsp if possible + + pcsp int32 + pcfile int32 + pcln int32 + npcdata int32 + nfuncdata int32 +} + +// layout of Itab known to compilers +// allocated in non-garbage-collected memory +type itab struct { + inter *interfacetype + _type *_type + link *itab + bad int32 + unused int32 + fun [1]uintptr // variable sized +} + +// Lock-free stack node. +// // Also known to export_test.go. +type lfnode struct { + next uint64 + pushcnt uintptr +} + +type forcegcstate struct { + lock mutex + g *g + idle uint32 +} + +/* + * known to compiler + */ +const ( + _Structrnd = regSize +) + +// startup_random_data holds random bytes initialized at startup. These come from +// the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.go or os_linux_386.go). +var startupRandomData []byte + +// extendRandom extends the random numbers in r[:n] to the whole slice r. +// Treats n<0 as n==0. +func extendRandom(r []byte, n int) { + // if n < 0 { + // n = 0 + // } + // for n < len(r) { + // // Extend random bits using hash function & time seed + // w := n + // if w > 16 { + // w = 16 + // } + // h := memhash(unsafe.Pointer(&r[n-w]), uintptr(nanotime()), uintptr(w)) + // for i := 0; i < ptrSize && n < len(r); i++ { + // r[n] = byte(h) + // n++ + // h >>= 8 + // } + // } +} + +/* + * deferred subroutine calls + */ +type _defer struct { + siz int32 + started bool + sp uintptr // sp at time of defer + pc uintptr + fn *funcval + _panic *_panic // panic that is running defer + link *_defer +} + +/* + * panics + */ +type _panic struct { + argp unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink + arg interface{} // argument to panic + link *_panic // link to earlier panic + recovered bool // whether this panic is over + aborted bool // the panic was aborted +} + +/* + * stack traces + */ + +type stkframe struct { + fn *_func // function being run + pc uintptr // program counter within fn + continpc uintptr // program counter where execution can continue, or 0 if not + lr uintptr // program counter at caller aka link register + sp uintptr // stack pointer at pc + fp uintptr // stack pointer at caller aka frame pointer + varp uintptr // top of local variables + argp uintptr // pointer to function arguments + arglen uintptr // number of bytes at argp + argmap *bitvector // force use of this argmap +} + +const ( + _TraceRuntimeFrames = 1 << iota // include frames for internal runtime functions. + _TraceTrap // the initial PC, SP are from a trap, not a return PC from a call + _TraceJumpStack // if traceback is on a systemstack, resume trace at g that called into it +) + +const ( + // The maximum number of frames we print for a traceback + _TracebackMaxFrames = 100 +) + +var ( + emptystring string + allg **g + allglen uintptr + lastg *g + allm *m + allp [_MaxGomaxprocs + 1]*p + gomaxprocs int32 + panicking uint32 + goos *int8 + ncpu int32 + signote note + forcegc forcegcstate + sched schedt + newprocs int32 + + // Information about what cpu features are available. + // Set on startup in asm_{x86,amd64}.s. + cpuid_ecx uint32 + cpuid_edx uint32 + lfenceBeforeRdtsc bool + + goarm uint8 // set by cmd/link on arm systems +) + +// Set by the linker so the runtime can determine the buildmode. +var ( + islibrary bool // -buildmode=c-shared + isarchive bool // -buildmode=c-archive +) + +/* + * mutual exclusion locks. in the uncontended case, + * as fast as spin locks (just a few user-level instructions), + * but on the contention path they sleep in the kernel. + * a zeroed Mutex is unlocked (no need to initialize each lock). + */ + +/* + * sleep and wakeup on one-time events. + * before any calls to notesleep or notewakeup, + * must call noteclear to initialize the Note. + * then, exactly one thread can call notesleep + * and exactly one thread can call notewakeup (once). + * once notewakeup has been called, the notesleep + * will return. future notesleep will return immediately. + * subsequent noteclear must be called only after + * previous notesleep has returned, e.g. it's disallowed + * to call noteclear straight after notewakeup. + * + * notetsleep is like notesleep but wakes up after + * a given number of nanoseconds even if the event + * has not yet happened. if a goroutine uses notetsleep to + * wake up early, it must wait to call noteclear until it + * can be sure that no other goroutine is calling + * notewakeup. + * + * notesleep/notetsleep are generally called on g0, + * notetsleepg is similar to notetsleep but is called on user g. + */ +// bool runtime·notetsleep(Note*, int64); // false - timeout +// bool runtime·notetsleepg(Note*, int64); // false - timeout + +/* + * Lock-free stack. + * Initialize uint64 head to 0, compare with 0 to test for emptiness. + * The stack does not keep pointers to nodes, + * so they can be garbage collected if there are no other pointers to nodes. + */ + +// for mmap, we only pass the lower 32 bits of file offset to the +// assembly routine; the higher bits (if required), should be provided +// by the assembly routine as 0. diff --git a/type.go b/type.go new file mode 100644 index 0000000..a52108b --- /dev/null +++ b/type.go @@ -0,0 +1,94 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Runtime type representation. + +package goroutine + +import "unsafe" + +// Needs to be in sync with ../cmd/internal/ld/decodesym.go:/^func.commonsize, +// ../cmd/internal/gc/reflect.go:/^func.dcommontype and +// ../reflect/type.go:/^type.rtype. +type _type struct { + size uintptr + ptrdata uintptr // size of memory prefix holding all pointers + hash uint32 + _unused uint8 + align uint8 + fieldalign uint8 + kind uint8 + alg *typeAlg + // gcdata stores the GC type data for the garbage collector. + // If the KindGCProg bit is set in kind, gcdata is a GC program. + // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. + gcdata *byte + _string *string + x *uncommontype + ptrto *_type + zero *byte // ptr to the zero value for this type +} + +type method struct { + name *string + pkgpath *string + mtyp *_type + typ *_type + ifn unsafe.Pointer + tfn unsafe.Pointer +} + +type uncommontype struct { + name *string + pkgpath *string + mhdr []method +} + +type imethod struct { + name *string + pkgpath *string + _type *_type +} + +type interfacetype struct { + typ _type + mhdr []imethod +} + +type maptype struct { + typ _type + key *_type + elem *_type + bucket *_type // internal type representing a hash bucket + hmap *_type // internal type representing a hmap + keysize uint8 // size of key slot + indirectkey bool // store ptr to key instead of key itself + valuesize uint8 // size of value slot + indirectvalue bool // store ptr to value instead of value itself + bucketsize uint16 // size of bucket + reflexivekey bool // true if k==k for all keys +} + +type chantype struct { + typ _type + elem *_type + dir uintptr +} + +type slicetype struct { + typ _type + elem *_type +} + +type functype struct { + typ _type + dotdotdot bool + in slice + out slice +} + +type ptrtype struct { + typ _type + elem *_type +}