From 75791bab05ec4a45a5c6a4dccd7f824ea8f4487c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 30 Aug 2016 21:07:47 +0000 Subject: [PATCH] runtime: use -fgo-c-header to build C header file Use the new -fgo-c-header option to build a header file for the Go runtime code in libgo/go/runtime, and use the new header file in the C runtime code in libgo/runtime. This will ensure that the Go code and C code share the same data structures as we convert the runtime from C to Go. The new file libgo/go/runtime/runtime2.go is copied from the Go 1.7 release, and then edited to remove unnecessary data structures and modify others for use with libgo. The new file libgo/go/runtime/mcache.go is an initial version of the same files in the Go 1.7 release, and will be replaced by the Go 1.7 file when we convert to the new memory allocator. The new file libgo/go/runtime/type.go describes the gccgo version of the reflection data structures, and replaces the Go 1.7 runtime file which describes the gc version of those structures. Using the new header file means changing a number of struct fields to use Go naming conventions (that is, no underscores) and to rename constants to have a leading underscore so that they are not exported from the Go package. These names were updated in the C code. The C code was also changed to drop the thread-local variable m, as was done some time ago in the gc sources. Now the m field is always accessed using g->m, where g is the single remaining thread-local variable. This in turn required some adjustments to set g->m correctly in all cases. Also pass the new -fgo-compiling-runtime option when compiling the runtime package, although that option doesn't do anything yet. Reviewed-on: https://go-review.googlesource.com/28051 From-SVN: r239872 --- gcc/go/gofrontend/MERGE | 2 +- libgo/Makefile.am | 46 +- libgo/Makefile.in | 46 +- libgo/go/runtime/mcache.go | 102 ++++ libgo/go/runtime/runtime2.go | 835 ++++++++++++++++++++++++++++ libgo/go/runtime/type.go | 100 ++++ libgo/mksysinfo.sh | 1 + libgo/runtime/go-cgo.c | 24 +- libgo/runtime/go-defer.c | 39 +- libgo/runtime/go-defer.h | 47 -- libgo/runtime/go-deferred-recover.c | 3 +- libgo/runtime/go-panic.c | 41 +- libgo/runtime/go-panic.h | 23 +- libgo/runtime/go-recover.c | 61 +- libgo/runtime/go-signal.c | 24 +- libgo/runtime/go-unwind.c | 56 +- libgo/runtime/heapdump.c | 45 +- libgo/runtime/lock_sema.c | 4 +- libgo/runtime/malloc.goc | 16 +- libgo/runtime/malloc.h | 100 +--- libgo/runtime/mcache.c | 4 +- libgo/runtime/mcentral.c | 2 +- libgo/runtime/mgc0.c | 52 +- libgo/runtime/mheap.c | 26 +- libgo/runtime/mprof.goc | 2 +- libgo/runtime/msize.c | 18 +- libgo/runtime/netpoll.goc | 4 +- libgo/runtime/panic.c | 23 +- libgo/runtime/proc.c | 720 ++++++++++++------------ libgo/runtime/runtime.c | 3 +- libgo/runtime/runtime.h | 268 ++------- libgo/runtime/runtime1.goc | 4 +- libgo/runtime/signal_unix.c | 16 +- 33 files changed, 1757 insertions(+), 1000 deletions(-) create mode 100644 libgo/go/runtime/mcache.go create mode 100644 libgo/go/runtime/runtime2.go create mode 100644 libgo/go/runtime/type.go delete mode 100644 libgo/runtime/go-defer.h diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e92aee31835..633dfcfdd8a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -9c91e7eeb404b5b639cd6e80e2a38da948bb35ec +394486a1cec9bbb81216311ed153179d9fe1c2c5 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 589ae66b61b..0a54a8972c5 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -595,6 +595,16 @@ s-version: Makefile $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go $(STAMP) $@ +runtime_sysinfo.go: s-runtime_sysinfo; @true +s-runtime_sysinfo: sysinfo.go + rm -f tmp-runtime_sysinfo.go + echo 'package runtime' > tmp-runtime_sysinfo.go + echo >> tmp-runtime_sysinfo.go + grep 'const _sizeof_ucontext_t ' sysinfo.go >> tmp-runtime_sysinfo.go + grep 'type _sigset_t ' sysinfo.go >> tmp-runtime_sysinfo.go + $(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go + $(STAMP) $@ + noinst_DATA = zstdpkglist.go # Generate the list of go std packages that were included in libgo @@ -877,6 +887,13 @@ libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC libnetgo_a_SOURCES = libnetgo_a_LIBADD = netgo.o +# Make sure runtime.inc is built before compiling any .c file. +$(libgo_la_OBJECTS): runtime.inc +$(libgo_llgo_la_OBJECTS): runtime.inc +$(libgobegin_a_OBJECTS): runtime.inc +$(libgobegin_llgo_a_OBJECTS): runtime.inc +$(libgolibbegin_a_OBJECTS): runtime.inc + LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) GOCFLAGS = $(CFLAGS) @@ -904,7 +921,7 @@ BUILDDEPS = \ BUILDPACKAGE = \ $(MKDIR_P) $(@D); \ files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \ - $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` -o $@ $$files + $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files # Build deps for netgo.o. BUILDNETGODEPS = \ @@ -1006,7 +1023,7 @@ bytes.lo.dep: $(srcdir)/go/bytes/*.go $(BUILDDEPS) bytes.lo: $(BUILDPACKAGE) -bytes/index.lo: go/bytes/indexbyte.c +bytes/index.lo: go/bytes/indexbyte.c runtime.inc @$(MKDIR_P) bytes $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c bytes/check: $(CHECK_DEPS) @@ -1191,7 +1208,7 @@ reflect-go.lo: $(BUILDPACKAGE) reflect/check: $(CHECK_DEPS) @$(CHECK) -reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c +reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc @$(MKDIR_P) reflect $(LTCOMPILE) -c -o $@ $< .PHONY: reflect/check @@ -1205,13 +1222,18 @@ regexp/check: $(CHECK_DEPS) @$(CHECK) .PHONY: regexp/check -extra_go_files_runtime = version.go +extra_go_files_runtime = runtime_sysinfo.go version.go @go_include@ runtime-go.lo.dep -runtime-go.lo.dep: $(srcdir)/go/runtime/*.go +runtime-go.lo.dep: $(srcdir)/go/runtime/*.go $(extra_go_files_runtime) $(BUILDDEPS) +runtime_go_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime runtime-go.lo: $(BUILDPACKAGE) +runtime.inc: s-runtime-inc; @true +s-runtime-inc: runtime-go.lo + $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp runtime.inc + $(STAMP) $@ runtime/check: $(CHECK_DEPS) @$(CHECK) .PHONY: runtime/check @@ -1239,7 +1261,7 @@ strings.lo.dep: $(srcdir)/go/strings/*.go $(BUILDDEPS) strings.lo: $(BUILDPACKAGE) -strings/index.lo: go/strings/indexbyte.c +strings/index.lo: go/strings/indexbyte.c runtime.inc @$(MKDIR_P) strings $(LTCOMPILE) -c -o strings/index.lo $(srcdir)/go/strings/indexbyte.c strings/check: $(CHECK_DEPS) @@ -2062,7 +2084,7 @@ log/syslog.lo.dep: $(srcdir)/go/log/syslog/*.go $(BUILDDEPS) log/syslog.lo: $(BUILDPACKAGE) -log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c log/syslog.lo +log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc log/syslog.lo @$(MKDIR_P) log/syslog $(LTCOMPILE) -c -o $@ $(srcdir)/go/log/syslog/syslog_c.c log/syslog/check: $(CHECK_DEPS) @@ -2348,7 +2370,7 @@ sync/atomic.lo.dep: $(srcdir)/go/sync/atomic/*.go $(BUILDDEPS) sync/atomic.lo: $(BUILDPACKAGE) -sync/atomic_c.lo: go/sync/atomic/atomic.c sync/atomic.lo +sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc sync/atomic.lo $(LTCOMPILE) -c -o $@ $(srcdir)/go/sync/atomic/atomic.c sync/atomic/check: $(CHECK_DEPS) @$(CHECK) @@ -2427,17 +2449,17 @@ unicode/utf8/check: $(CHECK_DEPS) .PHONY: unicode/utf8/check @go_include@ syscall.lo.dep -syscall.lo.dep: $(srcdir)/go/syscall/*.go +syscall.lo.dep: $(srcdir)/go/syscall/*.go $(extra_go_files_syscall) $(BUILDDEPS) syscall.lo: $(BUILDPACKAGE) -syscall/errno.lo: go/syscall/errno.c +syscall/errno.lo: go/syscall/errno.c runtime.inc @$(MKDIR_P) syscall $(LTCOMPILE) -c -o $@ $< -syscall/signame.lo: go/syscall/signame.c +syscall/signame.lo: go/syscall/signame.c runtime.inc @$(MKDIR_P) syscall $(LTCOMPILE) -c -o $@ $< -syscall/wait.lo: go/syscall/wait.c +syscall/wait.lo: go/syscall/wait.c runtime.inc @$(MKDIR_P) syscall $(LTCOMPILE) -c -o $@ $< syscall/check: $(CHECK_DEPS) diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 568683a7b0a..d9c510028b6 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -1162,7 +1162,7 @@ BUILDDEPS = \ BUILDPACKAGE = \ $(MKDIR_P) $(@D); \ files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \ - $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` -o $@ $$files + $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files # Build deps for netgo.o. @@ -1235,7 +1235,8 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \ @HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os = @HAVE_STAT_TIMESPEC_TRUE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os = --tag=solaristag @LIBGO_IS_SOLARIS_FALSE@matchargs_os = -extra_go_files_runtime = version.go +extra_go_files_runtime = runtime_sysinfo.go version.go +runtime_go_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime @LIBGO_IS_BSD_TRUE@golang_org_x_net_route_lo = \ @LIBGO_IS_BSD_TRUE@ golang_org/x/net/route/route.lo @@ -3570,6 +3571,16 @@ s-version: Makefile $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go $(STAMP) $@ +runtime_sysinfo.go: s-runtime_sysinfo; @true +s-runtime_sysinfo: sysinfo.go + rm -f tmp-runtime_sysinfo.go + echo 'package runtime' > tmp-runtime_sysinfo.go + echo >> tmp-runtime_sysinfo.go + grep 'const _sizeof_ucontext_t ' sysinfo.go >> tmp-runtime_sysinfo.go + grep 'type _sigset_t ' sysinfo.go >> tmp-runtime_sysinfo.go + $(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go + $(STAMP) $@ + # Generate the list of go std packages that were included in libgo zstdpkglist.go: s-zstdpkglist; @true s-zstdpkglist: Makefile @@ -3639,6 +3650,13 @@ s-epoll: Makefile $(SHELL) $(srcdir)/mvifdiff.sh epoll.go.tmp epoll.go $(STAMP) $@ +# Make sure runtime.inc is built before compiling any .c file. +$(libgo_la_OBJECTS): runtime.inc +$(libgo_llgo_la_OBJECTS): runtime.inc +$(libgobegin_a_OBJECTS): runtime.inc +$(libgobegin_llgo_a_OBJECTS): runtime.inc +$(libgolibbegin_a_OBJECTS): runtime.inc + @go_include@ bufio.lo.dep bufio.lo.dep: $(srcdir)/go/bufio/*.go $(BUILDDEPS) @@ -3653,7 +3671,7 @@ bytes.lo.dep: $(srcdir)/go/bytes/*.go $(BUILDDEPS) bytes.lo: $(BUILDPACKAGE) -bytes/index.lo: go/bytes/indexbyte.c +bytes/index.lo: go/bytes/indexbyte.c runtime.inc @$(MKDIR_P) bytes $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c bytes/check: $(CHECK_DEPS) @@ -3828,7 +3846,7 @@ reflect-go.lo: $(BUILDPACKAGE) reflect/check: $(CHECK_DEPS) @$(CHECK) -reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c +reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc @$(MKDIR_P) reflect $(LTCOMPILE) -c -o $@ $< .PHONY: reflect/check @@ -3843,10 +3861,14 @@ regexp/check: $(CHECK_DEPS) .PHONY: regexp/check @go_include@ runtime-go.lo.dep -runtime-go.lo.dep: $(srcdir)/go/runtime/*.go +runtime-go.lo.dep: $(srcdir)/go/runtime/*.go $(extra_go_files_runtime) $(BUILDDEPS) runtime-go.lo: $(BUILDPACKAGE) +runtime.inc: s-runtime-inc; @true +s-runtime-inc: runtime-go.lo + $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp runtime.inc + $(STAMP) $@ runtime/check: $(CHECK_DEPS) @$(CHECK) .PHONY: runtime/check @@ -3874,7 +3896,7 @@ strings.lo.dep: $(srcdir)/go/strings/*.go $(BUILDDEPS) strings.lo: $(BUILDPACKAGE) -strings/index.lo: go/strings/indexbyte.c +strings/index.lo: go/strings/indexbyte.c runtime.inc @$(MKDIR_P) strings $(LTCOMPILE) -c -o strings/index.lo $(srcdir)/go/strings/indexbyte.c strings/check: $(CHECK_DEPS) @@ -4688,7 +4710,7 @@ log/syslog.lo.dep: $(srcdir)/go/log/syslog/*.go $(BUILDDEPS) log/syslog.lo: $(BUILDPACKAGE) -log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c log/syslog.lo +log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc log/syslog.lo @$(MKDIR_P) log/syslog $(LTCOMPILE) -c -o $@ $(srcdir)/go/log/syslog/syslog_c.c log/syslog/check: $(CHECK_DEPS) @@ -4970,7 +4992,7 @@ sync/atomic.lo.dep: $(srcdir)/go/sync/atomic/*.go $(BUILDDEPS) sync/atomic.lo: $(BUILDPACKAGE) -sync/atomic_c.lo: go/sync/atomic/atomic.c sync/atomic.lo +sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc sync/atomic.lo $(LTCOMPILE) -c -o $@ $(srcdir)/go/sync/atomic/atomic.c sync/atomic/check: $(CHECK_DEPS) @$(CHECK) @@ -5049,17 +5071,17 @@ unicode/utf8/check: $(CHECK_DEPS) .PHONY: unicode/utf8/check @go_include@ syscall.lo.dep -syscall.lo.dep: $(srcdir)/go/syscall/*.go +syscall.lo.dep: $(srcdir)/go/syscall/*.go $(extra_go_files_syscall) $(BUILDDEPS) syscall.lo: $(BUILDPACKAGE) -syscall/errno.lo: go/syscall/errno.c +syscall/errno.lo: go/syscall/errno.c runtime.inc @$(MKDIR_P) syscall $(LTCOMPILE) -c -o $@ $< -syscall/signame.lo: go/syscall/signame.c +syscall/signame.lo: go/syscall/signame.c runtime.inc @$(MKDIR_P) syscall $(LTCOMPILE) -c -o $@ $< -syscall/wait.lo: go/syscall/wait.c +syscall/wait.lo: go/syscall/wait.c runtime.inc @$(MKDIR_P) syscall $(LTCOMPILE) -c -o $@ $< syscall/check: $(CHECK_DEPS) diff --git a/libgo/go/runtime/mcache.go b/libgo/go/runtime/mcache.go new file mode 100644 index 00000000000..e383e0d57d0 --- /dev/null +++ b/libgo/go/runtime/mcache.go @@ -0,0 +1,102 @@ +// 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 runtime + +// This is a temporary mcache.go for gccgo. +// At some point it will be replaced by the one in the gc runtime package. + +import "unsafe" + +const ( + // Computed constant. The definition of MaxSmallSize and the + // algorithm in msize.go produces some number of different allocation + // size classes. NumSizeClasses is that number. It's needed here + // because there are static arrays of this length; when msize runs its + // size choosing algorithm it double-checks that NumSizeClasses agrees. + _NumSizeClasses = 67 +) + +type mcachelist struct { + list *mlink + nlist uint32 +} + +// Per-thread (in Go, per-P) cache for small objects. +// No locking needed because it is per-thread (per-P). +// +// mcaches are allocated from non-GC'd memory, so any heap pointers +// must be specially handled. +type mcache struct { + // The following members are accessed on every malloc, + // so they are grouped here for better caching. + next_sample int32 // trigger heap sample after allocating this many bytes + local_cachealloc uintptr // bytes allocated (or freed) from cache since last lock of heap + + // Allocator cache for tiny objects w/o pointers. + // See "Tiny allocator" comment in malloc.go. + + // tiny points to the beginning of the current tiny block, or + // nil if there is no current tiny block. + // + // tiny is a heap pointer. Since mcache is in non-GC'd memory, + // we handle it by clearing it in releaseAll during mark + // termination. + tiny unsafe.Pointer + tinysize uintptr + + // The rest is not accessed on every malloc. + alloc [_NumSizeClasses]*mspan // spans to allocate from + free [_NumSizeClasses]mcachelist // lists of explicitly freed objects + + // Local allocator stats, flushed during GC. + local_nlookup uintptr // number of pointer lookups + local_largefree uintptr // bytes freed for large objects (>maxsmallsize) + local_nlargefree uintptr // number of frees for large objects (>maxsmallsize) + local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize) +} + +type mtypes struct { + compression byte + data uintptr +} + +type special struct { + next *special + offset uint16 + kind byte +} + +type mspan struct { + next *mspan // next span in list, or nil if none + prev *mspan // previous span's next field, or list head's first field if none + start uintptr + npages uintptr // number of pages in span + freelist *mlink + + // sweep generation: + // if sweepgen == h->sweepgen - 2, the span needs sweeping + // if sweepgen == h->sweepgen - 1, the span is currently being swept + // if sweepgen == h->sweepgen, the span is swept and ready to use + // h->sweepgen is incremented by 2 after every GC + + sweepgen uint32 + ref uint16 + sizeclass uint8 // size class + incache bool // being used by an mcache + state uint8 // mspaninuse etc + needzero uint8 // needs to be zeroed before allocation + elemsize uintptr // computed from sizeclass or from npages + unusedsince int64 // first time spotted by gc in mspanfree state + npreleased uintptr // number of pages released to the os + limit uintptr // end of data in span + types mtypes + speciallock mutex // guards specials list + specials *special // linked list of special records sorted by offset. + freebuf *mlink +} + +type mlink struct { + next *mlink +} diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go new file mode 100644 index 00000000000..05ce513aa9a --- /dev/null +++ b/libgo/go/runtime/runtime2.go @@ -0,0 +1,835 @@ +// 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 runtime + +import ( + "unsafe" +) + +// defined constants +const ( + // G status + // + // Beyond indicating the general state of a G, the G status + // acts like a lock on the goroutine's stack (and hence its + // ability to execute user code). + // + // If you add to this list, add to the list + // of "okay during garbage collection" status + // in mgcmark.go too. + + // _Gidle means this goroutine was just allocated and has not + // yet been initialized. + _Gidle = iota // 0 + + // _Grunnable means this goroutine is on a run queue. It is + // not currently executing user code. The stack is not owned. + _Grunnable // 1 + + // _Grunning means this goroutine may execute user code. The + // stack is owned by this goroutine. It is not on a run queue. + // It is assigned an M and a P. + _Grunning // 2 + + // _Gsyscall means this goroutine is executing a system call. + // It is not executing user code. The stack is owned by this + // goroutine. It is not on a run queue. It is assigned an M. + _Gsyscall // 3 + + // _Gwaiting means this goroutine is blocked in the runtime. + // It is not executing user code. It is not on a run queue, + // but should be recorded somewhere (e.g., a channel wait + // queue) so it can be ready()d when necessary. The stack is + // not owned *except* that a channel operation may read or + // write parts of the stack under the appropriate channel + // lock. Otherwise, it is not safe to access the stack after a + // goroutine enters _Gwaiting (e.g., it may get moved). + _Gwaiting // 4 + + // _Gmoribund_unused is currently unused, but hardcoded in gdb + // scripts. + _Gmoribund_unused // 5 + + // _Gdead means this goroutine is currently unused. It may be + // just exited, on a free list, or just being initialized. It + // is not executing user code. It may or may not have a stack + // allocated. The G and its stack (if any) are owned by the M + // that is exiting the G or that obtained the G from the free + // list. + _Gdead // 6 + + // _Genqueue_unused is currently unused. + _Genqueue_unused // 7 + + // _Gcopystack means this goroutine's stack is being moved. It + // is not executing user code and is not on a run queue. The + // stack is owned by the goroutine that put it in _Gcopystack. + _Gcopystack // 8 + + // _Gscan combined with one of the above states other than + // _Grunning indicates that GC is scanning the stack. The + // goroutine is not executing user code and the stack is owned + // by the goroutine that set the _Gscan bit. + // + // _Gscanrunning is different: it is used to briefly block + // state transitions while GC signals the G to scan its own + // stack. This is otherwise like _Grunning. + // + // atomicstatus&~Gscan gives the state the goroutine will + // return to when the scan completes. + _Gscan = 0x1000 + _Gscanrunnable = _Gscan + _Grunnable // 0x1001 + _Gscanrunning = _Gscan + _Grunning // 0x1002 + _Gscansyscall = _Gscan + _Gsyscall // 0x1003 + _Gscanwaiting = _Gscan + _Gwaiting // 0x1004 +) + +const ( + // P status + _Pidle = iota + _Prunning // Only this P is allowed to change from _Prunning. + _Psyscall + _Pgcstop + _Pdead +) + +// 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). +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 +} + +// 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. +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 funcval struct { + fn uintptr + // variable-size, fn-specific data here +} + +type iface struct { + tab unsafe.Pointer + data unsafe.Pointer +} + +type eface struct { + _type *_type + data unsafe.Pointer +} + +func efaceOf(ep *interface{}) *eface { + return (*eface)(unsafe.Pointer(ep)) +} + +// 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 + +//go:nosplit +func (gp guintptr) ptr() *g { return (*g)(unsafe.Pointer(gp)) } + +//go:nosplit +func (gp *guintptr) set(g *g) { *gp = guintptr(unsafe.Pointer(g)) } + +/* +//go:nosplit +func (gp *guintptr) cas(old, new guintptr) bool { + return atomic.Casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new)) +} +*/ + +type puintptr uintptr + +//go:nosplit +func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) } + +//go:nosplit +func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) } + +type muintptr uintptr + +//go:nosplit +func (mp muintptr) ptr() *m { return (*m)(unsafe.Pointer(mp)) } + +//go:nosplit +func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) } + +// sudog represents a g in a wait list, such as for sending/receiving +// on a channel. +// +// sudog is necessary because the g ↔ synchronization object relation +// is many-to-many. A g can be on many wait lists, so there may be +// many sudogs for one g; and many gs may be waiting on the same +// synchronization object, so there may be many sudogs for one object. +// +// sudogs are allocated from a special pool. Use acquireSudog and +// releaseSudog to allocate and free them. +/* +Commented out for gccgo for now. + +type sudog struct { + // The following fields are protected by the hchan.lock of the + // channel this sudog is blocking on. shrinkstack depends on + // this. + + g *g + selectdone *uint32 // CAS to 1 to win select race (may point to stack) + next *sudog + prev *sudog + elem unsafe.Pointer // data element (may point to stack) + + // The following fields are never accessed concurrently. + // waitlink is only accessed by g. + + releasetime int64 + ticket uint32 + waitlink *sudog // g.waiting list + c *hchan // channel +} +*/ + +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 +} + +/* +Not used by gccgo. + +type libcall struct { + fn uintptr + n uintptr // number of parameters + args uintptr // parameters + r1 uintptr // return values + r2 uintptr + err uintptr // error number +} + +*/ + +/* +Not used by gccgo. + +// 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 +} +*/ + +/* +Not used by gccgo. + +// 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). + // Not for gccgo: stack stack // offset known to runtime/cgo + // Not for gccgo: stackguard0 uintptr // offset known to liblink + // Not for gccgo: 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 + // Not for gccgo: stackAlloc uintptr // stack allocation is [stack.lo,stack.lo+stackAlloc) + // Not for gccgo: sched gobuf + // Not for gccgo: syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc + // Not for gccgo: syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc + // Not for gccgo: stkbar []stkbar // stack barriers, from low to high (see top of mstkbar.go) + // Not for gccgo: stkbarPos uintptr // index of lowest stack barrier not hit + // Not for gccgo: stktopsp uintptr // expected sp at top of stack, to check in traceback + param unsafe.Pointer // passed parameter on wakeup + atomicstatus uint32 + // Not for gccgo: 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; transition from true to false by calling queueRescan and false to true by calling dequeueRescan + 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) + traceseq uint64 // trace event sequencer + tracelastp puintptr // last P emitted an event for this goroutine + lockedm *m + sig uint32 + + // Temporary gccgo field. + writenbuf int32 + // Not for gccgo yet: writebuf []byte + // Temporary different type for gccgo. + 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 + // Not for gccgo for now: waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order + // Not for gccgo: cgoCtxt []uintptr // cgo traceback context + + // Per-G GC state + + // gcRescan is this G's index in work.rescan.list. If this is + // -1, this G is not on the rescan list. + // + // If gcphase != _GCoff and this G is visible to the garbage + // collector, writes to this are protected by work.rescan.lock. + gcRescan int32 + + // gcAssistBytes is this G's GC assist credit in terms of + // bytes allocated. If this is positive, then the G has credit + // to allocate gcAssistBytes bytes without assisting. If this + // is negative, then the G must correct this by performing + // scan work. We track this in bytes to make it fast to update + // and check for debt in the malloc hot path. The assist ratio + // determines how this corresponds to scan work debt. + gcAssistBytes int64 + + // Remaining fields are specific to gccgo. + + exception unsafe.Pointer // current exception being thrown + isforeign bool // whether current exception is not from Go + + // Fields that hold stack and context information if status is Gsyscall + gcstack unsafe.Pointer + gcstacksize uintptr + gcnextsegment unsafe.Pointer + gcnextsp unsafe.Pointer + gcinitialsp unsafe.Pointer + gcregs _ucontext_t + + entry unsafe.Pointer // goroutine entry point + fromgogo bool // whether entered from gogo function + + issystem bool // do not output in stack dump + isbackground bool // ignore in deadlock detector + + traceback *traceback // stack traceback buffer + + context _ucontext_t // saved context for setcontext + stackcontext [10]unsafe.Pointer // split-stack context +} + +type m struct { + g0 *g // goroutine with scheduling stack + // Not for gccgo: morebuf gobuf // gobuf arg to morestack + // Not for gccgo: 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 sigset // storage for saved signal mask + // Not for gccgo: tls [6]uintptr // thread-local storage (for x86 extern register) + mstartfn uintptr + 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 + newSigstack bool // minit on C thread called sigaltstack + printlock int8 + fastrand uint32 + ncgocall uint64 // number of cgo calls in total + ncgo int32 // number of cgo calls currently in progress + // Not for gccgo: cgoCallersUse uint32 // if non-zero, cgoCallers in use temporarily + // Not for gccgo: cgoCallers *cgoCallers // cgo traceback if crashing in cgo call + park note + alllink *m // on allm + schedlink muintptr + mcache *mcache + lockedg *g + createstack [32]location // stack that created this thread. + // Not for gccgo: freglo [16]uint32 // d[i] lsb and f[i] + // Not for gccgo: freghi [16]uint32 // d[i] msb and f[i+16] + // Not for gccgo: fflag uint32 // floating point compare flags + locked uint32 // tracking for lockosthread + nextwaitm uintptr // next m waiting for lock + 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 + // Not for gccgo: thread uintptr // thread handle + + // these are here because they are too large to be on the stack + // of low-level NOSPLIT functions. + // Not for gccgo: libcall libcall + // Not for gccgo: libcallpc uintptr // for cpu profiler + // Not for gccgo: libcallsp uintptr + // Not for gccgo: libcallg guintptr + // Not for gccgo: syscall libcall // stores syscall parameters on windows + + // Not for gccgo: mOS + + // Remaining fields are specific to gccgo. + + gsignalstack unsafe.Pointer // stack for gsignal + gsignalstacksize uintptr + + dropextram bool // drop after call is done + + gcing int32 + + waitsema uintptr // semaphore on systems that don't use futexes + + cgomal *cgoMal // allocations via _cgo_allocate +} + +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 + // Not for gccgo: racectx uintptr + + // Not for gccgo yet: deferpool [5][]*_defer // pool of available defer structs of different sizes (see panic.go) + // Not for gccgo yet: deferpoolbuf [5][32]*_defer + // Temporary gccgo type for deferpool field. + deferpool *_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]guintptr + // 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 + + // Not for gccgo for now: sudogcache []*sudog + // Not for gccgo for now: sudogbuf [128]*sudog + + // Not for gccgo for now: tracebuf traceBufPtr + + // Not for gccgo for now: palloc persistentAlloc // per-P to avoid mutex + + // Per-P GC state + // Not for gccgo for now: gcAssistTime int64 // Nanoseconds in assistAlloc + // Not for gccgo for now: gcBgMarkWorker guintptr + // Not for gccgo for now: 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. + // Not for gccgo for now: 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 +) + +/* +Commented out for gccgo for now. + +type schedt struct { + // accessed atomically. keep at top to ensure alignment on 32-bit systems. + goidgen uint64 + lastpoll uint64 + + lock mutex + + 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) + + ngsys uint32 // number of system goroutines; updated atomically + + pidle puintptr // idle p's + npidle uint32 + nmspinning uint32 // See "Worker thread parking/unparking" comment in proc.go. + + // Global runnable queue. + runqhead guintptr + runqtail guintptr + runqsize int32 + + // Global cache of dead G's. + gflock mutex + gfreeStack *g + gfreeNoStack *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 + + // 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 +) + +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 + _SigGoExit // cause all runtime procs to exit (only used on Plan 9). + _SigSetStack // add SA_ONSTACK to libc handler + _SigUnblock // unblocked in minit +) + +/* +gccgo does not use this. + +// 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 + _ int32 // previously legacy frame size; kept for layout compatibility + + pcsp int32 + pcfile int32 + pcln int32 + npcdata int32 + nfuncdata int32 +} + +*/ + +// 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 +} + +/* +// 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 < sys.PtrSize && n < len(r); i++ { + r[n] = byte(h) + n++ + h >>= 8 + } + } +} +*/ + +// deferred subroutine calls +// This is the gccgo version. +type _defer struct { + // The next entry in the stack. + next *_defer + + // The stack variable for the function which called this defer + // statement. This is set to true if we are returning from + // that function, false if we are panicing through it. + frame *bool + + // The value of the panic stack when this function is + // deferred. This function can not recover this value from + // the panic stack. This can happen if a deferred function + // has a defer statement itself. + _panic *_panic + + // The function to call. + pfn uintptr + + // The argument to pass to the function. + arg unsafe.Pointer + + // The return address that a recover thunk matches against. + // This is set by __go_set_defer_retaddr which is called by + // the thunks created by defer statements. + retaddr uintptr + + // Set to true if a function created by reflect.MakeFunc is + // permitted to recover. The return address of such a + // function function will be somewhere in libffi, so __retaddr + // is not useful. + makefunccanrecover bool + + // Set to true if this defer stack entry is not part of the + // defer pool. + special bool +} + +// panics +// This is the gccgo version. +type _panic struct { + // The next entry in the stack. + next *_panic + + // The value associated with this panic. + arg interface{} + + // Whether this panic has been recovered. + recovered bool + + // Whether this panic was pushed on the stack because of an + // exception thrown in some other language. + isforeign bool +} + +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 +) + +// The maximum number of frames we print for a traceback +const _TracebackMaxFrames = 100 + +var ( +// emptystring string +// allglen uintptr +// allm *m +// allp [_MaxGomaxprocs + 1]*p +// gomaxprocs int32 +// panicking uint32 +// ncpu int32 +// 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 +// cpuid_ebx7 uint32 +// lfenceBeforeRdtsc bool +// support_avx bool +// support_avx2 bool + +// goarm uint8 // set by cmd/link on arm systems +// framepointer_enabled bool // set by cmd/link +) + +// Set by the linker so the runtime can determine the buildmode. +var ( +// islibrary bool // -buildmode=c-shared +// isarchive bool // -buildmode=c-archive +) + +// Types that are only used by gccgo. + +// _ucontext_t is a Go version of the C ucontext_t type, used by getcontext. +// _sizeof_ucontext_t is defined by the Makefile from . +type _ucontext_t [_sizeof_ucontext_t / unsafe.Sizeof(uintptr(0))]unsafe.Pointer + +// traceback is used to collect stack traces from other goroutines. +type traceback struct { + gp *g + locbuf [_TracebackMaxFrames]location + c int +} + +// location is a location in the program, used for backtraces. +type location struct { + pc uintptr + filename string + function string + lineno int +} + +// cgoMal tracks allocations made by _cgo_allocate +// FIXME: _cgo_allocate has been removed from gc and can probably be +// removed from gccgo too. +type cgoMal struct { + next *cgoMal + alloc unsafe.Pointer +} + +// sigset is the Go version of the C type sigset_t. +// _sigset_t is defined by the Makefile from . +type sigset _sigset_t diff --git a/libgo/go/runtime/type.go b/libgo/go/runtime/type.go new file mode 100644 index 00000000000..fb5f034dd68 --- /dev/null +++ b/libgo/go/runtime/type.go @@ -0,0 +1,100 @@ +// 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 runtime + +import "unsafe" + +type _type struct { + kind uint8 + align int8 + fieldAlign uint8 + _ uint8 + size uintptr + hash uint32 + + hashfn func(unsafe.Pointer, uintptr) uintptr + equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool + + gc unsafe.Pointer + string *string + *uncommonType + ptrToThis *_type +} + +type method struct { + name *string + pkgPath *string + mtyp *_type + typ *_type + tfn unsafe.Pointer +} + +type uncommonType struct { + name *string + pkgPath *string + methods []method +} + +type imethod struct { + name *string + pkgPath *string + typ *_type +} + +type interfaceType struct { + typ _type + methods []imethod +} + +type mapType struct { + typ _type + key *_type + elem *_type +} + +type arrayType struct { + typ _type + elem *_type + slice *_type + len uintptr +} + +type chanType struct { + typ _type + elem *_type + dir uintptr +} + +type slicetype struct { + typ _type + elem *_type +} + +type functype struct { + typ _type + dotdotdot bool + in []*_type + out []*_type +} + +type ptrtype struct { + typ _type + elem *_type +} + +type structfield struct { + name *string // nil for embedded fields + pkgPath *string // nil for exported Names; otherwise import path + typ *_type // type of field + tag *string // nil if no tag + offset uintptr // byte offset of field within struct +} + +type structtype struct { + typ _type + fields []structfield +} diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh index ac5f0863199..10e38036c60 100755 --- a/libgo/mksysinfo.sh +++ b/libgo/mksysinfo.sh @@ -29,6 +29,7 @@ cat > sysinfo.c < #include #include +#include #include /* needs u_char/u_short, but is only included by if _SGIAPI (i.e. _SGI_SOURCE diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c index 610bcf5ec4e..598c2617840 100644 --- a/libgo/runtime/go-cgo.c +++ b/libgo/runtime/go-cgo.c @@ -36,7 +36,6 @@ void syscall_cgocall () { M* m; - G* g; if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0)) runtime_newextram (); @@ -45,8 +44,7 @@ syscall_cgocall () m = runtime_m (); ++m->ncgocall; - g = runtime_g (); - ++g->ncgo; + ++m->ncgo; runtime_entersyscall (); } @@ -59,18 +57,18 @@ syscall_cgocalldone () g = runtime_g (); __go_assert (g != NULL); - --g->ncgo; - if (g->ncgo == 0) + --g->m->ncgo; + if (g->m->ncgo == 0) { /* We are going back to Go, and we are not in a recursive call. Let the garbage collector clean up any unreferenced memory. */ - g->cgomal = NULL; + g->m->cgomal = NULL; } /* If we are invoked because the C function called _cgo_panic, then _cgo_panic will already have exited syscall mode. */ - if (g->status == Gsyscall) + if (g->atomicstatus == _Gsyscall) runtime_exitsyscall (); runtime_unlockOSThread(); @@ -93,7 +91,7 @@ syscall_cgocallback () runtime_exitsyscall (); - if (runtime_g ()->ncgo == 0) + if (runtime_m ()->ncgo == 0) { /* The C call to Go came from a thread not currently running any Go. In the case of -buildmode=c-archive or c-shared, this @@ -119,7 +117,7 @@ syscall_cgocallbackdone () runtime_entersyscall (); mp = runtime_m (); - if (mp->dropextram && runtime_g ()->ncgo == 0) + if (mp->dropextram && mp->ncgo == 0) { mp->dropextram = false; runtime_dropm (); @@ -133,16 +131,16 @@ void * alloc_saved (size_t n) { void *ret; - G *g; + M *m; CgoMal *c; ret = __go_alloc (n); - g = runtime_g (); + m = runtime_m (); c = (CgoMal *) __go_alloc (sizeof (CgoMal)); - c->next = g->cgomal; + c->next = m->cgomal; c->alloc = ret; - g->cgomal = c; + m->cgomal = c; return ret; } diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c index 3a48fe1130e..f3e14bd0b96 100644 --- a/libgo/runtime/go-defer.c +++ b/libgo/runtime/go-defer.c @@ -9,7 +9,6 @@ #include "runtime.h" #include "go-alloc.h" #include "go-panic.h" -#include "go-defer.h" /* This function is called each time we need to defer a call. */ @@ -17,19 +16,19 @@ void __go_defer (_Bool *frame, void (*pfn) (void *), void *arg) { G *g; - struct __go_defer_stack *n; + Defer *n; g = runtime_g (); n = runtime_newdefer (); - n->__next = g->defer; - n->__frame = frame; - n->__panic = g->panic; - n->__pfn = pfn; - n->__arg = arg; - n->__retaddr = NULL; - n->__makefunc_can_recover = 0; - n->__special = 0; - g->defer = n; + n->next = g->_defer; + n->frame = frame; + n->_panic = g->_panic; + n->pfn = (uintptr) pfn; + n->arg = arg; + n->retaddr = 0; + n->makefunccanrecover = 0; + n->special = 0; + g->_defer = n; } /* This function is called when we want to undefer the stack. */ @@ -40,19 +39,19 @@ __go_undefer (_Bool *frame) G *g; g = runtime_g (); - while (g->defer != NULL && g->defer->__frame == frame) + while (g->_defer != NULL && g->_defer->frame == frame) { - struct __go_defer_stack *d; + Defer *d; void (*pfn) (void *); - d = g->defer; - pfn = d->__pfn; - d->__pfn = NULL; + d = g->_defer; + pfn = (void (*) (void *)) d->pfn; + d->pfn = 0; if (pfn != NULL) - (*pfn) (d->__arg); + (*pfn) (d->arg); - g->defer = d->__next; + g->_defer = d->next; /* This may be called by a cgo callback routine to defer the call to syscall.CgocallBackDone, in which case we will not @@ -79,7 +78,7 @@ __go_set_defer_retaddr (void *retaddr) G *g; g = runtime_g (); - if (g->defer != NULL) - g->defer->__retaddr = __builtin_extract_return_addr (retaddr); + if (g->_defer != NULL) + g->_defer->retaddr = (uintptr) __builtin_extract_return_addr (retaddr); return 0; } diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h deleted file mode 100644 index acf2d40c69c..00000000000 --- a/libgo/runtime/go-defer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* go-defer.h -- the defer stack. - - Copyright 2010 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. */ - -struct __go_panic_stack; - -/* The defer stack is a list of these structures. */ - -struct __go_defer_stack -{ - /* The next entry in the stack. */ - struct __go_defer_stack *__next; - - /* The stack variable for the function which called this defer - statement. This is set to 1 if we are returning from that - function, 0 if we are panicing through it. */ - _Bool *__frame; - - /* The value of the panic stack when this function is deferred. - This function can not recover this value from the panic stack. - This can happen if a deferred function has a defer statement - itself. */ - struct __go_panic_stack *__panic; - - /* The function to call. */ - void (*__pfn) (void *); - - /* The argument to pass to the function. */ - void *__arg; - - /* The return address that a recover thunk matches against. This is - set by __go_set_defer_retaddr which is called by the thunks - created by defer statements. */ - const void *__retaddr; - - /* Set to true if a function created by reflect.MakeFunc is - permitted to recover. The return address of such a function - function will be somewhere in libffi, so __retaddr is not - useful. */ - _Bool __makefunc_can_recover; - - /* Set to true if this defer stack entry is not part of the defer - pool. */ - _Bool __special; -}; diff --git a/libgo/runtime/go-deferred-recover.c b/libgo/runtime/go-deferred-recover.c index 78ef287cf00..408ef2a75f5 100644 --- a/libgo/runtime/go-deferred-recover.c +++ b/libgo/runtime/go-deferred-recover.c @@ -8,7 +8,6 @@ #include "runtime.h" #include "go-panic.h" -#include "go-defer.h" /* This is called when a call to recover is deferred. That is, something like @@ -82,7 +81,7 @@ __go_deferred_recover () G *g; g = runtime_g (); - if (g->defer == NULL || g->defer->__panic != g->panic) + if (g->_defer == NULL || g->_defer->_panic != g->_panic) { struct __go_empty_interface ret; diff --git a/libgo/runtime/go-panic.c b/libgo/runtime/go-panic.c index 77975c6e083..436a96626b8 100644 --- a/libgo/runtime/go-panic.c +++ b/libgo/runtime/go-panic.c @@ -11,23 +11,22 @@ #include "arch.h" #include "malloc.h" #include "go-alloc.h" -#include "go-defer.h" #include "go-panic.h" #include "interface.h" /* Print the panic stack. This is used when there is no recover. */ static void -__printpanics (struct __go_panic_stack *p) +__printpanics (Panic *p) { - if (p->__next != NULL) + if (p->next != NULL) { - __printpanics (p->__next); + __printpanics (p->next); runtime_printf ("\t"); } runtime_printf ("panic: "); - runtime_printany (p->__arg); - if (p->__was_recovered) + runtime_printany (p->arg); + if (p->recovered) runtime_printf (" [recovered]"); runtime_printf ("\n"); } @@ -39,39 +38,39 @@ void __go_panic (struct __go_empty_interface arg) { G *g; - struct __go_panic_stack *n; + Panic *n; g = runtime_g (); - n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack)); - n->__arg = arg; - n->__next = g->panic; - g->panic = n; + n = (Panic *) __go_alloc (sizeof (Panic)); + n->arg = arg; + n->next = g->_panic; + g->_panic = n; /* Run all the defer functions. */ while (1) { - struct __go_defer_stack *d; + Defer *d; void (*pfn) (void *); - d = g->defer; + d = g->_defer; if (d == NULL) break; - pfn = d->__pfn; - d->__pfn = NULL; + pfn = (void (*) (void *)) d->pfn; + d->pfn = 0; if (pfn != NULL) { - (*pfn) (d->__arg); + (*pfn) (d->arg); - if (n->__was_recovered) + if (n->recovered) { /* Some defer function called recover. That means that we should stop running this panic. */ - g->panic = n->__next; + g->_panic = n->next; __go_free (n); /* Now unwind the stack by throwing an exception. The @@ -91,10 +90,10 @@ __go_panic (struct __go_empty_interface arg) it did not call recover, we know that we are not returning from the calling function--we are panicing through it. */ - *d->__frame = 0; + *d->frame = 0; } - g->defer = d->__next; + g->_defer = d->next; /* This may be called by a cgo callback routine to defer the call to syscall.CgocallBackDone, in which case we will not @@ -107,6 +106,6 @@ __go_panic (struct __go_empty_interface arg) /* The panic was not recovered. */ runtime_startpanic (); - __printpanics (g->panic); + __printpanics (g->_panic); runtime_dopanic (0); } diff --git a/libgo/runtime/go-panic.h b/libgo/runtime/go-panic.h index d29fe88b57a..1b172d92db9 100644 --- a/libgo/runtime/go-panic.h +++ b/libgo/runtime/go-panic.h @@ -11,25 +11,6 @@ struct String; struct __go_type_descriptor; -struct __go_defer_stack; - -/* The stack of panic calls. */ - -struct __go_panic_stack -{ - /* The next entry in the stack. */ - struct __go_panic_stack *__next; - - /* The value associated with this panic. */ - struct __go_empty_interface __arg; - - /* Whether this panic has been recovered. */ - _Bool __was_recovered; - - /* Whether this panic was pushed on the stack because of an - exception thrown in some other language. */ - _Bool __is_foreign; -}; extern void __go_panic (struct __go_empty_interface) __attribute__ ((noreturn)); @@ -42,8 +23,8 @@ extern _Bool __go_can_recover (void *); extern void __go_makefunc_can_recover (void *retaddr); -struct Location; -extern void __go_makefunc_ffi_can_recover (struct Location *, int); +struct location; +extern void __go_makefunc_ffi_can_recover (struct location *, int); extern void __go_makefunc_returning (void); diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c index fc66f61cab3..4d2f0f9fc39 100644 --- a/libgo/runtime/go-recover.c +++ b/libgo/runtime/go-recover.c @@ -7,33 +7,32 @@ #include "runtime.h" #include "interface.h" #include "go-panic.h" -#include "go-defer.h" /* If the top of the defer stack can be recovered, then return it. Otherwise return NULL. */ -static struct __go_defer_stack * +static Defer * current_defer () { G *g; - struct __go_defer_stack *d; + Defer *d; g = runtime_g (); - d = g->defer; + d = g->_defer; if (d == NULL) return NULL; /* The panic which would be recovered is the one on the top of the panic stack. We do not want to recover it if that panic was on the top of the panic stack when this function was deferred. */ - if (d->__panic == g->panic) + if (d->_panic == g->_panic) return NULL; /* The deferred thunk will call _go_set_defer_retaddr. If this has not happened, then we have not been called via defer, and we can not recover. */ - if (d->__retaddr == NULL) + if (d->retaddr == 0) return NULL; return d; @@ -48,7 +47,7 @@ current_defer () _Bool __go_can_recover (void *retaddr) { - struct __go_defer_stack *d; + Defer *d; const char* ret; const char* dret; Location locs[16]; @@ -64,7 +63,7 @@ __go_can_recover (void *retaddr) ret = (const char *) __builtin_extract_return_addr (retaddr); - dret = (const char *) d->__retaddr; + dret = (const char *) (uintptr) d->retaddr; if (ret <= dret && ret + 16 >= dret) return 1; @@ -111,7 +110,7 @@ __go_can_recover (void *retaddr) /* If the function calling recover was created by reflect.MakeFunc, then __go_makefunc_can_recover or __go_makefunc_ffi_can_recover will have set the __makefunc_can_recover field. */ - if (!d->__makefunc_can_recover) + if (!d->makefunccanrecover) return 0; /* We look up the stack, ignoring libffi functions and functions in @@ -178,7 +177,7 @@ __go_can_recover (void *retaddr) void __go_makefunc_can_recover (void *retaddr) { - struct __go_defer_stack *d; + Defer *d; d = current_defer (); if (d == NULL) @@ -186,24 +185,24 @@ __go_makefunc_can_recover (void *retaddr) /* If we are already in a call stack of MakeFunc functions, there is nothing we can usefully check here. */ - if (d->__makefunc_can_recover) + if (d->makefunccanrecover) return; if (__go_can_recover (retaddr)) - d->__makefunc_can_recover = 1; + d->makefunccanrecover = 1; } /* This function is called when code is about to enter a function created by the libffi version of reflect.MakeFunc. This function is passed the names of the callers of the libffi code that called the stub. It uses to decide whether it is permitted to call - recover, and sets d->__makefunc_can_recover so that __go_recover - can make the same decision. */ + recover, and sets d->makefunccanrecover so that __go_recover can + make the same decision. */ void -__go_makefunc_ffi_can_recover (struct Location *loc, int n) +__go_makefunc_ffi_can_recover (struct location *loc, int n) { - struct __go_defer_stack *d; + Defer *d; const byte *name; intgo len; @@ -213,7 +212,7 @@ __go_makefunc_ffi_can_recover (struct Location *loc, int n) /* If we are already in a call stack of MakeFunc functions, there is nothing we can usefully check here. */ - if (d->__makefunc_can_recover) + if (d->makefunccanrecover) return; /* LOC points to the caller of our caller. That will be a thunk. @@ -228,26 +227,26 @@ __go_makefunc_ffi_can_recover (struct Location *loc, int n) if (len > 4 && __builtin_strchr ((const char *) name, '.') == NULL && __builtin_strncmp ((const char *) name, "__go_", 4) == 0) - d->__makefunc_can_recover = 1; + d->makefunccanrecover = 1; } /* This function is called when code is about to exit a function created by reflect.MakeFunc. It is called by the function stub - used by MakeFunc. It clears the __makefunc_can_recover field. - It's OK to always clear this field, because __go_can_recover will - only be called by a stub created for a function that calls recover. - That stub will not call a function created by reflect.MakeFunc, so - by the time we get here any caller higher up on the call stack no + used by MakeFunc. It clears the makefunccanrecover field. It's OK + to always clear this field, because __go_can_recover will only be + called by a stub created for a function that calls recover. That + stub will not call a function created by reflect.MakeFunc, so by + the time we get here any caller higher up on the call stack no longer needs the information. */ void __go_makefunc_returning (void) { - struct __go_defer_stack *d; + Defer *d; - d = runtime_g ()->defer; + d = runtime_g ()->_defer; if (d != NULL) - d->__makefunc_can_recover = 0; + d->makefunccanrecover = 0; } /* This is only called when it is valid for the caller to recover the @@ -257,11 +256,11 @@ struct __go_empty_interface __go_recover () { G *g; - struct __go_panic_stack *p; + Panic *p; g = runtime_g (); - if (g->panic == NULL || g->panic->__was_recovered) + if (g->_panic == NULL || g->_panic->recovered) { struct __go_empty_interface ret; @@ -269,7 +268,7 @@ __go_recover () ret.__object = NULL; return ret; } - p = g->panic; - p->__was_recovered = 1; - return p->__arg; + p = g->_panic; + p->recovered = 1; + return p->arg; } diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c index a948c31cca0..0aef2fc9b08 100644 --- a/libgo/runtime/go-signal.c +++ b/libgo/runtime/go-signal.c @@ -26,11 +26,11 @@ extern void __splitstack_setcontext(void *context[10]); #endif -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define D SigDefault +#define N _SigNotify +#define K _SigKill +#define T _SigThrow +#define P _SigPanic +#define D _SigDefault /* Signal actions. This collects the sigtab tables for several different targets from the master library. SIGKILL and SIGSTOP are @@ -182,14 +182,14 @@ runtime_sighandler (int sig, Siginfo *info, #ifdef SA_SIGINFO notify = info != NULL && info->si_code == SI_USER; #endif - if (notify || (t->flags & SigNotify) != 0) + if (notify || (t->flags & _SigNotify) != 0) { if (__go_sigsend (sig)) return; } - if ((t->flags & SigKill) != 0) + if ((t->flags & _SigKill) != 0) runtime_exit (2); - if ((t->flags & SigThrow) == 0) + if ((t->flags & _SigThrow) == 0) return; runtime_startpanic (); @@ -320,7 +320,7 @@ sig_panic_info_handler (int sig, Siginfo *info, void *context) #endif } - /* All signals with SigPanic should be in cases above, and this + /* All signals with _SigPanic should be in cases above, and this handler should only be invoked for those signals. */ __builtin_unreachable (); } @@ -365,7 +365,7 @@ sig_panic_handler (int sig) #endif } - /* All signals with SigPanic should be in cases above, and this + /* All signals with _SigPanic should be in cases above, and this handler should only be invoked for those signals. */ __builtin_unreachable (); } @@ -406,7 +406,7 @@ sig_tramp_info (int sig, Siginfo *info, void *context) /* We are running on the signal stack. Set the split stack context so that the stack guards are checked correctly. */ #ifdef USING_SPLIT_STACK - __splitstack_setcontext (&mp->gsignal->stack_context[0]); + __splitstack_setcontext (&mp->gsignal->stackcontext[0]); #endif } @@ -451,7 +451,7 @@ runtime_setsig (int32 i, GoSighandler *fn, bool restart) t = &runtime_sigtab[i]; - if ((t->flags & SigPanic) == 0) + if ((t->flags & _SigPanic) == 0) { #ifdef SA_SIGINFO sa.sa_flags = SA_ONSTACK | SA_SIGINFO; diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c index 87d9eb3ef4e..ea11e4e3b1d 100644 --- a/libgo/runtime/go-unwind.c +++ b/libgo/runtime/go-unwind.c @@ -15,7 +15,6 @@ #include "runtime.h" #include "go-alloc.h" -#include "go-defer.h" #include "go-panic.h" /* The code for a Go exception. */ @@ -57,43 +56,42 @@ __go_check_defer (_Bool *frame) /* Some other language has thrown an exception. We know there are no defer handlers, so there is nothing to do. */ } - else if (g->is_foreign) + else if (g->isforeign) { - struct __go_panic_stack *n; - _Bool was_recovered; + Panic *n; + _Bool recovered; /* Some other language has thrown an exception. We need to run the local defer handlers. If they call recover, we stop unwinding the stack here. */ - n = ((struct __go_panic_stack *) - __go_alloc (sizeof (struct __go_panic_stack))); + n = (Panic *) __go_alloc (sizeof (Panic)); - n->__arg.__type_descriptor = NULL; - n->__arg.__object = NULL; - n->__was_recovered = 0; - n->__is_foreign = 1; - n->__next = g->panic; - g->panic = n; + n->arg.__type_descriptor = NULL; + n->arg.__object = NULL; + n->recovered = 0; + n->isforeign = 1; + n->next = g->_panic; + g->_panic = n; while (1) { - struct __go_defer_stack *d; + Defer *d; void (*pfn) (void *); - d = g->defer; - if (d == NULL || d->__frame != frame || d->__pfn == NULL) + d = g->_defer; + if (d == NULL || d->frame != frame || d->pfn == 0) break; - pfn = d->__pfn; - g->defer = d->__next; + pfn = (void (*) (void *)) d->pfn; + g->_defer = d->next; - (*pfn) (d->__arg); + (*pfn) (d->arg); if (runtime_m () != NULL) runtime_freedefer (d); - if (n->__was_recovered) + if (n->recovered) { /* The recover function caught the panic thrown by some other language. */ @@ -101,11 +99,11 @@ __go_check_defer (_Bool *frame) } } - was_recovered = n->__was_recovered; - g->panic = n->__next; + recovered = n->recovered; + g->_panic = n->next; __go_free (n); - if (was_recovered) + if (recovered) { /* Just return and continue executing Go code. */ *frame = 1; @@ -115,17 +113,17 @@ __go_check_defer (_Bool *frame) /* We are panicing through this function. */ *frame = 0; } - else if (g->defer != NULL - && g->defer->__pfn == NULL - && g->defer->__frame == frame) + else if (g->_defer != NULL + && g->_defer->pfn == 0 + && g->_defer->frame == frame) { - struct __go_defer_stack *d; + Defer *d; /* This is the defer function which called recover. Simply return to stop the stack unwind, and let the Go code continue to execute. */ - d = g->defer; - g->defer = d->__next; + d = g->_defer; + g->_defer = d->next; if (runtime_m () != NULL) runtime_freedefer (d); @@ -432,7 +430,7 @@ PERSONALITY_FUNCTION (int version, else { g->exception = ue_header; - g->is_foreign = is_foreign; + g->isforeign = is_foreign; } _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), diff --git a/libgo/runtime/heapdump.c b/libgo/runtime/heapdump.c index 52a91e87da7..18fe913c4eb 100644 --- a/libgo/runtime/heapdump.c +++ b/libgo/runtime/heapdump.c @@ -14,7 +14,6 @@ #include "malloc.h" #include "mgc0.h" #include "go-type.h" -#include "go-defer.h" #include "go-panic.h" #define hash __hash @@ -265,15 +264,15 @@ dumpgoroutine(G *gp) dumpint((uintptr)0); dumpint(gp->goid); dumpint(gp->gopc); - dumpint(gp->status); + dumpint(gp->atomicstatus); dumpbool(gp->issystem); dumpbool(gp->isbackground); dumpint(gp->waitsince); - dumpcstr((const int8 *)gp->waitreason); + dumpstr(gp->waitreason); dumpint((uintptr)0); dumpint((uintptr)gp->m); - dumpint((uintptr)gp->defer); - dumpint((uintptr)gp->panic); + dumpint((uintptr)gp->_defer); + dumpint((uintptr)gp->_panic); // dump stack // child.args.n = -1; @@ -285,24 +284,24 @@ dumpgoroutine(G *gp) // runtime_gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, &child, false); // dump defer & panic records - for(d = gp->defer; d != nil; d = d->__next) { + for(d = gp->_defer; d != nil; d = d->next) { dumpint(TagDefer); dumpint((uintptr)d); dumpint((uintptr)gp); - dumpint((uintptr)d->__arg); - dumpint((uintptr)d->__frame); - dumpint((uintptr)d->__pfn); + dumpint((uintptr)d->arg); + dumpint((uintptr)d->frame); + dumpint((uintptr)d->pfn); dumpint((uintptr)0); - dumpint((uintptr)d->__next); + dumpint((uintptr)d->next); } - for (p = gp->panic; p != nil; p = p->__next) { + for (p = gp->_panic; p != nil; p = p->next) { dumpint(TagPanic); dumpint((uintptr)p); dumpint((uintptr)gp); - dumpint((uintptr)p->__arg.__type_descriptor); - dumpint((uintptr)p->__arg.__object); + dumpint((uintptr)p->arg.__type_descriptor); + dumpint((uintptr)p->arg.__object); dumpint((uintptr)0); - dumpint((uintptr)p->__next); + dumpint((uintptr)p->next); } } @@ -315,15 +314,15 @@ dumpgs(void) // goroutines & stacks for(i = 0; i < runtime_allglen; i++) { gp = runtime_allg[i]; - switch(gp->status){ + switch(gp->atomicstatus){ default: - runtime_printf("unexpected G.status %d\n", gp->status); + runtime_printf("unexpected G.status %d\n", gp->atomicstatus); runtime_throw("mark - bad status"); - case Gdead: + case _Gdead: break; - case Grunnable: - case Gsyscall: - case Gwaiting: + case _Grunnable: + case _Gsyscall: + case _Gwaiting: dumpgoroutine(gp); break; } @@ -602,7 +601,7 @@ mdump(G *gp) flush(); gp->param = nil; - gp->status = Grunning; + gp->atomicstatus = _Grunning; runtime_gogo(gp); } @@ -632,8 +631,8 @@ runtime_debug_WriteHeapDump(uintptr fd) // Call dump routine on M stack. g = runtime_g(); - g->status = Gwaiting; - g->waitreason = "dumping heap"; + g->atomicstatus = _Gwaiting; + g->waitreason = runtime_gostringnocopy((const byte*)"dumping heap"); runtime_mcall(mdump); // Reset dump file. diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c index ef611fb36ad..06ac6e7f90d 100644 --- a/libgo/runtime/lock_sema.c +++ b/libgo/runtime/lock_sema.c @@ -73,7 +73,7 @@ unlocked: // for this lock, chained through m->nextwaitm. // Queue this M. for(;;) { - m->nextwaitm = (void*)(v&~LOCKED); + m->nextwaitm = v&~LOCKED; if(runtime_casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED))) break; v = (uintptr)runtime_atomicloadp((void**)&l->key); @@ -104,7 +104,7 @@ runtime_unlock(Lock *l) // Other M's are waiting for the lock. // Dequeue an M. mp = (void*)(v&~LOCKED); - if(runtime_casp((void**)&l->key, (void*)v, mp->nextwaitm)) { + if(runtime_cas(&l->key, v, mp->nextwaitm)) { // Dequeued an M. Wake it. runtime_semawakeup(mp); break; diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc index c111a0eeefd..fbb7b744eeb 100644 --- a/libgo/runtime/malloc.goc +++ b/libgo/runtime/malloc.goc @@ -92,11 +92,11 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) return &runtime_zerobase; } - m = runtime_m(); g = runtime_g(); + m = g->m; incallback = false; - if(m->mcache == nil && g->ncgo > 0) { + if(m->mcache == nil && m->ncgo > 0) { // For gccgo this case can occur when a cgo or SWIG function // has an interface return type and the function // returns a non-pointer, so memory allocation occurs @@ -165,11 +165,11 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag) tiny = (byte*)ROUND((uintptr)tiny, 4); else if((size&1) == 0) tiny = (byte*)ROUND((uintptr)tiny, 2); - size1 = size + (tiny - c->tiny); + size1 = size + (tiny - (byte*)c->tiny); if(size1 <= tinysize) { // The object fits into existing tiny block. v = (MLink*)tiny; - c->tiny += size1; + c->tiny = (byte*)c->tiny + size1; c->tinysize -= size1; m->mallocing = 0; m->locks--; @@ -281,7 +281,7 @@ largealloc(uint32 flag, uintptr *sizep) s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1, !(flag & FlagNoZero)); if(s == nil) runtime_throw("out of memory"); - s->limit = (byte*)(s->start<limit = (uintptr)((byte*)(s->start<start << PageShift); // setup for mark sweep @@ -475,7 +475,7 @@ runtime_purgecachedstats(MCache *c) // Protected by either heap or GC lock. h = &runtime_mheap; - mstats.heap_alloc += c->local_cachealloc; + mstats.heap_alloc += (intptr)c->local_cachealloc; c->local_cachealloc = 0; mstats.nlookup += c->local_nlookup; c->local_nlookup = 0; @@ -493,7 +493,7 @@ extern uintptr runtime_sizeof_C_MStats __asm__ (GOSYM_PREFIX "runtime.Sizeof_C_MStats"); // Size of the trailing by_size array differs between Go and C, -// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. +// _NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. // sizeof_C_MStats is what C thinks about size of Go struct. // Initialized in mallocinit because it's defined in go/runtime/mem.go. @@ -511,7 +511,7 @@ runtime_mallocinit(void) uint64 i; bool reserved; - runtime_sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]); + runtime_sizeof_C_MStats = sizeof(MStats) - (_NumSizeClasses - 61) * sizeof(mstats.by_size[0]); p = nil; p_size = 0; diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h index 065f74a9b58..acd919f7abe 100644 --- a/libgo/runtime/malloc.h +++ b/libgo/runtime/malloc.h @@ -82,11 +82,11 @@ typedef struct MCentral MCentral; typedef struct MHeap MHeap; -typedef struct MSpan MSpan; +typedef struct mspan MSpan; typedef struct MStats MStats; -typedef struct MLink MLink; -typedef struct MTypes MTypes; -typedef struct GCStats GCStats; +typedef struct mlink MLink; +typedef struct mtypes MTypes; +typedef struct gcstats GCStats; enum { @@ -100,10 +100,10 @@ enum { // Computed constant. The definition of MaxSmallSize and the // algorithm in msize.c produce some number of different allocation - // size classes. NumSizeClasses is that number. It's needed here + // size classes. _NumSizeClasses is that number. It's needed here // because there are static arrays of this length; when msize runs its // size choosing algorithm it double-checks that NumSizeClasses agrees. - NumSizeClasses = 67, + // _NumSizeClasses is defined in runtime2.go as 67. // Tunable constants. MaxSmallSize = 32<<10, @@ -148,13 +148,6 @@ enum #else #define MaxMem ((uintptr)-1) #endif - -// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) -struct MLink -{ - MLink *next; -}; - // SysAlloc obtains a large chunk of zeroed memory from the // operating system, typically on the order of a hundred kilobytes // or a megabyte. @@ -274,7 +267,7 @@ struct MStats uint32 size; uint64 nmalloc; uint64 nfree; - } by_size[NumSizeClasses]; + } by_size[_NumSizeClasses]; }; extern MStats mstats @@ -284,7 +277,7 @@ void runtime_updatememstats(GCStats *stats); // Size classes. Computed and initialized by InitSizes. // // SizeToClass(0 <= n <= MaxSmallSize) returns the size class, -// 1 <= sizeclass < NumSizeClasses, for n. +// 1 <= sizeclass < _NumSizeClasses, for n. // Size class 0 is reserved to mean "not small". // // class_to_size[i] = largest size in class i @@ -293,41 +286,14 @@ void runtime_updatememstats(GCStats *stats); int32 runtime_SizeToClass(int32); uintptr runtime_roundupsize(uintptr); -extern int32 runtime_class_to_size[NumSizeClasses]; -extern int32 runtime_class_to_allocnpages[NumSizeClasses]; +extern int32 runtime_class_to_size[_NumSizeClasses]; +extern int32 runtime_class_to_allocnpages[_NumSizeClasses]; extern int8 runtime_size_to_class8[1024/8 + 1]; extern int8 runtime_size_to_class128[(MaxSmallSize-1024)/128 + 1]; extern void runtime_InitSizes(void); -typedef struct MCacheList MCacheList; -struct MCacheList -{ - MLink *list; - uint32 nlist; -}; - -// Per-thread (in Go, per-P) cache for small objects. -// No locking needed because it is per-thread (per-P). -struct MCache -{ - // The following members are accessed on every malloc, - // so they are grouped here for better caching. - int32 next_sample; // trigger heap sample after allocating this many bytes - intptr local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap - // Allocator cache for tiny objects w/o pointers. - // See "Tiny allocator" comment in malloc.goc. - byte* tiny; - uintptr tinysize; - // The rest is not accessed on every malloc. - MSpan* alloc[NumSizeClasses]; // spans to allocate from - MCacheList free[NumSizeClasses];// lists of explicitly freed objects - // Local allocator stats, flushed during GC. - uintptr local_nlookup; // number of pointer lookups - uintptr local_largefree; // bytes freed for large objects (>MaxSmallSize) - uintptr local_nlargefree; // number of frees for large objects (>MaxSmallSize) - uintptr local_nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize) -}; +typedef struct mcachelist MCacheList; MSpan* runtime_MCache_Refill(MCache *c, int32 sizeclass); void runtime_MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size); @@ -364,11 +330,6 @@ enum MTypes_Words = 2, MTypes_Bytes = 3, }; -struct MTypes -{ - byte compression; // one of MTypes_* - uintptr data; -}; enum { @@ -380,13 +341,7 @@ enum // if that happens. }; -typedef struct Special Special; -struct Special -{ - Special* next; // linked list in span - uint16 offset; // span offset of object - byte kind; // kind of Special -}; +typedef struct special Special; // The described object has a finalizer set for it. typedef struct SpecialFinalizer SpecialFinalizer; @@ -415,33 +370,6 @@ enum MSpanListHead, MSpanDead, }; -struct MSpan -{ - MSpan *next; // in a span linked list - MSpan *prev; // in a span linked list - PageID start; // starting page number - uintptr npages; // number of pages in span - MLink *freelist; // list of free objects - // sweep generation: - // if sweepgen == h->sweepgen - 2, the span needs sweeping - // if sweepgen == h->sweepgen - 1, the span is currently being swept - // if sweepgen == h->sweepgen, the span is swept and ready to use - // h->sweepgen is incremented by 2 after every GC - uint32 sweepgen; - uint16 ref; // capacity - number of objects in freelist - uint8 sizeclass; // size class - bool incache; // being used by an MCache - uint8 state; // MSpanInUse etc - uint8 needzero; // needs to be zeroed before allocation - uintptr elemsize; // computed from sizeclass or from npages - int64 unusedsince; // First time spotted by GC in MSpanFree state - uintptr npreleased; // number of pages released to the OS - byte *limit; // end of data in span - MTypes types; // types of allocated objects in this span - Lock specialLock; // guards specials list - Special *specials; // linked list of special records sorted by offset. - MLink *freebuf; // objects freed explicitly, not incorporated into freelist yet -}; void runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages); void runtime_MSpan_EnsureSwept(MSpan *span); @@ -509,7 +437,7 @@ struct MHeap struct { MCentral; byte pad[64]; - } central[NumSizeClasses]; + } central[_NumSizeClasses]; FixAlloc spanalloc; // allocator for Span* FixAlloc cachealloc; // allocator for MCache* @@ -520,7 +448,7 @@ struct MHeap // Malloc stats. uint64 largefree; // bytes freed for large objects (>MaxSmallSize) uint64 nlargefree; // number of frees for large objects (>MaxSmallSize) - uint64 nsmallfree[NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize) + uint64 nsmallfree[_NumSizeClasses]; // number of frees for small objects (<=MaxSmallSize) }; extern MHeap runtime_mheap; diff --git a/libgo/runtime/mcache.c b/libgo/runtime/mcache.c index 746711a0d3b..43962714695 100644 --- a/libgo/runtime/mcache.c +++ b/libgo/runtime/mcache.c @@ -27,7 +27,7 @@ runtime_allocmcache(void) c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc); runtime_unlock(&runtime_mheap); runtime_memclr((byte*)c, sizeof(*c)); - for(i = 0; i < NumSizeClasses; i++) + for(i = 0; i < _NumSizeClasses; i++) c->alloc[i] = &emptymspan; // Set first allocation sample size. @@ -115,7 +115,7 @@ runtime_MCache_ReleaseAll(MCache *c) MSpan *s; MCacheList *l; - for(i=0; ialloc[i]; if(s != &emptymspan) { runtime_MCentral_UncacheSpan(&runtime_mheap.central[i], s); diff --git a/libgo/runtime/mcentral.c b/libgo/runtime/mcentral.c index e41a83fbf03..62e2c2d7dfb 100644 --- a/libgo/runtime/mcentral.c +++ b/libgo/runtime/mcentral.c @@ -272,7 +272,7 @@ MCentral_Grow(MCentral *c) // Carve span into sequence of blocks. tailp = &s->freelist; p = (byte*)(s->start << PageShift); - s->limit = p + size*n; + s->limit = (uintptr)(p + size*n); for(i=0; i>PageShift; s = runtime_mheap.spans[x]; - if(s == nil || k < s->start || (const byte*)obj >= s->limit || s->state != MSpanInUse) + if(s == nil || k < s->start || (uintptr)obj >= s->limit || s->state != MSpanInUse) return false; p = (byte*)((uintptr)s->start<sizeclass == 0) { @@ -517,7 +517,7 @@ flushptrbuf(Scanbuf *sbuf) x = k; x -= (uintptr)arena_start>>PageShift; s = runtime_mheap.spans[x]; - if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse) + if(s == nil || k < s->start || (uintptr)obj >= s->limit || s->state != MSpanInUse) continue; p = (byte*)((uintptr)s->start<sizeclass == 0) { @@ -651,8 +651,8 @@ static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR}; static uintptr chanProg[2] = {0, GC_CHAN}; // Local variables of a program fragment or loop -typedef struct Frame Frame; -struct Frame { +typedef struct GCFrame GCFrame; +struct GCFrame { uintptr count, elemsize, b; const uintptr *loop_or_ret; }; @@ -731,7 +731,7 @@ scanblock(Workbuf *wbuf, bool keepworking) const Type *t, *et; Slice *sliceptr; String *stringptr; - Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4]; + GCFrame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4]; BufferList *scanbuffers; Scanbuf sbuf; Eface *eface; @@ -1057,7 +1057,7 @@ scanblock(Workbuf *wbuf, bool keepworking) // Stack push. *stack_ptr-- = stack_top; - stack_top = (Frame){count, elemsize, i, pc}; + stack_top = (GCFrame){count, elemsize, i, pc}; continue; case GC_ARRAY_NEXT: @@ -1074,7 +1074,7 @@ scanblock(Workbuf *wbuf, bool keepworking) case GC_CALL: // Stack push. *stack_ptr-- = stack_top; - stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/}; + stack_top = (GCFrame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/}; pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2)); // target of the CALL instruction continue; @@ -1357,7 +1357,7 @@ markroot(ParFor *desc, uint32 i) gp = runtime_allg[i - RootCount]; // remember when we've first observed the G blocked // needed only to output in traceback - if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince == 0) + if((gp->atomicstatus == _Gwaiting || gp->atomicstatus == _Gsyscall) && gp->waitsince == 0) gp->waitsince = work.tstart; addstackroots(gp, &wbuf); break; @@ -1472,17 +1472,17 @@ handoff(Workbuf *b) static void addstackroots(G *gp, Workbuf **wbufp) { - switch(gp->status){ + switch(gp->atomicstatus){ default: - runtime_printf("unexpected G.status %d (goroutine %p %D)\n", gp->status, gp, gp->goid); + runtime_printf("unexpected G.status %d (goroutine %p %D)\n", gp->atomicstatus, gp, gp->goid); runtime_throw("mark - bad status"); - case Gdead: + case _Gdead: return; - case Grunning: + case _Grunning: runtime_throw("mark - world not stopped"); - case Grunnable: - case Gsyscall: - case Gwaiting: + case _Grunnable: + case _Gsyscall: + case _Gwaiting: break; } @@ -1512,12 +1512,12 @@ addstackroots(G *gp, Workbuf **wbufp) // the system call instead, since that won't change underfoot. if(gp->gcstack != nil) { sp = gp->gcstack; - spsize = gp->gcstack_size; - next_segment = gp->gcnext_segment; - next_sp = gp->gcnext_sp; - initial_sp = gp->gcinitial_sp; + spsize = gp->gcstacksize; + next_segment = gp->gcnextsegment; + next_sp = gp->gcnextsp; + initial_sp = gp->gcinitialsp; } else { - sp = __splitstack_find_context(&gp->stack_context[0], + sp = __splitstack_find_context(&gp->stackcontext[0], &spsize, &next_segment, &next_sp, &initial_sp); } @@ -1543,11 +1543,11 @@ addstackroots(G *gp, Workbuf **wbufp) } else { // Scanning another goroutine's stack. // The goroutine is usually asleep (the world is stopped). - bottom = (byte*)gp->gcnext_sp; + bottom = (byte*)gp->gcnextsp; if(bottom == nil) return; } - top = (byte*)gp->gcinitial_sp + gp->gcstack_size; + top = (byte*)gp->gcinitialsp + gp->gcstacksize; if(top > bottom) enqueue1(wbufp, (Obj){bottom, top - bottom, 0}); else @@ -2186,8 +2186,8 @@ runtime_gc(int32 force) // switch to g0, call gc(&a), then switch back g = runtime_g(); g->param = &a; - g->status = Gwaiting; - g->waitreason = "garbage collection"; + g->atomicstatus = _Gwaiting; + g->waitreason = runtime_gostringnocopy((const byte*)"garbage collection"); runtime_mcall(mgc); m = runtime_m(); } @@ -2214,7 +2214,7 @@ mgc(G *gp) { gc(gp->param); gp->param = nil; - gp->status = Grunning; + gp->atomicstatus = _Grunning; runtime_gogo(gp); } @@ -2404,7 +2404,7 @@ runtime_ReadMemStats(MStats *stats) runtime_stoptheworld(); runtime_updatememstats(nil); // Size of the trailing by_size array differs between Go and C, - // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. + // _NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. runtime_memmove(stats, &mstats, runtime_sizeof_C_MStats); m->gcing = 0; m->locks++; diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c index 793915ef44c..04dc971d688 100644 --- a/libgo/runtime/mheap.c +++ b/libgo/runtime/mheap.c @@ -176,7 +176,7 @@ runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool n MSpan *s; runtime_lock(h); - mstats.heap_alloc += runtime_m()->mcache->local_cachealloc; + mstats.heap_alloc += (intptr)runtime_m()->mcache->local_cachealloc; runtime_m()->mcache->local_cachealloc = 0; s = MHeap_AllocLocked(h, npage, sizeclass); if(s != nil) { @@ -377,7 +377,7 @@ runtime_MHeap_LookupMaybe(MHeap *h, void *v) q = p; q -= (uintptr)h->arena_start >> PageShift; s = h->spans[q]; - if(s == nil || p < s->start || (byte*)v >= s->limit || s->state != MSpanInUse) + if(s == nil || p < s->start || (uintptr)v >= s->limit || s->state != MSpanInUse) return nil; return s; } @@ -387,7 +387,7 @@ void runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct) { runtime_lock(h); - mstats.heap_alloc += runtime_m()->mcache->local_cachealloc; + mstats.heap_alloc += (intptr)runtime_m()->mcache->local_cachealloc; runtime_m()->mcache->local_cachealloc = 0; mstats.heap_inuse -= s->npages<unusedsince = 0; span->npreleased = 0; span->types.compression = MTypes_Empty; - span->specialLock.key = 0; + span->speciallock.key = 0; span->specials = nil; span->needzero = 0; span->freebuf = nil; @@ -681,13 +681,13 @@ addspecial(void *p, Special *s) offset = (uintptr)p - (span->start << PageShift); kind = s->kind; - runtime_lock(&span->specialLock); + runtime_lock(&span->speciallock); // Find splice point, check for existing record. t = &span->specials; while((x = *t) != nil) { if(offset == x->offset && kind == x->kind) { - runtime_unlock(&span->specialLock); + runtime_unlock(&span->speciallock); runtime_m()->locks--; return false; // already exists } @@ -699,7 +699,7 @@ addspecial(void *p, Special *s) s->offset = offset; s->next = x; *t = s; - runtime_unlock(&span->specialLock); + runtime_unlock(&span->speciallock); runtime_m()->locks--; return true; } @@ -725,20 +725,20 @@ removespecial(void *p, byte kind) offset = (uintptr)p - (span->start << PageShift); - runtime_lock(&span->specialLock); + runtime_lock(&span->speciallock); t = &span->specials; while((s = *t) != nil) { // This function is used for finalizers only, so we don't check for // "interior" specials (p must be exactly equal to s->offset). if(offset == s->offset && kind == s->kind) { *t = s->next; - runtime_unlock(&span->specialLock); + runtime_unlock(&span->speciallock); runtime_m()->locks--; return s; } t = &s->next; } - runtime_unlock(&span->specialLock); + runtime_unlock(&span->speciallock); runtime_m()->locks--; return nil; } @@ -838,7 +838,7 @@ runtime_freeallspecials(MSpan *span, void *p, uintptr size) // this is required to not cause deadlock between span->specialLock and proflock list = nil; offset = (uintptr)p - (span->start << PageShift); - runtime_lock(&span->specialLock); + runtime_lock(&span->speciallock); t = &span->specials; while((s = *t) != nil) { if(offset + size <= s->offset) @@ -850,7 +850,7 @@ runtime_freeallspecials(MSpan *span, void *p, uintptr size) } else t = &s->next; } - runtime_unlock(&span->specialLock); + runtime_unlock(&span->speciallock); while(list != nil) { s = list; @@ -908,7 +908,7 @@ runtime_MHeap_SplitSpan(MHeap *h, MSpan *s) // Allocate a new span for the first half. t = runtime_FixAlloc_Alloc(&h->spanalloc); runtime_MSpan_Init(t, s->start, npages/2); - t->limit = (byte*)((t->start + npages/2) << PageShift); + t->limit = (uintptr)((t->start + npages/2) << PageShift); t->state = MSpanInUse; t->elemsize = npages << (PageShift - 1); t->sweepgen = s->sweepgen; diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc index 4e8cfc9caca..bb3f9e8c8e0 100644 --- a/libgo/runtime/mprof.goc +++ b/libgo/runtime/mprof.goc @@ -479,7 +479,7 @@ func GoroutineProfile(b Slice) (n int, ok bool) { saveg(g, r++); for(i = 0; i < runtime_allglen; i++) { gp = runtime_allg[i]; - if(gp == g || gp->status == Gdead) + if(gp == g || gp->atomicstatus == _Gdead) continue; saveg(gp, r++); } diff --git a/libgo/runtime/msize.c b/libgo/runtime/msize.c index 34509d04568..1bafc82bd61 100644 --- a/libgo/runtime/msize.c +++ b/libgo/runtime/msize.c @@ -29,8 +29,8 @@ #include "arch.h" #include "malloc.h" -int32 runtime_class_to_size[NumSizeClasses]; -int32 runtime_class_to_allocnpages[NumSizeClasses]; +int32 runtime_class_to_size[_NumSizeClasses]; +int32 runtime_class_to_allocnpages[_NumSizeClasses]; // The SizeToClass lookup is implemented using two arrays, // one mapping sizes <= 1024 to their class and one mapping @@ -101,14 +101,14 @@ runtime_InitSizes(void) runtime_class_to_size[sizeclass] = size; sizeclass++; } - if(sizeclass != NumSizeClasses) { - runtime_printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses); - runtime_throw("InitSizes - bad NumSizeClasses"); + if(sizeclass != _NumSizeClasses) { + runtime_printf("sizeclass=%d _NumSizeClasses=%d\n", sizeclass, _NumSizeClasses); + runtime_throw("InitSizes - bad _NumSizeClasses"); } // Initialize the size_to_class tables. nextsize = 0; - for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { + for (sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++) { for(; nextsize < 1024 && nextsize <= runtime_class_to_size[sizeclass]; nextsize+=8) runtime_size_to_class8[nextsize/8] = sizeclass; if(nextsize >= 1024) @@ -120,7 +120,7 @@ runtime_InitSizes(void) if(0) { for(n=0; n < MaxSmallSize; n++) { sizeclass = runtime_SizeToClass(n); - if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime_class_to_size[sizeclass] < n) { + if(sizeclass < 1 || sizeclass >= _NumSizeClasses || runtime_class_to_size[sizeclass] < n) { runtime_printf("size=%d sizeclass=%d runtime_class_to_size=%d\n", n, sizeclass, runtime_class_to_size[sizeclass]); runtime_printf("incorrect SizeToClass"); goto dump; @@ -140,9 +140,9 @@ runtime_InitSizes(void) dump: if(1){ - runtime_printf("NumSizeClasses=%d\n", NumSizeClasses); + runtime_printf("NumSizeClasses=%d\n", _NumSizeClasses); runtime_printf("runtime_class_to_size:"); - for(sizeclass=0; sizeclassschedlink = *gpp; + rg->schedlink = (uintptr)*gpp; *gpp = rg; } if(wg) { - wg->schedlink = *gpp; + wg->schedlink = (uintptr)*gpp; *gpp = wg; } } diff --git a/libgo/runtime/panic.c b/libgo/runtime/panic.c index de000db9889..3fb3bde3223 100644 --- a/libgo/runtime/panic.c +++ b/libgo/runtime/panic.c @@ -4,7 +4,6 @@ #include "runtime.h" #include "malloc.h" -#include "go-defer.h" #include "go-panic.h" // Code related to defer, panic and recover. @@ -21,10 +20,10 @@ runtime_newdefer() P *p; d = nil; - p = runtime_m()->p; + p = (P*)runtime_m()->p; d = p->deferpool; if(d) - p->deferpool = d->__next; + p->deferpool = d->next; if(d == nil) { // deferpool is empty d = runtime_malloc(sizeof(Defer)); @@ -39,10 +38,10 @@ runtime_freedefer(Defer *d) { P *p; - if(d->__special) + if(d->special) return; - p = runtime_m()->p; - d->__next = p->deferpool; + p = (P*)runtime_m()->p; + d->next = p->deferpool; p->deferpool = d; // No need to wipe out pointers in argp/pc/fn/args, // because we empty the pool before GC. @@ -58,14 +57,14 @@ __go_rundefer(void) Defer *d; g = runtime_g(); - while((d = g->defer) != nil) { + while((d = g->_defer) != nil) { void (*pfn)(void*); - g->defer = d->__next; - pfn = d->__pfn; - d->__pfn = nil; + g->_defer = d->next; + pfn = (void (*) (void *))d->pfn; + d->pfn = 0; if (pfn != nil) - (*pfn)(d->__arg); + (*pfn)(d->arg); runtime_freedefer(d); } } @@ -171,7 +170,7 @@ runtime_canpanic(G *gp) return false; if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0) return false; - if(gp->status != Grunning) + if(gp->atomicstatus != _Grunning) return false; #ifdef GOOS_windows if(m->libcallsp != 0) diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index defb0a59bb1..1ac03a42372 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -19,7 +19,6 @@ #include "defs.h" #include "malloc.h" #include "go-type.h" -#include "go-defer.h" #ifdef USING_SPLIT_STACK @@ -62,7 +61,6 @@ static void gtraceback(G*); #endif static __thread G *g; -static __thread M *m; #ifndef SETCONTEXT_CLOBBERS_TLS @@ -179,14 +177,15 @@ M* runtime_m(void) __attribute__ ((noinline, no_split_stack)); M* runtime_m(void) { - return m; + if(g == nil) + return nil; + return g->m; } -// Set m and g. +// Set g. void -runtime_setmg(M* mp, G* gp) +runtime_setg(G* gp) { - m = mp; g = gp; } @@ -242,12 +241,12 @@ void runtime_gogo(G* newg) { #ifdef USING_SPLIT_STACK - __splitstack_setcontext(&newg->stack_context[0]); + __splitstack_setcontext(&newg->stackcontext[0]); #endif g = newg; newg->fromgogo = true; - fixcontext(&newg->context); - setcontext(&newg->context); + fixcontext((ucontext_t*)&newg->context[0]); + setcontext((ucontext_t*)&newg->context[0]); runtime_throw("gogo setcontext returned"); } @@ -266,37 +265,37 @@ runtime_mcall(void (*pfn)(G*)) // collector. __builtin_unwind_init(); - mp = m; gp = g; + mp = gp->m; if(gp == mp->g0) runtime_throw("runtime: mcall called on m->g0 stack"); if(gp != nil) { #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&g->stack_context[0]); + __splitstack_getcontext(&g->stackcontext[0]); #else - gp->gcnext_sp = &pfn; + gp->gcnextsp = &pfn; #endif gp->fromgogo = false; - getcontext(&gp->context); + getcontext((ucontext_t*)&gp->context[0]); // When we return from getcontext, we may be running - // in a new thread. That means that m and g may have - // changed. They are global variables so we will - // reload them, but the addresses of m and g may be - // cached in our local stack frame, and those - // addresses may be wrong. Call functions to reload - // the values for this thread. - mp = runtime_m(); + // in a new thread. That means that g may have + // changed. It is a global variables so we will + // reload it, but the address of g may be cached in + // our local stack frame, and that address may be + // wrong. Call the function to reload the value for + // this thread. gp = runtime_g(); + mp = gp->m; if(gp->traceback != nil) gtraceback(gp); } if (gp == nil || !gp->fromgogo) { #ifdef USING_SPLIT_STACK - __splitstack_setcontext(&mp->g0->stack_context[0]); + __splitstack_setcontext(&mp->g0->stackcontext[0]); #endif mp->g0->entry = (byte*)pfn; mp->g0->param = gp; @@ -306,8 +305,8 @@ runtime_mcall(void (*pfn)(G*)) // the getcontext call just above. g = mp->g0; - fixcontext(&mp->g0->context); - setcontext(&mp->g0->context); + fixcontext((ucontext_t*)&mp->g0->context[0]); + setcontext((ucontext_t*)&mp->g0->context[0]); runtime_throw("runtime: mcall function returned"); } } @@ -360,10 +359,6 @@ struct Sched { enum { - // The max value of GOMAXPROCS. - // There are no fundamental restrictions on the value. - MaxGomaxprocs = 1<<8, - // Number of goroutine ids to grab from runtime_sched.goidgen to local per-P cache at once. // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number. GoidCacheBatch = 16, @@ -442,6 +437,7 @@ bool runtime_isstarted; void runtime_schedinit(void) { + M *m; int32 n, procs; String s; const byte *p; @@ -481,11 +477,11 @@ runtime_schedinit(void) s = runtime_getenv("GOMAXPROCS"); p = s.str; if(p != nil && (n = runtime_atoi(p, s.len)) > 0) { - if(n > MaxGomaxprocs) - n = MaxGomaxprocs; + if(n > _MaxGomaxprocs) + n = _MaxGomaxprocs; procs = n; } - runtime_allp = runtime_malloc((MaxGomaxprocs+1)*sizeof(runtime_allp[0])); + runtime_allp = runtime_malloc((_MaxGomaxprocs+1)*sizeof(runtime_allp[0])); procresize(procs); // Can not enable GC until all roots are registered. @@ -583,17 +579,17 @@ runtime_main(void* dummy __attribute__((unused))) runtime_lockOSThread(); // Defer unlock so that runtime.Goexit during init does the unlock too. - d.__pfn = initDone; - d.__next = g->defer; - d.__arg = (void*)-1; - d.__panic = g->panic; - d.__retaddr = nil; - d.__makefunc_can_recover = 0; - d.__frame = &frame; - d.__special = true; - g->defer = &d; - - if(m != &runtime_m0) + d.pfn = (uintptr)(void*)initDone; + d.next = g->_defer; + d.arg = (void*)-1; + d._panic = g->_panic; + d.retaddr = 0; + d.makefunccanrecover = 0; + d.frame = &frame; + d.special = true; + g->_defer = &d; + + if(g->m != &runtime_m0) runtime_throw("runtime_main not on m0"); __go_go(runtime_MHeap_Scavenger, nil); @@ -605,9 +601,9 @@ runtime_main(void* dummy __attribute__((unused))) closechan(runtime_main_init_done); - if(g->defer != &d || d.__pfn != initDone) + if(g->_defer != &d || (void*)d.pfn != initDone) runtime_throw("runtime: bad defer entry after init"); - g->defer = d.__next; + g->_defer = d.next; runtime_unlockOSThread(); // For gccgo we have to wait until after main is initialized @@ -640,42 +636,42 @@ runtime_main(void* dummy __attribute__((unused))) void runtime_goroutineheader(G *gp) { - const char *status; + String status; int64 waitfor; - switch(gp->status) { - case Gidle: - status = "idle"; + switch(gp->atomicstatus) { + case _Gidle: + status = runtime_gostringnocopy((const byte*)"idle"); break; - case Grunnable: - status = "runnable"; + case _Grunnable: + status = runtime_gostringnocopy((const byte*)"runnable"); break; - case Grunning: - status = "running"; + case _Grunning: + status = runtime_gostringnocopy((const byte*)"running"); break; - case Gsyscall: - status = "syscall"; + case _Gsyscall: + status = runtime_gostringnocopy((const byte*)"syscall"); break; - case Gwaiting: - if(gp->waitreason) + case _Gwaiting: + if(gp->waitreason.len > 0) status = gp->waitreason; else - status = "waiting"; + status = runtime_gostringnocopy((const byte*)"waiting"); break; default: - status = "???"; + status = runtime_gostringnocopy((const byte*)"???"); break; } // approx time the G is blocked, in minutes waitfor = 0; - if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince != 0) + if((gp->atomicstatus == _Gwaiting || gp->atomicstatus == _Gsyscall) && gp->waitsince != 0) waitfor = (runtime_nanotime() - gp->waitsince) / (60LL*1000*1000*1000); if(waitfor < 1) - runtime_printf("goroutine %D [%s]:\n", gp->goid, status); + runtime_printf("goroutine %D [%S]:\n", gp->goid, status); else - runtime_printf("goroutine %D [%s, %D minutes]:\n", gp->goid, status, waitfor); + runtime_printf("goroutine %D [%S, %D minutes]:\n", gp->goid, status, waitfor); } void @@ -693,13 +689,6 @@ runtime_printcreatedby(G *g) } } -struct Traceback -{ - G* gp; - Location locbuf[TracebackMaxFrames]; - int32 c; -}; - void runtime_tracebackothers(G * volatile me) { @@ -712,15 +701,15 @@ runtime_tracebackothers(G * volatile me) traceback = runtime_gotraceback(nil); // Show the current goroutine first, if we haven't already. - if((gp = m->curg) != nil && gp != me) { + if((gp = g->m->curg) != nil && gp != me) { runtime_printf("\n"); runtime_goroutineheader(gp); gp->traceback = &tb; #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&me->stack_context[0]); + __splitstack_getcontext(&me->stackcontext[0]); #endif - getcontext(&me->context); + getcontext((ucontext_t*)&me->context[0]); if(gp->traceback != nil) { runtime_gogo(gp); @@ -733,7 +722,7 @@ runtime_tracebackothers(G * volatile me) runtime_lock(&allglock); for(i = 0; i < runtime_allglen; i++) { gp = runtime_allg[i]; - if(gp == me || gp == m->curg || gp->status == Gdead) + if(gp == me || gp == g->m->curg || gp->atomicstatus == _Gdead) continue; if(gp->issystem && traceback < 2) continue; @@ -749,19 +738,19 @@ runtime_tracebackothers(G * volatile me) // This means that if g is running or in a syscall, we // can't reliably print a stack trace. FIXME. - if(gp->status == Grunning) { + if(gp->atomicstatus == _Grunning) { runtime_printf("\tgoroutine running on other thread; stack unavailable\n"); runtime_printcreatedby(gp); - } else if(gp->status == Gsyscall) { + } else if(gp->atomicstatus == _Gsyscall) { runtime_printf("\tgoroutine in C code; stack unavailable\n"); runtime_printcreatedby(gp); } else { gp->traceback = &tb; #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&me->stack_context[0]); + __splitstack_getcontext(&me->stackcontext[0]); #endif - getcontext(&me->context); + getcontext((ucontext_t*)&me->context[0]); if(gp->traceback != nil) { runtime_gogo(gp); @@ -794,8 +783,12 @@ gtraceback(G* gp) traceback = gp->traceback; gp->traceback = nil; + if(gp->m != nil) + runtime_throw("gtraceback: m is not nil"); + gp->m = traceback->gp->m; traceback->c = runtime_callers(1, traceback->locbuf, sizeof traceback->locbuf / sizeof traceback->locbuf[0], false); + gp->m = nil; runtime_gogo(traceback->gp); } @@ -804,7 +797,7 @@ mcommoninit(M *mp) { // If there is no mcache runtime_callers() will crash, // and we are most likely in sysmon thread so the stack is senseless anyway. - if(m->mcache) + if(g->m->mcache) runtime_callers(1, mp->createstack, nelem(mp->createstack), false); mp->fastrand = 0x49f6428aUL + mp->id + runtime_cputicks(); @@ -828,16 +821,16 @@ void runtime_ready(G *gp) { // Mark runnable. - m->locks++; // disable preemption because it can be holding p in a local var - if(gp->status != Gwaiting) { - runtime_printf("goroutine %D has status %d\n", gp->goid, gp->status); - runtime_throw("bad g->status in ready"); + g->m->locks++; // disable preemption because it can be holding p in a local var + if(gp->atomicstatus != _Gwaiting) { + runtime_printf("goroutine %D has status %d\n", gp->goid, gp->atomicstatus); + runtime_throw("bad g->atomicstatus in ready"); } - gp->status = Grunnable; - runqput(m->p, gp); + gp->atomicstatus = _Grunnable; + runqput((P*)g->m->p, gp); if(runtime_atomicload(&runtime_sched.npidle) != 0 && runtime_atomicload(&runtime_sched.nmspinning) == 0) // TODO: fast atomic wakep(); - m->locks--; + g->m->locks--; } int32 @@ -884,7 +877,7 @@ runtime_helpgc(int32 nproc) runtime_lock(&runtime_sched); pos = 0; for(n = 1; n < nproc; n++) { // one M is currently running - if(runtime_allp[pos]->mcache == m->mcache) + if(runtime_allp[pos]->mcache == g->m->mcache) pos++; mp = mget(); if(mp == nil) @@ -938,18 +931,18 @@ runtime_stoptheworld(void) runtime_atomicstore((uint32*)&runtime_sched.gcwaiting, 1); preemptall(); // stop current P - m->p->status = Pgcstop; + ((P*)g->m->p)->status = _Pgcstop; runtime_sched.stopwait--; - // try to retake all P's in Psyscall status + // try to retake all P's in _Psyscall status for(i = 0; i < runtime_gomaxprocs; i++) { p = runtime_allp[i]; s = p->status; - if(s == Psyscall && runtime_cas(&p->status, s, Pgcstop)) + if(s == _Psyscall && runtime_cas(&p->status, s, _Pgcstop)) runtime_sched.stopwait--; } // stop idle P's while((p = pidleget()) != nil) { - p->status = Pgcstop; + p->status = _Pgcstop; runtime_sched.stopwait--; } wait = runtime_sched.stopwait > 0; @@ -964,7 +957,7 @@ runtime_stoptheworld(void) runtime_throw("stoptheworld: not stopped"); for(i = 0; i < runtime_gomaxprocs; i++) { p = runtime_allp[i]; - if(p->status != Pgcstop) + if(p->status != _Pgcstop) runtime_throw("stoptheworld: not stopped"); } } @@ -972,7 +965,7 @@ runtime_stoptheworld(void) static void mhelpgc(void) { - m->helpgc = -1; + g->m->helpgc = -1; } void @@ -983,7 +976,7 @@ runtime_starttheworld(void) G *gp; bool add; - m->locks++; // disable preemption because it can be holding p in a local var + g->m->locks++; // disable preemption because it can be holding p in a local var gp = runtime_netpoll(false); // non-blocking injectglist(gp); add = needaddgcproc(); @@ -1003,8 +996,8 @@ runtime_starttheworld(void) pidleput(p); break; } - p->m = mget(); - p->link = p1; + p->m = (uintptr)mget(); + p->link = (uintptr)p1; p1 = p; } if(runtime_sched.sysmonwait) { @@ -1015,13 +1008,13 @@ runtime_starttheworld(void) while(p1) { p = p1; - p1 = p1->link; + p1 = (P*)p1->link; if(p->m) { - mp = p->m; - p->m = nil; + mp = (M*)p->m; + p->m = 0; if(mp->nextp) runtime_throw("starttheworld: inconsistent mp->nextp"); - mp->nextp = p; + mp->nextp = (uintptr)p; runtime_notewakeup(&mp->park); } else { // Start M to run P. Do not start another M below. @@ -1040,15 +1033,18 @@ runtime_starttheworld(void) // the maximum number of procs. newm(mhelpgc, nil); } - m->locks--; + g->m->locks--; } // Called to start an M. void* runtime_mstart(void* mp) { + M *m; + m = (M*)mp; g = m->g0; + g->m = m; initcontext(); @@ -1059,15 +1055,15 @@ runtime_mstart(void* mp) // Once we call schedule we're never coming back, // so other calls can reuse this stack space. #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&g->stack_context[0]); + __splitstack_getcontext(&g->stackcontext[0]); #else - g->gcinitial_sp = ∓ - // Setting gcstack_size to 0 is a marker meaning that gcinitial_sp + g->gcinitialsp = ∓ + // Setting gcstacksize to 0 is a marker meaning that gcinitialsp // is the top of the stack, not the bottom. - g->gcstack_size = 0; - g->gcnext_sp = ∓ + g->gcstacksize = 0; + g->gcnextsp = ∓ #endif - getcontext(&g->context); + getcontext((ucontext_t*)&g->context[0]); if(g->entry != nil) { // Got here from mcall. @@ -1097,14 +1093,14 @@ runtime_mstart(void* mp) } if(m->mstartfn) - m->mstartfn(); + ((void (*)(void))m->mstartfn)(); if(m->helpgc) { m->helpgc = 0; stopm(); } else if(m != &runtime_m0) { - acquirep(m->nextp); - m->nextp = nil; + acquirep((P*)m->nextp); + m->nextp = 0; } schedule(); @@ -1127,12 +1123,12 @@ struct CgoThreadStart // Allocate a new m unassociated with any thread. // Can use p for allocation context if needed. M* -runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacksize) +runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, uintptr* ret_g0_stacksize) { M *mp; - m->locks++; // disable GC because it can be called from sysmon - if(m->p == nil) + g->m->locks++; // disable GC because it can be called from sysmon + if(g->m->p == 0) acquirep(p); // temporarily borrow p for mallocs in this function #if 0 if(mtype == nil) { @@ -1145,10 +1141,11 @@ runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacks mp = runtime_mal(sizeof *mp); mcommoninit(mp); mp->g0 = runtime_malg(stacksize, ret_g0_stack, ret_g0_stacksize); + mp->g0->m = mp; - if(p == m->p) + if(p == (P*)g->m->p) releasep(); - m->locks--; + g->m->locks--; return mp; } @@ -1235,26 +1232,26 @@ runtime_needm(void) // after exitsyscall makes sure it is okay to be // running at all (that is, there's no garbage collection // running right now). - mp->needextram = mp->schedlink == nil; - unlockextra(mp->schedlink); + mp->needextram = mp->schedlink == 0; + unlockextra((M*)mp->schedlink); - // Install m and g (= m->curg). - runtime_setmg(mp, mp->curg); + // Install g (= m->curg). + runtime_setg(mp->curg); // Initialize g's context as in mstart. initcontext(); - g->status = Gsyscall; + g->atomicstatus = _Gsyscall; g->entry = nil; g->param = nil; #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&g->stack_context[0]); + __splitstack_getcontext(&g->stackcontext[0]); #else - g->gcinitial_sp = ∓ + g->gcinitialsp = ∓ g->gcstack = nil; - g->gcstack_size = 0; - g->gcnext_sp = ∓ + g->gcstacksize = 0; + g->gcnextsp = ∓ #endif - getcontext(&g->context); + getcontext((ucontext_t*)&g->context[0]); if(g->entry != nil) { // Got here from mcall. @@ -1284,7 +1281,7 @@ runtime_newextram(void) M *mp, *mnext; G *gp; byte *g0_sp, *sp; - size_t g0_spsize, spsize; + uintptr g0_spsize, spsize; // Create extra goroutine locked to extra m. // The goroutine is the context in which the cgo callback will run. @@ -1293,9 +1290,10 @@ runtime_newextram(void) // the goroutine stack ends. mp = runtime_allocm(nil, StackMin, &g0_sp, &g0_spsize); gp = runtime_malg(StackMin, &sp, &spsize); - gp->status = Gdead; + gp->atomicstatus = _Gdead; + gp->m = mp; mp->curg = gp; - mp->locked = LockInternal; + mp->locked = _LockInternal; mp->lockedg = gp; gp->lockedm = mp; gp->goid = runtime_xadd64(&runtime_sched.goidgen, 1); @@ -1304,14 +1302,14 @@ runtime_newextram(void) // The context for gp will be set up in runtime_needm. But // here we need to set up the context for g0. - getcontext(&mp->g0->context); - mp->g0->context.uc_stack.ss_sp = g0_sp; - mp->g0->context.uc_stack.ss_size = g0_spsize; - makecontext(&mp->g0->context, kickoff, 0); + getcontext((ucontext_t*)&mp->g0->context[0]); + ((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_sp = g0_sp; + ((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_size = (size_t)g0_spsize; + makecontext((ucontext_t*)&mp->g0->context[0], kickoff, 0); // Add m to the extra list. mnext = lockextra(true); - mp->schedlink = mnext; + mp->schedlink = (uintptr)mnext; unlockextra(mp); } @@ -1347,16 +1345,16 @@ runtime_dropm(void) runtime_unminit(); // Clear m and g, and return m to the extra list. - // After the call to setmg we can only call nosplit functions. - mp = m; - runtime_setmg(nil, nil); + // After the call to setg we can only call nosplit functions. + mp = g->m; + runtime_setg(nil); - mp->curg->status = Gdead; + mp->curg->atomicstatus = _Gdead; mp->curg->gcstack = nil; - mp->curg->gcnext_sp = nil; + mp->curg->gcnextsp = nil; mnext = lockextra(true); - mp->schedlink = mnext; + mp->schedlink = (uintptr)mnext; unlockextra(mp); } @@ -1417,7 +1415,7 @@ countextra() continue; } c = 0; - for(mc = mp; mc != nil; mc = mc->schedlink) + for(mc = mp; mc != nil; mc = (M*)mc->schedlink) c++; runtime_atomicstorep(&runtime_extram, mp); return c; @@ -1431,8 +1429,8 @@ newm(void(*fn)(void), P *p) M *mp; mp = runtime_allocm(p, -1, nil, nil); - mp->nextp = p; - mp->mstartfn = fn; + mp->nextp = (uintptr)p; + mp->mstartfn = (uintptr)(void*)fn; runtime_newosproc(mp); } @@ -1442,6 +1440,9 @@ newm(void(*fn)(void), P *p) static void stopm(void) { + M* m; + + m = g->m; if(m->locks) runtime_throw("stopm holding locks"); if(m->p) @@ -1456,6 +1457,7 @@ retry: mput(m); runtime_unlock(&runtime_sched); runtime_notesleep(&m->park); + m = g->m; runtime_noteclear(&m->park); if(m->helpgc) { runtime_gchelper(); @@ -1463,14 +1465,14 @@ retry: m->mcache = nil; goto retry; } - acquirep(m->nextp); - m->nextp = nil; + acquirep((P*)m->nextp); + m->nextp = 0; } static void mspinning(void) { - m->spinning = true; + g->m->spinning = true; } // Schedules some M to run the p (creates an M if necessary). @@ -1505,7 +1507,7 @@ startm(P *p, bool spinning) if(mp->nextp) runtime_throw("startm: m has p"); mp->spinning = spinning; - mp->nextp = p; + mp->nextp = (uintptr)p; runtime_notewakeup(&mp->park); } @@ -1527,7 +1529,7 @@ handoffp(P *p) } runtime_lock(&runtime_sched); if(runtime_sched.gcwaiting) { - p->status = Pgcstop; + p->status = _Pgcstop; if(--runtime_sched.stopwait == 0) runtime_notewakeup(&runtime_sched.stopnote); runtime_unlock(&runtime_sched); @@ -1565,8 +1567,10 @@ wakep(void) static void stoplockedm(void) { + M *m; P *p; + m = g->m; if(m->lockedg == nil || m->lockedg->lockedm != m) runtime_throw("stoplockedm: inconsistent locking"); if(m->p) { @@ -1577,11 +1581,12 @@ stoplockedm(void) incidlelocked(1); // Wait until another thread schedules lockedg again. runtime_notesleep(&m->park); + m = g->m; runtime_noteclear(&m->park); - if(m->lockedg->status != Grunnable) + if(m->lockedg->atomicstatus != _Grunnable) runtime_throw("stoplockedm: not runnable"); - acquirep(m->nextp); - m->nextp = nil; + acquirep((P*)m->nextp); + m->nextp = 0; } // Schedules the locked m to run the locked gp. @@ -1592,14 +1597,14 @@ startlockedm(G *gp) P *p; mp = gp->lockedm; - if(mp == m) + if(mp == g->m) runtime_throw("startlockedm: locked to me"); if(mp->nextp) runtime_throw("startlockedm: m has p"); // directly handoff current P to the locked m incidlelocked(-1); p = releasep(); - mp->nextp = p; + mp->nextp = (uintptr)p; runtime_notewakeup(&mp->park); stopm(); } @@ -1613,13 +1618,13 @@ gcstopm(void) if(!runtime_sched.gcwaiting) runtime_throw("gcstopm: not waiting for gc"); - if(m->spinning) { - m->spinning = false; + if(g->m->spinning) { + g->m->spinning = false; runtime_xadd(&runtime_sched.nmspinning, -1); } p = releasep(); runtime_lock(&runtime_sched); - p->status = Pgcstop; + p->status = _Pgcstop; if(--runtime_sched.stopwait == 0) runtime_notewakeup(&runtime_sched.stopnote); runtime_unlock(&runtime_sched); @@ -1633,19 +1638,19 @@ execute(G *gp) { int32 hz; - if(gp->status != Grunnable) { - runtime_printf("execute: bad g status %d\n", gp->status); + if(gp->atomicstatus != _Grunnable) { + runtime_printf("execute: bad g status %d\n", gp->atomicstatus); runtime_throw("execute: bad g status"); } - gp->status = Grunning; + gp->atomicstatus = _Grunning; gp->waitsince = 0; - m->p->schedtick++; - m->curg = gp; - gp->m = m; + ((P*)g->m->p)->schedtick++; + g->m->curg = gp; + gp->m = g->m; // Check whether the profiler needs to be turned on or off. hz = runtime_sched.profilehz; - if(m->profilehz != hz) + if(g->m->profilehz != hz) runtime_resetcpuprofiler(hz); runtime_gogo(gp); @@ -1668,13 +1673,13 @@ top: if(runtime_fingwait && runtime_fingwake && (gp = runtime_wakefing()) != nil) runtime_ready(gp); // local runq - gp = runqget(m->p); + gp = runqget((P*)g->m->p); if(gp) return gp; // global runq if(runtime_sched.runqsize) { runtime_lock(&runtime_sched); - gp = globrunqget(m->p, 0); + gp = globrunqget((P*)g->m->p, 0); runtime_unlock(&runtime_sched); if(gp) return gp; @@ -1682,17 +1687,17 @@ top: // poll network gp = runtime_netpoll(false); // non-blocking if(gp) { - injectglist(gp->schedlink); - gp->status = Grunnable; + injectglist((G*)gp->schedlink); + gp->atomicstatus = _Grunnable; return gp; } // If number of spinning M's >= number of busy P's, block. // This is necessary to prevent excessive CPU consumption // when GOMAXPROCS>>1 but the program parallelism is low. - if(!m->spinning && 2 * runtime_atomicload(&runtime_sched.nmspinning) >= runtime_gomaxprocs - runtime_atomicload(&runtime_sched.npidle)) // TODO: fast atomic + if(!g->m->spinning && 2 * runtime_atomicload(&runtime_sched.nmspinning) >= runtime_gomaxprocs - runtime_atomicload(&runtime_sched.npidle)) // TODO: fast atomic goto stop; - if(!m->spinning) { - m->spinning = true; + if(!g->m->spinning) { + g->m->spinning = true; runtime_xadd(&runtime_sched.nmspinning, 1); } // random steal from other P's @@ -1700,10 +1705,10 @@ top: if(runtime_sched.gcwaiting) goto top; p = runtime_allp[runtime_fastrand1()%runtime_gomaxprocs]; - if(p == m->p) + if(p == (P*)g->m->p) gp = runqget(p); else - gp = runqsteal(m->p, p); + gp = runqsteal((P*)g->m->p, p); if(gp) return gp; } @@ -1715,15 +1720,15 @@ stop: goto top; } if(runtime_sched.runqsize) { - gp = globrunqget(m->p, 0); + gp = globrunqget((P*)g->m->p, 0); runtime_unlock(&runtime_sched); return gp; } p = releasep(); pidleput(p); runtime_unlock(&runtime_sched); - if(m->spinning) { - m->spinning = false; + if(g->m->spinning) { + g->m->spinning = false; runtime_xadd(&runtime_sched.nmspinning, -1); } // check all runqueues once again @@ -1742,9 +1747,9 @@ stop: } // poll network if(runtime_xchg64(&runtime_sched.lastpoll, 0) != 0) { - if(m->p) + if(g->m->p) runtime_throw("findrunnable: netpoll with p"); - if(m->spinning) + if(g->m->spinning) runtime_throw("findrunnable: netpoll with spinning"); gp = runtime_netpoll(true); // block until new work is available runtime_atomicstore64(&runtime_sched.lastpoll, runtime_nanotime()); @@ -1754,8 +1759,8 @@ stop: runtime_unlock(&runtime_sched); if(p) { acquirep(p); - injectglist(gp->schedlink); - gp->status = Grunnable; + injectglist((G*)gp->schedlink); + gp->atomicstatus = _Grunnable; return gp; } injectglist(gp); @@ -1770,8 +1775,8 @@ resetspinning(void) { int32 nmspinning; - if(m->spinning) { - m->spinning = false; + if(g->m->spinning) { + g->m->spinning = false; nmspinning = runtime_xadd(&runtime_sched.nmspinning, -1); if(nmspinning < 0) runtime_throw("findrunnable: negative nmspinning"); @@ -1797,8 +1802,8 @@ injectglist(G *glist) runtime_lock(&runtime_sched); for(n = 0; glist; n++) { gp = glist; - glist = gp->schedlink; - gp->status = Grunnable; + glist = (G*)gp->schedlink; + gp->atomicstatus = _Grunnable; globrunqput(gp); } runtime_unlock(&runtime_sched); @@ -1815,7 +1820,7 @@ schedule(void) G *gp; uint32 tick; - if(m->locks) + if(g->m->locks) runtime_throw("schedule: holding locks"); top: @@ -1828,19 +1833,19 @@ top: // Check the global runnable queue once in a while to ensure fairness. // Otherwise two goroutines can completely occupy the local runqueue // by constantly respawning each other. - tick = m->p->schedtick; + tick = ((P*)g->m->p)->schedtick; // This is a fancy way to say tick%61==0, // it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors. if(tick - (((uint64)tick*0x4325c53fu)>>36)*61 == 0 && runtime_sched.runqsize > 0) { runtime_lock(&runtime_sched); - gp = globrunqget(m->p, 1); + gp = globrunqget((P*)g->m->p, 1); runtime_unlock(&runtime_sched); if(gp) resetspinning(); } if(gp == nil) { - gp = runqget(m->p); - if(gp && m->spinning) + gp = runqget((P*)g->m->p); + if(gp && g->m->spinning) runtime_throw("schedule: spinning with local work"); } if(gp == nil) { @@ -1863,11 +1868,11 @@ top: void runtime_park(bool(*unlockf)(G*, void*), void *lock, const char *reason) { - if(g->status != Grunning) + if(g->atomicstatus != _Grunning) runtime_throw("bad g status"); - m->waitlock = lock; - m->waitunlockf = unlockf; - g->waitreason = reason; + g->m->waitlock = lock; + g->m->waitunlockf = unlockf; + g->waitreason = runtime_gostringnocopy((const byte*)reason); runtime_mcall(park0); } @@ -1891,17 +1896,19 @@ runtime_parkunlock(Lock *lock, const char *reason) static void park0(G *gp) { + M *m; bool ok; - gp->status = Gwaiting; + m = g->m; + gp->atomicstatus = _Gwaiting; gp->m = nil; m->curg = nil; if(m->waitunlockf) { - ok = m->waitunlockf(gp, m->waitlock); + ok = ((bool (*)(G*, void*))m->waitunlockf)(gp, m->waitlock); m->waitunlockf = nil; m->waitlock = nil; if(!ok) { - gp->status = Grunnable; + gp->atomicstatus = _Grunnable; execute(gp); // Schedule it back, never returns. } } @@ -1916,7 +1923,7 @@ park0(G *gp) void runtime_gosched(void) { - if(g->status != Grunning) + if(g->atomicstatus != _Grunning) runtime_throw("bad g status"); runtime_mcall(runtime_gosched0); } @@ -1925,7 +1932,10 @@ runtime_gosched(void) void runtime_gosched0(G *gp) { - gp->status = Grunnable; + M *m; + + m = g->m; + gp->atomicstatus = _Grunnable; gp->m = nil; m->curg = nil; runtime_lock(&runtime_sched); @@ -1946,7 +1956,7 @@ void runtime_goexit(void) __attribute__ ((noinline)); void runtime_goexit(void) { - if(g->status != Grunning) + if(g->atomicstatus != _Grunning) runtime_throw("bad g status"); runtime_mcall(goexit0); } @@ -1955,25 +1965,28 @@ runtime_goexit(void) static void goexit0(G *gp) { - gp->status = Gdead; + M *m; + + m = g->m; + gp->atomicstatus = _Gdead; gp->entry = nil; gp->m = nil; gp->lockedm = nil; gp->paniconfault = 0; - gp->defer = nil; // should be true already but just in case. - gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data. + gp->_defer = nil; // should be true already but just in case. + gp->_panic = nil; // non-nil for Goexit during panic. points at stack-allocated data. gp->writenbuf = 0; gp->writebuf = nil; - gp->waitreason = nil; + gp->waitreason = runtime_gostringnocopy(nil); gp->param = nil; m->curg = nil; m->lockedg = nil; - if(m->locked & ~LockExternal) { + if(m->locked & ~_LockExternal) { runtime_printf("invalid m->locked = %d\n", m->locked); runtime_throw("internal lockOSThread error"); } m->locked = 0; - gfput(m->p, gp); + gfput((P*)m->p, gp); schedule(); } @@ -1994,7 +2007,7 @@ runtime_entersyscall() { // Save the registers in the g structure so that any pointers // held in registers will be seen by the garbage collector. - getcontext(&g->gcregs); + getcontext((ucontext_t*)&g->gcregs[0]); // Do the work in a separate function, so that this function // doesn't save any registers on its own stack. If this @@ -2011,24 +2024,24 @@ runtime_entersyscall() static void doentersyscall() { - // Disable preemption because during this function g is in Gsyscall status, + // Disable preemption because during this function g is in _Gsyscall status, // but can have inconsistent g->sched, do not let GC observe it. - m->locks++; + g->m->locks++; // Leave SP around for GC and traceback. #ifdef USING_SPLIT_STACK - g->gcstack = __splitstack_find(nil, nil, &g->gcstack_size, - &g->gcnext_segment, &g->gcnext_sp, - &g->gcinitial_sp); + g->gcstack = __splitstack_find(nil, nil, &g->gcstacksize, + &g->gcnextsegment, &g->gcnextsp, + &g->gcinitialsp); #else { void *v; - g->gcnext_sp = (byte *) &v; + g->gcnextsp = (byte *) &v; } #endif - g->status = Gsyscall; + g->atomicstatus = _Gsyscall; if(runtime_atomicload(&runtime_sched.sysmonwait)) { // TODO: fast atomic runtime_lock(&runtime_sched); @@ -2039,19 +2052,19 @@ doentersyscall() runtime_unlock(&runtime_sched); } - m->mcache = nil; - m->p->m = nil; - runtime_atomicstore(&m->p->status, Psyscall); + g->m->mcache = nil; + ((P*)(g->m->p))->m = 0; + runtime_atomicstore(&((P*)g->m->p)->status, _Psyscall); if(runtime_atomicload(&runtime_sched.gcwaiting)) { runtime_lock(&runtime_sched); - if (runtime_sched.stopwait > 0 && runtime_cas(&m->p->status, Psyscall, Pgcstop)) { + if (runtime_sched.stopwait > 0 && runtime_cas(&((P*)g->m->p)->status, _Psyscall, _Pgcstop)) { if(--runtime_sched.stopwait == 0) runtime_notewakeup(&runtime_sched.stopnote); } runtime_unlock(&runtime_sched); } - m->locks--; + g->m->locks--; } // The same as runtime_entersyscall(), but with a hint that the syscall is blocking. @@ -2060,29 +2073,29 @@ runtime_entersyscallblock(void) { P *p; - m->locks++; // see comment in entersyscall + g->m->locks++; // see comment in entersyscall // Leave SP around for GC and traceback. #ifdef USING_SPLIT_STACK - g->gcstack = __splitstack_find(nil, nil, &g->gcstack_size, - &g->gcnext_segment, &g->gcnext_sp, - &g->gcinitial_sp); + g->gcstack = __splitstack_find(nil, nil, &g->gcstacksize, + &g->gcnextsegment, &g->gcnextsp, + &g->gcinitialsp); #else - g->gcnext_sp = (byte *) &p; + g->gcnextsp = (byte *) &p; #endif // Save the registers in the g structure so that any pointers // held in registers will be seen by the garbage collector. - getcontext(&g->gcregs); + getcontext((ucontext_t*)&g->gcregs[0]); - g->status = Gsyscall; + g->atomicstatus = _Gsyscall; p = releasep(); handoffp(p); if(g->isbackground) // do not consider blocked scavenger for deadlock detection incidlelocked(1); - m->locks--; + g->m->locks--; } // The goroutine g exited its system call. @@ -2094,29 +2107,29 @@ runtime_exitsyscall(void) { G *gp; - m->locks++; // see comment in entersyscall - gp = g; + gp->m->locks++; // see comment in entersyscall + if(gp->isbackground) // do not consider blocked scavenger for deadlock detection incidlelocked(-1); - g->waitsince = 0; + gp->waitsince = 0; if(exitsyscallfast()) { // There's a cpu for us, so we can run. - m->p->syscalltick++; - gp->status = Grunning; + ((P*)gp->m->p)->syscalltick++; + gp->atomicstatus = _Grunning; // Garbage collector isn't running (since we are), // so okay to clear gcstack and gcsp. #ifdef USING_SPLIT_STACK gp->gcstack = nil; #endif - gp->gcnext_sp = nil; - runtime_memclr(&gp->gcregs, sizeof gp->gcregs); - m->locks--; + gp->gcnextsp = nil; + runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs); + gp->m->locks--; return; } - m->locks--; + gp->m->locks--; // Call the scheduler. runtime_mcall(exitsyscall0); @@ -2130,34 +2143,37 @@ runtime_exitsyscall(void) #ifdef USING_SPLIT_STACK gp->gcstack = nil; #endif - gp->gcnext_sp = nil; - runtime_memclr(&gp->gcregs, sizeof gp->gcregs); + gp->gcnextsp = nil; + runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs); - // Don't refer to m again, we might be running on a different - // thread after returning from runtime_mcall. - runtime_m()->p->syscalltick++; + // Note that this gp->m might be different than the earlier + // gp->m after returning from runtime_mcall. + ((P*)gp->m->p)->syscalltick++; } static bool exitsyscallfast(void) { + G *gp; P *p; + gp = g; + // Freezetheworld sets stopwait but does not retake P's. if(runtime_sched.stopwait) { - m->p = nil; + gp->m->p = 0; return false; } // Try to re-acquire the last P. - if(m->p && m->p->status == Psyscall && runtime_cas(&m->p->status, Psyscall, Prunning)) { + if(gp->m->p && ((P*)gp->m->p)->status == _Psyscall && runtime_cas(&((P*)gp->m->p)->status, _Psyscall, _Prunning)) { // There's a cpu for us, so we can run. - m->mcache = m->p->mcache; - m->p->m = m; + gp->m->mcache = ((P*)gp->m->p)->mcache; + ((P*)gp->m->p)->m = (uintptr)gp->m; return true; } // Try to get any other idle P. - m->p = nil; + gp->m->p = 0; if(runtime_sched.pidle) { runtime_lock(&runtime_sched); p = pidleget(); @@ -2179,9 +2195,11 @@ exitsyscallfast(void) static void exitsyscall0(G *gp) { + M *m; P *p; - gp->status = Grunnable; + m = g->m; + gp->atomicstatus = _Grunnable; gp->m = nil; m->curg = nil; runtime_lock(&runtime_sched); @@ -2235,7 +2253,7 @@ syscall_runtime_AfterFork(void) // Allocate a new g, with a stack big enough for stacksize bytes. G* -runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) +runtime_malg(int32 stacksize, byte** ret_stack, uintptr* ret_stacksize) { G *newg; @@ -2243,11 +2261,13 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) if(stacksize >= 0) { #if USING_SPLIT_STACK int dont_block_signals = 0; + size_t ss_stacksize; *ret_stack = __splitstack_makecontext(stacksize, - &newg->stack_context[0], - ret_stacksize); - __splitstack_block_signals_context(&newg->stack_context[0], + &newg->stackcontext[0], + &ss_stacksize); + *ret_stacksize = (uintptr)ss_stacksize; + __splitstack_block_signals_context(&newg->stackcontext[0], &dont_block_signals, nil); #else // In 64-bit mode, the maximum Go allocation space is @@ -2265,9 +2285,9 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) *ret_stack = runtime_mallocgc(stacksize, 0, FlagNoProfiling|FlagNoGC); runtime_xadd(&runtime_stacks_sys, stacksize); } - *ret_stacksize = stacksize; - newg->gcinitial_sp = *ret_stack; - newg->gcstack_size = (size_t)stacksize; + *ret_stacksize = (uintptr)stacksize; + newg->gcinitialsp = *ret_stack; + newg->gcstacksize = (uintptr)stacksize; #endif } return newg; @@ -2310,36 +2330,39 @@ __go_go(void (*fn)(void*), void* arg) //runtime_printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret); if(fn == nil) { - m->throwing = -1; // do not dump full stacks + g->m->throwing = -1; // do not dump full stacks runtime_throw("go of nil func value"); } - m->locks++; // disable preemption because it can be holding p in a local var + g->m->locks++; // disable preemption because it can be holding p in a local var - p = m->p; + p = (P*)g->m->p; if((newg = gfget(p)) != nil) { #ifdef USING_SPLIT_STACK int dont_block_signals = 0; - sp = __splitstack_resetcontext(&newg->stack_context[0], + sp = __splitstack_resetcontext(&newg->stackcontext[0], &spsize); - __splitstack_block_signals_context(&newg->stack_context[0], + __splitstack_block_signals_context(&newg->stackcontext[0], &dont_block_signals, nil); #else - sp = newg->gcinitial_sp; - spsize = newg->gcstack_size; + sp = newg->gcinitialsp; + spsize = newg->gcstacksize; if(spsize == 0) runtime_throw("bad spsize in __go_go"); - newg->gcnext_sp = sp; + newg->gcnextsp = sp; #endif } else { - newg = runtime_malg(StackMin, &sp, &spsize); + uintptr malsize; + + newg = runtime_malg(StackMin, &sp, &malsize); + spsize = (size_t)malsize; allgadd(newg); } newg->entry = (byte*)fn; newg->param = arg; newg->gopc = (uintptr)__builtin_return_address(0); - newg->status = Grunnable; + newg->atomicstatus = _Grunnable; if(p->goidcache == p->goidcacheend) { p->goidcache = runtime_xadd64(&runtime_sched.goidgen, GoidCacheBatch); p->goidcacheend = p->goidcache + GoidCacheBatch; @@ -2353,19 +2376,19 @@ __go_go(void (*fn)(void*), void* arg) size_t volatile vspsize = spsize; G * volatile vnewg = newg; - getcontext(&vnewg->context); - vnewg->context.uc_stack.ss_sp = vsp; + getcontext((ucontext_t*)&vnewg->context[0]); + ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp = vsp; #ifdef MAKECONTEXT_STACK_TOP - vnewg->context.uc_stack.ss_sp += vspsize; + ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp += vspsize; #endif - vnewg->context.uc_stack.ss_size = vspsize; - makecontext(&vnewg->context, kickoff, 0); + ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_size = vspsize; + makecontext((ucontext_t*)&vnewg->context[0], kickoff, 0); runqput(p, vnewg); if(runtime_atomicload(&runtime_sched.npidle) != 0 && runtime_atomicload(&runtime_sched.nmspinning) == 0 && fn != runtime_main) // TODO: fast atomic wakep(); - m->locks--; + g->m->locks--; return vnewg; } } @@ -2400,7 +2423,7 @@ allgadd(G *gp) static void gfput(P *p, G *gp) { - gp->schedlink = p->gfree; + gp->schedlink = (uintptr)p->gfree; p->gfree = gp; p->gfreecnt++; if(p->gfreecnt >= 64) { @@ -2408,8 +2431,8 @@ gfput(P *p, G *gp) while(p->gfreecnt >= 32) { p->gfreecnt--; gp = p->gfree; - p->gfree = gp->schedlink; - gp->schedlink = runtime_sched.gfree; + p->gfree = (G*)gp->schedlink; + gp->schedlink = (uintptr)runtime_sched.gfree; runtime_sched.gfree = gp; } runtime_unlock(&runtime_sched.gflock); @@ -2430,15 +2453,15 @@ retry: while(p->gfreecnt < 32 && runtime_sched.gfree) { p->gfreecnt++; gp = runtime_sched.gfree; - runtime_sched.gfree = gp->schedlink; - gp->schedlink = p->gfree; + runtime_sched.gfree = (G*)gp->schedlink; + gp->schedlink = (uintptr)p->gfree; p->gfree = gp; } runtime_unlock(&runtime_sched.gflock); goto retry; } if(gp) { - p->gfree = gp->schedlink; + p->gfree = (G*)gp->schedlink; p->gfreecnt--; } return gp; @@ -2454,8 +2477,8 @@ gfpurge(P *p) while(p->gfreecnt) { p->gfreecnt--; gp = p->gfree; - p->gfree = gp->schedlink; - gp->schedlink = runtime_sched.gfree; + p->gfree = (G*)gp->schedlink; + gp->schedlink = (uintptr)runtime_sched.gfree; runtime_sched.gfree = gp; } runtime_unlock(&runtime_sched.gflock); @@ -2482,8 +2505,8 @@ runtime_gomaxprocsfunc(int32 n) { int32 ret; - if(n > MaxGomaxprocs) - n = MaxGomaxprocs; + if(n > _MaxGomaxprocs) + n = _MaxGomaxprocs; runtime_lock(&runtime_sched); ret = runtime_gomaxprocs; if(n <= 0 || n == ret) { @@ -2493,10 +2516,10 @@ runtime_gomaxprocsfunc(int32 n) runtime_unlock(&runtime_sched); runtime_semacquire(&runtime_worldsema, false); - m->gcing = 1; + g->m->gcing = 1; runtime_stoptheworld(); newprocs = n; - m->gcing = 0; + g->m->gcing = 0; runtime_semrelease(&runtime_worldsema); runtime_starttheworld(); @@ -2509,22 +2532,22 @@ runtime_gomaxprocsfunc(int32 n) static void lockOSThread(void) { - m->lockedg = g; - g->lockedm = m; + g->m->lockedg = g; + g->lockedm = g->m; } void runtime_LockOSThread(void) __asm__ (GOSYM_PREFIX "runtime.LockOSThread"); void runtime_LockOSThread(void) { - m->locked |= LockExternal; + g->m->locked |= _LockExternal; lockOSThread(); } void runtime_lockOSThread(void) { - m->locked += LockInternal; + g->m->locked += _LockInternal; lockOSThread(); } @@ -2535,9 +2558,9 @@ runtime_lockOSThread(void) static void unlockOSThread(void) { - if(m->locked != 0) + if(g->m->locked != 0) return; - m->lockedg = nil; + g->m->lockedg = nil; g->lockedm = nil; } @@ -2546,23 +2569,23 @@ void runtime_UnlockOSThread(void) __asm__ (GOSYM_PREFIX "runtime.UnlockOSThread" void runtime_UnlockOSThread(void) { - m->locked &= ~LockExternal; + g->m->locked &= ~_LockExternal; unlockOSThread(); } void runtime_unlockOSThread(void) { - if(m->locked < LockInternal) + if(g->m->locked < _LockInternal) runtime_throw("runtime: internal error: misuse of lockOSThread/unlockOSThread"); - m->locked -= LockInternal; + g->m->locked -= _LockInternal; unlockOSThread(); } bool runtime_lockedOSThread(void) { - return g->lockedm != nil && m->lockedg != nil; + return g->lockedm != nil && g->m->lockedg != nil; } int32 @@ -2580,8 +2603,8 @@ runtime_gcount(void) // Compromise solution is to introduce per-P counters of active goroutines. for(i = 0; i < runtime_allglen; i++) { gp = runtime_allg[i]; - s = gp->status; - if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting) + s = gp->atomicstatus; + if(s == _Grunnable || s == _Grunning || s == _Gsyscall || s == _Gwaiting) n++; } runtime_unlock(&allglock); @@ -2609,7 +2632,7 @@ static void GC(void) {} void runtime_sigprof() { - M *mp = m; + M *mp = g->m; int32 n, i; bool traceback; @@ -2675,7 +2698,7 @@ runtime_setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) // Disable preemption, otherwise we can be rescheduled to another thread // that has profiling enabled. - m->locks++; + g->m->locks++; // Stop profiler on this thread so that it is safe to lock prof. // if a profiling signal came in while we had prof locked, @@ -2693,7 +2716,7 @@ runtime_setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) if(hz != 0) runtime_resetcpuprofiler(hz); - m->locks--; + g->m->locks--; } // Change number of processors. The world is stopped, sched is locked. @@ -2706,7 +2729,7 @@ procresize(int32 new) P *p; old = runtime_gomaxprocs; - if(old < 0 || old > MaxGomaxprocs || new <= 0 || new >MaxGomaxprocs) + if(old < 0 || old > _MaxGomaxprocs || new <= 0 || new >_MaxGomaxprocs) runtime_throw("procresize: invalid arg"); // initialize new P's for(i = 0; i < new; i++) { @@ -2714,12 +2737,12 @@ procresize(int32 new) if(p == nil) { p = (P*)runtime_mallocgc(sizeof(*p), 0, FlagNoInvokeGC); p->id = i; - p->status = Pgcstop; + p->status = _Pgcstop; runtime_atomicstorep(&runtime_allp[i], p); } if(p->mcache == nil) { if(old==0 && i==0) - p->mcache = m->mcache; // bootstrap + p->mcache = g->m->mcache; // bootstrap else p->mcache = runtime_allocmcache(); } @@ -2739,9 +2762,9 @@ procresize(int32 new) empty = false; // pop from tail of local queue p->runqtail--; - gp = p->runq[p->runqtail%nelem(p->runq)]; + gp = (G*)p->runq[p->runqtail%nelem(p->runq)]; // push onto head of global queue - gp->schedlink = runtime_sched.runqhead; + gp->schedlink = (uintptr)runtime_sched.runqhead; runtime_sched.runqhead = gp; if(runtime_sched.runqtail == nil) runtime_sched.runqtail = gp; @@ -2753,7 +2776,7 @@ procresize(int32 new) // so if we have a spare G we want to put it into allp[1]. for(i = 1; (uint32)i < (uint32)new * nelem(p->runq)/2 && runtime_sched.runqsize > 0; i++) { gp = runtime_sched.runqhead; - runtime_sched.runqhead = gp->schedlink; + runtime_sched.runqhead = (G*)gp->schedlink; if(runtime_sched.runqhead == nil) runtime_sched.runqtail = nil; runtime_sched.runqsize--; @@ -2766,21 +2789,21 @@ procresize(int32 new) runtime_freemcache(p->mcache); p->mcache = nil; gfpurge(p); - p->status = Pdead; + p->status = _Pdead; // can't free P itself because it can be referenced by an M in syscall } - if(m->p) - m->p->m = nil; - m->p = nil; - m->mcache = nil; + if(g->m->p) + ((P*)g->m->p)->m = 0; + g->m->p = 0; + g->m->mcache = nil; p = runtime_allp[0]; - p->m = nil; - p->status = Pidle; + p->m = 0; + p->status = _Pidle; acquirep(p); for(i = new-1; i > 0; i--) { p = runtime_allp[i]; - p->status = Pidle; + p->status = _Pidle; pidleput(p); } runtime_atomicstore((uint32*)&runtime_gomaxprocs, new); @@ -2790,36 +2813,41 @@ procresize(int32 new) static void acquirep(P *p) { + M *m; + + m = g->m; if(m->p || m->mcache) runtime_throw("acquirep: already in go"); - if(p->m || p->status != Pidle) { - runtime_printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? p->m->id : 0, p->status); + if(p->m || p->status != _Pidle) { + runtime_printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? ((M*)p->m)->id : 0, p->status); runtime_throw("acquirep: invalid p state"); } m->mcache = p->mcache; - m->p = p; - p->m = m; - p->status = Prunning; + m->p = (uintptr)p; + p->m = (uintptr)m; + p->status = _Prunning; } // Disassociate p and the current m. static P* releasep(void) { + M *m; P *p; - if(m->p == nil || m->mcache == nil) + m = g->m; + if(m->p == 0 || m->mcache == nil) runtime_throw("releasep: invalid arg"); - p = m->p; - if(p->m != m || p->mcache != m->mcache || p->status != Prunning) { + p = (P*)m->p; + if((M*)p->m != m || p->mcache != m->mcache || p->status != _Prunning) { runtime_printf("releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d\n", m, m->p, p->m, m->mcache, p->mcache, p->status); runtime_throw("releasep: invalid p state"); } - m->p = nil; + m->p = 0; m->mcache = nil; - p->m = nil; - p->status = Pidle; + p->m = 0; + p->status = _Pidle; return p; } @@ -2870,10 +2898,10 @@ checkdead(void) gp = runtime_allg[i]; if(gp->isbackground) continue; - s = gp->status; - if(s == Gwaiting) + s = gp->atomicstatus; + if(s == _Gwaiting) grunning++; - else if(s == Grunnable || s == Grunning || s == Gsyscall) { + else if(s == _Grunnable || s == _Grunning || s == _Gsyscall) { runtime_unlock(&allglock); runtime_printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s); runtime_throw("checkdead: runnable g"); @@ -2882,7 +2910,7 @@ checkdead(void) runtime_unlock(&allglock); if(grunning == 0) // possible if main goroutine calls runtime_Goexit() runtime_throw("no goroutines (main called runtime.Goexit) - deadlock!"); - m->throwing = -1; // do not dump full stacks + g->m->throwing = -1; // do not dump full stacks runtime_throw("all goroutines are asleep - deadlock!"); } @@ -2958,7 +2986,7 @@ struct Pdesc uint32 syscalltick; int64 syscallwhen; }; -static Pdesc pdesc[MaxGomaxprocs]; +static Pdesc pdesc[_MaxGomaxprocs]; static uint32 retake(int64 now) @@ -2975,7 +3003,7 @@ retake(int64 now) continue; pd = &pdesc[i]; s = p->status; - if(s == Psyscall) { + if(s == _Psyscall) { // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us). t = p->syscalltick; if(pd->syscalltick != t) { @@ -2995,12 +3023,12 @@ retake(int64 now) // Otherwise the M from which we retake can exit the syscall, // increment nmidle and report deadlock. incidlelocked(-1); - if(runtime_cas(&p->status, s, Pidle)) { + if(runtime_cas(&p->status, s, _Pidle)) { n++; handoffp(p); } incidlelocked(1); - } else if(s == Prunning) { + } else if(s == _Prunning) { // Preempt G if it's running for more than 10ms. t = p->schedtick; if(pd->schedtick != t) { @@ -3060,7 +3088,7 @@ runtime_schedtrace(bool detailed) p = runtime_allp[i]; if(p == nil) continue; - mp = p->m; + mp = (M*)p->m; h = runtime_atomicload(&p->runqhead); t = runtime_atomicload(&p->runqtail); if(detailed) @@ -3084,7 +3112,7 @@ runtime_schedtrace(bool detailed) return; } for(mp = runtime_allm; mp; mp = mp->alllink) { - p = mp->p; + p = (P*)mp->p; gp = mp->curg; lockedg = mp->lockedg; id1 = -1; @@ -3100,15 +3128,15 @@ runtime_schedtrace(bool detailed) " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n", mp->id, id1, id2, mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc, - mp->spinning, m->blocked, id3); + mp->spinning, mp->blocked, id3); } runtime_lock(&allglock); for(gi = 0; gi < runtime_allglen; gi++) { gp = runtime_allg[gi]; mp = gp->m; lockedm = gp->lockedm; - runtime_printf(" G%D: status=%d(%s) m=%d lockedm=%d\n", - gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1, + runtime_printf(" G%D: status=%d(%S) m=%d lockedm=%d\n", + gp->goid, gp->atomicstatus, gp->waitreason, mp ? mp->id : -1, lockedm ? lockedm->id : -1); } runtime_unlock(&allglock); @@ -3120,7 +3148,7 @@ runtime_schedtrace(bool detailed) static void mput(M *mp) { - mp->schedlink = runtime_sched.midle; + mp->schedlink = (uintptr)runtime_sched.midle; runtime_sched.midle = mp; runtime_sched.nmidle++; checkdead(); @@ -3134,7 +3162,7 @@ mget(void) M *mp; if((mp = runtime_sched.midle) != nil){ - runtime_sched.midle = mp->schedlink; + runtime_sched.midle = (M*)mp->schedlink; runtime_sched.nmidle--; } return mp; @@ -3145,9 +3173,9 @@ mget(void) static void globrunqput(G *gp) { - gp->schedlink = nil; + gp->schedlink = 0; if(runtime_sched.runqtail) - runtime_sched.runqtail->schedlink = gp; + runtime_sched.runqtail->schedlink = (uintptr)gp; else runtime_sched.runqhead = gp; runtime_sched.runqtail = gp; @@ -3159,9 +3187,9 @@ globrunqput(G *gp) static void globrunqputbatch(G *ghead, G *gtail, int32 n) { - gtail->schedlink = nil; + gtail->schedlink = 0; if(runtime_sched.runqtail) - runtime_sched.runqtail->schedlink = ghead; + runtime_sched.runqtail->schedlink = (uintptr)ghead; else runtime_sched.runqhead = ghead; runtime_sched.runqtail = gtail; @@ -3189,11 +3217,11 @@ globrunqget(P *p, int32 max) if(runtime_sched.runqsize == 0) runtime_sched.runqtail = nil; gp = runtime_sched.runqhead; - runtime_sched.runqhead = gp->schedlink; + runtime_sched.runqhead = (G*)gp->schedlink; n--; while(n--) { gp1 = runtime_sched.runqhead; - runtime_sched.runqhead = gp1->schedlink; + runtime_sched.runqhead = (G*)gp1->schedlink; runqput(p, gp1); } return gp; @@ -3204,7 +3232,7 @@ globrunqget(P *p, int32 max) static void pidleput(P *p) { - p->link = runtime_sched.pidle; + p->link = (uintptr)runtime_sched.pidle; runtime_sched.pidle = p; runtime_xadd(&runtime_sched.npidle, 1); // TODO: fast atomic } @@ -3218,7 +3246,7 @@ pidleget(void) p = runtime_sched.pidle; if(p) { - runtime_sched.pidle = p->link; + runtime_sched.pidle = (P*)p->link; runtime_xadd(&runtime_sched.npidle, -1); // TODO: fast atomic } return p; @@ -3236,7 +3264,7 @@ retry: h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with consumers t = p->runqtail; if(t - h < nelem(p->runq)) { - p->runq[t%nelem(p->runq)] = gp; + p->runq[t%nelem(p->runq)] = (uintptr)gp; runtime_atomicstore(&p->runqtail, t+1); // store-release, makes the item available for consumption return; } @@ -3260,13 +3288,13 @@ runqputslow(P *p, G *gp, uint32 h, uint32 t) if(n != nelem(p->runq)/2) runtime_throw("runqputslow: queue is not full"); for(i=0; irunq[(h+i)%nelem(p->runq)]; + batch[i] = (G*)p->runq[(h+i)%nelem(p->runq)]; if(!runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume return false; batch[n] = gp; // Link the goroutines. for(i=0; ischedlink = batch[i+1]; + batch[i]->schedlink = (uintptr)batch[i+1]; // Now put the batch on global queue. runtime_lock(&runtime_sched); globrunqputbatch(batch[0], batch[n], n+1); @@ -3287,7 +3315,7 @@ runqget(P *p) t = p->runqtail; if(t == h) return nil; - gp = p->runq[h%nelem(p->runq)]; + gp = (G*)p->runq[h%nelem(p->runq)]; if(runtime_cas(&p->runqhead, h, h+1)) // cas-release, commits consume return gp; } @@ -3311,7 +3339,7 @@ runqgrab(P *p, G **batch) if(n > nelem(p->runq)/2) // read inconsistent h and t continue; for(i=0; irunq[(h+i)%nelem(p->runq)]; + batch[i] = (G*)p->runq[(h+i)%nelem(p->runq)]; if(runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume break; } @@ -3340,7 +3368,7 @@ runqsteal(P *p, P *p2) if(t - h + n >= nelem(p->runq)) runtime_throw("runqsteal: runq overflow"); for(i=0; irunq[t%nelem(p->runq)] = batch[i]; + p->runq[t%nelem(p->runq)] = (uintptr)batch[i]; runtime_atomicstore(&p->runqtail, t); // store-release, makes the item available for consumption return gp; } @@ -3480,7 +3508,7 @@ sync_runtime_canSpin(intgo i) if (i >= ACTIVE_SPIN || runtime_ncpu <= 1 || runtime_gomaxprocs <= (int32)(runtime_sched.npidle+runtime_sched.nmspinning)+1) { return false; } - p = m->p; + p = (P*)g->m->p; return p != nil && p->runqhead == p->runqtail; } diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c index 4140d33d041..c7d33bcef4c 100644 --- a/libgo/runtime/runtime.c +++ b/libgo/runtime/runtime.c @@ -272,7 +272,8 @@ runtime_tickspersecond(void) void runtime_mpreinit(M *mp) { - mp->gsignal = runtime_malg(32*1024, &mp->gsignalstack, &mp->gsignalstacksize); // OS X wants >=8K, Linux >=2K + mp->gsignal = runtime_malg(32*1024, (byte**)&mp->gsignalstack, &mp->gsignalstacksize); // OS X wants >=8K, Linux >=2K + mp->gsignal->m = mp; } // Called to initialize a new m (including the bootstrap m). diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index ba5eab78c78..617766b8a99 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -56,24 +56,24 @@ typedef uintptr uintreg; typedef uint8 bool; typedef uint8 byte; typedef struct Func Func; -typedef struct G G; -typedef struct Lock Lock; -typedef struct M M; -typedef struct P P; -typedef struct Note Note; +typedef struct g G; +typedef struct mutex Lock; +typedef struct m M; +typedef struct p P; +typedef struct note Note; typedef struct String String; typedef struct FuncVal FuncVal; typedef struct SigTab SigTab; -typedef struct MCache MCache; +typedef struct mcache MCache; typedef struct FixAlloc FixAlloc; typedef struct Hchan Hchan; typedef struct Timers Timers; typedef struct Timer Timer; -typedef struct GCStats GCStats; +typedef struct gcstats GCStats; typedef struct LFNode LFNode; typedef struct ParFor ParFor; typedef struct ParForThread ParForThread; -typedef struct CgoMal CgoMal; +typedef struct cgoMal CgoMal; typedef struct PollDesc PollDesc; typedef struct DebugVars DebugVars; @@ -81,8 +81,8 @@ typedef struct __go_open_array Slice; typedef struct __go_interface Iface; typedef struct __go_empty_interface Eface; typedef struct __go_type_descriptor Type; -typedef struct __go_defer_stack Defer; -typedef struct __go_panic_stack Panic; +typedef struct _defer Defer; +typedef struct _panic Panic; typedef struct __go_ptr_type PtrType; typedef struct __go_func_type FuncType; @@ -90,9 +90,26 @@ typedef struct __go_interface_type InterfaceType; typedef struct __go_map_type MapType; typedef struct __go_channel_type ChanType; -typedef struct Traceback Traceback; +typedef struct traceback Traceback; -typedef struct Location Location; +typedef struct location Location; + +struct String +{ + const byte* str; + intgo len; +}; + +struct FuncVal +{ + void (*fn)(void); + // variable-size, fn-specific data here +}; + +#include "array.h" +#include "interface.h" + +#include "runtime.inc" /* * Per-CPU declaration. @@ -103,33 +120,6 @@ extern G* runtime_g(void); extern M runtime_m0; extern G runtime_g0; -/* - * defined constants - */ -enum -{ - // G status - // - // If you add to this list, add to the list - // of "okay during garbage collection" status - // in mgc0.c too. - Gidle, - Grunnable, - Grunning, - Gsyscall, - Gwaiting, - Gmoribund_unused, // currently unused, but hardcoded in gdb scripts - Gdead, -}; -enum -{ - // P status - Pidle, - Prunning, - Psyscall, - Pgcstop, - Pdead, -}; enum { true = 1, @@ -146,184 +136,6 @@ enum // Global <-> per-M stack segment cache transfer batch size. StackCacheBatch = 16, }; -/* - * structures - */ -struct Lock -{ - // 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. - uintptr key; -}; -struct Note -{ - // 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. - uintptr key; -}; -struct String -{ - const byte* str; - intgo len; -}; -struct FuncVal -{ - void (*fn)(void); - // variable-size, fn-specific data here -}; -struct GCStats -{ - // the struct must consist of only uint64's, - // because it is casted to uint64[]. - uint64 nhandoff; - uint64 nhandoffcnt; - uint64 nprocyield; - uint64 nosyield; - uint64 nsleep; -}; - -// A location in the program, used for backtraces. -struct Location -{ - uintptr pc; - String filename; - String function; - intgo lineno; -}; - -struct G -{ - Defer* defer; - Panic* panic; - void* exception; // current exception being thrown - bool is_foreign; // whether current exception from other language - void *gcstack; // if status==Gsyscall, gcstack = stackbase to use during gc - size_t gcstack_size; - void* gcnext_segment; - void* gcnext_sp; - void* gcinitial_sp; - ucontext_t gcregs; - byte* entry; // initial function - void* param; // passed parameter on wakeup - bool fromgogo; // reached from gogo - int16 status; - uint32 selgen; // valid sudog pointer - int64 goid; - int64 waitsince; // approx time when the G become blocked - const char* waitreason; // if status==Gwaiting - G* schedlink; - bool ispanic; - bool issystem; // do not output in stack dump - bool isbackground; // ignore in deadlock detector - bool paniconfault; // panic (instead of crash) on unexpected fault address - M* m; // for debuggers, but offset not hard-coded - M* lockedm; - int32 sig; - int32 writenbuf; - byte* writebuf; - uintptr sigcode0; - uintptr sigcode1; - // uintptr sigpc; - uintptr gopc; // pc of go statement that created this goroutine - - int32 ncgo; - CgoMal* cgomal; - - Traceback* traceback; - - ucontext_t context; - void* stack_context[10]; -}; - -struct M -{ - G* g0; // goroutine with scheduling stack - G* gsignal; // signal-handling G - byte* gsignalstack; - size_t gsignalstacksize; - void (*mstartfn)(void); - G* curg; // current running goroutine - G* caughtsig; // goroutine running during fatal signal - P* p; // attached P for executing Go code (nil if not executing Go code) - P* nextp; - int32 id; - int32 mallocing; - int32 throwing; - int32 gcing; - int32 locks; - int32 softfloat; - int32 dying; - int32 profilehz; - int32 helpgc; - bool spinning; // M is out of work and is actively looking for work - bool blocked; // M is blocked on a Note - uint32 fastrand; - uint64 ncgocall; // number of cgo calls in total - int32 ncgo; // number of cgo calls currently in progress - CgoMal* cgomal; - Note park; - M* alllink; // on allm - M* schedlink; - MCache *mcache; - G* lockedg; - Location createstack[32]; // Stack that created this thread. - uint32 locked; // tracking for LockOSThread - M* nextwaitm; // next M waiting for lock - uintptr waitsema; // semaphore for parking on locks - uint32 waitsemacount; - uint32 waitsemalock; - GCStats gcstats; - bool needextram; - bool dropextram; // for gccgo: drop after call is done. - uint8 traceback; - bool (*waitunlockf)(G*, void*); - void* waitlock; - uintptr end[]; -}; - -struct P -{ - Lock; - - int32 id; - uint32 status; // one of Pidle/Prunning/... - P* link; - uint32 schedtick; // incremented on every scheduler call - uint32 syscalltick; // incremented on every system call - M* m; // back-link to associated M (nil if idle) - MCache* mcache; - Defer* deferpool; // pool of available Defer structs (see panic.c) - - // Cache of goroutine ids, amortizes accesses to runtime_sched.goidgen. - uint64 goidcache; - uint64 goidcacheend; - - // Queue of runnable goroutines. - uint32 runqhead; - uint32 runqtail; - G* runq[256]; - - // Available G's (status == Gdead) - G* gfree; - int32 gfreecnt; - - byte pad[64]; -}; - -// 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->lockedcount 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. -enum -{ - LockExternal = 1, - LockInternal = 2, -}; struct SigTab { @@ -331,16 +143,6 @@ struct SigTab int32 flags; void* fwdsig; }; -enum -{ - SigNotify = 1<<0, // let signal.Notify have signal, even if from kernel - SigKill = 1<<1, // if signal.Notify doesn't take it, exit quietly - SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly - SigPanic = 1<<3, // if the signal is from the kernel, panic - SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it - SigHandling = 1<<5, // our signal handler is registered - SigGoExit = 1<<6, // cause all runtime procs to exit (only used on Plan 9). -}; // Layout of in-memory per-function information prepared by linker // See http://golang.org/s/go12symtab. @@ -438,14 +240,6 @@ struct ParFor uint64 nsleep; }; -// Track memory allocated by code not written in Go during a cgo call, -// so that the garbage collector can see them. -struct CgoMal -{ - CgoMal *next; - void *alloc; -}; - // Holds variables parsed from GODEBUG env var. struct DebugVars { @@ -565,7 +359,7 @@ void runtime_ready(G*); String runtime_getenv(const char*); int32 runtime_atoi(const byte*, intgo); void* runtime_mstart(void*); -G* runtime_malg(int32, byte**, size_t*); +G* runtime_malg(int32, byte**, uintptr*); void runtime_mpreinit(M*); void runtime_minit(void); void runtime_unminit(void); @@ -604,7 +398,7 @@ int32 runtime_round2(int32 x); // round x up to a power of 2. #define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST) #define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST) -void runtime_setmg(M*, G*); +void runtime_setg(G*); void runtime_newextram(void); #define runtime_exit(s) exit(s) #define runtime_breakpoint() __builtin_trap() diff --git a/libgo/runtime/runtime1.goc b/libgo/runtime/runtime1.goc index cd9d3017b51..26b5566017d 100644 --- a/libgo/runtime/runtime1.goc +++ b/libgo/runtime/runtime1.goc @@ -65,7 +65,7 @@ func sync.runtime_procPin() (p int) { mp = runtime_m(); // Disable preemption. mp->locks++; - p = mp->p->id; + p = ((P*)mp->p)->id; } func sync.runtime_procUnpin() { @@ -78,7 +78,7 @@ func sync_atomic.runtime_procPin() (p int) { mp = runtime_m(); // Disable preemption. mp->locks++; - p = mp->p->id; + p = ((P*)mp->p)->id; } func sync_atomic.runtime_procUnpin() { diff --git a/libgo/runtime/signal_unix.c b/libgo/runtime/signal_unix.c index 5bee0d2a706..2cca08cf47b 100644 --- a/libgo/runtime/signal_unix.c +++ b/libgo/runtime/signal_unix.c @@ -26,7 +26,7 @@ runtime_initsig(bool preinit) // First call: basic setup. for(i = 0; runtime_sigtab[i].sig != -1; i++) { t = &runtime_sigtab[i]; - if((t->flags == 0) || (t->flags & SigDefault)) + if((t->flags == 0) || (t->flags & _SigDefault)) continue; t->fwdsig = runtime_getsig(i); @@ -42,10 +42,10 @@ runtime_initsig(bool preinit) } } - if(runtime_isarchive && (t->flags&SigPanic) == 0) + if(runtime_isarchive && (t->flags&_SigPanic) == 0) continue; - t->flags |= SigHandling; + t->flags |= _SigHandling; runtime_setsig(i, runtime_sighandler, true); } } @@ -67,8 +67,8 @@ runtime_sigenable(uint32 sig) if(t == nil) return; - if((t->flags & SigNotify) && !(t->flags & SigHandling)) { - t->flags |= SigHandling; + if((t->flags & _SigNotify) && !(t->flags & _SigHandling)) { + t->flags |= _SigHandling; t->fwdsig = runtime_getsig(i); runtime_setsig(i, runtime_sighandler, true); } @@ -92,7 +92,7 @@ runtime_sigdisable(uint32 sig) return; if((sig == SIGHUP || sig == SIGINT) && t->fwdsig == GO_SIG_IGN) { - t->flags &= ~SigHandling; + t->flags &= ~_SigHandling; runtime_setsig(i, t->fwdsig, true); } } @@ -114,8 +114,8 @@ runtime_sigignore(uint32 sig) if(t == nil) return; - if((t->flags & SigNotify) != 0) { - t->flags &= ~SigHandling; + if((t->flags & _SigNotify) != 0) { + t->flags &= ~_SigHandling; runtime_setsig(i, GO_SIG_IGN, true); } } -- 2.30.2