From 6150414cb8819ab9f054298ec7f8006a43ab8eea Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 16 Nov 2014 14:25:33 -0500 Subject: runtime: update URL for heap dump format I just created that redirect, so we can change it once the wiki moves. LGTM=bradfitz, khr R=khr, bradfitz CC=golang-codereviews https://golang.org/cl/177780043 --- src/runtime/heapdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/runtime') diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index eddbc1d1c9..7eba8c0057 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -7,7 +7,7 @@ // finalizers, etc.) to a file. // The format of the dumped file is described at -// http://code.google.com/p/go-wiki/wiki/heapdump14 +// http://golang.org/s/go14heapdump. #include "runtime.h" #include "arch_GOARCH.h" -- cgit v1.3-5-g9baa From b3932baba4e15e175e8f0e040d5e8bbd357a60d8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 16 Nov 2014 16:44:45 -0500 Subject: runtime: fix sudog leak The SudoG used to sit on the stack, so it was cheap to allocated and didn't need to be cleaned up when finished. For the conversion to Go, we had to move sudog off the stack for a few reasons, so we added a cache of recently used sudogs to keep allocation cheap. But we didn't add any of the necessary cleanup before adding a SudoG to the new cache, and so the cached SudoGs had stale pointers inside them that have caused all sorts of awful, hard to debug problems. CL 155760043 made sure SudoG.elem is cleaned up. CL 150520043 made sure SudoG.selectdone is cleaned up. This CL makes sure SudoG.next, SudoG.prev, and SudoG.waitlink are cleaned up. I should have done this when I did the other two fields; instead I wasted a week tracking down a leak they caused. A dangling SudoG.waitlink can point into a sudogcache list that has been "forgotten" in order to let the GC collect it, but that dangling .waitlink keeps the list from being collected. And then the list holding the SudoG with the dangling waitlink can find itself in the same situation, and so on. We end up with lists of lists of unusable SudoGs that are still linked into the object graph and never collected (given the right mix of non-trivial selects and non-channel synchronization). More details in golang.org/issue/9110. Fixes #9110. LGTM=r R=r CC=dvyukov, golang-codereviews, iant, khr https://golang.org/cl/177870043 --- src/runtime/chan.go | 1 + src/runtime/mgc0.go | 16 ++++++++ src/runtime/proc.go | 10 +++++ src/runtime/select.go | 2 + src/runtime/sema.go | 2 + test/fixedbugs/issue9110.go | 90 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 121 insertions(+) create mode 100644 test/fixedbugs/issue9110.go (limited to 'src/runtime') diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 0049701826..0eb87df74f 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -630,6 +630,7 @@ func (q *waitq) dequeue() *sudog { return nil } q.first = sgp.next + sgp.next = nil if q.last == sgp { q.last = nil } diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 3a7204b54f..cbf5e9cfde 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -51,10 +51,26 @@ func clearpools() { if c := p.mcache; c != nil { c.tiny = nil c.tinysize = 0 + + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var sg, sgnext *sudog + for sg = c.sudogcache; sg != nil; sg = sgnext { + sgnext = sg.next + sg.next = nil + } c.sudogcache = nil } + // clear defer pools for i := range p.deferpool { + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var d, dlink *_defer + for d = p.deferpool[i]; d != nil; d = dlink { + dlink = d.link + d.link = nil + } p.deferpool[i] = nil } } diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 5b8c7d8ae9..517ca03df6 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -152,6 +152,7 @@ func acquireSudog() *sudog { gothrow("acquireSudog: found s.elem != nil in cache") } c.sudogcache = s.next + s.next = nil return s } @@ -177,6 +178,15 @@ func releaseSudog(s *sudog) { if s.selectdone != nil { gothrow("runtime: sudog with non-nil selectdone") } + if s.next != nil { + gothrow("runtime: sudog with non-nil next") + } + if s.prev != nil { + gothrow("runtime: sudog with non-nil prev") + } + if s.waitlink != nil { + gothrow("runtime: sudog with non-nil waitlink") + } gp := getg() if gp.param != nil { gothrow("runtime: releaseSudog with non-nil gp.param") diff --git a/src/runtime/select.go b/src/runtime/select.go index efe68c1f5c..f735a71e2f 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -404,6 +404,7 @@ loop: } } sgnext = sglist.waitlink + sglist.waitlink = nil releaseSudog(sglist) sglist = sgnext } @@ -641,6 +642,7 @@ func (q *waitq) dequeueSudoG(s *sudog) { if q.last == sgp { q.last = prevsgp } + s.next = nil return } l = &sgp.next diff --git a/src/runtime/sema.go b/src/runtime/sema.go index d2a028c01b..26dbd30ea3 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -201,6 +201,7 @@ func syncsemacquire(s *syncSema) { } unlock(&s.lock) if wake != nil { + wake.next = nil goready(wake.g) } } else { @@ -242,6 +243,7 @@ func syncsemrelease(s *syncSema, n uint32) { if wake.releasetime != 0 { wake.releasetime = cputicks() } + wake.next = nil goready(wake.g) n-- } diff --git a/test/fixedbugs/issue9110.go b/test/fixedbugs/issue9110.go new file mode 100644 index 0000000000..729463305e --- /dev/null +++ b/test/fixedbugs/issue9110.go @@ -0,0 +1,90 @@ +// run + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Scenario that used to leak arbitrarily many SudoG structs. +// See golang.org/issue/9110. + +package main + +import ( + "runtime" + "runtime/debug" + "sync" + "time" +) + +func main() { + debug.SetGCPercent(1000000) // only GC when we ask for GC + + var stats, stats1, stats2 runtime.MemStats + + release := func() {} + for i := 0; i < 20; i++ { + if i == 10 { + // Should be warmed up by now. + runtime.ReadMemStats(&stats1) + } + + c := make(chan int) + for i := 0; i < 10; i++ { + go func() { + select { + case <-c: + case <-c: + case <-c: + } + }() + } + time.Sleep(1 * time.Millisecond) + release() + + close(c) // let select put its sudog's into the cache + time.Sleep(1 * time.Millisecond) + + // pick up top sudog + var cond1 sync.Cond + var mu1 sync.Mutex + cond1.L = &mu1 + go func() { + mu1.Lock() + cond1.Wait() + mu1.Unlock() + }() + time.Sleep(1 * time.Millisecond) + + // pick up next sudog + var cond2 sync.Cond + var mu2 sync.Mutex + cond2.L = &mu2 + go func() { + mu2.Lock() + cond2.Wait() + mu2.Unlock() + }() + time.Sleep(1 * time.Millisecond) + + // put top sudog back + cond1.Broadcast() + time.Sleep(1 * time.Millisecond) + + // drop cache on floor + runtime.GC() + + // release cond2 after select has gotten to run + release = func() { + cond2.Broadcast() + time.Sleep(1 * time.Millisecond) + } + } + + runtime.GC() + + runtime.ReadMemStats(&stats2) + + if int(stats2.HeapObjects)-int(stats1.HeapObjects) > 20 { // normally at most 1 or 2; was 300 with leak + print("BUG: object leak: ", stats.HeapObjects, " -> ", stats1.HeapObjects, " -> ", stats2.HeapObjects, "\n") + } +} -- cgit v1.3-5-g9baa From fc288681cf5ac27bb3478cadf8a3e60f4b654082 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Mon, 17 Nov 2014 17:18:21 +1100 Subject: [dev.cc] runtime: replace deleted netpollfd function LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/169710043 --- src/runtime/netpoll_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/runtime') diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go index 88e8781376..8a15f182cd 100644 --- a/src/runtime/netpoll_windows.go +++ b/src/runtime/netpoll_windows.go @@ -108,7 +108,7 @@ retry: op = entries[i].op errno = 0 qty = 0 - if stdcall5(_WSAGetOverlappedResult, netpollfd(op.pd), uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { + if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { errno = int32(getlasterror()) } handlecompletion(&gp, op, errno, qty) -- cgit v1.3-5-g9baa From 55f19ed866d55ebfdbed59893ff93fb00a7c35fe Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Tue, 18 Nov 2014 09:55:15 +1100 Subject: runtime: fix getcallersp documentation LGTM=bradfitz R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/180760043 --- src/runtime/stubs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/runtime') diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index fe8f9c9222..1282397adb 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -231,7 +231,7 @@ func setcallerpc(argp unsafe.Pointer, pc uintptr) // // func f(arg1, arg2, arg3 int) { // pc := getcallerpc(unsafe.Pointer(&arg1)) -// sp := getcallerpc(unsafe.Pointer(&arg2)) +// sp := getcallersp(unsafe.Pointer(&arg1)) // } // // These two lines find the PC and SP immediately following -- cgit v1.3-5-g9baa From 0e8fed098c164a832fbe9541a6d3c7bb952c9b0c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 09:54:50 -0500 Subject: [dev.cc] runtime: two missed references to "M stack" LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/177940043 --- src/runtime/asm_amd64p32.s | 2 +- src/runtime/panic.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index cead3cd075..b8370efd36 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -169,7 +169,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 // of the G stack. We need to distinguish the routine that // lives at the bottom of the G stack from the one that lives // at the top of the system stack because the one at the top of -// the M stack terminates the stack walk (see topofstack()). +// the system stack terminates the stack walk (see topofstack()). TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 RET diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 8929467025..95e780b1d9 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -162,7 +162,7 @@ func init() { // Allocate a Defer, usually using per-P pool. // Each defer must be released with freedefer. -// Note: runs on M stack +// Note: runs on g0 stack func newdefer(siz int32) *_defer { var d *_defer sc := deferclass(uintptr(siz)) -- cgit v1.3-5-g9baa From 312a64ec4eb3e0fdb6ab6b23deb99699abc7f54e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 18 Nov 2014 11:38:23 -0500 Subject: [dev.cc] runtime: convert defs_linux_power64*.h to go LGTM=austin R=austin CC=golang-codereviews https://golang.org/cl/176990043 --- src/runtime/defs_linux_power64.go | 186 ++++++++++++++++++++++++++++++++ src/runtime/defs_linux_power64.h | 204 ------------------------------------ src/runtime/defs_linux_power64le.go | 186 ++++++++++++++++++++++++++++++++ src/runtime/defs_linux_power64le.h | 204 ------------------------------------ 4 files changed, 372 insertions(+), 408 deletions(-) create mode 100644 src/runtime/defs_linux_power64.go delete mode 100644 src/runtime/defs_linux_power64.h create mode 100644 src/runtime/defs_linux_power64le.go delete mode 100644 src/runtime/defs_linux_power64le.h (limited to 'src/runtime') diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go new file mode 100644 index 0000000000..df877a67f7 --- /dev/null +++ b/src/runtime/defs_linux_power64.go @@ -0,0 +1,186 @@ +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +package runtime + +const ( + _EINTR = 0x4 + _EAGAIN = 0xb + _ENOMEM = 0xc + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x20 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + + _SA_RESTART = 0x10000000 + _SA_ONSTACK = 0x8000000 + _SA_SIGINFO = 0x4 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGBUS = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGUSR1 = 0xa + _SIGSEGV = 0xb + _SIGUSR2 = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGSTKFLT = 0x10 + _SIGCHLD = 0x11 + _SIGCONT = 0x12 + _SIGSTOP = 0x13 + _SIGTSTP = 0x14 + _SIGTTIN = 0x15 + _SIGTTOU = 0x16 + _SIGURG = 0x17 + _SIGXCPU = 0x18 + _SIGXFSZ = 0x19 + _SIGVTALRM = 0x1a + _SIGPROF = 0x1b + _SIGWINCH = 0x1c + _SIGIO = 0x1d + _SIGPWR = 0x1e + _SIGSYS = 0x1f + + _FPE_INTDIV = 0x1 + _FPE_INTOVF = 0x2 + _FPE_FLTDIV = 0x3 + _FPE_FLTOVF = 0x4 + _FPE_FLTUND = 0x5 + _FPE_FLTRES = 0x6 + _FPE_FLTINV = 0x7 + _FPE_FLTSUB = 0x8 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EPOLLIN = 0x1 + _EPOLLOUT = 0x4 + _EPOLLERR = 0x8 + _EPOLLHUP = 0x10 + _EPOLLRDHUP = 0x2000 + _EPOLLET = -0x80000000 + _EPOLL_CLOEXEC = 0x80000 + _EPOLL_CTL_ADD = 0x1 + _EPOLL_CTL_DEL = 0x2 + _EPOLL_CTL_MOD = 0x3 +) + +//struct Sigset { +// uint64 sig[1]; +//}; +//typedef uint64 Sigset; + +type timespec struct { + tv_sec int64 + tv_nsec int64 +} + +type timeval struct { + tv_sec int64 + tv_usec int64 +} + +type sigactiont struct { + sa_handler uintptr + sa_flags uint64 + sa_restorer uintptr + sa_mask uint64 +} + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + pad_cgo_0 [4]byte + _sifields [112]byte +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type epollevent struct { + events uint32 + pad_cgo_0 [4]byte + data [8]byte // unaligned uintptr +} + +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +const ( + _O_RDONLY = 0x0 + _O_CLOEXEC = 0x80000 + _SA_RESTORER = 0 +) + +type ptregs struct { + gpr [32]uint64 + nip uint64 + msr uint64 + orig_gpr3 uint64 + ctr uint64 + link uint64 + xer uint64 + ccr uint64 + softe uint64 + trap uint64 + dar uint64 + dsisr uint64 + result uint64 +} + +type vreg struct { + u [4]uint32 +} + +type sigaltstackt struct { + ss_sp *byte + ss_flags int32 + pad_cgo_0 [4]byte + ss_size uint64 +} + +type sigcontext struct { + _unused [4]uint64 + signal int32 + _pad0 int32 + handler uint64 + oldmask uint64 + regs *ptregs + gp_regs [48]uint64 + fp_regs [33]float64 + v_regs *vreg + vmx_reserve [101]int64 +} + +type ucontext struct { + uc_flags uint64 + uc_link *ucontext + uc_stack sigaltstackt + uc_sigmask uint64 + __unused [15]uint64 + uc_mcontext sigcontext +} diff --git a/src/runtime/defs_linux_power64.h b/src/runtime/defs_linux_power64.h deleted file mode 100644 index 93742fa346..0000000000 --- a/src/runtime/defs_linux_power64.h +++ /dev/null @@ -1,204 +0,0 @@ -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - EINTR = 0x4, - EAGAIN = 0xb, - ENOMEM = 0xc, - - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - - MADV_DONTNEED = 0x4, - - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_SIGINFO = 0x4, - - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - - ITIMER_REAL = 0x0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - - EPOLLIN = 0x1, - EPOLLOUT = 0x4, - EPOLLERR = 0x8, - EPOLLHUP = 0x10, - EPOLLRDHUP = 0x2000, - EPOLLET = -0x80000000, - EPOLL_CLOEXEC = 0x80000, - EPOLL_CTL_ADD = 0x1, - EPOLL_CTL_DEL = 0x2, - EPOLL_CTL_MOD = 0x3, -}; - -typedef struct Sigset Sigset; -typedef struct Timespec Timespec; -typedef struct Timeval Timeval; -typedef struct SigactionT SigactionT; -typedef struct Siginfo Siginfo; -typedef struct Itimerval Itimerval; -typedef struct EpollEvent EpollEvent; - -#pragma pack on - -//struct Sigset { -// uint64 sig[1]; -//}; -//typedef uint64 Sigset; - -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; -struct SigactionT { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte Pad_cgo_0[4]; - byte _sifields[112]; -}; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -struct EpollEvent { - uint32 events; - byte Pad_cgo_0[4]; - byte data[8]; // unaligned uintptr -}; - - -#pragma pack off -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - O_RDONLY = 0x0, - O_CLOEXEC = 0x80000, - SA_RESTORER = 0, -}; - -typedef struct Ptregs Ptregs; -typedef struct Vreg Vreg; -typedef struct SigaltstackT SigaltstackT; -typedef struct Sigcontext Sigcontext; -typedef struct Ucontext Ucontext; - -#pragma pack on - -struct Ptregs { - uint64 gpr[32]; - uint64 nip; - uint64 msr; - uint64 orig_gpr3; - uint64 ctr; - uint64 link; - uint64 xer; - uint64 ccr; - uint64 softe; - uint64 trap; - uint64 dar; - uint64 dsisr; - uint64 result; -}; -typedef uint64 Gregset[48]; -typedef float64 FPregset[33]; -struct Vreg { - uint32 u[4]; -}; - -struct SigaltstackT { - byte *ss_sp; - int32 ss_flags; - byte Pad_cgo_0[4]; - uint64 ss_size; -}; - -struct Sigcontext { - uint64 _unused[4]; - int32 signal; - int32 _pad0; - uint64 handler; - uint64 oldmask; - Ptregs *regs; - uint64 gp_regs[48]; - float64 fp_regs[33]; - Vreg *v_regs; - int64 vmx_reserve[101]; -}; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - SigaltstackT uc_stack; - uint64 uc_sigmask; - uint64 __unused[15]; - Sigcontext uc_mcontext; -}; - - -#pragma pack off diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go new file mode 100644 index 0000000000..df877a67f7 --- /dev/null +++ b/src/runtime/defs_linux_power64le.go @@ -0,0 +1,186 @@ +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +package runtime + +const ( + _EINTR = 0x4 + _EAGAIN = 0xb + _ENOMEM = 0xc + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x20 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + + _SA_RESTART = 0x10000000 + _SA_ONSTACK = 0x8000000 + _SA_SIGINFO = 0x4 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGBUS = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGUSR1 = 0xa + _SIGSEGV = 0xb + _SIGUSR2 = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGSTKFLT = 0x10 + _SIGCHLD = 0x11 + _SIGCONT = 0x12 + _SIGSTOP = 0x13 + _SIGTSTP = 0x14 + _SIGTTIN = 0x15 + _SIGTTOU = 0x16 + _SIGURG = 0x17 + _SIGXCPU = 0x18 + _SIGXFSZ = 0x19 + _SIGVTALRM = 0x1a + _SIGPROF = 0x1b + _SIGWINCH = 0x1c + _SIGIO = 0x1d + _SIGPWR = 0x1e + _SIGSYS = 0x1f + + _FPE_INTDIV = 0x1 + _FPE_INTOVF = 0x2 + _FPE_FLTDIV = 0x3 + _FPE_FLTOVF = 0x4 + _FPE_FLTUND = 0x5 + _FPE_FLTRES = 0x6 + _FPE_FLTINV = 0x7 + _FPE_FLTSUB = 0x8 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EPOLLIN = 0x1 + _EPOLLOUT = 0x4 + _EPOLLERR = 0x8 + _EPOLLHUP = 0x10 + _EPOLLRDHUP = 0x2000 + _EPOLLET = -0x80000000 + _EPOLL_CLOEXEC = 0x80000 + _EPOLL_CTL_ADD = 0x1 + _EPOLL_CTL_DEL = 0x2 + _EPOLL_CTL_MOD = 0x3 +) + +//struct Sigset { +// uint64 sig[1]; +//}; +//typedef uint64 Sigset; + +type timespec struct { + tv_sec int64 + tv_nsec int64 +} + +type timeval struct { + tv_sec int64 + tv_usec int64 +} + +type sigactiont struct { + sa_handler uintptr + sa_flags uint64 + sa_restorer uintptr + sa_mask uint64 +} + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + pad_cgo_0 [4]byte + _sifields [112]byte +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type epollevent struct { + events uint32 + pad_cgo_0 [4]byte + data [8]byte // unaligned uintptr +} + +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +const ( + _O_RDONLY = 0x0 + _O_CLOEXEC = 0x80000 + _SA_RESTORER = 0 +) + +type ptregs struct { + gpr [32]uint64 + nip uint64 + msr uint64 + orig_gpr3 uint64 + ctr uint64 + link uint64 + xer uint64 + ccr uint64 + softe uint64 + trap uint64 + dar uint64 + dsisr uint64 + result uint64 +} + +type vreg struct { + u [4]uint32 +} + +type sigaltstackt struct { + ss_sp *byte + ss_flags int32 + pad_cgo_0 [4]byte + ss_size uint64 +} + +type sigcontext struct { + _unused [4]uint64 + signal int32 + _pad0 int32 + handler uint64 + oldmask uint64 + regs *ptregs + gp_regs [48]uint64 + fp_regs [33]float64 + v_regs *vreg + vmx_reserve [101]int64 +} + +type ucontext struct { + uc_flags uint64 + uc_link *ucontext + uc_stack sigaltstackt + uc_sigmask uint64 + __unused [15]uint64 + uc_mcontext sigcontext +} diff --git a/src/runtime/defs_linux_power64le.h b/src/runtime/defs_linux_power64le.h deleted file mode 100644 index 93742fa346..0000000000 --- a/src/runtime/defs_linux_power64le.h +++ /dev/null @@ -1,204 +0,0 @@ -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - EINTR = 0x4, - EAGAIN = 0xb, - ENOMEM = 0xc, - - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - - MADV_DONTNEED = 0x4, - - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_SIGINFO = 0x4, - - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - - ITIMER_REAL = 0x0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - - EPOLLIN = 0x1, - EPOLLOUT = 0x4, - EPOLLERR = 0x8, - EPOLLHUP = 0x10, - EPOLLRDHUP = 0x2000, - EPOLLET = -0x80000000, - EPOLL_CLOEXEC = 0x80000, - EPOLL_CTL_ADD = 0x1, - EPOLL_CTL_DEL = 0x2, - EPOLL_CTL_MOD = 0x3, -}; - -typedef struct Sigset Sigset; -typedef struct Timespec Timespec; -typedef struct Timeval Timeval; -typedef struct SigactionT SigactionT; -typedef struct Siginfo Siginfo; -typedef struct Itimerval Itimerval; -typedef struct EpollEvent EpollEvent; - -#pragma pack on - -//struct Sigset { -// uint64 sig[1]; -//}; -//typedef uint64 Sigset; - -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; -struct SigactionT { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte Pad_cgo_0[4]; - byte _sifields[112]; -}; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -struct EpollEvent { - uint32 events; - byte Pad_cgo_0[4]; - byte data[8]; // unaligned uintptr -}; - - -#pragma pack off -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - O_RDONLY = 0x0, - O_CLOEXEC = 0x80000, - SA_RESTORER = 0, -}; - -typedef struct Ptregs Ptregs; -typedef struct Vreg Vreg; -typedef struct SigaltstackT SigaltstackT; -typedef struct Sigcontext Sigcontext; -typedef struct Ucontext Ucontext; - -#pragma pack on - -struct Ptregs { - uint64 gpr[32]; - uint64 nip; - uint64 msr; - uint64 orig_gpr3; - uint64 ctr; - uint64 link; - uint64 xer; - uint64 ccr; - uint64 softe; - uint64 trap; - uint64 dar; - uint64 dsisr; - uint64 result; -}; -typedef uint64 Gregset[48]; -typedef float64 FPregset[33]; -struct Vreg { - uint32 u[4]; -}; - -struct SigaltstackT { - byte *ss_sp; - int32 ss_flags; - byte Pad_cgo_0[4]; - uint64 ss_size; -}; - -struct Sigcontext { - uint64 _unused[4]; - int32 signal; - int32 _pad0; - uint64 handler; - uint64 oldmask; - Ptregs *regs; - uint64 gp_regs[48]; - float64 fp_regs[33]; - Vreg *v_regs; - int64 vmx_reserve[101]; -}; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - SigaltstackT uc_stack; - uint64 uc_sigmask; - uint64 __unused[15]; - Sigcontext uc_mcontext; -}; - - -#pragma pack off -- cgit v1.3-5-g9baa From 0fe444d3e81d890ce496b6a260494473948b060a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 18 Nov 2014 12:07:50 -0500 Subject: [dev.cc] runtime: generate GOOS- and GOARCH-specific files with go generate Eventually I'd like almost everything cmd/dist generates to be done with 'go generate' and checked in, to simplify the bootstrap process. The only thing cmd/dist really needs to do is write things like the current experiment info and the current version. This is a first step toward that. It replaces the _NaCl etc constants with generated ones goos_nacl, goos_darwin, goarch_386, and so on. LGTM=dave, austin R=austin, dave, bradfitz CC=golang-codereviews, iant, r https://golang.org/cl/174290043 --- src/cmd/dist/build.c | 7 ++-- src/cmd/dist/buildruntime.c | 60 ----------------------------- src/runtime/arch1_386.go | 2 +- src/runtime/arch1_amd64.go | 2 +- src/runtime/arch1_arm.go | 2 +- src/runtime/gengoos.go | 82 ++++++++++++++++++++++++++++++++++++++++ src/runtime/malloc2.go | 2 +- src/runtime/runtime2.go | 16 ++++---- src/runtime/stack1.go | 2 +- src/runtime/stack2.go | 2 +- src/runtime/zgoarch_386.go | 12 ++++++ src/runtime/zgoarch_amd64.go | 12 ++++++ src/runtime/zgoarch_amd64p32.go | 12 ++++++ src/runtime/zgoarch_arm.go | 12 ++++++ src/runtime/zgoarch_power64.go | 12 ++++++ src/runtime/zgoarch_power64le.go | 12 ++++++ src/runtime/zgoos_android.go | 19 ++++++++++ src/runtime/zgoos_darwin.go | 19 ++++++++++ src/runtime/zgoos_dragonfly.go | 19 ++++++++++ src/runtime/zgoos_freebsd.go | 19 ++++++++++ src/runtime/zgoos_linux.go | 19 ++++++++++ src/runtime/zgoos_nacl.go | 19 ++++++++++ src/runtime/zgoos_netbsd.go | 19 ++++++++++ src/runtime/zgoos_openbsd.go | 19 ++++++++++ src/runtime/zgoos_plan9.go | 19 ++++++++++ src/runtime/zgoos_solaris.go | 19 ++++++++++ src/runtime/zgoos_windows.go | 19 ++++++++++ 27 files changed, 379 insertions(+), 79 deletions(-) create mode 100644 src/runtime/gengoos.go create mode 100644 src/runtime/zgoarch_386.go create mode 100644 src/runtime/zgoarch_amd64.go create mode 100644 src/runtime/zgoarch_amd64p32.go create mode 100644 src/runtime/zgoarch_arm.go create mode 100644 src/runtime/zgoarch_power64.go create mode 100644 src/runtime/zgoarch_power64le.go create mode 100644 src/runtime/zgoos_android.go create mode 100644 src/runtime/zgoos_darwin.go create mode 100644 src/runtime/zgoos_dragonfly.go create mode 100644 src/runtime/zgoos_freebsd.go create mode 100644 src/runtime/zgoos_linux.go create mode 100644 src/runtime/zgoos_nacl.go create mode 100644 src/runtime/zgoos_netbsd.go create mode 100644 src/runtime/zgoos_openbsd.go create mode 100644 src/runtime/zgoos_plan9.go create mode 100644 src/runtime/zgoos_solaris.go create mode 100644 src/runtime/zgoos_windows.go (limited to 'src/runtime') diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c index e4f307bee5..bfb3d15b82 100644 --- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -615,8 +615,6 @@ static struct { {"anames9.c", mkanames}, {"zdefaultcc.go", mkzdefaultcc}, {"zsys_", mkzsys}, - {"zgoarch_", mkzgoarch}, - {"zgoos_", mkzgoos}, {"zversion.go", mkzversion}, {"zaexperiment.h", mkzexperiment}, @@ -1419,12 +1417,13 @@ clean(void) xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4)); } - // remove src/runtime/z* unconditionally + // remove src/runtime/z* unconditionally, + // except leave zgoos and zgoarch, now maintained with go generate. vreset(&dir); bpathf(&path, "%s/src/runtime", goroot); xreaddir(&dir, bstr(&path)); for(j=0; j -// -void -mkzgoarch(char *dir, char *file) -{ - Buf b, out; - - USED(dir); - - binit(&b); - binit(&out); - - bwritestr(&out, bprintf(&b, - "// auto generated by go tool dist\n" - "\n" - "package runtime\n" - "\n" - "const theGoarch = `%s`\n", goarch)); - - writefile(&out, file, 0); - - bfree(&b); - bfree(&out); -} - -// mkzgoos writes zgoos_$GOOS.go: -// -// package runtime -// const theGoos = -// -void -mkzgoos(char *dir, char *file) -{ - Buf b, out; - - USED(dir); - - binit(&b); - binit(&out); - - bwritestr(&out, "// auto generated by go tool dist\n\n"); - - if(streq(goos, "linux")) { - bwritestr(&out, "// +build !android\n\n"); - } - - bwritestr(&out, bprintf(&b, - "package runtime\n" - "\n" - "const theGoos = `%s`\n", goos)); - - writefile(&out, file, 0); - - bfree(&b); - bfree(&out); -} - #define MAXWINCB 2000 /* maximum number of windows callbacks allowed */ // mkzsys writes zsys_$GOOS_$GOARCH.s, diff --git a/src/runtime/arch1_386.go b/src/runtime/arch1_386.go index 7746dfbf06..a73e207edd 100644 --- a/src/runtime/arch1_386.go +++ b/src/runtime/arch1_386.go @@ -9,7 +9,7 @@ const ( _BigEndian = 0 _CacheLineSize = 64 _RuntimeGogoBytes = 64 - _PhysPageSize = _NaCl*65536 + (1-_NaCl)*4096 // 4k normally; 64k on NaCl + _PhysPageSize = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl _PCQuantum = 1 _Int64Align = 4 ) diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go index 83c9c2dc9c..794b7f65c4 100644 --- a/src/runtime/arch1_amd64.go +++ b/src/runtime/arch1_amd64.go @@ -8,7 +8,7 @@ const ( thechar = '6' _BigEndian = 0 _CacheLineSize = 64 - _RuntimeGogoBytes = 64 + (_Plan9|_Solaris|_Windows)*16 + _RuntimeGogoBytes = 64 + (goos_plan9|goos_solaris|goos_windows)*16 _PhysPageSize = 4096 _PCQuantum = 1 _Int64Align = 8 diff --git a/src/runtime/arch1_arm.go b/src/runtime/arch1_arm.go index 5cb79fd686..6662eaeac3 100644 --- a/src/runtime/arch1_arm.go +++ b/src/runtime/arch1_arm.go @@ -9,7 +9,7 @@ const ( _BigEndian = 0 _CacheLineSize = 32 _RuntimeGogoBytes = 60 - _PhysPageSize = 65536*_NaCl + 4096*(1-_NaCl) + _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl) _PCQuantum = 4 _Int64Align = 4 ) diff --git a/src/runtime/gengoos.go b/src/runtime/gengoos.go new file mode 100644 index 0000000000..029575bee2 --- /dev/null +++ b/src/runtime/gengoos.go @@ -0,0 +1,82 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "strconv" + "strings" +) + +var gooses, goarches []string + +func main() { + data, err := ioutil.ReadFile("../go/build/syslist.go") + if err != nil { + log.Fatal(err) + } + const ( + goosPrefix = `const goosList = ` + goarchPrefix = `const goarchList = ` + ) + for _, line := range strings.Split(string(data), "\n") { + if strings.HasPrefix(line, goosPrefix) { + text, err := strconv.Unquote(strings.TrimPrefix(line, goosPrefix)) + if err != nil { + log.Fatalf("parsing goosList %#q: %v", strings.TrimPrefix(line, goosPrefix), err) + } + gooses = strings.Fields(text) + } + if strings.HasPrefix(line, goarchPrefix) { + text, err := strconv.Unquote(strings.TrimPrefix(line, goarchPrefix)) + if err != nil { + log.Fatal("parsing goarchList: %v", err) + } + goarches = strings.Fields(text) + } + } + + for _, target := range gooses { + var buf bytes.Buffer + fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") + fmt.Fprintf(&buf, "// +build %s\n\n", target) // usually redundant, but not always; see linux vs android + fmt.Fprintf(&buf, "package runtime\n\n") + fmt.Fprintf(&buf, "const theGoos = `%s`\n\n", target) + for _, goos := range gooses { + value := 0 + if goos == target { + value = 1 + } + fmt.Fprintf(&buf, "const goos_%s = %d\n", goos, value) + } + err := ioutil.WriteFile("zgoos_"+target+".go", buf.Bytes(), 0666) + if err != nil { + log.Fatal(err) + } + } + + for _, target := range goarches { + var buf bytes.Buffer + fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") + fmt.Fprintf(&buf, "package runtime\n\n") + fmt.Fprintf(&buf, "const theGoarch = `%s`\n\n", target) + for _, goarch := range goarches { + value := 0 + if goarch == target { + value = 1 + } + fmt.Fprintf(&buf, "const goarch_%s = %d\n", goarch, value) + } + err := ioutil.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666) + if err != nil { + log.Fatal(err) + } + } +} diff --git a/src/runtime/malloc2.go b/src/runtime/malloc2.go index e4bd963d30..c175c2aec7 100644 --- a/src/runtime/malloc2.go +++ b/src/runtime/malloc2.go @@ -126,7 +126,7 @@ const ( // See http://golang.org/issue/5402 and http://golang.org/issue/5236. // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits. // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. - _MHeapMap_TotalBits = (_64bit*_Windows)*35 + (_64bit*(1-_Windows))*37 + (1-_64bit)*32 + _MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32 _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index c999b3072d..7987a73730 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -45,7 +45,13 @@ const ( _Pdead ) -// XXX inserting below here +// The next line makes 'go generate' write the zgen_*.go files with +// per-OS and per-arch information, including constants +// named goos_$GOOS and goarch_$GOARCH for every +// known GOOS and GOARCH. The constant is 1 on the +// current system, 0 otherwise; multiplying by them is +// useful for defining GOOS- or GOARCH-specific constants. +//go:generate go run gengoos.go type mutex struct { // Futex-based impl treats it as uint32 key, @@ -395,14 +401,6 @@ type itab struct { fun [0]uintptr } -const ( - // TODO: Generate in cmd/dist. - _NaCl = 0 - _Windows = 0 - _Solaris = 0 - _Plan9 = 0 -) - // Lock-free stack node. type lfnode struct { next *lfnode diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go index 40dfc76a6d..ad83e58951 100644 --- a/src/runtime/stack1.go +++ b/src/runtime/stack1.go @@ -775,7 +775,7 @@ func shrinkstack(gp *g) { } /* TODO - if _Windows && gp.m != nil && gp.m.libcallsp != 0 { + if goos_windows && gp.m != nil && gp.m.libcallsp != 0 { return } */ diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go index c3718c205e..e50b32c784 100644 --- a/src/runtime/stack2.go +++ b/src/runtime/stack2.go @@ -59,7 +59,7 @@ const ( // to each stack below the usual guard area for OS-specific // purposes like signal handling. Used on Windows and on // Plan 9 because they do not use a separate stack. - _StackSystem = _Windows*512*ptrSize + _Plan9*512 + _StackSystem = goos_windows*512*ptrSize + goos_plan9*512 // The minimum size of stack used by Go code _StackMin = 2048 diff --git a/src/runtime/zgoarch_386.go b/src/runtime/zgoarch_386.go new file mode 100644 index 0000000000..057a746bb5 --- /dev/null +++ b/src/runtime/zgoarch_386.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `386` + +const goarch_386 = 1 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_amd64.go b/src/runtime/zgoarch_amd64.go new file mode 100644 index 0000000000..a712407269 --- /dev/null +++ b/src/runtime/zgoarch_amd64.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `amd64` + +const goarch_386 = 0 +const goarch_amd64 = 1 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_amd64p32.go b/src/runtime/zgoarch_amd64p32.go new file mode 100644 index 0000000000..2b6a142bb7 --- /dev/null +++ b/src/runtime/zgoarch_amd64p32.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `amd64p32` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 1 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_arm.go b/src/runtime/zgoarch_arm.go new file mode 100644 index 0000000000..4030210050 --- /dev/null +++ b/src/runtime/zgoarch_arm.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `arm` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 1 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_power64.go b/src/runtime/zgoarch_power64.go new file mode 100644 index 0000000000..cc361f0505 --- /dev/null +++ b/src/runtime/zgoarch_power64.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `power64` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 1 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_power64le.go b/src/runtime/zgoarch_power64le.go new file mode 100644 index 0000000000..41294e61b9 --- /dev/null +++ b/src/runtime/zgoarch_power64le.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `power64le` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 1 diff --git a/src/runtime/zgoos_android.go b/src/runtime/zgoos_android.go new file mode 100644 index 0000000000..abfba808ba --- /dev/null +++ b/src/runtime/zgoos_android.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build android + +package runtime + +const theGoos = `android` + +const goos_android = 1 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_darwin.go b/src/runtime/zgoos_darwin.go new file mode 100644 index 0000000000..eb39b53dd4 --- /dev/null +++ b/src/runtime/zgoos_darwin.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build darwin + +package runtime + +const theGoos = `darwin` + +const goos_android = 0 +const goos_darwin = 1 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_dragonfly.go b/src/runtime/zgoos_dragonfly.go new file mode 100644 index 0000000000..f6e839d3d8 --- /dev/null +++ b/src/runtime/zgoos_dragonfly.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build dragonfly + +package runtime + +const theGoos = `dragonfly` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 1 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_freebsd.go b/src/runtime/zgoos_freebsd.go new file mode 100644 index 0000000000..3c47aef2ab --- /dev/null +++ b/src/runtime/zgoos_freebsd.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build freebsd + +package runtime + +const theGoos = `freebsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 1 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_linux.go b/src/runtime/zgoos_linux.go new file mode 100644 index 0000000000..5d899e3db6 --- /dev/null +++ b/src/runtime/zgoos_linux.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build linux + +package runtime + +const theGoos = `linux` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 1 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_nacl.go b/src/runtime/zgoos_nacl.go new file mode 100644 index 0000000000..b5c4281fb5 --- /dev/null +++ b/src/runtime/zgoos_nacl.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build nacl + +package runtime + +const theGoos = `nacl` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 1 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_netbsd.go b/src/runtime/zgoos_netbsd.go new file mode 100644 index 0000000000..b2e45222ae --- /dev/null +++ b/src/runtime/zgoos_netbsd.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build netbsd + +package runtime + +const theGoos = `netbsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 1 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_openbsd.go b/src/runtime/zgoos_openbsd.go new file mode 100644 index 0000000000..331c96dd66 --- /dev/null +++ b/src/runtime/zgoos_openbsd.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build openbsd + +package runtime + +const theGoos = `openbsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 1 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_plan9.go b/src/runtime/zgoos_plan9.go new file mode 100644 index 0000000000..f29eb45230 --- /dev/null +++ b/src/runtime/zgoos_plan9.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build plan9 + +package runtime + +const theGoos = `plan9` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 1 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_solaris.go b/src/runtime/zgoos_solaris.go new file mode 100644 index 0000000000..ac613db33c --- /dev/null +++ b/src/runtime/zgoos_solaris.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build solaris + +package runtime + +const theGoos = `solaris` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 1 +const goos_windows = 0 diff --git a/src/runtime/zgoos_windows.go b/src/runtime/zgoos_windows.go new file mode 100644 index 0000000000..43710d862f --- /dev/null +++ b/src/runtime/zgoos_windows.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build windows + +package runtime + +const theGoos = `windows` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 1 -- cgit v1.3-5-g9baa From 54d731452d0e06ccbf211ac0893a9739ad08bd75 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:09 -0500 Subject: [dev.cc] runtime: convert power64 signal handlers from C to Go The power64 equivalent of CL 168500044 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175280043 --- src/runtime/signal_linux_power64.h | 49 ------------ src/runtime/signal_linux_power64le.h | 49 ------------ src/runtime/signal_linux_power64x.go | 71 +++++++++++++++++ src/runtime/signal_power64x.c | 137 --------------------------------- src/runtime/signal_power64x.go | 144 +++++++++++++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 235 deletions(-) delete mode 100644 src/runtime/signal_linux_power64.h delete mode 100644 src/runtime/signal_linux_power64le.h create mode 100644 src/runtime/signal_linux_power64x.go delete mode 100644 src/runtime/signal_power64x.c create mode 100644 src/runtime/signal_power64x.go (limited to 'src/runtime') diff --git a/src/runtime/signal_linux_power64.h b/src/runtime/signal_linux_power64.h deleted file mode 100644 index 8406489209..0000000000 --- a/src/runtime/signal_linux_power64.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) -#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) -#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) -#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) -#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) -#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) -#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) -#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) -#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) -#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) -#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) -#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) -#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) -#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) -#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) -#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) -#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) - -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) -#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) -#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) -#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) -#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) -#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) - -#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) -#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/runtime/signal_linux_power64le.h b/src/runtime/signal_linux_power64le.h deleted file mode 100644 index 8406489209..0000000000 --- a/src/runtime/signal_linux_power64le.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) -#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) -#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) -#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) -#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) -#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) -#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) -#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) -#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) -#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) -#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) -#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) -#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) -#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) -#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) -#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) -#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) - -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) -#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) -#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) -#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) -#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) -#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) - -#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) -#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/runtime/signal_linux_power64x.go b/src/runtime/signal_linux_power64x.go new file mode 100644 index 0000000000..8f357033bf --- /dev/null +++ b/src/runtime/signal_linux_power64x.go @@ -0,0 +1,71 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build power64 power64le + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *ptregs { return (*ucontext)(c.ctxt).uc_mcontext.regs } +func (c *sigctxt) r0() uint64 { return c.regs().gpr[0] } +func (c *sigctxt) r1() uint64 { return c.regs().gpr[1] } +func (c *sigctxt) r2() uint64 { return c.regs().gpr[2] } +func (c *sigctxt) r3() uint64 { return c.regs().gpr[3] } +func (c *sigctxt) r4() uint64 { return c.regs().gpr[4] } +func (c *sigctxt) r5() uint64 { return c.regs().gpr[5] } +func (c *sigctxt) r6() uint64 { return c.regs().gpr[6] } +func (c *sigctxt) r7() uint64 { return c.regs().gpr[7] } +func (c *sigctxt) r8() uint64 { return c.regs().gpr[8] } +func (c *sigctxt) r9() uint64 { return c.regs().gpr[9] } +func (c *sigctxt) r10() uint64 { return c.regs().gpr[10] } +func (c *sigctxt) r11() uint64 { return c.regs().gpr[11] } +func (c *sigctxt) r12() uint64 { return c.regs().gpr[12] } +func (c *sigctxt) r13() uint64 { return c.regs().gpr[13] } +func (c *sigctxt) r14() uint64 { return c.regs().gpr[14] } +func (c *sigctxt) r15() uint64 { return c.regs().gpr[15] } +func (c *sigctxt) r16() uint64 { return c.regs().gpr[16] } +func (c *sigctxt) r17() uint64 { return c.regs().gpr[17] } +func (c *sigctxt) r18() uint64 { return c.regs().gpr[18] } +func (c *sigctxt) r19() uint64 { return c.regs().gpr[19] } +func (c *sigctxt) r20() uint64 { return c.regs().gpr[20] } +func (c *sigctxt) r21() uint64 { return c.regs().gpr[21] } +func (c *sigctxt) r22() uint64 { return c.regs().gpr[22] } +func (c *sigctxt) r23() uint64 { return c.regs().gpr[23] } +func (c *sigctxt) r24() uint64 { return c.regs().gpr[24] } +func (c *sigctxt) r25() uint64 { return c.regs().gpr[25] } +func (c *sigctxt) r26() uint64 { return c.regs().gpr[26] } +func (c *sigctxt) r27() uint64 { return c.regs().gpr[27] } +func (c *sigctxt) r28() uint64 { return c.regs().gpr[28] } +func (c *sigctxt) r29() uint64 { return c.regs().gpr[29] } +func (c *sigctxt) r30() uint64 { return c.regs().gpr[30] } +func (c *sigctxt) r31() uint64 { return c.regs().gpr[31] } +func (c *sigctxt) sp() uint64 { return c.regs().gpr[1] } +func (c *sigctxt) pc() uint64 { return c.regs().nip } +func (c *sigctxt) trap() uint64 { return c.regs().trap } +func (c *sigctxt) ctr() uint64 { return c.regs().ctr } +func (c *sigctxt) link() uint64 { return c.regs().link } +func (c *sigctxt) xer() uint64 { return c.regs().xer } +func (c *sigctxt) ccr() uint64 { return c.regs().ccr } + +func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } +func (c *sigctxt) sigaddr() uint64 { return uint64(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) fault() uint64 { return c.regs().dar } + +func (c *sigctxt) set_r0(x uint64) { c.regs().gpr[0] = x } +func (c *sigctxt) set_r30(x uint64) { c.regs().gpr[30] = x } +func (c *sigctxt) set_pc(x uint64) { c.regs().nip = x } +func (c *sigctxt) set_sp(x uint64) { c.regs().gpr[1] = x } +func (c *sigctxt) set_link(x uint64) { c.regs().link = x } + +func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint64) { + *(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x) +} diff --git a/src/runtime/signal_power64x.c b/src/runtime/signal_power64x.c deleted file mode 100644 index c0bf1c4a51..0000000000 --- a/src/runtime/signal_power64x.c +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux -// +build power64 power64le - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signal_GOOS_GOARCH.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Siginfo *info, void *ctxt) -{ - USED(info); USED(ctxt); - runtime·printf("r0 %X\t", SIG_R0(info, ctxt)); - runtime·printf("r1 %X\n", SIG_R1(info, ctxt)); - runtime·printf("r2 %X\t", SIG_R2(info, ctxt)); - runtime·printf("r3 %X\n", SIG_R3(info, ctxt)); - runtime·printf("r4 %X\t", SIG_R4(info, ctxt)); - runtime·printf("r5 %X\n", SIG_R5(info, ctxt)); - runtime·printf("r6 %X\t", SIG_R6(info, ctxt)); - runtime·printf("r7 %X\n", SIG_R7(info, ctxt)); - runtime·printf("r8 %X\t", SIG_R8(info, ctxt)); - runtime·printf("r9 %X\n", SIG_R9(info, ctxt)); - runtime·printf("r10 %X\t", SIG_R10(info, ctxt)); - runtime·printf("r11 %X\n", SIG_R11(info, ctxt)); - runtime·printf("r12 %X\t", SIG_R12(info, ctxt)); - runtime·printf("r13 %X\n", SIG_R13(info, ctxt)); - runtime·printf("r14 %X\t", SIG_R14(info, ctxt)); - runtime·printf("r15 %X\n", SIG_R15(info, ctxt)); - runtime·printf("r16 %X\t", SIG_R16(info, ctxt)); - runtime·printf("r17 %X\n", SIG_R17(info, ctxt)); - runtime·printf("r18 %X\t", SIG_R18(info, ctxt)); - runtime·printf("r19 %X\n", SIG_R19(info, ctxt)); - runtime·printf("r20 %X\t", SIG_R20(info, ctxt)); - runtime·printf("r21 %X\n", SIG_R21(info, ctxt)); - runtime·printf("r22 %X\t", SIG_R22(info, ctxt)); - runtime·printf("r23 %X\n", SIG_R23(info, ctxt)); - runtime·printf("r24 %X\t", SIG_R24(info, ctxt)); - runtime·printf("r25 %X\n", SIG_R25(info, ctxt)); - runtime·printf("r26 %X\t", SIG_R26(info, ctxt)); - runtime·printf("r27 %X\n", SIG_R27(info, ctxt)); - runtime·printf("r28 %X\t", SIG_R28(info, ctxt)); - runtime·printf("r29 %X\n", SIG_R29(info, ctxt)); - runtime·printf("r30 %X\t", SIG_R30(info, ctxt)); - runtime·printf("r31 %X\n", SIG_R31(info, ctxt)); - runtime·printf("pc %X\t", SIG_PC(info, ctxt)); - runtime·printf("ctr %X\n", SIG_CTR(info, ctxt)); - runtime·printf("link %X\t", SIG_LINK(info, ctxt)); - runtime·printf("xer %X\n", SIG_XER(info, ctxt)); - runtime·printf("ccr %X\t", SIG_CCR(info, ctxt)); - runtime·printf("trap %X\n", SIG_TRAP(info, ctxt)); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) -{ - SigTab *t; - bool crash; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LINK(info, ctxt), gp, g->m); - return; - } - t = &runtime·sigtab[sig]; - if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = sig; - gp->sigcode0 = SIG_CODE0(info, ctxt); - gp->sigcode1 = SIG_FAULT(info, ctxt); - gp->sigpc = SIG_PC(info, ctxt); - - // We arrange link, and pc to pretend the panicking - // function calls sigpanic directly. - // Always save LINK to stack so that panics in leaf - // functions are correctly handled. This smashes - // the stack frame but we're not going back there - // anyway. - SIG_SP(info, ctxt) -= sizeof(uintptr); - *(uintptr*)SIG_SP(info, ctxt) = SIG_LINK(info, ctxt); - // Don't bother saving PC if it's zero, which is - // probably a call to a nil func: the old link register - // is more useful in the stack trace. - if(gp->sigpc != 0) - SIG_LINK(info, ctxt) = gp->sigpc; - // In case we are panicking from external C code - SIG_R0(info, ctxt) = 0; - SIG_R30(info, ctxt) = (uintptr)gp; - SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic; - return; - } - - if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - - g->m->throwing = 1; - g->m->caughtsig = gp; - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - if(sig < 0 || sig >= NSIG) - runtime·printf("Signal %d\n", sig); - else - runtime·printf("%s\n", runtime·sigtab[sig].name); - - runtime·printf("PC=%x\n", SIG_PC(info, ctxt)); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·goroutineheader(gp); - runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(info, ctxt); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); -} diff --git a/src/runtime/signal_power64x.go b/src/runtime/signal_power64x.go new file mode 100644 index 0000000000..fc83beb1b6 --- /dev/null +++ b/src/runtime/signal_power64x.go @@ -0,0 +1,144 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build power64 power64le + +package runtime + +import "unsafe" + +func dumpregs(c *sigctxt) { + print("r0 ", hex(c.r0()), "\t") + print("r1 ", hex(c.r1()), "\n") + print("r2 ", hex(c.r2()), "\t") + print("r3 ", hex(c.r3()), "\n") + print("r4 ", hex(c.r4()), "\t") + print("r5 ", hex(c.r5()), "\n") + print("r6 ", hex(c.r6()), "\t") + print("r7 ", hex(c.r7()), "\n") + print("r8 ", hex(c.r8()), "\t") + print("r9 ", hex(c.r9()), "\n") + print("r10 ", hex(c.r10()), "\t") + print("r11 ", hex(c.r11()), "\n") + print("r12 ", hex(c.r12()), "\t") + print("r13 ", hex(c.r13()), "\n") + print("r14 ", hex(c.r14()), "\t") + print("r15 ", hex(c.r15()), "\n") + print("r16 ", hex(c.r16()), "\t") + print("r17 ", hex(c.r17()), "\n") + print("r18 ", hex(c.r18()), "\t") + print("r19 ", hex(c.r19()), "\n") + print("r20 ", hex(c.r20()), "\t") + print("r21 ", hex(c.r21()), "\n") + print("r22 ", hex(c.r22()), "\t") + print("r23 ", hex(c.r23()), "\n") + print("r24 ", hex(c.r24()), "\t") + print("r25 ", hex(c.r25()), "\n") + print("r26 ", hex(c.r26()), "\t") + print("r27 ", hex(c.r27()), "\n") + print("r28 ", hex(c.r28()), "\t") + print("r29 ", hex(c.r29()), "\n") + print("r30 ", hex(c.r30()), "\t") + print("r31 ", hex(c.r31()), "\n") + print("pc ", hex(c.pc()), "\t") + print("ctr ", hex(c.ctr()), "\n") + print("link ", hex(c.link()), "\t") + print("xer ", hex(c.xer()), "\n") + print("ccr ", hex(c.ccr()), "\t") + print("trap ", hex(c.trap()), "\n") +} + +func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { + _g_ := getg() + c := &sigctxt{info, ctxt} + + if sig == _SIGPROF { + sigprof((*byte)(unsafe.Pointer(uintptr(c.pc()))), (*byte)(unsafe.Pointer(uintptr(c.sp()))), (*byte)(unsafe.Pointer(uintptr(c.link()))), gp, _g_.m) + return + } + flags := int32(_SigThrow) + if sig < uint32(len(sigtable)) { + flags = sigtable[sig].flags + } + if c.sigcode() != _SI_USER && flags&_SigPanic != 0 { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = sig + gp.sigcode0 = uintptr(c.sigcode()) + gp.sigcode1 = uintptr(c.fault()) + gp.sigpc = uintptr(c.pc()) + + // We arrange link, and pc to pretend the panicking + // function calls sigpanic directly. + // Always save LINK to stack so that panics in leaf + // functions are correctly handled. This smashes + // the stack frame but we're not going back there + // anyway. + sp := c.sp() - ptrSize + c.set_sp(sp) + *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link() + + // Don't bother saving PC if it's zero, which is + // probably a call to a nil func: the old link register + // is more useful in the stack trace. + if gp.sigpc != 0 { + c.set_link(uint64(gp.sigpc)) + } + + // In case we are panicking from external C code + c.set_r0(0) + c.set_r30(uint64(uintptr(unsafe.Pointer(gp)))) + c.set_pc(uint64(funcPC(sigpanic))) + return + } + + if c.sigcode() == _SI_USER || flags&_SigNotify != 0 { + if sigsend(sig) { + return + } + } + + if flags&_SigKill != 0 { + exit(2) + } + + if flags&_SigThrow == 0 { + return + } + + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + + if sig < uint32(len(sigtable)) { + print(sigtable[sig].name, "\n") + } else { + print("Signal ", sig, "\n") + } + + print("PC=", hex(c.pc()), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp) + tracebackothers(gp) + print("\n") + dumpregs(c) + } + + if docrash { + crash() + } + + exit(2) +} -- cgit v1.3-5-g9baa From 3f27c3ae373fb32f55739c8695e7baaa33e2b2e3 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:26 -0500 Subject: [dev.cc] runtime: convert power64 assembly files for C to Go transition The power64 equivalent of CL 168510043 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/178940043 --- src/runtime/asm_power64x.s | 13 +++++++++---- src/runtime/sys_linux_power64x.s | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/asm_power64x.s b/src/runtime/asm_power64x.s index a75bb8ce1e..901dedbe59 100644 --- a/src/runtime/asm_power64x.s +++ b/src/runtime/asm_power64x.s @@ -4,7 +4,8 @@ // +build power64 power64le -#include "zasm_GOOS_GOARCH.h" +#include "go_asm.h" +#include "go_tls.h" #include "funcdata.h" #include "textflag.h" @@ -472,7 +473,7 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16 // return 1; // } else // return 0; -TEXT runtime·casp(SB), NOSPLIT, $0-25 +TEXT runtime·casp1(SB), NOSPLIT, $0-25 BR runtime·cas64(SB) // uint32 xadd(uint32 volatile *ptr, int32 delta) @@ -529,7 +530,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24 MOVD R3, ret+16(FP) RETURN -TEXT runtime·xchgp(SB), NOSPLIT, $0-24 +TEXT runtime·xchgp1(SB), NOSPLIT, $0-24 BR runtime·xchg64(SB) TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24 @@ -538,7 +539,7 @@ TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24 TEXT runtime·procyield(SB),NOSPLIT,$0-0 RETURN -TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16 +TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16 BR runtime·atomicstore64(SB) TEXT runtime·atomicstore(SB), NOSPLIT, $0-12 @@ -986,3 +987,7 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0 TEXT runtime·goexit(SB),NOSPLIT,$-8-0 MOVD R0, R0 // NOP BL runtime·goexit1(SB) // does not return + +TEXT runtime·getg(SB),NOSPLIT,$-8-8 + MOVD g, ret+0(FP) + RETURN diff --git a/src/runtime/sys_linux_power64x.s b/src/runtime/sys_linux_power64x.s index fb24d3e795..395f657bf7 100644 --- a/src/runtime/sys_linux_power64x.s +++ b/src/runtime/sys_linux_power64x.s @@ -9,7 +9,8 @@ // System calls and other sys.stuff for Power64, Linux // -#include "zasm_GOOS_GOARCH.h" +#include "go_asm.h" +#include "go_tls.h" #include "textflag.h" #define SYS_exit 1 -- cgit v1.3-5-g9baa From 0da27cb8b0e82d429a9c3ee591208327e3e7a8c9 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:37 -0500 Subject: [dev.cc] runtime: convert power64-specific .c and .h files to Go The power64 equivalent of CL 174860043 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/179890043 --- src/runtime/arch1_power64.go | 15 +++++++++ src/runtime/arch1_power64le.go | 15 +++++++++ src/runtime/arch_power64.h | 14 --------- src/runtime/arch_power64le.h | 14 --------- src/runtime/atomic_power64x.go | 69 ++++++++++++++++++++++++++++++++++++++++++ src/runtime/sys_power64x.c | 38 ----------------------- src/runtime/sys_power64x.go | 37 ++++++++++++++++++++++ 7 files changed, 136 insertions(+), 66 deletions(-) create mode 100644 src/runtime/arch1_power64.go create mode 100644 src/runtime/arch1_power64le.go delete mode 100644 src/runtime/arch_power64.h delete mode 100644 src/runtime/arch_power64le.h create mode 100644 src/runtime/atomic_power64x.go delete mode 100644 src/runtime/sys_power64x.c create mode 100644 src/runtime/sys_power64x.go (limited to 'src/runtime') diff --git a/src/runtime/arch1_power64.go b/src/runtime/arch1_power64.go new file mode 100644 index 0000000000..01e2b70f95 --- /dev/null +++ b/src/runtime/arch1_power64.go @@ -0,0 +1,15 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +const ( + thechar = '9' + _BigEndian = 1 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536 + _PCQuantum = 4 + _Int64Align = 8 +) diff --git a/src/runtime/arch1_power64le.go b/src/runtime/arch1_power64le.go new file mode 100644 index 0000000000..6580732a37 --- /dev/null +++ b/src/runtime/arch1_power64le.go @@ -0,0 +1,15 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +const ( + thechar = '9' + _BigEndian = 0 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536 + _PCQuantum = 4 + _Int64Align = 8 +) diff --git a/src/runtime/arch_power64.h b/src/runtime/arch_power64.h deleted file mode 100644 index 7cfb9da2fc..0000000000 --- a/src/runtime/arch_power64.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -enum { - thechar = '9', - BigEndian = 1, - CacheLineSize = 64, - RuntimeGogoBytes = 64, - PhysPageSize = 65536, - PCQuantum = 4, - Int64Align = 8 -}; - diff --git a/src/runtime/arch_power64le.h b/src/runtime/arch_power64le.h deleted file mode 100644 index 684ac9953b..0000000000 --- a/src/runtime/arch_power64le.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -enum { - thechar = '9', - BigEndian = 0, - CacheLineSize = 64, - RuntimeGogoBytes = 64, - PhysPageSize = 65536, - PCQuantum = 4, - Int64Align = 8 -}; - diff --git a/src/runtime/atomic_power64x.go b/src/runtime/atomic_power64x.go new file mode 100644 index 0000000000..a0dcf514b5 --- /dev/null +++ b/src/runtime/atomic_power64x.go @@ -0,0 +1,69 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build power64 power64le + +package runtime + +import "unsafe" + +//go:noescape +func xadd(ptr *uint32, delta int32) uint32 + +//go:noescape +func xadd64(ptr *uint64, delta int64) uint64 + +//go:noescape +func xchg(ptr *uint32, new uint32) uint32 + +//go:noescape +func xchg64(ptr *uint64, new uint64) uint64 + +// xchgp cannot have a go:noescape annotation, because +// while ptr does not escape, new does. If new is marked as +// not escaping, the compiler will make incorrect escape analysis +// decisions about the value being xchg'ed. +// Instead, make xchgp a wrapper around the actual atomic. +// When calling the wrapper we mark ptr as noescape explicitly. + +//go:nosplit +func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer { + return xchgp1(noescape(ptr), new) +} + +func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer + +//go:noescape +func xchguintptr(ptr *uintptr, new uintptr) uintptr + +//go:noescape +func atomicload(ptr *uint32) uint32 + +//go:noescape +func atomicload64(ptr *uint64) uint64 + +//go:noescape +func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer + +//go:noescape +func atomicor8(ptr *uint8, val uint8) + +//go:noescape +func cas64(ptr *uint64, old, new uint64) bool + +//go:noescape +func atomicstore(ptr *uint32, val uint32) + +//go:noescape +func atomicstore64(ptr *uint64, val uint64) + +// atomicstorep cannot have a go:noescape annotation. +// See comment above for xchgp. + +//go:nosplit +func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) { + atomicstorep1(noescape(ptr), new) +} + +func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/sys_power64x.c b/src/runtime/sys_power64x.c deleted file mode 100644 index 79d976255f..0000000000 --- a/src/runtime/sys_power64x.c +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build power64 power64le - -#include "runtime.h" - -// adjust Gobuf as if it executed a call to fn with context ctxt -// and then did an immediate Gosave. -void -runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt) -{ - if(gobuf->lr != 0) - runtime·throw("invalid use of gostartcall"); - gobuf->lr = gobuf->pc; - gobuf->pc = (uintptr)fn; - gobuf->ctxt = ctxt; -} - -// Called to rewind context saved during morestack back to beginning of function. -// To help us, the linker emits a jmp back to the beginning right after the -// call to morestack. We just have to decode and apply that jump. -void -runtime·rewindmorestack(Gobuf *gobuf) -{ - uint32 inst; - - inst = *(uint32*)gobuf->pc; - if((gobuf->pc&3) == 0 && (inst>>24) == 0x4b && (inst&3) == 0) { - //runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>8)); - gobuf->pc += (int32)(inst<<8)>>8; - return; - } - runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst); - runtime·throw("runtime: misuse of rewindmorestack"); -} - diff --git a/src/runtime/sys_power64x.go b/src/runtime/sys_power64x.go new file mode 100644 index 0000000000..f32d1a44f1 --- /dev/null +++ b/src/runtime/sys_power64x.go @@ -0,0 +1,37 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build power64 power64le + +package runtime + +import "unsafe" + +// adjust Gobuf as if it executed a call to fn with context ctxt +// and then did an immediate Gosave. +func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) { + if buf.lr != 0 { + gothrow("invalid use of gostartcall") + } + buf.lr = buf.pc + buf.pc = uintptr(fn) + buf.ctxt = ctxt +} + +// Called to rewind context saved during morestack back to beginning of function. +// To help us, the linker emits a jmp back to the beginning right after the +// call to morestack. We just have to decode and apply that jump. +func rewindmorestack(buf *gobuf) { + var inst uint32 + if buf.pc&3 == 0 && buf.pc != 0 { + inst = *(*uint32)(unsafe.Pointer(buf.pc)) + if inst>>24 == 0x4b && inst&3 == 0 { + //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<8)>>8)), "\n"); + buf.pc += uintptr(int32(inst<<8) >> 8) + return + } + } + print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n") + gothrow("runtime: misuse of rewindmorestack") +} -- cgit v1.3-5-g9baa From 70f6769b60de9759f1c74f453f544767574898bc Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:19:48 -0500 Subject: [dev.cc] runtime: catch defs_linux_power64*.go up to other archs Fix a constant conversion error. Add set_{sec,nsec} for timespec and set_usec for timeval. Fix type of sigaltstackt.ss_size. LGTM=rsc R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/180840043 --- src/runtime/defs_linux_power64.go | 16 ++++++++++++++-- src/runtime/defs_linux_power64le.go | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go index df877a67f7..0dfc09caa4 100644 --- a/src/runtime/defs_linux_power64.go +++ b/src/runtime/defs_linux_power64.go @@ -79,7 +79,7 @@ const ( _EPOLLERR = 0x8 _EPOLLHUP = 0x10 _EPOLLRDHUP = 0x2000 - _EPOLLET = -0x80000000 + _EPOLLET = 0x80000000 _EPOLL_CLOEXEC = 0x80000 _EPOLL_CTL_ADD = 0x1 _EPOLL_CTL_DEL = 0x2 @@ -96,11 +96,23 @@ type timespec struct { tv_nsec int64 } +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = x +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + type timeval struct { tv_sec int64 tv_usec int64 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = int64(x) +} + type sigactiont struct { sa_handler uintptr sa_flags uint64 @@ -160,7 +172,7 @@ type sigaltstackt struct { ss_sp *byte ss_flags int32 pad_cgo_0 [4]byte - ss_size uint64 + ss_size uintptr } type sigcontext struct { diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go index df877a67f7..0dfc09caa4 100644 --- a/src/runtime/defs_linux_power64le.go +++ b/src/runtime/defs_linux_power64le.go @@ -79,7 +79,7 @@ const ( _EPOLLERR = 0x8 _EPOLLHUP = 0x10 _EPOLLRDHUP = 0x2000 - _EPOLLET = -0x80000000 + _EPOLLET = 0x80000000 _EPOLL_CLOEXEC = 0x80000 _EPOLL_CTL_ADD = 0x1 _EPOLL_CTL_DEL = 0x2 @@ -96,11 +96,23 @@ type timespec struct { tv_nsec int64 } +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = x +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + type timeval struct { tv_sec int64 tv_usec int64 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = int64(x) +} + type sigactiont struct { sa_handler uintptr sa_flags uint64 @@ -160,7 +172,7 @@ type sigaltstackt struct { ss_sp *byte ss_flags int32 pad_cgo_0 [4]byte - ss_size uint64 + ss_size uintptr } type sigcontext struct { -- cgit v1.3-5-g9baa From f4627d1b05cdc0b9401f6582423f1cbbeadd705a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 18 Nov 2014 15:50:36 -0500 Subject: [dev.cc] runtime: merge power64 onM/onM_signalok into systemstack This is the power64 component of CL 174950043. With this, dev.cc compiles on power64 and power64le and passes most tests if GOGC=off (but crashes in go_bootstrap if GC is on). LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175290043 --- src/runtime/asm_power64x.s | 52 +++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 33 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/asm_power64x.s b/src/runtime/asm_power64x.s index 901dedbe59..3f2ab6d0e6 100644 --- a/src/runtime/asm_power64x.s +++ b/src/runtime/asm_power64x.s @@ -145,58 +145,44 @@ TEXT runtime·mcall(SB), NOSPLIT, $-8-8 BL (CTR) BR runtime·badmcall2(SB) -// switchtoM is a dummy routine that onM leaves at the bottom +// systemstack_switch is a dummy routine that systemstack leaves at the bottom // of the G stack. We need to distinguish the routine that // lives at the bottom of the G stack from the one that lives -// at the top of the M stack because the one at the top of -// the M stack terminates the stack walk (see topofstack()). -TEXT runtime·switchtoM(SB), NOSPLIT, $0-0 +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 UNDEF BL (LR) // make sure this function is not leaf RETURN -// func onM_signalok(fn func()) -TEXT runtime·onM_signalok(SB), NOSPLIT, $8-8 - MOVD g, R3 // R3 = g - MOVD g_m(R3), R4 // R4 = g->m - MOVD m_gsignal(R4), R4 // R4 = g->m->gsignal - MOVD fn+0(FP), R11 // context for call below - CMP R3, R4 - BEQ onsignal - MOVD R11, 8(R1) - BL runtime·onM(SB) - RETURN - -onsignal: - MOVD 0(R11), R3 // code pointer - MOVD R3, CTR - BL (CTR) - RETURN - -// void onM(fn func()) -TEXT runtime·onM(SB), NOSPLIT, $0-8 +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 MOVD fn+0(FP), R3 // R3 = fn MOVD R3, R11 // context MOVD g_m(g), R4 // R4 = m + MOVD m_gsignal(R4), R5 // R5 = gsignal + CMP g, R5 + BEQ noswitch + MOVD m_g0(R4), R5 // R5 = g0 CMP g, R5 - BEQ onm + BEQ noswitch MOVD m_curg(R4), R6 CMP g, R6 - BEQ oncurg + BEQ switch - // Not g0, not curg. Must be gsignal, but that's not allowed. + // Bad: g is not gsignal, not g0, not curg. What is it? // Hide call from linker nosplit analysis. - MOVD $runtime·badonm(SB), R3 + MOVD $runtime·badsystemstack(SB), R3 MOVD R3, CTR BL (CTR) -oncurg: +switch: // save our state in g->sched. Pretend to - // be switchtoM if the G stack is scanned. - MOVD $runtime·switchtoM(SB), R6 + // be systemstack_switch if the G stack is scanned. + MOVD $runtime·systemstack_switch(SB), R6 ADD $8, R6 // get past prologue MOVD R6, (g_sched+gobuf_pc)(g) MOVD R1, (g_sched+gobuf_sp)(g) @@ -206,7 +192,7 @@ oncurg: // switch to g0 MOVD R5, g MOVD (g_sched+gobuf_sp)(g), R3 - // make it look like mstart called onM on g0, to stop traceback + // make it look like mstart called systemstack on g0, to stop traceback SUB $8, R3 MOVD $runtime·mstart(SB), R4 MOVD R4, 0(R3) @@ -224,7 +210,7 @@ oncurg: MOVD R0, (g_sched+gobuf_sp)(g) RETURN -onm: +noswitch: // already on m stack, just call directly MOVD 0(R11), R3 // code pointer MOVD R3, CTR -- cgit v1.3-5-g9baa From b27c0618eb468d9ac322a65bd40db6e829694907 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Wed, 19 Nov 2014 11:55:15 +1100 Subject: [dev.cc] runtime: update sys_windows_386.s and sys_windows_amd64.s for Go conversion LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/176970043 --- src/runtime/sys_windows_386.s | 16 ++++++++-------- src/runtime/sys_windows_amd64.s | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 2793e52216..c8a830cdf8 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -44,7 +44,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24 // stderr MOVL $-12, 0(SP) MOVL SP, BP - CALL *runtime·GetStdHandle(SB) + CALL *runtime·_GetStdHandle(SB) MOVL BP, SP MOVL AX, 0(SP) // handle @@ -56,7 +56,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24 MOVL $0, 0(DX) MOVL DX, 12(SP) MOVL $0, 16(SP) // overlapped - CALL *runtime·WriteFile(SB) + CALL *runtime·_WriteFile(SB) MOVL BP, SI RET @@ -208,7 +208,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 MOVL BX, g_m(SP) LEAL -8192(SP), CX MOVL CX, (g_stack+stack_lo)(SP) - ADDL $const_StackGuard, CX + ADDL $const__StackGuard, CX MOVL CX, g_stackguard0(SP) MOVL CX, g_stackguard1(SP) MOVL DX, (g_stack+stack_hi)(SP) @@ -255,8 +255,8 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0 MOVL -4(BX)(AX*4), BX // extract callback context - MOVL cbctxt_gobody(BX), AX - MOVL cbctxt_argsize(BX), DX + MOVL wincallbackcontext_gobody(BX), AX + MOVL wincallbackcontext_argsize(BX), DX // preserve whatever's at the memory location that // the callback will use to store the return value @@ -266,7 +266,7 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0 ADDL $4, DX // remember how to restore stack on return - MOVL cbctxt_restorestack(BX), BX + MOVL wincallbackcontext_restorestack(BX), BX PUSHL BX // call target Go function @@ -314,7 +314,7 @@ TEXT runtime·tstart(SB),NOSPLIT,$0 MOVL AX, (g_stack+stack_hi)(DX) SUBL $(64*1024), AX // stack size MOVL AX, (g_stack+stack_lo)(DX) - ADDL $const_StackGuard, AX + ADDL $const__StackGuard, AX MOVL AX, g_stackguard0(DX) MOVL AX, g_stackguard1(DX) @@ -415,7 +415,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20 MOVL $0, alertable-16(SP) MOVL $-1, handle-20(SP) MOVL SP, BP - MOVL runtime·NtWaitForSingleObject(SB), AX + MOVL runtime·_NtWaitForSingleObject(SB), AX CALL AX MOVL BP, SP RET diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 5e5c2e7f5a..68f7cd3924 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -66,7 +66,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48 // stderr MOVQ $-12, CX // stderr MOVQ CX, 0(SP) - MOVQ runtime·GetStdHandle(SB), AX + MOVQ runtime·_GetStdHandle(SB), AX CALL AX MOVQ AX, CX // handle @@ -79,7 +79,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48 MOVQ $0, 0(R9) MOVQ R9, 24(SP) MOVQ $0, 32(SP) // overlapped - MOVQ runtime·WriteFile(SB), AX + MOVQ runtime·_WriteFile(SB), AX CALL AX RET @@ -245,7 +245,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 LEAQ -8192(SP), CX MOVQ CX, (g_stack+stack_lo)(SP) - ADDQ $const_StackGuard, CX + ADDQ $const__StackGuard, CX MOVQ CX, g_stackguard0(SP) MOVQ CX, g_stackguard1(SP) MOVQ DX, (g_stack+stack_hi)(SP) @@ -294,8 +294,8 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 MOVQ -8(CX)(AX*8), AX // extract callback context - MOVQ cbctxt_argsize(AX), DX - MOVQ cbctxt_gobody(AX), AX + MOVQ wincallbackcontext_argsize(AX), DX + MOVQ wincallbackcontext_gobody(AX), AX // preserve whatever's at the memory location that // the callback will use to store the return value @@ -355,7 +355,7 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 MOVQ AX, (g_stack+stack_hi)(DX) SUBQ $(64*1024), AX // stack size MOVQ AX, (g_stack+stack_lo)(DX) - ADDQ $const_StackGuard, AX + ADDQ $const__StackGuard, AX MOVQ AX, g_stackguard0(DX) MOVQ AX, g_stackguard1(DX) @@ -436,7 +436,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$16 MOVQ BX, (R8) MOVQ $-1, CX // handle MOVQ $0, DX // alertable - MOVQ runtime·NtWaitForSingleObject(SB), AX + MOVQ runtime·_NtWaitForSingleObject(SB), AX CALL AX MOVQ 8(SP), SP RET -- cgit v1.3-5-g9baa From b76e836042dd65b39cfe7af0f8ff5f73f12142a2 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 19 Nov 2014 11:30:58 -0500 Subject: [dev.cc] runtime: allow more address bits in lfstack on Power64 Previously, lfstack assumed Linux limited user space addresses to 43 bits on Power64 based on a paper from 2001. It turns out the limit is now 46 bits, so lfstack was truncating pointers. Raise the limit to 48 bits (for some future proofing and to make it match amd64) and add a self-test that will fail in a useful way if ever unpack(pack(x)) != x. With this change, dev.cc passes all.bash on power64le. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/174430043 --- src/runtime/lfstack.go | 4 ++++ src/runtime/lfstack_linux_power64x.go | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go index 4a20fff9d8..8a36a67b35 100644 --- a/src/runtime/lfstack.go +++ b/src/runtime/lfstack.go @@ -12,6 +12,10 @@ import "unsafe" func lfstackpush(head *uint64, node *lfnode) { node.pushcnt++ new := lfstackPack(node, node.pushcnt) + if node1, _ := lfstackUnpack(new); node1 != node { + println("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n") + gothrow("lfstackpush") + } for { old := atomicload64(head) node.next, _ = lfstackUnpack(old) diff --git a/src/runtime/lfstack_linux_power64x.go b/src/runtime/lfstack_linux_power64x.go index 7a122bf92c..89e389fc72 100644 --- a/src/runtime/lfstack_linux_power64x.go +++ b/src/runtime/lfstack_linux_power64x.go @@ -9,18 +9,24 @@ package runtime import "unsafe" -// On Power64, Linux limits the user address space to 43 bits. -// (https://www.kernel.org/doc/ols/2001/ppc64.pdf) -// In addition to the 21 bits taken from the top, we can take 3 from the -// bottom, because node must be pointer-aligned, giving a total of 24 bits +// On Power64, Linux limits the user address space to 46 bits (see +// TASK_SIZE_USER64 in the Linux kernel). This has grown over time, +// so here we allow 48 bit addresses. +// +// In addition to the 16 bits taken from the top, we can take 3 from the +// bottom, because node must be pointer-aligned, giving a total of 19 bits // of count. +const ( + addrBits = 48 + cntBits = 64 - addrBits + 3 +) func lfstackPack(node *lfnode, cnt uintptr) uint64 { - return uint64(uintptr(unsafe.Pointer(node)))<<21 | uint64(cnt&(1<<24-1)) + return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<> 24 << 3))) - cnt = uintptr(val & (1<<24 - 1)) + node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3))) + cnt = uintptr(val & (1< Date: Wed, 19 Nov 2014 14:24:41 -0500 Subject: [dev.cc] runtime: decode power64 branch instructions the way the CPU does Previously, this used the top 8 bits of an instruction as a sort-of opcode and ignored the top two bits of the relative PC. This worked because these jumps are always negative and never big enough for the top two bits of the relative PC (also the bottom 2 bits of the sort-of opcode) to be anything other than 0b11, but the code is confusing because it doesn't match the actual structure of the instruction. Instead, use the real 6 bit opcode and use all 24 bits of relative PC. LGTM=rsc R=rsc, dave CC=golang-codereviews https://golang.org/cl/179960043 --- src/runtime/sys_power64x.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/sys_power64x.go b/src/runtime/sys_power64x.go index f32d1a44f1..90ebde7b40 100644 --- a/src/runtime/sys_power64x.go +++ b/src/runtime/sys_power64x.go @@ -26,9 +26,9 @@ func rewindmorestack(buf *gobuf) { var inst uint32 if buf.pc&3 == 0 && buf.pc != 0 { inst = *(*uint32)(unsafe.Pointer(buf.pc)) - if inst>>24 == 0x4b && inst&3 == 0 { - //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<8)>>8)), "\n"); - buf.pc += uintptr(int32(inst<<8) >> 8) + if inst>>26 == 18 && inst&3 == 0 { + //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<6)>>6)), "\n"); + buf.pc += uintptr(int32(inst<<6) >> 6) return } } -- cgit v1.3-5-g9baa From f4a525452e1442c08e2a973a5871445258ed0054 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 19 Nov 2014 14:56:49 -0500 Subject: [dev.cc] runtime: add explicit siginfo.si_addr field struct siginfo_t's si_addr field is part of a union. Previously, we represented this union in Go using an opaque byte array and accessed the si_addr field using unsafe (and wrong on 386 and arm!) pointer arithmetic. Since si_addr is the only field we use from this union, this replaces the opaque byte array with an explicit declaration of the si_addr field and accesses it directly. LGTM=minux, rsc R=rsc, minux CC=golang-codereviews https://golang.org/cl/179970044 --- src/runtime/defs_linux_386.go | 9 +++++---- src/runtime/defs_linux_amd64.go | 10 +++++----- src/runtime/defs_linux_arm.go | 9 +++++---- src/runtime/defs_linux_power64.go | 10 +++++----- src/runtime/defs_linux_power64le.go | 10 +++++----- src/runtime/signal_linux_386.go | 2 +- src/runtime/signal_linux_amd64.go | 2 +- src/runtime/signal_linux_arm.go | 2 +- src/runtime/signal_linux_power64x.go | 2 +- 9 files changed, 29 insertions(+), 27 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go index ddf592c91b..f55924b61c 100644 --- a/src/runtime/defs_linux_386.go +++ b/src/runtime/defs_linux_386.go @@ -155,10 +155,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - _sifields [116]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint32 } type sigaltstackt struct { diff --git a/src/runtime/defs_linux_amd64.go b/src/runtime/defs_linux_amd64.go index 7f8f5816c6..a73f475148 100644 --- a/src/runtime/defs_linux_amd64.go +++ b/src/runtime/defs_linux_amd64.go @@ -117,11 +117,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - pad_cgo_0 [4]byte - _sifields [112]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 } type itimerval struct { diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go index a874b15941..c3a6e2f019 100644 --- a/src/runtime/defs_linux_arm.go +++ b/src/runtime/defs_linux_arm.go @@ -147,10 +147,11 @@ type itimerval struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - _sifields [4]uint8 + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint32 } type sigactiont struct { diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go index 0dfc09caa4..f90b84874b 100644 --- a/src/runtime/defs_linux_power64.go +++ b/src/runtime/defs_linux_power64.go @@ -121,11 +121,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - pad_cgo_0 [4]byte - _sifields [112]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 } type itimerval struct { diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go index 0dfc09caa4..f90b84874b 100644 --- a/src/runtime/defs_linux_power64le.go +++ b/src/runtime/defs_linux_power64le.go @@ -121,11 +121,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - pad_cgo_0 [4]byte - _sifields [112]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 } type itimerval struct { diff --git a/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go index 41eae80ea2..085f66e898 100644 --- a/src/runtime/signal_linux_386.go +++ b/src/runtime/signal_linux_386.go @@ -26,7 +26,7 @@ func (c *sigctxt) cs() uint32 { return uint32(c.regs().cs) } func (c *sigctxt) fs() uint32 { return uint32(c.regs().fs) } func (c *sigctxt) gs() uint32 { return uint32(c.regs().gs) } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint32 { return uint32(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr } func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x } func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x } diff --git a/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go index d94b191024..5e339b8a46 100644 --- a/src/runtime/signal_linux_amd64.go +++ b/src/runtime/signal_linux_amd64.go @@ -36,7 +36,7 @@ func (c *sigctxt) cs() uint64 { return uint64(c.regs().cs) } func (c *sigctxt) fs() uint64 { return uint64(c.regs().fs) } func (c *sigctxt) gs() uint64 { return uint64(c.regs().gs) } func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) } -func (c *sigctxt) sigaddr() uint64 { return uint64(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr } func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x } func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x } diff --git a/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go index 4a5670e740..bdb4314fa8 100644 --- a/src/runtime/signal_linux_arm.go +++ b/src/runtime/signal_linux_arm.go @@ -35,7 +35,7 @@ func (c *sigctxt) error() uint32 { return c.regs().error_code } func (c *sigctxt) oldmask() uint32 { return c.regs().oldmask } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint32 { return uint32(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr } func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x } func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x } diff --git a/src/runtime/signal_linux_power64x.go b/src/runtime/signal_linux_power64x.go index 8f357033bf..0a406b31fc 100644 --- a/src/runtime/signal_linux_power64x.go +++ b/src/runtime/signal_linux_power64x.go @@ -56,7 +56,7 @@ func (c *sigctxt) xer() uint64 { return c.regs().xer } func (c *sigctxt) ccr() uint64 { return c.regs().ccr } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint64 { return uint64(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr } func (c *sigctxt) fault() uint64 { return c.regs().dar } func (c *sigctxt) set_r0(x uint64) { c.regs().gpr[0] = x } -- cgit v1.3-5-g9baa From 378c2515aeec0e23662631dc6ba63148594ad92b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 19 Nov 2014 15:25:33 -0500 Subject: runtime: remove assumption that noptrdata data bss noptrbss are ordered and contiguous The assumption can be violated by external linkers reordering them or inserting non-Go sections in between them. I looked briefly at trying to write out the _go_.o in external linking mode in a way that forced the ordering, but no matter what there's no way to force Go's data and Go's bss to be next to each other. If there is any data or bss from non-Go objects, it's very likely to get stuck in between them. Instead, rewrite the two places we know about that make the assumption. I grepped for noptrdata to look for more and didn't find any. The added race test (os/exec in external linking mode) fails without the changes in the runtime. It crashes with an invalid pointer dereference. Fixes #9133. LGTM=dneil R=dneil CC=dvyukov, golang-codereviews, iant https://golang.org/cl/179980043 --- src/run.bash | 5 +++-- src/runtime/malloc.go | 11 +++++++++-- src/runtime/race.c | 44 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 9 deletions(-) (limited to 'src/runtime') diff --git a/src/run.bash b/src/run.bash index 3c9430c87e..9a0e1cb0f2 100755 --- a/src/run.bash +++ b/src/run.bash @@ -70,9 +70,10 @@ case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) echo echo '# Testing race detector.' - go test -race -i runtime/race flag + go test -race -i runtime/race flag os/exec go test -race -run=Output runtime/race - go test -race -short flag + go test -race -short flag os/exec + go test -race -short -ldflags=-linkmode=external flag os/exec esac xcd() { diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 8cf1c3d342..1170449440 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -490,6 +490,8 @@ func GC() { // linker-provided var noptrdata struct{} +var enoptrdata struct{} +var noptrbss struct{} var enoptrbss struct{} // SetFinalizer sets the finalizer associated with x to f. @@ -566,8 +568,13 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { // func main() { // runtime.SetFinalizer(Foo, nil) // } - // The segments are, in order: text, rodata, noptrdata, data, bss, noptrbss. - if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { + // The relevant segments are: noptrdata, data, bss, noptrbss. + // We cannot assume they are in any order or even contiguous, + // due to external linking. + if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) || + uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) || + uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) || + uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { return } gothrow("runtime.SetFinalizer: pointer not in allocated block") diff --git a/src/runtime/race.c b/src/runtime/race.c index 9ac73fbccf..e400c8d102 100644 --- a/src/runtime/race.c +++ b/src/runtime/race.c @@ -63,8 +63,14 @@ void __tsan_go_ignore_sync_end(void); #pragma cgo_import_static __tsan_go_atomic64_compare_exchange extern byte runtime·noptrdata[]; +extern byte runtime·enoptrdata[]; +extern byte runtime·data[]; +extern byte runtime·edata[]; +extern byte runtime·bss[]; +extern byte runtime·ebss[]; +extern byte runtime·noptrbss[]; extern byte runtime·enoptrbss[]; - + // start/end of heap for race_amd64.s uintptr runtime·racearenastart; uintptr runtime·racearenaend; @@ -86,7 +92,13 @@ isvalidaddr(uintptr addr) { if(addr >= runtime·racearenastart && addr < runtime·racearenaend) return true; - if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrbss) + if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrdata) + return true; + if(addr >= (uintptr)runtime·data && addr < (uintptr)runtime·edata) + return true; + if(addr >= (uintptr)runtime·bss && addr < (uintptr)runtime·ebss) + return true; + if(addr >= (uintptr)runtime·noptrbss && addr < (uintptr)runtime·enoptrbss) return true; return false; } @@ -95,15 +107,37 @@ isvalidaddr(uintptr addr) uintptr runtime·raceinit(void) { - uintptr racectx, start, size; + uintptr racectx, start, end, size; // cgo is required to initialize libc, which is used by race runtime if(!runtime·iscgo) runtime·throw("raceinit: race build must use cgo"); runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk); // Round data segment to page boundaries, because it's used in mmap(). - start = (uintptr)runtime·noptrdata & ~(PageSize-1); - size = ROUND((uintptr)runtime·enoptrbss - start, PageSize); + // The relevant sections are noptrdata, data, bss, noptrbss. + // In external linking mode, there may be other non-Go data mixed in, + // and the sections may even occur out of order. + // Work out a conservative range of addresses. + start = ~(uintptr)0; + end = 0; + if(start > (uintptr)runtime·noptrdata) + start = (uintptr)runtime·noptrdata; + if(start > (uintptr)runtime·data) + start = (uintptr)runtime·data; + if(start > (uintptr)runtime·noptrbss) + start = (uintptr)runtime·noptrbss; + if(start > (uintptr)runtime·bss) + start = (uintptr)runtime·bss; + if(end < (uintptr)runtime·enoptrdata) + end = (uintptr)runtime·enoptrdata; + if(end < (uintptr)runtime·edata) + end = (uintptr)runtime·edata; + if(end < (uintptr)runtime·enoptrbss) + end = (uintptr)runtime·enoptrbss; + if(end < (uintptr)runtime·ebss) + end = (uintptr)runtime·ebss; + start = start & ~(PageSize-1); + size = ROUND(end - start, PageSize); runtime·racecall(__tsan_map_shadow, start, size); return racectx; } -- cgit v1.3-5-g9baa From ab4578adefd216a6753728b5503ff22fae4ab60b Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 20 Nov 2014 12:24:03 +1100 Subject: [dev.cc] runtime: convert remaining windows C code to Go LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/177090043 --- src/runtime/netpoll_windows.go | 2 +- src/runtime/os1_windows.go | 564 ++++++++++++++++++++++++++++++++++ src/runtime/os1_windows_386.go | 118 ++++++++ src/runtime/os1_windows_amd64.go | 137 +++++++++ src/runtime/os2_windows.go | 25 ++ src/runtime/os_windows.c | 636 --------------------------------------- src/runtime/os_windows.go | 16 - src/runtime/os_windows.h | 42 --- src/runtime/os_windows_386.c | 128 -------- src/runtime/os_windows_amd64.c | 150 --------- src/runtime/stubs2.go | 1 + src/runtime/syscall_windows.go | 18 +- 12 files changed, 853 insertions(+), 984 deletions(-) create mode 100644 src/runtime/os1_windows.go create mode 100644 src/runtime/os1_windows_386.go create mode 100644 src/runtime/os1_windows_amd64.go create mode 100644 src/runtime/os2_windows.go delete mode 100644 src/runtime/os_windows.c delete mode 100644 src/runtime/os_windows.h delete mode 100644 src/runtime/os_windows_386.c delete mode 100644 src/runtime/os_windows_amd64.c (limited to 'src/runtime') diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go index 8a15f182cd..23d5dc00f0 100644 --- a/src/runtime/netpoll_windows.go +++ b/src/runtime/netpoll_windows.go @@ -152,5 +152,5 @@ func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) { } op.errno = errno op.qty = qty - netpollready(gpp, op.pd, mode) + netpollready((**g)(noescape(unsafe.Pointer(gpp))), op.pd, mode) } diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go new file mode 100644 index 0000000000..abd2297a30 --- /dev/null +++ b/src/runtime/os1_windows.go @@ -0,0 +1,564 @@ +// 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" +) + +//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" +//go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll" +//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll" +//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom "advapi32.dll" +//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext "advapi32.dll" +//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._ExitProcess ExitProcess "kernel32.dll" +//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" +//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" +//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll" +//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll" +//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll" +//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW "kernel32.dll" +//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA "kernel32.dll" +//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" +//go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll" +//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" +//go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll" +//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" +//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll" +//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" +//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll" +//go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll" +//go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll" +//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll" +//go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll" +//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll" + +var ( + _AddVectoredExceptionHandler, + _CloseHandle, + _CreateEventA, + _CreateThread, + _CreateWaitableTimerA, + _CryptAcquireContextW, + _CryptGenRandom, + _CryptReleaseContext, + _DuplicateHandle, + _ExitProcess, + _FreeEnvironmentStringsW, + _GetEnvironmentStringsW, + _GetProcAddress, + _GetStdHandle, + _GetSystemInfo, + _GetThreadContext, + _LoadLibraryW, + _LoadLibraryA, + _NtWaitForSingleObject, + _ResumeThread, + _SetConsoleCtrlHandler, + _SetEvent, + _SetProcessPriorityBoost, + _SetThreadPriority, + _SetUnhandledExceptionFilter, + _SetWaitableTimer, + _Sleep, + _SuspendThread, + _WaitForSingleObject, + _WriteFile, + _timeBeginPeriod stdFunction +) + +var _GetQueuedCompletionStatusEx stdFunction + +// in sys_windows_386.s and sys_windows_amd64.s +func externalthreadhandler() +func exceptiontramp() +func firstcontinuetramp() +func lastcontinuetramp() + +//go:nosplit +func getLoadLibrary() uintptr { + return uintptr(unsafe.Pointer(_LoadLibraryW)) +} + +//go:nosplit +func getGetProcAddress() uintptr { + return uintptr(unsafe.Pointer(_GetProcAddress)) +} + +func getproccount() int32 { + var info systeminfo + stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) + return int32(info.dwnumberofprocessors) +} + +const ( + currentProcess = ^uintptr(0) // -1 = current process + currentThread = ^uintptr(1) // -2 = current thread +) + +var ( + kernel32Name = []byte("kernel32.dll\x00") + addVectoredContinueHandlerName = []byte("AddVectoredContinueHandler\x00") + getQueuedCompletionStatusExName = []byte("GetQueuedCompletionStatusEx\x00") +) + +func osinit() { + setBadSignalMsg() + + kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0]))) + + externalthreadhandlerp = funcPC(externalthreadhandler) + + stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp)) + addVectoredContinueHandler := uintptr(0) + if kernel32 != 0 { + addVectoredContinueHandler = stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&addVectoredContinueHandlerName[0]))) + } + if addVectoredContinueHandler == 0 || unsafe.Sizeof(&kernel32) == 4 { + // use SetUnhandledExceptionFilter for windows-386 or + // if VectoredContinueHandler is unavailable. + // note: SetUnhandledExceptionFilter handler won't be called, if debugging. + stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp)) + } else { + stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 1, funcPC(firstcontinuetramp)) + stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 0, funcPC(lastcontinuetramp)) + } + + stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) + + stdcall1(_timeBeginPeriod, 1) + + ncpu = getproccount() + + // Windows dynamic priority boosting assumes that a process has different types + // of dedicated threads -- GUI, IO, computational, etc. Go processes use + // equivalent threads that all do a mix of GUI, IO, computations, etc. + // In such context dynamic priority boosting does nothing but harm, so we turn it off. + stdcall2(_SetProcessPriorityBoost, currentProcess, 1) + + if kernel32 != 0 { + _GetQueuedCompletionStatusEx = stdFunction(unsafe.Pointer(stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&getQueuedCompletionStatusExName[0]))))) + } +} + +var random_data [_HashRandomBytes]byte + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + const ( + prov_rsa_full = 1 + crypt_verifycontext = 0xF0000000 + ) + var handle uintptr + *rnd = nil + *rnd_len = 0 + if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 { + if stdcall3(_CryptGenRandom, handle, _HashRandomBytes, uintptr(unsafe.Pointer(&random_data[0]))) != 0 { + *rnd = unsafe.Pointer(&random_data[0]) + *rnd_len = _HashRandomBytes + } + stdcall2(_CryptReleaseContext, handle, 0) + } +} + +func goenvs() { + var p *uint16 + + env := (*uint16)(unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))) + + n := 0 + for p = env; *p != 0; n++ { + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + } + + envs = makeStringSlice(int(n)) + + p = env + for i := 0; i < n; i++ { + envs[i] = gostringw(p) + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + } + + stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env))) +} + +//go:nosplit +func exit(code int32) { + stdcall1(_ExitProcess, uintptr(code)) +} + +//go:nosplit +func write(fd uintptr, buf unsafe.Pointer, n int32) int32 { + const ( + _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 + _STD_ERROR_HANDLE = ^uintptr(11) // -12 + ) + var handle uintptr + switch fd { + case 1: + handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) + case 2: + handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) + default: + // assume fd is real windows handle. + handle = fd + } + var written uint32 + stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) + return int32(written) +} + +//go:nosplit +func semasleep(ns int64) int32 { + // store ms in ns to save stack space + if ns < 0 { + ns = _INFINITE + } else { + ns = int64(timediv(ns, 1000000, nil)) + if ns == 0 { + ns = 1 + } + } + if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 { + return -1 // timeout + } + return 0 +} + +//go:nosplit +func semawakeup(mp *m) { + stdcall1(_SetEvent, mp.waitsema) +} + +//go:nosplit +func semacreate() uintptr { + return stdcall4(_CreateEventA, 0, 0, 0, 0) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 + thandle := stdcall6(_CreateThread, 0, 0x20000, + funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), + _STACK_SIZE_PARAM_IS_A_RESERVATION, 0) + if thandle == 0 { + println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")") + gothrow("runtime.newosproc") + } +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + var thandle uintptr + stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) + atomicstoreuintptr(&getg().m.thread, thandle) +} + +// Called from dropm to undo the effect of an minit. +func unminit() { + tp := &getg().m.thread + stdcall1(_CloseHandle, *tp) + *tp = 0 +} + +// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ +type _KSYSTEM_TIME struct { + LowPart uint32 + High1Time int32 + High2Time int32 +} + +const ( + _INTERRUPT_TIME = 0x7ffe0008 + _SYSTEM_TIME = 0x7ffe0014 +) + +//go:nosplit +func systime(addr uintptr) int64 { + timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr)) + + var t _KSYSTEM_TIME + for i := 1; i < 10000; i++ { + // these fields must be read in that order (see URL above) + t.High1Time = timeaddr.High1Time + t.LowPart = timeaddr.LowPart + t.High2Time = timeaddr.High2Time + if t.High1Time == t.High2Time { + return int64(t.High1Time)<<32 | int64(t.LowPart) + } + if (i % 100) == 0 { + osyield() + } + } + systemstack(func() { + gothrow("interrupt/system time is changing too fast") + }) + return 0 +} + +//go:nosplit +func unixnano() int64 { + return (systime(_SYSTEM_TIME) - 116444736000000000) * 100 +} + +//go:nosplit +func nanotime() int64 { + return systime(_INTERRUPT_TIME) * 100 +} + +// Calling stdcall on os stack. +//go:nosplit +func stdcall(fn stdFunction) uintptr { + gp := getg() + mp := gp.m + mp.libcall.fn = uintptr(unsafe.Pointer(fn)) + + if mp.profilehz != 0 { + // leave pc/sp for cpu profiler + mp.libcallg = gp + mp.libcallpc = getcallerpc(unsafe.Pointer(&fn)) + // sp must be the last, because once async cpu profiler finds + // all three values to be non-zero, it will use them + mp.libcallsp = getcallersp(unsafe.Pointer(&fn)) + } + asmcgocall(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&mp.libcall)) + mp.libcallsp = 0 + return mp.libcall.r1 +} + +//go:nosplit +func stdcall0(fn stdFunction) uintptr { + mp := getg().m + mp.libcall.n = 0 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes + return stdcall(fn) +} + +//go:nosplit +func stdcall1(fn stdFunction, a0 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 1 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 2 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 3 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 4 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 5 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 6 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 7 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +// in sys_windows_386.s and sys_windows_amd64.s +func usleep1(usec uint32) + +//go:nosplit +func osyield() { + usleep1(1) +} + +//go:nosplit +func usleep(us uint32) { + // Have 1us units; want 100ns units. + usleep1(10 * us) +} + +func issigpanic(code uint32) uint32 { + switch code { + default: + return 0 + case _EXCEPTION_ACCESS_VIOLATION: + case _EXCEPTION_INT_DIVIDE_BY_ZERO: + case _EXCEPTION_INT_OVERFLOW: + case _EXCEPTION_FLT_DENORMAL_OPERAND: + case _EXCEPTION_FLT_DIVIDE_BY_ZERO: + case _EXCEPTION_FLT_INEXACT_RESULT: + case _EXCEPTION_FLT_OVERFLOW: + case _EXCEPTION_FLT_UNDERFLOW: + case _EXCEPTION_BREAKPOINT: + } + return 1 +} + +func initsig() { + /* + // TODO(brainman): I don't think we need that bit of code + // following line keeps these functions alive at link stage + // if there's a better way please write it here + void *e = runtime·exceptiontramp; + void *f = runtime·firstcontinuetramp; + void *l = runtime·lastcontinuetramp; + USED(e); + USED(f); + USED(l); + */ +} + +func ctrlhandler1(_type uint32) uint32 { + var s uint32 + + switch _type { + case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: + s = _SIGINT + default: + return 0 + } + + if sigsend(s) { + return 1 + } + exit(2) // SIGINT, SIGTERM, etc + return 0 +} + +// in sys_windows_386.s and sys_windows_amd64.s +func profileloop() + +var profiletimer uintptr + +func profilem(mp *m) { + var r *context + rbuf := make([]byte, unsafe.Sizeof(*r)+15) + + tls := &mp.tls[0] + if mp == &m0 { + tls = &tls0[0] + } + gp := *((**g)(unsafe.Pointer(tls))) + + // align Context to 16 bytes + r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) + r.contextflags = _CONTEXT_CONTROL + stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r))) + dosigprof(r, gp, mp) +} + +func profileloop1() { + stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) + + for { + stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) + first := (*m)(atomicloadp(unsafe.Pointer(&allm))) + for mp := first; mp != nil; mp = mp.alllink { + thread := atomicloaduintptr(&mp.thread) + // Do not profile threads blocked on Notes, + // this includes idle worker threads, + // idle timer thread, idle heap scavenger, etc. + if thread == 0 || mp.profilehz == 0 || mp.blocked { + continue + } + stdcall1(_SuspendThread, thread) + if mp.profilehz != 0 && !mp.blocked { + profilem(mp) + } + stdcall1(_ResumeThread, thread) + } + } +} + +var cpuprofilerlock mutex + +func resetcpuprofiler(hz int32) { + lock(&cpuprofilerlock) + if profiletimer == 0 { + timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) + atomicstoreuintptr(&profiletimer, timer) + thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) + stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) + stdcall1(_CloseHandle, thread) + } + unlock(&cpuprofilerlock) + + ms := int32(0) + due := ^int64(^uint64(1 << 63)) + if hz > 0 { + ms = 1000 / hz + if ms == 0 { + ms = 1 + } + due = int64(ms) * -10000 + } + stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) + atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) +} + +func memlimit() uintptr { + return 0 +} + +var ( + badsignalmsg [100]byte + badsignallen int32 +) + +func setBadSignalMsg() { + const msg = "runtime: signal received on thread not created by Go.\n" + for i, c := range msg { + badsignalmsg[i] = byte(c) + badsignallen++ + } +} + +func crash() { + // TODO: This routine should do whatever is needed + // to make the Windows program abort/crash as it + // would if Go was not intercepting signals. + // On Unix the routine would remove the custom signal + // handler and then raise a signal (like SIGABRT). + // Something like that should happen here. + // It's okay to leave this empty for now: if crash returns + // the ordinary exit-after-panic happens. +} diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go new file mode 100644 index 0000000000..0afef91566 --- /dev/null +++ b/src/runtime/os1_windows_386.go @@ -0,0 +1,118 @@ +// 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" +) + +var text struct{} + +func dumpregs(r *context) { + print("eax ", hex(r.eax), "\n") + print("ebx ", hex(r.ebx), "\n") + print("ecx ", hex(r.ecx), "\n") + print("edx ", hex(r.edx), "\n") + print("edi ", hex(r.edi), "\n") + print("esi ", hex(r.esi), "\n") + print("ebp ", hex(r.ebp), "\n") + print("esp ", hex(r.esp), "\n") + print("eip ", hex(r.eip), "\n") + print("eflags ", hex(r.eflags), "\n") + print("cs ", hex(r.segcs), "\n") + print("fs ", hex(r.segfs), "\n") + print("gs ", hex(r.seggs), "\n") +} + +func isgoexception(info *exceptionrecord, r *context) bool { + // Only handle exception if executing instructions in Go binary + // (not Windows library code). + if r.eip < uint32(uintptr(unsafe.Pointer(&text))) || uint32(uintptr(unsafe.Pointer(&etext))) < r.eip { + return false + } + + if issigpanic(info.exceptioncode) == 0 { + return false + } + + return true +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). +func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = info.exceptioncode + gp.sigcode0 = uintptr(info.exceptioninformation[0]) + gp.sigcode1 = uintptr(info.exceptioninformation[1]) + gp.sigpc = uintptr(r.eip) + + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if r.eip != 0 { + sp := unsafe.Pointer(uintptr(r.esp)) + sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp-- + *((*uintptr)(sp)) = uintptr(r.eip) + r.esp = uint32(uintptr(sp)) + } + r.eip = uint32(funcPC(sigpanic)) + return _EXCEPTION_CONTINUE_EXECUTION +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 { + _g_ := getg() + + if panicking != 0 { // traceback already printed + exit(2) + } + panicking = 1 + + print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.eip), "\n") + + print("PC=", hex(r.eip), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + tracebacktrap(uintptr(r.eip), uintptr(r.esp), 0, gp) + tracebackothers(gp) + dumpregs(r) + } + + if docrash { + crash() + } + + exit(2) + return 0 // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func dosigprof(r *context, gp *g, mp *m) { + sigprof((*byte)(unsafe.Pointer(uintptr(r.eip))), (*byte)(unsafe.Pointer(uintptr(r.esp))), nil, gp, mp) +} diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go new file mode 100644 index 0000000000..0d21b38812 --- /dev/null +++ b/src/runtime/os1_windows_amd64.go @@ -0,0 +1,137 @@ +// Copyright 2011 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" +) + +var text struct{} + +func dumpregs(r *context) { + print("rax ", hex(r.rax), "\n") + print("rbx ", hex(r.rbx), "\n") + print("rcx ", hex(r.rcx), "\n") + print("rdi ", hex(r.rdi), "\n") + print("rsi ", hex(r.rsi), "\n") + print("rbp ", hex(r.rbp), "\n") + print("rsp ", hex(r.rsp), "\n") + print("r8 ", hex(r.r8), "\n") + print("r9 ", hex(r.r9), "\n") + print("r10 ", hex(r.r10), "\n") + print("r11 ", hex(r.r11), "\n") + print("r12 ", hex(r.r12), "\n") + print("r13 ", hex(r.r13), "\n") + print("r14 ", hex(r.r14), "\n") + print("r15 ", hex(r.r15), "\n") + print("rip ", hex(r.rip), "\n") + print("rflags ", hex(r.eflags), "\n") + print("cs ", hex(r.segcs), "\n") + print("fs ", hex(r.segfs), "\n") + print("gs ", hex(r.seggs), "\n") +} + +func isgoexception(info *exceptionrecord, r *context) bool { + // Only handle exception if executing instructions in Go binary + // (not Windows library code). + if r.rip < uint64(uintptr(unsafe.Pointer(&text))) || uint64(uintptr(unsafe.Pointer(&etext))) < r.rip { + return false + } + + if issigpanic(info.exceptioncode) == 0 { + return false + } + + return true +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). + +func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = info.exceptioncode + gp.sigcode0 = uintptr(info.exceptioninformation[0]) + gp.sigcode1 = uintptr(info.exceptioninformation[1]) + gp.sigpc = uintptr(r.rip) + + // Only push runtime·sigpanic if r->rip != 0. + // If r->rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if r.rip != 0 { + sp := unsafe.Pointer(uintptr(r.rsp)) + sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp-- + *((*uintptr)(sp)) = uintptr(r.rip) + r.rsp = uint64(uintptr(sp)) + } + r.rip = uint64(funcPC(sigpanic)) + return _EXCEPTION_CONTINUE_EXECUTION +} + +// It seems Windows searches ContinueHandler's list even +// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. +// firstcontinuehandler will stop that search, +// if exceptionhandler did the same earlier. +func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + return _EXCEPTION_CONTINUE_EXECUTION +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 { + _g_ := getg() + + if panicking != 0 { // traceback already printed + exit(2) + } + panicking = 1 + + print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.rip), "\n") + + print("PC=", hex(r.rip), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + tracebacktrap(uintptr(r.rip), uintptr(r.rsp), 0, gp) + tracebackothers(gp) + dumpregs(r) + } + + if docrash { + crash() + } + + exit(2) + return 0 // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func dosigprof(r *context, gp *g, mp *m) { + sigprof((*byte)(unsafe.Pointer(uintptr(r.rip))), (*byte)(unsafe.Pointer(uintptr(r.rsp))), nil, gp, mp) +} diff --git a/src/runtime/os2_windows.go b/src/runtime/os2_windows.go new file mode 100644 index 0000000000..d5b1f471fc --- /dev/null +++ b/src/runtime/os2_windows.go @@ -0,0 +1,25 @@ +// 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" + +// Call a Windows function with stdcall conventions, +// and switch to os stack during the call. +func asmstdcall(fn unsafe.Pointer) + +func getlasterror() uint32 +func setlasterror(err uint32) + +// Function to be called by windows CreateThread +// to start new os thread. +func tstart_stdcall(newm *m) uint32 + +func ctrlhandler(_type uint32) uint32 + +// TODO(brainman): should not need those +const ( + _NSIG = 65 +) diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c deleted file mode 100644 index b8b8eda5f3..0000000000 --- a/src/runtime/os_windows.c +++ /dev/null @@ -1,636 +0,0 @@ -// 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. - -#include "runtime.h" -#include "type.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "textflag.h" -#include "arch_GOARCH.h" -#include "malloc.h" - -#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" -#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" -#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" -#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" -#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll" -#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll" -#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll" -#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll" -#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll" -#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll" -#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" -#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll" -#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll" -#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll" -#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll" -#pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll" -#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" -#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll" -#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" -#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" -#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" -#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" -#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" -#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" -#pragma dynimport runtime·Sleep Sleep "kernel32.dll" -#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" -#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" -#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll" -#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" - -extern void *runtime·AddVectoredExceptionHandler; -extern void *runtime·CloseHandle; -extern void *runtime·CreateEvent; -extern void *runtime·CreateThread; -extern void *runtime·CreateWaitableTimer; -extern void *runtime·CryptAcquireContextW; -extern void *runtime·CryptGenRandom; -extern void *runtime·CryptReleaseContext; -extern void *runtime·DuplicateHandle; -extern void *runtime·ExitProcess; -extern void *runtime·FreeEnvironmentStringsW; -extern void *runtime·GetEnvironmentStringsW; -extern void *runtime·GetProcAddress; -extern void *runtime·GetStdHandle; -extern void *runtime·GetSystemInfo; -extern void *runtime·GetThreadContext; -extern void *runtime·LoadLibrary; -extern void *runtime·LoadLibraryA; -extern void *runtime·NtWaitForSingleObject; -extern void *runtime·ResumeThread; -extern void *runtime·SetConsoleCtrlHandler; -extern void *runtime·SetEvent; -extern void *runtime·SetProcessPriorityBoost; -extern void *runtime·SetThreadPriority; -extern void *runtime·SetUnhandledExceptionFilter; -extern void *runtime·SetWaitableTimer; -extern void *runtime·Sleep; -extern void *runtime·SuspendThread; -extern void *runtime·WaitForSingleObject; -extern void *runtime·WriteFile; -extern void *runtime·timeBeginPeriod; - -#pragma dataflag NOPTR -void *runtime·GetQueuedCompletionStatusEx; - -extern uintptr runtime·externalthreadhandlerp; -void runtime·externalthreadhandler(void); -void runtime·exceptiontramp(void); -void runtime·firstcontinuetramp(void); -void runtime·lastcontinuetramp(void); - -#pragma textflag NOSPLIT -uintptr -runtime·getLoadLibrary(void) -{ - return (uintptr)runtime·LoadLibrary; -} - -#pragma textflag NOSPLIT -uintptr -runtime·getGetProcAddress(void) -{ - return (uintptr)runtime·GetProcAddress; -} - -static int32 -getproccount(void) -{ - SystemInfo info; - - runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info); - return info.dwNumberOfProcessors; -} - -void -runtime·osinit(void) -{ - void *kernel32; - void *addVectoredContinueHandler; - - kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); - - runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler; - - runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp); - addVectoredContinueHandler = nil; - if(kernel32 != nil) - addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler"); - if(addVectoredContinueHandler == nil || sizeof(void*) == 4) { - // use SetUnhandledExceptionFilter for windows-386 or - // if VectoredContinueHandler is unavailable. - // note: SetUnhandledExceptionFilter handler won't be called, if debugging. - runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp); - } else { - runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp); - runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp); - } - - runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1); - - runtime·stdcall1(runtime·timeBeginPeriod, 1); - - runtime·ncpu = getproccount(); - - // Windows dynamic priority boosting assumes that a process has different types - // of dedicated threads -- GUI, IO, computational, etc. Go processes use - // equivalent threads that all do a mix of GUI, IO, computations, etc. - // In such context dynamic priority boosting does nothing but harm, so we turn it off. - runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1); - - if(kernel32 != nil) { - runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx"); - } -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - uintptr handle; - *rnd = nil; - *rnd_len = 0; - if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil, - 1 /* PROV_RSA_FULL */, - 0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) { - static byte random_data[HashRandomBytes]; - if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) { - *rnd = random_data; - *rnd_len = HashRandomBytes; - } - runtime·stdcall2(runtime·CryptReleaseContext, handle, 0); - } -} - -void -runtime·goenvs(void) -{ - extern Slice runtime·envs; - - uint16 *env; - String *s; - int32 i, n; - uint16 *p; - - env = runtime·stdcall0(runtime·GetEnvironmentStringsW); - - n = 0; - for(p=env; *p; n++) - p += runtime·findnullw(p)+1; - - runtime·envs = runtime·makeStringSlice(n); - s = (String*)runtime·envs.array; - - p = env; - for(i=0; im->waitsema, ns) != 0) - return -1; // timeout - return 0; -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - runtime·stdcall1(runtime·SetEvent, mp->waitsema); -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0); -} - -#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000) - -void -runtime·newosproc(M *mp, void *stk) -{ - void *thandle; - - USED(stk); - - thandle = runtime·stdcall6(runtime·CreateThread, - (uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp, - STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)nil); - if(thandle == nil) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); - runtime·throw("runtime.newosproc"); - } -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - USED(mp); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - uintptr thandle; - - // -1 = current process, -2 = current thread - runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS); - runtime·atomicstoreuintptr(&g->m->thread, thandle); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·stdcall1(runtime·CloseHandle, g->m->thread); - g->m->thread = 0; -} - -// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ -typedef struct KSYSTEM_TIME { - uint32 LowPart; - int32 High1Time; - int32 High2Time; -} KSYSTEM_TIME; - -#pragma dataflag NOPTR -const KSYSTEM_TIME* INTERRUPT_TIME = (KSYSTEM_TIME*)0x7ffe0008; -#pragma dataflag NOPTR -const KSYSTEM_TIME* SYSTEM_TIME = (KSYSTEM_TIME*)0x7ffe0014; - -static void badsystime(void); - -#pragma textflag NOSPLIT -int64 -runtime·systime(KSYSTEM_TIME *timeaddr) -{ - KSYSTEM_TIME t; - int32 i; - void (*fn)(void); - - for(i = 1; i < 10000; i++) { - // these fields must be read in that order (see URL above) - t.High1Time = timeaddr->High1Time; - t.LowPart = timeaddr->LowPart; - t.High2Time = timeaddr->High2Time; - if(t.High1Time == t.High2Time) - return (int64)t.High1Time<<32 | t.LowPart; - if((i%100) == 0) - runtime·osyield(); - } - fn = badsystime; - runtime·onM(&fn); - return 0; -} - -#pragma textflag NOSPLIT -int64 -runtime·unixnano(void) -{ - return (runtime·systime(SYSTEM_TIME) - 116444736000000000LL) * 100LL; -} - -static void -badsystime(void) -{ - runtime·throw("interrupt/system time is changing too fast"); -} - -#pragma textflag NOSPLIT -int64 -runtime·nanotime(void) -{ - return runtime·systime(INTERRUPT_TIME) * 100LL; -} - -// Calling stdcall on os stack. -#pragma textflag NOSPLIT -static void* -stdcall(void *fn) -{ - g->m->libcall.fn = (uintptr)fn; - if(g->m->profilehz != 0) { - // leave pc/sp for cpu profiler - g->m->libcallg = g; - g->m->libcallpc = (uintptr)runtime·getcallerpc(&fn); - // sp must be the last, because once async cpu profiler finds - // all three values to be non-zero, it will use them - g->m->libcallsp = (uintptr)runtime·getcallersp(&fn); - } - runtime·asmcgocall(runtime·asmstdcall, &g->m->libcall); - g->m->libcallsp = 0; - return (void*)g->m->libcall.r1; -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall0(void *fn) -{ - g->m->libcall.n = 0; - g->m->libcall.args = (uintptr)&fn; // it's unused but must be non-nil, otherwise crashes - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall1(void *fn, uintptr a0) -{ - USED(a0); - g->m->libcall.n = 1; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall2(void *fn, uintptr a0, uintptr a1) -{ - USED(a0, a1); - g->m->libcall.n = 2; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2) -{ - USED(a0, a1, a2); - g->m->libcall.n = 3; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3) -{ - USED(a0, a1, a2, a3); - g->m->libcall.n = 4; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4) -{ - USED(a0, a1, a2, a3, a4); - g->m->libcall.n = 5; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5) -{ - USED(a0, a1, a2, a3, a4, a5); - g->m->libcall.n = 6; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6) -{ - USED(a0, a1, a2, a3, a4, a5, a6); - g->m->libcall.n = 7; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -extern void runtime·usleep1(uint32); - -#pragma textflag NOSPLIT -void -runtime·osyield(void) -{ - runtime·usleep1(1); -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 us) -{ - // Have 1us units; want 100ns units. - runtime·usleep1(10*us); -} - -uint32 -runtime·issigpanic(uint32 code) -{ - switch(code) { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_BREAKPOINT: - return 1; - } - return 0; -} - -void -runtime·initsig(void) -{ - // following line keeps these functions alive at link stage - // if there's a better way please write it here - void *e = runtime·exceptiontramp; - void *f = runtime·firstcontinuetramp; - void *l = runtime·lastcontinuetramp; - USED(e); - USED(f); - USED(l); -} - -uint32 -runtime·ctrlhandler1(uint32 type) -{ - int32 s; - - switch(type) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - s = SIGINT; - break; - default: - return 0; - } - - if(runtime·sigsend(s)) - return 1; - runtime·exit(2); // SIGINT, SIGTERM, etc - return 0; -} - -extern void runtime·dosigprof(Context *r, G *gp, M *mp); -extern void runtime·profileloop(void); -#pragma dataflag NOPTR -static void *profiletimer; - -static void -profilem(M *mp) -{ - extern M runtime·m0; - extern uint32 runtime·tls0[]; - byte rbuf[sizeof(Context)+15]; - Context *r; - void *tls; - G *gp; - - tls = mp->tls; - if(mp == &runtime·m0) - tls = runtime·tls0; - gp = *(G**)tls; - - // align Context to 16 bytes - r = (Context*)((uintptr)(&rbuf[15]) & ~15); - r->ContextFlags = CONTEXT_CONTROL; - runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r); - runtime·dosigprof(r, gp, mp); -} - -void -runtime·profileloop1(void) -{ - M *mp, *allm; - uintptr thread; - - runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST); - - for(;;) { - runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1); - allm = runtime·atomicloadp(&runtime·allm); - for(mp = allm; mp != nil; mp = mp->alllink) { - thread = runtime·atomicloaduintptr(&mp->thread); - // Do not profile threads blocked on Notes, - // this includes idle worker threads, - // idle timer thread, idle heap scavenger, etc. - if(thread == 0 || mp->profilehz == 0 || mp->blocked) - continue; - runtime·stdcall1(runtime·SuspendThread, (uintptr)thread); - if(mp->profilehz != 0 && !mp->blocked) - profilem(mp); - runtime·stdcall1(runtime·ResumeThread, (uintptr)thread); - } - } -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - static Mutex lock; - void *timer, *thread; - int32 ms; - int64 due; - - runtime·lock(&lock); - if(profiletimer == nil) { - timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·atomicstorep(&profiletimer, timer); - thread = runtime·stdcall6(runtime·CreateThread, - (uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·stdcall2(runtime·SetThreadPriority, (uintptr)thread, THREAD_PRIORITY_HIGHEST); - runtime·stdcall1(runtime·CloseHandle, (uintptr)thread); - } - runtime·unlock(&lock); - - ms = 0; - due = 1LL<<63; - if(hz > 0) { - ms = 1000 / hz; - if(ms == 0) - ms = 1; - due = ms * -10000; - } - runtime·stdcall6(runtime·SetWaitableTimer, - (uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·atomicstore((uint32*)&g->m->profilehz, hz); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -#pragma dataflag NOPTR -int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n"; -int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1; - -void -runtime·crash(void) -{ - // TODO: This routine should do whatever is needed - // to make the Windows program abort/crash as it - // would if Go was not intercepting signals. - // On Unix the routine would remove the custom signal - // handler and then raise a signal (like SIGABRT). - // Something like that should happen here. - // It's okay to leave this empty for now: if crash returns - // the ordinary exit-after-panic happens. -} diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index fcd8f44cc4..097b5d6290 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -4,24 +4,8 @@ package runtime -import "unsafe" - type stdFunction *byte -func stdcall0(fn stdFunction) uintptr -func stdcall1(fn stdFunction, a0 uintptr) uintptr -func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr -func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr -func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr -func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr -func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr -func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr - -func asmstdcall(fn unsafe.Pointer) -func getlasterror() uint32 -func setlasterror(err uint32) -func usleep1(usec uint32) - func os_sigpipe() { gothrow("too many writes on closed pipe") } diff --git a/src/runtime/os_windows.h b/src/runtime/os_windows.h deleted file mode 100644 index d5d168d77b..0000000000 --- a/src/runtime/os_windows.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -extern void *runtime·LoadLibrary; -extern void *runtime·GetProcAddress; -extern void *runtime·GetQueuedCompletionStatusEx; - -// Call a Windows function with stdcall conventions, -// and switch to os stack during the call. -void runtime·asmstdcall(void *c); -void *runtime·stdcall0(void *fn); -void *runtime·stdcall1(void *fn, uintptr a0); -void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1); -void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2); -void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3); -void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4); -void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5); -void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6); - -uint32 runtime·getlasterror(void); -void runtime·setlasterror(uint32 err); - -// Function to be called by windows CreateThread -// to start new os thread. -uint32 runtime·tstart_stdcall(M *newm); - -uint32 runtime·issigpanic(uint32); -void runtime·sigpanic(void); -uint32 runtime·ctrlhandler(uint32 type); - -// Windows dll function to go callback entry. -byte *runtime·compilecallback(Eface fn, bool cleanstack); -void *runtime·callbackasm(void); - -void runtime·install_exception_handler(void); -void runtime·remove_exception_handler(void); - -// TODO(brainman): should not need those -enum { - NSIG = 65, -}; diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c deleted file mode 100644 index 9962f0dc2e..0000000000 --- a/src/runtime/os_windows_386.c +++ /dev/null @@ -1,128 +0,0 @@ -// 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *r) -{ - runtime·printf("eax %x\n", r->Eax); - runtime·printf("ebx %x\n", r->Ebx); - runtime·printf("ecx %x\n", r->Ecx); - runtime·printf("edx %x\n", r->Edx); - runtime·printf("edi %x\n", r->Edi); - runtime·printf("esi %x\n", r->Esi); - runtime·printf("ebp %x\n", r->Ebp); - runtime·printf("esp %x\n", r->Esp); - runtime·printf("eip %x\n", r->Eip); - runtime·printf("eflags %x\n", r->EFlags); - runtime·printf("cs %x\n", r->SegCs); - runtime·printf("fs %x\n", r->SegFs); - runtime·printf("gs %x\n", r->SegGs); -} - -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) -{ - extern byte runtime·text[], runtime·etext[]; - - // Only handle exception if executing instructions in Go binary - // (not Windows library code). - if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) - return false; - - if(!runtime·issigpanic(info->ExceptionCode)) - return false; - - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Eip; - - // Only push runtime·sigpanic if r->eip != 0. - // If r->eip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Eip != 0) { - sp = (uintptr*)r->Esp; - *--sp = r->Eip; - r->Esp = (uintptr)sp; - } - r->Eip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode, - (uintptr)info->ExceptionInformation[0], (uintptr)info->ExceptionInformation[1], (uintptr)r->Eip); - - runtime·printf("PC=%x\n", r->Eip); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·tracebacktrap(r->Eip, r->Esp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); - return 0; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp, M *mp) -{ - runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp); -} diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c deleted file mode 100644 index e4617e4cef..0000000000 --- a/src/runtime/os_windows_amd64.c +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2011 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *r) -{ - runtime·printf("rax %X\n", r->Rax); - runtime·printf("rbx %X\n", r->Rbx); - runtime·printf("rcx %X\n", r->Rcx); - runtime·printf("rdx %X\n", r->Rdx); - runtime·printf("rdi %X\n", r->Rdi); - runtime·printf("rsi %X\n", r->Rsi); - runtime·printf("rbp %X\n", r->Rbp); - runtime·printf("rsp %X\n", r->Rsp); - runtime·printf("r8 %X\n", r->R8 ); - runtime·printf("r9 %X\n", r->R9 ); - runtime·printf("r10 %X\n", r->R10); - runtime·printf("r11 %X\n", r->R11); - runtime·printf("r12 %X\n", r->R12); - runtime·printf("r13 %X\n", r->R13); - runtime·printf("r14 %X\n", r->R14); - runtime·printf("r15 %X\n", r->R15); - runtime·printf("rip %X\n", r->Rip); - runtime·printf("rflags %X\n", r->EFlags); - runtime·printf("cs %X\n", (uint64)r->SegCs); - runtime·printf("fs %X\n", (uint64)r->SegFs); - runtime·printf("gs %X\n", (uint64)r->SegGs); -} - -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) -{ - extern byte runtime·text[], runtime·etext[]; - - // Only handle exception if executing instructions in Go binary - // (not Windows library code). - if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) - return false; - - if(!runtime·issigpanic(info->ExceptionCode)) - return false; - - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Rip; - - // Only push runtime·sigpanic if r->rip != 0. - // If r->rip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Rip != 0) { - sp = (uintptr*)r->Rsp; - *--sp = r->Rip; - r->Rsp = (uintptr)sp; - } - r->Rip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// It seems Windows searches ContinueHandler's list even -// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. -// firstcontinuehandler will stop that search, -// if exceptionhandler did the same earlier. -uint32 -runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - USED(gp); - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode, - info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip); - - - runtime·printf("PC=%X\n", r->Rip); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); - return 0; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp, M *mp) -{ - runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp); -} diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index 526b3c5691..cb0b0f0ed5 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // +build !solaris +// +build !windows package runtime diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index efbcab510d..661ee59d7b 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -41,20 +41,20 @@ func callbackasmAddr(i int) uintptr { func compileCallback(fn eface, cleanstack bool) (code uintptr) { if fn._type == nil || (fn._type.kind&kindMask) != kindFunc { - panic("compilecallback: not a function") + panic("compileCallback: not a function") } ft := (*functype)(unsafe.Pointer(fn._type)) - if len(ft.out) != 1 { - panic("compilecallback: function must have one output parameter") + if ft.out.len != 1 { + panic("compileCallback: function must have one output parameter") } uintptrSize := unsafe.Sizeof(uintptr(0)) - if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize { - panic("compilecallback: output parameter size is wrong") + if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize { + panic("compileCallback: output parameter size is wrong") } argsize := uintptr(0) - for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] { + for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] { if (*t).size > uintptrSize { - panic("compilecallback: input parameter size is wrong") + panic("compileCallback: input parameter size is wrong") } argsize += uintptrSize } @@ -87,8 +87,6 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { return callbackasmAddr(n) } -func getLoadLibrary() uintptr - //go:nosplit func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { var c libcall @@ -103,8 +101,6 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { return } -func getGetProcAddress() uintptr - //go:nosplit func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { var c libcall -- cgit v1.3-5-g9baa From 2b3f37908060837f8715c61af110b01b8a590c7c Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 20 Nov 2014 09:51:02 -0500 Subject: runtime: fix atomic operations on non-heap addresses Race detector runtime does not tolerate operations on addresses that was not previously declared with __tsan_map_shadow (namely, data, bss and heap). The corresponding address checks for atomic operations were removed in https://golang.org/cl/111310044 Restore these checks. It's tricker than just not calling into race runtime, because it is the race runtime that makes the atomic operations themselves (if we do not call into race runtime we skip the atomic operation itself as well). So instead we call __tsan_go_ignore_sync_start/end around the atomic operation. This forces race runtime to skip all other processing except than doing the atomic operation itself. Fixes #9136. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/179030043 --- src/runtime/race.c | 13 ++++++------ src/runtime/race/race_unix_test.go | 30 ++++++++++++++++++++++++++ src/runtime/race_amd64.s | 43 ++++++++++++++++++++++++++++++++------ 3 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 src/runtime/race/race_unix_test.go (limited to 'src/runtime') diff --git a/src/runtime/race.c b/src/runtime/race.c index e400c8d102..5b0d116640 100644 --- a/src/runtime/race.c +++ b/src/runtime/race.c @@ -71,6 +71,9 @@ extern byte runtime·ebss[]; extern byte runtime·noptrbss[]; extern byte runtime·enoptrbss[]; +// start/end of global data (data+bss). +uintptr runtime·racedatastart; +uintptr runtime·racedataend; // start/end of heap for race_amd64.s uintptr runtime·racearenastart; uintptr runtime·racearenaend; @@ -92,13 +95,7 @@ isvalidaddr(uintptr addr) { if(addr >= runtime·racearenastart && addr < runtime·racearenaend) return true; - if(addr >= (uintptr)runtime·noptrdata && addr < (uintptr)runtime·enoptrdata) - return true; - if(addr >= (uintptr)runtime·data && addr < (uintptr)runtime·edata) - return true; - if(addr >= (uintptr)runtime·bss && addr < (uintptr)runtime·ebss) - return true; - if(addr >= (uintptr)runtime·noptrbss && addr < (uintptr)runtime·enoptrbss) + if(addr >= runtime·racedatastart && addr < runtime·racedataend) return true; return false; } @@ -139,6 +136,8 @@ runtime·raceinit(void) start = start & ~(PageSize-1); size = ROUND(end - start, PageSize); runtime·racecall(__tsan_map_shadow, start, size); + runtime·racedatastart = start; + runtime·racedataend = start + size; return racectx; } diff --git a/src/runtime/race/race_unix_test.go b/src/runtime/race/race_unix_test.go new file mode 100644 index 0000000000..84f0acece6 --- /dev/null +++ b/src/runtime/race/race_unix_test.go @@ -0,0 +1,30 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build race +// +build darwin freebsd linux + +package race_test + +import ( + "sync/atomic" + "syscall" + "testing" + "unsafe" +) + +// Test that race detector does not crash when accessing non-Go allocated memory (issue 9136). +func TestNonGoMemory(t *testing.T) { + data, err := syscall.Mmap(-1, 0, 4096, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE) + if err != nil { + t.Fatalf("failed to mmap memory: %v", err) + } + p := (*uint32)(unsafe.Pointer(&data[0])) + atomic.AddUint32(p, 1) + (*p)++ + if *p != 2 { + t.Fatalf("data[0] = %v, expect 2", *p) + } + syscall.Munmap(data) +} diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index bdea28c7c0..a96d9de123 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -138,17 +138,15 @@ TEXT racecalladdr<>(SB), NOSPLIT, $0-0 get_tls(R12) MOVQ g(R12), R14 MOVQ g_racectx(R14), RARG0 // goroutine context - // Check that addr is within [arenastart, arenaend) or within [noptrdata, enoptrbss). + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). CMPQ RARG1, runtime·racearenastart(SB) JB racecalladdr_data CMPQ RARG1, runtime·racearenaend(SB) JB racecalladdr_call racecalladdr_data: - MOVQ $runtime·noptrdata(SB), R13 - CMPQ RARG1, R13 + CMPQ RARG1, runtime·racedatastart(SB) JB racecalladdr_ret - MOVQ $runtime·enoptrbss(SB), R13 - CMPQ RARG1, R13 + CMPQ RARG1, runtime·racedataend(SB) JAE racecalladdr_ret racecalladdr_call: MOVQ AX, AX // w/o this 6a miscompiles this function @@ -166,6 +164,7 @@ TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 MOVQ callpc+0(FP), RARG1 // void __tsan_func_enter(ThreadState *thr, void *pc); MOVQ $__tsan_func_enter(SB), AX + // racecall<> preserves R15 CALL racecall<>(SB) MOVQ R15, DX // restore function entry context RET @@ -306,13 +305,45 @@ TEXT sync∕atomic·CompareAndSwapPointer(SB), NOSPLIT, $0-0 TEXT racecallatomic<>(SB), NOSPLIT, $0-0 // Trigger SIGSEGV early. MOVQ 16(SP), R12 - MOVL (R12), R12 + MOVL (R12), R13 + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). + CMPQ R12, runtime·racearenastart(SB) + JB racecallatomic_data + CMPQ R12, runtime·racearenaend(SB) + JB racecallatomic_ok +racecallatomic_data: + CMPQ R12, runtime·racedatastart(SB) + JB racecallatomic_ignore + CMPQ R12, runtime·racedataend(SB) + JAE racecallatomic_ignore +racecallatomic_ok: + // Addr is within the good range, call the atomic function. get_tls(R12) MOVQ g(R12), R14 MOVQ g_racectx(R14), RARG0 // goroutine context MOVQ 8(SP), RARG1 // caller pc MOVQ (SP), RARG2 // pc LEAQ 16(SP), RARG3 // arguments + JMP racecall<>(SB) // does not return +racecallatomic_ignore: + // Addr is outside the good range. + // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op. + // An attempt to synchronize on the address would cause crash. + MOVQ AX, R15 // remember the original function + MOVQ $__tsan_go_ignore_sync_begin(SB), AX + MOVQ g(R12), R14 + MOVQ g_racectx(R14), RARG0 // goroutine context + CALL racecall<>(SB) + MOVQ R15, AX // restore the original function + // Call the atomic function. + MOVQ g_racectx(R14), RARG0 // goroutine context + MOVQ 8(SP), RARG1 // caller pc + MOVQ (SP), RARG2 // pc + LEAQ 16(SP), RARG3 // arguments + CALL racecall<>(SB) + // Call __tsan_go_ignore_sync_end. + MOVQ $__tsan_go_ignore_sync_end(SB), AX + MOVQ g_racectx(R14), RARG0 // goroutine context JMP racecall<>(SB) // void runtime·racecall(void(*f)(...), ...) -- cgit v1.3-5-g9baa From 0a38b2cdaf6bac030b1a3c5a895ce681be40862b Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 21 Nov 2014 12:15:18 +1100 Subject: [dev.cc] runtime: fix windows goenvs conversion mistake uint16 occupies 2 bytes, not 1 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/178100043 --- src/runtime/os1_windows.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go index abd2297a30..57ea050f26 100644 --- a/src/runtime/os1_windows.go +++ b/src/runtime/os1_windows.go @@ -175,7 +175,7 @@ func goenvs() { n := 0 for p = env; *p != 0; n++ { - p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p))) } envs = makeStringSlice(int(n)) @@ -183,7 +183,7 @@ func goenvs() { p = env for i := 0; i < n; i++ { envs[i] = gostringw(p) - p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1))) + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p))) } stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env))) -- cgit v1.3-5-g9baa From 841de809bb9d36ea7949b67857978d35f4fcc2f2 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 21 Nov 2014 15:59:22 +1100 Subject: [dev.cc] runtime: windows does not use _cgo_setenv and _cgo_unsetenv LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/175480043 --- src/runtime/proc.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 50920afe8b..295190cb4e 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -63,11 +63,13 @@ func main() { if _cgo_free == nil { gothrow("_cgo_free missing") } - if _cgo_setenv == nil { - gothrow("_cgo_setenv missing") - } - if _cgo_unsetenv == nil { - gothrow("_cgo_unsetenv missing") + if GOOS != "windows" { + if _cgo_setenv == nil { + gothrow("_cgo_setenv missing") + } + if _cgo_unsetenv == nil { + gothrow("_cgo_unsetenv missing") + } } } -- cgit v1.3-5-g9baa From ad8179281d314663f94358589a8c39ecf644007b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 21 Nov 2014 10:22:18 -0500 Subject: [dev.cc] runtime: convert nacl support to Go LGTM=dave R=minux, dave CC=golang-codereviews https://golang.org/cl/181030043 --- src/runtime/arch1_amd64p32.go | 15 ++ src/runtime/arch_amd64p32.h | 17 -- src/runtime/lfstack_32bit.go | 2 +- src/runtime/mem_bsd.go | 4 +- src/runtime/mem_nacl.c | 120 -------------- src/runtime/os1_nacl.go | 197 +++++++++++++++++++++++ src/runtime/os2_nacl.go | 154 ++++++++++++++++++ src/runtime/os_nacl.c | 312 ------------------------------------ src/runtime/os_nacl.go | 21 ++- src/runtime/os_nacl.h | 162 ------------------- src/runtime/os_nacl_arm.c | 24 --- src/runtime/os_nacl_arm.go | 17 ++ src/runtime/signal_nacl.go | 45 ++++++ src/runtime/signal_nacl_386.go | 34 ++++ src/runtime/signal_nacl_386.h | 23 --- src/runtime/signal_nacl_amd64p32.go | 44 +++++ src/runtime/signal_nacl_amd64p32.h | 31 ---- src/runtime/signal_nacl_arm.go | 47 ++++++ src/runtime/signal_nacl_arm.h | 28 ---- src/runtime/signals_nacl.h | 53 ------ src/runtime/stubs2.go | 1 + 21 files changed, 573 insertions(+), 778 deletions(-) create mode 100644 src/runtime/arch1_amd64p32.go delete mode 100644 src/runtime/arch_amd64p32.h delete mode 100644 src/runtime/mem_nacl.c create mode 100644 src/runtime/os1_nacl.go create mode 100644 src/runtime/os2_nacl.go delete mode 100644 src/runtime/os_nacl.c delete mode 100644 src/runtime/os_nacl.h delete mode 100644 src/runtime/os_nacl_arm.c create mode 100644 src/runtime/os_nacl_arm.go create mode 100644 src/runtime/signal_nacl.go create mode 100644 src/runtime/signal_nacl_386.go delete mode 100644 src/runtime/signal_nacl_386.h create mode 100644 src/runtime/signal_nacl_amd64p32.go delete mode 100644 src/runtime/signal_nacl_amd64p32.h create mode 100644 src/runtime/signal_nacl_arm.go delete mode 100644 src/runtime/signal_nacl_arm.h delete mode 100644 src/runtime/signals_nacl.h (limited to 'src/runtime') diff --git a/src/runtime/arch1_amd64p32.go b/src/runtime/arch1_amd64p32.go new file mode 100644 index 0000000000..2cee21f0ca --- /dev/null +++ b/src/runtime/arch1_amd64p32.go @@ -0,0 +1,15 @@ +// Copyright 2011 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 + +const ( + thechar = '6' + _BigEndian = 0 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl) + _PCQuantum = 1 + _Int64Align = 8 +) diff --git a/src/runtime/arch_amd64p32.h b/src/runtime/arch_amd64p32.h deleted file mode 100644 index d3e8649875..0000000000 --- a/src/runtime/arch_amd64p32.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2011 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. - -enum { - thechar = '6', - BigEndian = 0, - CacheLineSize = 64, - RuntimeGogoBytes = 64, -#ifdef GOOS_nacl - PhysPageSize = 65536, -#else - PhysPageSize = 4096, -#endif - PCQuantum = 1, - Int64Align = 8 -}; diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go index 61d8678d9c..4b8bcbac6a 100644 --- a/src/runtime/lfstack_32bit.go +++ b/src/runtime/lfstack_32bit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build 386 arm +// +build 386 arm nacl package runtime diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go index 4bd40a39fc..e9be5ec8c9 100644 --- a/src/runtime/mem_bsd.go +++ b/src/runtime/mem_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build dragonfly freebsd netbsd openbsd solaris +// +build dragonfly freebsd nacl netbsd openbsd solaris package runtime @@ -38,7 +38,7 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { // On 64-bit, people with ulimit -v set complain if we reserve too // much address space. Instead, assume that the reservation is okay // and check the assumption in SysMap. - if ptrSize == 8 && uint64(n) > 1<<32 { + if ptrSize == 8 && uint64(n) > 1<<32 || goos_nacl != 0 { *reserved = false return v } diff --git a/src/runtime/mem_nacl.c b/src/runtime/mem_nacl.c deleted file mode 100644 index 6c836f18a7..0000000000 --- a/src/runtime/mem_nacl.c +++ /dev/null @@ -1,120 +0,0 @@ -// 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. - -#include "runtime.h" -#include "arch_GOARCH.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "malloc.h" -#include "textflag.h" - -enum -{ - Debug = 0, -}; - -#pragma textflag NOSPLIT -void* -runtime·sysAlloc(uintptr n, uint64 *stat) -{ - void *v; - - v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(v < (void*)4096) { - if(Debug) - runtime·printf("sysAlloc(%p): %p\n", n, v); - return nil; - } - runtime·xadd64(stat, n); - if(Debug) - runtime·printf("sysAlloc(%p) = %p\n", n, v); - return v; -} - -void -runtime·SysUnused(void *v, uintptr n) -{ - if(Debug) - runtime·printf("SysUnused(%p, %p)\n", v, n); -} - -void -runtime·SysUsed(void *v, uintptr n) -{ - USED(v); - USED(n); -} - -void -runtime·SysFree(void *v, uintptr n, uint64 *stat) -{ - if(Debug) - runtime·printf("SysFree(%p, %p)\n", v, n); - runtime·xadd64(stat, -(uint64)n); - runtime·munmap(v, n); -} - -void -runtime·SysFault(void *v, uintptr n) -{ - runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); -} - -void* -runtime·SysReserve(void *v, uintptr n, bool *reserved) -{ - void *p; - - // On 64-bit, people with ulimit -v set complain if we reserve too - // much address space. Instead, assume that the reservation is okay - // and check the assumption in SysMap. - if(NaCl || sizeof(void*) == 8) { - *reserved = false; - return v; - } - - p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(p < (void*)4096) - return nil; - *reserved = true; - return p; -} - -void -runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat) -{ - void *p; - - runtime·xadd64(stat, n); - - // On 64-bit, we don't actually have v reserved, so tread carefully. - if(!reserved) { - p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(p == (void*)ENOMEM) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·throw("runtime: out of memory"); - } - if(p != v) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p); - runtime·throw("runtime: address space conflict"); - } - if(Debug) - runtime·printf("SysMap(%p, %p) = %p\n", v, n, p); - return; - } - - p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); - if(p == (void*)ENOMEM) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·throw("runtime: out of memory"); - } - if(p != v) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p); - runtime·throw("runtime: cannot map pages in arena address space"); - } - if(Debug) - runtime·printf("SysMap(%p, %p) = %p\n", v, n, p); -} diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go new file mode 100644 index 0000000000..7b4c99a3dd --- /dev/null +++ b/src/runtime/os1_nacl.go @@ -0,0 +1,197 @@ +// 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. + +package runtime + +import "unsafe" + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +func sigtramp() + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + _g_ := getg() + + // Initialize signal handling + ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024) + if ret < 0 { + print("runtime: nacl_exception_stack: error ", -ret, "\n") + } + + ret = nacl_exception_handler(funcPC(sigtramp), nil) + if ret < 0 { + print("runtime: nacl_exception_handler: error ", -ret, "\n") + } +} + +// Called from dropm to undo the effect of an minit. +func unminit() { +} + +func osinit() { + ncpu = 1 + getg().m.procid = 2 + //nacl_exception_handler(funcPC(sigtramp), nil); +} + +func crash() { + *(*int32)(nil) = 0 +} + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + *rnd = nil + *rnd_len = 0 +} + +func goenvs() { + goenvs_unix() +} + +func initsig() { +} + +//go:nosplit +func usleep(us uint32) { + var ts timespec + + ts.tv_sec = int64(us / 1e6) + ts.tv_nsec = int32(us%1e6) * 1e3 + nacl_nanosleep(&ts, nil) +} + +func mstart_nacl() + +func newosproc(mp *m, stk unsafe.Pointer) { + tls := (*[3]unsafe.Pointer)(unsafe.Pointer(&mp.tls)) + tls[0] = unsafe.Pointer(mp.g0) + tls[1] = unsafe.Pointer(mp) + ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&tls[2]), nil) + if ret < 0 { + print("nacl_thread_create: error ", -ret, "\n") + gothrow("newosproc") + } +} + +//go:nosplit +func semacreate() uintptr { + var cond uintptr + systemstack(func() { + mu := nacl_mutex_create(0) + if mu < 0 { + print("nacl_mutex_create: error ", -mu, "\n") + gothrow("semacreate") + } + c := nacl_cond_create(0) + if c < 0 { + print("nacl_cond_create: error ", -cond, "\n") + gothrow("semacreate") + } + cond = uintptr(c) + _g_ := getg() + _g_.m.waitsemalock = uint32(mu) + }) + return cond +} + +//go:nosplit +func semasleep(ns int64) int32 { + var ret int32 + + systemstack(func() { + _g_ := getg() + if nacl_mutex_lock(int32(_g_.m.waitsemalock)) < 0 { + gothrow("semasleep") + } + + for _g_.m.waitsemacount == 0 { + if ns < 0 { + if nacl_cond_wait(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock)) < 0 { + gothrow("semasleep") + } + } else { + var ts timespec + end := ns + nanotime() + ts.tv_sec = end / 1e9 + ts.tv_nsec = int32(end % 1e9) + r := nacl_cond_timed_wait_abs(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock), &ts) + if r == -_ETIMEDOUT { + nacl_mutex_unlock(int32(_g_.m.waitsemalock)) + ret = -1 + return + } + if r < 0 { + gothrow("semasleep") + } + } + } + + _g_.m.waitsemacount = 0 + nacl_mutex_unlock(int32(_g_.m.waitsemalock)) + ret = 0 + }) + return ret +} + +//go:nosplit +func semawakeup(mp *m) { + systemstack(func() { + if nacl_mutex_lock(int32(mp.waitsemalock)) < 0 { + gothrow("semawakeup") + } + if mp.waitsemacount != 0 { + gothrow("semawakeup") + } + mp.waitsemacount = 1 + nacl_cond_signal(int32(mp.waitsema)) + nacl_mutex_unlock(int32(mp.waitsemalock)) + }) +} + +func memlimit() uintptr { + return 0 +} + +// This runs on a foreign stack, without an m or a g. No stack split. +//go:nosplit +func badsignal2() { + write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1))) + exit(2) +} + +var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n") + +func madvise(addr unsafe.Pointer, n uintptr, flags int32) {} +func munmap(addr unsafe.Pointer, n uintptr) {} +func resetcpuprofiler(hz int32) {} +func sigdisable(uint32) {} +func sigenable(uint32) {} +func closeonexec(int32) {} + +var writelock uint32 // test-and-set spin lock for write + +/* +An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s. + +void (*nacl_irt_query)(void); + +int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1"; +void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf +int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1); + +int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3"; +void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect +int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3); + +int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1"; +void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice +int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1); +*/ diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go new file mode 100644 index 0000000000..0c91e0f737 --- /dev/null +++ b/src/runtime/os2_nacl.go @@ -0,0 +1,154 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +const ( + _NSIG = 32 + _SI_USER = 1 + + // native_client/src/trusted/service_runtime/include/sys/errno.h + // The errors are mainly copied from Linux. + _EPERM = 1 /* Operation not permitted */ + _ENOENT = 2 /* No such file or directory */ + _ESRCH = 3 /* No such process */ + _EINTR = 4 /* Interrupted system call */ + _EIO = 5 /* I/O error */ + _ENXIO = 6 /* No such device or address */ + _E2BIG = 7 /* Argument list too long */ + _ENOEXEC = 8 /* Exec format error */ + _EBADF = 9 /* Bad file number */ + _ECHILD = 10 /* No child processes */ + _EAGAIN = 11 /* Try again */ + _ENOMEM = 12 /* Out of memory */ + _EACCES = 13 /* Permission denied */ + _EFAULT = 14 /* Bad address */ + _EBUSY = 16 /* Device or resource busy */ + _EEXIST = 17 /* File exists */ + _EXDEV = 18 /* Cross-device link */ + _ENODEV = 19 /* No such device */ + _ENOTDIR = 20 /* Not a directory */ + _EISDIR = 21 /* Is a directory */ + _EINVAL = 22 /* Invalid argument */ + _ENFILE = 23 /* File table overflow */ + _EMFILE = 24 /* Too many open files */ + _ENOTTY = 25 /* Not a typewriter */ + _EFBIG = 27 /* File too large */ + _ENOSPC = 28 /* No space left on device */ + _ESPIPE = 29 /* Illegal seek */ + _EROFS = 30 /* Read-only file system */ + _EMLINK = 31 /* Too many links */ + _EPIPE = 32 /* Broken pipe */ + _ENAMETOOLONG = 36 /* File name too long */ + _ENOSYS = 38 /* Function not implemented */ + _EDQUOT = 122 /* Quota exceeded */ + _EDOM = 33 /* Math arg out of domain of func */ + _ERANGE = 34 /* Math result not representable */ + _EDEADLK = 35 /* Deadlock condition */ + _ENOLCK = 37 /* No record locks available */ + _ENOTEMPTY = 39 /* Directory not empty */ + _ELOOP = 40 /* Too many symbolic links */ + _ENOMSG = 42 /* No message of desired type */ + _EIDRM = 43 /* Identifier removed */ + _ECHRNG = 44 /* Channel number out of range */ + _EL2NSYNC = 45 /* Level 2 not synchronized */ + _EL3HLT = 46 /* Level 3 halted */ + _EL3RST = 47 /* Level 3 reset */ + _ELNRNG = 48 /* Link number out of range */ + _EUNATCH = 49 /* Protocol driver not attached */ + _ENOCSI = 50 /* No CSI structure available */ + _EL2HLT = 51 /* Level 2 halted */ + _EBADE = 52 /* Invalid exchange */ + _EBADR = 53 /* Invalid request descriptor */ + _EXFULL = 54 /* Exchange full */ + _ENOANO = 55 /* No anode */ + _EBADRQC = 56 /* Invalid request code */ + _EBADSLT = 57 /* Invalid slot */ + _EDEADLOCK = _EDEADLK /* File locking deadlock error */ + _EBFONT = 59 /* Bad font file fmt */ + _ENOSTR = 60 /* Device not a stream */ + _ENODATA = 61 /* No data (for no delay io) */ + _ETIME = 62 /* Timer expired */ + _ENOSR = 63 /* Out of streams resources */ + _ENONET = 64 /* Machine is not on the network */ + _ENOPKG = 65 /* Package not installed */ + _EREMOTE = 66 /* The object is remote */ + _ENOLINK = 67 /* The link has been severed */ + _EADV = 68 /* Advertise error */ + _ESRMNT = 69 /* Srmount error */ + _ECOMM = 70 /* Communication error on send */ + _EPROTO = 71 /* Protocol error */ + _EMULTIHOP = 72 /* Multihop attempted */ + _EDOTDOT = 73 /* Cross mount point (not really error) */ + _EBADMSG = 74 /* Trying to read unreadable message */ + _EOVERFLOW = 75 /* Value too large for defined data type */ + _ENOTUNIQ = 76 /* Given log. name not unique */ + _EBADFD = 77 /* f.d. invalid for this operation */ + _EREMCHG = 78 /* Remote address changed */ + _ELIBACC = 79 /* Can't access a needed shared lib */ + _ELIBBAD = 80 /* Accessing a corrupted shared lib */ + _ELIBSCN = 81 /* .lib section in a.out corrupted */ + _ELIBMAX = 82 /* Attempting to link in too many libs */ + _ELIBEXEC = 83 /* Attempting to exec a shared library */ + _EILSEQ = 84 + _EUSERS = 87 + _ENOTSOCK = 88 /* Socket operation on non-socket */ + _EDESTADDRREQ = 89 /* Destination address required */ + _EMSGSIZE = 90 /* Message too long */ + _EPROTOTYPE = 91 /* Protocol wrong type for socket */ + _ENOPROTOOPT = 92 /* Protocol not available */ + _EPROTONOSUPPORT = 93 /* Unknown protocol */ + _ESOCKTNOSUPPORT = 94 /* Socket type not supported */ + _EOPNOTSUPP = 95 /* Operation not supported on transport endpoint */ + _EPFNOSUPPORT = 96 /* Protocol family not supported */ + _EAFNOSUPPORT = 97 /* Address family not supported by protocol family */ + _EADDRINUSE = 98 /* Address already in use */ + _EADDRNOTAVAIL = 99 /* Address not available */ + _ENETDOWN = 100 /* Network interface is not configured */ + _ENETUNREACH = 101 /* Network is unreachable */ + _ENETRESET = 102 + _ECONNABORTED = 103 /* Connection aborted */ + _ECONNRESET = 104 /* Connection reset by peer */ + _ENOBUFS = 105 /* No buffer space available */ + _EISCONN = 106 /* Socket is already connected */ + _ENOTCONN = 107 /* Socket is not connected */ + _ESHUTDOWN = 108 /* Can't send after socket shutdown */ + _ETOOMANYREFS = 109 + _ETIMEDOUT = 110 /* Connection timed out */ + _ECONNREFUSED = 111 /* Connection refused */ + _EHOSTDOWN = 112 /* Host is down */ + _EHOSTUNREACH = 113 /* Host is unreachable */ + _EALREADY = 114 /* Socket already connected */ + _EINPROGRESS = 115 /* Connection already in progress */ + _ESTALE = 116 + _ENOTSUP = _EOPNOTSUPP /* Not supported */ + _ENOMEDIUM = 123 /* No medium (in tape drive) */ + _ECANCELED = 125 /* Operation canceled. */ + _ELBIN = 2048 /* Inode is remote (not really error) */ + _EFTYPE = 2049 /* Inappropriate file type or format */ + _ENMFILE = 2050 /* No more files */ + _EPROCLIM = 2051 + _ENOSHARE = 2052 /* No such host or network path */ + _ECASECLASH = 2053 /* Filename exists with different case */ + _EWOULDBLOCK = _EAGAIN /* Operation would block */ + + // native_client/src/trusted/service_runtime/include/bits/mman.h. + // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h. + // Those MAP_*values are different from these. + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_SHARED = 0x1 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + _MAP_ANON = 0x20 + + _MADV_FREE = 0 + _SIGFPE = 8 + _FPE_INTDIV = 0 +) + +type siginfo struct{} diff --git a/src/runtime/os_nacl.c b/src/runtime/os_nacl.c deleted file mode 100644 index 14b5583033..0000000000 --- a/src/runtime/os_nacl.c +++ /dev/null @@ -1,312 +0,0 @@ -// 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "arch_GOARCH.h" -#include "textflag.h" -#include "stack.h" - -int8 *goos = "nacl"; -extern SigTab runtime·sigtab[]; - -void runtime·sigtramp(void); - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K - mp->gsignal->m = mp; -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - int32 ret; - - // Initialize signal handling - ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stack.lo, 32*1024); - if(ret < 0) - runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret); - - ret = runtime·nacl_exception_handler(runtime·sigtramp, nil); - if(ret < 0) - runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ -} - -int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n"; -int8 runtime·sigtrampp[] = "runtime: sigtramp"; - -extern byte runtime·tls0[]; - -void -runtime·osinit(void) -{ - runtime·ncpu = 1; - g->m->procid = 2; -//runtime·nacl_exception_handler(runtime·sigtramp, nil); -} - -void -runtime·crash(void) -{ - *(int32*)0 = 0; -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - *rnd = nil; - *rnd_len = 0; -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -void -runtime·initsig(void) -{ -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 us) -{ - Timespec ts; - - ts.tv_sec = us/1000000; - ts.tv_nsec = (us%1000000)*1000; - runtime·nacl_nanosleep(&ts, nil); -} - -void runtime·mstart_nacl(void); - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 ret; - void **tls; - - tls = (void**)mp->tls; - tls[0] = mp->g0; - tls[1] = mp; - ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0); - if(ret < 0) { - runtime·printf("nacl_thread_create: error %d\n", -ret); - runtime·throw("newosproc"); - } -} - -static void -semacreate(void) -{ - int32 mu, cond; - - mu = runtime·nacl_mutex_create(0); - if(mu < 0) { - runtime·printf("nacl_mutex_create: error %d\n", -mu); - runtime·throw("semacreate"); - } - cond = runtime·nacl_cond_create(0); - if(cond < 0) { - runtime·printf("nacl_cond_create: error %d\n", -cond); - runtime·throw("semacreate"); - } - g->m->waitsemalock = mu; - g->m->scalararg[0] = cond; // assigned to m->waitsema -} - -#pragma textflag NOSPLIT -uint32 -runtime·semacreate(void) -{ - void (*fn)(void); - uint32 x; - - fn = semacreate; - runtime·onM(&fn); - x = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return x; -} - -static void -semasleep(void) -{ - int32 ret; - int64 ns; - - ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; - g->m->scalararg[0] = 0; - g->m->scalararg[1] = 0; - - ret = runtime·nacl_mutex_lock(g->m->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_mutex_lock: error %d\n", -ret); - runtime·throw("semasleep"); - } - if(g->m->waitsemacount > 0) { - g->m->waitsemacount = 0; - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = 0; - return; - } - - while(g->m->waitsemacount == 0) { - if(ns < 0) { - ret = runtime·nacl_cond_wait(g->m->waitsema, g->m->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_cond_wait: error %d\n", -ret); - runtime·throw("semasleep"); - } - } else { - Timespec ts; - - ns += runtime·nanotime(); - ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); - ret = runtime·nacl_cond_timed_wait_abs(g->m->waitsema, g->m->waitsemalock, &ts); - if(ret == -ETIMEDOUT) { - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = -1; - return; - } - if(ret < 0) { - //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret); - runtime·throw("semasleep"); - } - } - } - - g->m->waitsemacount = 0; - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = 0; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 r; - void (*fn)(void); - - g->m->scalararg[0] = (uint32)ns; - g->m->scalararg[1] = (uint32)(ns>>32); - fn = semasleep; - runtime·onM(&fn); - r = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return r; -} - -static void -semawakeup(void) -{ - int32 ret; - M *mp; - - mp = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - - ret = runtime·nacl_mutex_lock(mp->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_mutex_lock: error %d\n", -ret); - runtime·throw("semawakeup"); - } - if(mp->waitsemacount != 0) { - //runtime·printf("semawakeup: double wakeup\n"); - runtime·throw("semawakeup"); - } - mp->waitsemacount = 1; - runtime·nacl_cond_signal(mp->waitsema); - runtime·nacl_mutex_unlock(mp->waitsemalock); -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - void (*fn)(void); - - g->m->ptrarg[0] = mp; - fn = semawakeup; - runtime·onM(&fn); -} - -uintptr -runtime·memlimit(void) -{ - runtime·printf("memlimit\n"); - return 0; -} - -#pragma dataflag NOPTR -static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag NOSPLIT -void -runtime·badsignal2(void) -{ - runtime·write(2, badsignal, sizeof badsignal - 1); - runtime·exit(2); -} - -void runtime·madvise(byte*, uintptr, int32) { } -void runtime·munmap(byte*, uintptr) {} - -void -runtime·resetcpuprofiler(int32 hz) -{ - USED(hz); -} - -void -runtime·sigdisable(uint32) -{ -} - -void -runtime·sigenable(uint32) -{ -} - -void -runtime·closeonexec(int32) -{ -} - -uint32 runtime·writelock; // test-and-set spin lock for runtime.write - -/* -An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s. - -void (*runtime·nacl_irt_query)(void); - -int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1"; -void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf -int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1); - -int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3"; -void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect -int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3); - -int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1"; -void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice -int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1); -*/ diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go index 8dd43ff06f..eff9ec30e4 100644 --- a/src/runtime/os_nacl.go +++ b/src/runtime/os_nacl.go @@ -6,8 +6,8 @@ package runtime import "unsafe" -func nacl_exception_stack(p unsafe.Pointer, size int32) int32 -func nacl_exception_handler(fn, arg unsafe.Pointer) int32 +func nacl_exception_stack(p uintptr, size int32) int32 +func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32 func nacl_sem_create(flag int32) int32 func nacl_sem_wait(sem int32) int32 func nacl_sem_post(sem int32) int32 @@ -19,9 +19,20 @@ func nacl_cond_create(flag int32) int32 func nacl_cond_wait(cond, n int32) int32 func nacl_cond_signal(cond int32) int32 func nacl_cond_broadcast(cond int32) int32 -func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32 -func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32 -func nacl_nanosleep(ts, extra unsafe.Pointer) int32 + +//go:noescape +func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32 +func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32 + +//go:noescape +func nacl_nanosleep(ts, extra *timespec) int32 +func nanotime() int64 +func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer +func exit(code int32) +func osyield() + +//go:noescape +func write(fd uintptr, p unsafe.Pointer, n int32) int32 func os_sigpipe() { gothrow("too many writes on closed pipe") diff --git a/src/runtime/os_nacl.h b/src/runtime/os_nacl.h deleted file mode 100644 index 7c9d9c242f..0000000000 --- a/src/runtime/os_nacl.h +++ /dev/null @@ -1,162 +0,0 @@ -enum { - NSIG = 32, - SI_USER = 1, - - // native_client/src/trusted/service_runtime/include/sys/errno.h - // The errors are mainly copied from Linux. - EPERM = 1, /* Operation not permitted */ - ENOENT = 2, /* No such file or directory */ - ESRCH = 3, /* No such process */ - EINTR = 4, /* Interrupted system call */ - EIO = 5, /* I/O error */ - ENXIO = 6, /* No such device or address */ - E2BIG = 7, /* Argument list too long */ - ENOEXEC = 8, /* Exec format error */ - EBADF = 9, /* Bad file number */ - ECHILD = 10, /* No child processes */ - EAGAIN = 11, /* Try again */ - ENOMEM = 12, /* Out of memory */ - EACCES = 13, /* Permission denied */ - EFAULT = 14, /* Bad address */ - EBUSY = 16, /* Device or resource busy */ - EEXIST = 17, /* File exists */ - EXDEV = 18, /* Cross-device link */ - ENODEV = 19, /* No such device */ - ENOTDIR = 20, /* Not a directory */ - EISDIR = 21, /* Is a directory */ - EINVAL = 22, /* Invalid argument */ - ENFILE = 23, /* File table overflow */ - EMFILE = 24, /* Too many open files */ - ENOTTY = 25, /* Not a typewriter */ - EFBIG = 27, /* File too large */ - ENOSPC = 28, /* No space left on device */ - ESPIPE = 29, /* Illegal seek */ - EROFS = 30, /* Read-only file system */ - EMLINK = 31, /* Too many links */ - EPIPE = 32, /* Broken pipe */ - ENAMETOOLONG = 36, /* File name too long */ - ENOSYS = 38, /* Function not implemented */ - EDQUOT = 122, /* Quota exceeded */ - EDOM = 33, /* Math arg out of domain of func */ - ERANGE = 34, /* Math result not representable */ - EDEADLK = 35, /* Deadlock condition */ - ENOLCK = 37, /* No record locks available */ - ENOTEMPTY = 39, /* Directory not empty */ - ELOOP = 40, /* Too many symbolic links */ - ENOMSG = 42, /* No message of desired type */ - EIDRM = 43, /* Identifier removed */ - ECHRNG = 44, /* Channel number out of range */ - EL2NSYNC = 45, /* Level 2 not synchronized */ - EL3HLT = 46, /* Level 3 halted */ - EL3RST = 47, /* Level 3 reset */ - ELNRNG = 48, /* Link number out of range */ - EUNATCH = 49, /* Protocol driver not attached */ - ENOCSI = 50, /* No CSI structure available */ - EL2HLT = 51, /* Level 2 halted */ - EBADE = 52, /* Invalid exchange */ - EBADR = 53, /* Invalid request descriptor */ - EXFULL = 54, /* Exchange full */ - ENOANO = 55, /* No anode */ - EBADRQC = 56, /* Invalid request code */ - EBADSLT = 57, /* Invalid slot */ - EDEADLOCK = EDEADLK, /* File locking deadlock error */ - EBFONT = 59, /* Bad font file fmt */ - ENOSTR = 60, /* Device not a stream */ - ENODATA = 61, /* No data (for no delay io) */ - ETIME = 62, /* Timer expired */ - ENOSR = 63, /* Out of streams resources */ - ENONET = 64, /* Machine is not on the network */ - ENOPKG = 65, /* Package not installed */ - EREMOTE = 66, /* The object is remote */ - ENOLINK = 67, /* The link has been severed */ - EADV = 68, /* Advertise error */ - ESRMNT = 69, /* Srmount error */ - ECOMM = 70, /* Communication error on send */ - EPROTO = 71, /* Protocol error */ - EMULTIHOP = 72, /* Multihop attempted */ - EDOTDOT = 73, /* Cross mount point (not really error) */ - EBADMSG = 74, /* Trying to read unreadable message */ - EOVERFLOW = 75, /* Value too large for defined data type */ - ENOTUNIQ = 76, /* Given log. name not unique */ - EBADFD = 77, /* f.d. invalid for this operation */ - EREMCHG = 78, /* Remote address changed */ - ELIBACC = 79, /* Can't access a needed shared lib */ - ELIBBAD = 80, /* Accessing a corrupted shared lib */ - ELIBSCN = 81, /* .lib section in a.out corrupted */ - ELIBMAX = 82, /* Attempting to link in too many libs */ - ELIBEXEC = 83, /* Attempting to exec a shared library */ - EILSEQ = 84, - EUSERS = 87, - ENOTSOCK = 88, /* Socket operation on non-socket */ - EDESTADDRREQ = 89, /* Destination address required */ - EMSGSIZE = 90, /* Message too long */ - EPROTOTYPE = 91, /* Protocol wrong type for socket */ - ENOPROTOOPT = 92, /* Protocol not available */ - EPROTONOSUPPORT = 93, /* Unknown protocol */ - ESOCKTNOSUPPORT = 94, /* Socket type not supported */ - EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */ - EPFNOSUPPORT = 96, /* Protocol family not supported */ - EAFNOSUPPORT = 97, /* Address family not supported by protocol family */ - EADDRINUSE = 98, /* Address already in use */ - EADDRNOTAVAIL = 99, /* Address not available */ - ENETDOWN = 100, /* Network interface is not configured */ - ENETUNREACH = 101, /* Network is unreachable */ - ENETRESET = 102, - ECONNABORTED = 103, /* Connection aborted */ - ECONNRESET = 104, /* Connection reset by peer */ - ENOBUFS = 105, /* No buffer space available */ - EISCONN = 106, /* Socket is already connected */ - ENOTCONN = 107, /* Socket is not connected */ - ESHUTDOWN = 108, /* Can't send after socket shutdown */ - ETOOMANYREFS = 109, - ETIMEDOUT = 110, /* Connection timed out */ - ECONNREFUSED = 111, /* Connection refused */ - EHOSTDOWN = 112, /* Host is down */ - EHOSTUNREACH = 113, /* Host is unreachable */ - EALREADY = 114, /* Socket already connected */ - EINPROGRESS = 115, /* Connection already in progress */ - ESTALE = 116, - ENOTSUP = EOPNOTSUPP, /* Not supported */ - ENOMEDIUM = 123, /* No medium (in tape drive) */ - ECANCELED = 125, /* Operation canceled. */ - ELBIN = 2048, /* Inode is remote (not really error) */ - EFTYPE = 2049, /* Inappropriate file type or format */ - ENMFILE = 2050, /* No more files */ - EPROCLIM = 2051, - ENOSHARE = 2052, /* No such host or network path */ - ECASECLASH = 2053, /* Filename exists with different case */ - EWOULDBLOCK = EAGAIN, /* Operation would block */ - - // native_client/src/trusted/service_runtime/include/bits/mman.h. - // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h. - // Those MAP_*values are different from these. - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_SHARED = 0x1, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - MAP_ANON = 0x20, -}; -typedef byte* kevent_udata; - -int32 runtime·nacl_exception_stack(byte*, int32); -int32 runtime·nacl_exception_handler(void*, void*); -int32 runtime·nacl_sem_create(int32); -int32 runtime·nacl_sem_wait(int32); -int32 runtime·nacl_sem_post(int32); -int32 runtime·nacl_mutex_create(int32); -int32 runtime·nacl_mutex_lock(int32); -int32 runtime·nacl_mutex_trylock(int32); -int32 runtime·nacl_mutex_unlock(int32); -int32 runtime·nacl_cond_create(int32); -int32 runtime·nacl_cond_wait(int32, int32); -int32 runtime·nacl_cond_signal(int32); -int32 runtime·nacl_cond_broadcast(int32); -int32 runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*); -int32 runtime·nacl_thread_create(void*, void*, void*, void*); -int32 runtime·nacl_nanosleep(Timespec*, Timespec*); - -void runtime·sigpanic(void); diff --git a/src/runtime/os_nacl_arm.c b/src/runtime/os_nacl_arm.c deleted file mode 100644 index 1248ea6449..0000000000 --- a/src/runtime/os_nacl_arm.c +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "textflag.h" - -void -runtime·checkgoarm(void) -{ - return; // NaCl/ARM only supports ARMv7 -} - -#pragma textflag NOSPLIT -int64 -runtime·cputicks(void) -{ - // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). - // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. - // TODO: need more entropy to better seed fastrand1. - return runtime·nanotime(); -} diff --git a/src/runtime/os_nacl_arm.go b/src/runtime/os_nacl_arm.go new file mode 100644 index 0000000000..a43e7c47b7 --- /dev/null +++ b/src/runtime/os_nacl_arm.go @@ -0,0 +1,17 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +func checkgoarm() { + return // NaCl/ARM only supports ARMv7 +} + +//go:nosplit +func cputicks() int64 { + // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). + // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. + // TODO: need more entropy to better seed fastrand1. + return nanotime() +} diff --git a/src/runtime/signal_nacl.go b/src/runtime/signal_nacl.go new file mode 100644 index 0000000000..122648bc33 --- /dev/null +++ b/src/runtime/signal_nacl.go @@ -0,0 +1,45 @@ +// 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 + +type sigTabT struct { + flags int32 + name string +} + +var sigtable = [...]sigTabT{ + /* 0 */ {0, "SIGNONE: no trap"}, + /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, + /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, + /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, + /* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, + /* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, + /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, + /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, + /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, + /* 9 */ {0, "SIGKILL: kill"}, + /* 10 */ {_SigPanic, "SIGBUS: bus error"}, + /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, + /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, + /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, + /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, + /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, + /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"}, + /* 17 */ {0, "SIGSTOP: stop"}, + /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, + /* 19 */ {0, "SIGCONT: continue after stop"}, + /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, + /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, + /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, + /* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, + /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, + /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, + /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, + /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, + /* 28 */ {_SigNotify, "SIGWINCH: window size change"}, + /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, + /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, + /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, +} diff --git a/src/runtime/signal_nacl_386.go b/src/runtime/signal_nacl_386.go new file mode 100644 index 0000000000..0a1e7c6ea5 --- /dev/null +++ b/src/runtime/signal_nacl_386.go @@ -0,0 +1,34 @@ +// Copyright 2013 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" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregs386 { return &(*exccontext)(c.ctxt).regs } +func (c *sigctxt) eax() uint32 { return c.regs().eax } +func (c *sigctxt) ebx() uint32 { return c.regs().ebx } +func (c *sigctxt) ecx() uint32 { return c.regs().ecx } +func (c *sigctxt) edx() uint32 { return c.regs().edx } +func (c *sigctxt) edi() uint32 { return c.regs().edi } +func (c *sigctxt) esi() uint32 { return c.regs().esi } +func (c *sigctxt) ebp() uint32 { return c.regs().ebp } +func (c *sigctxt) esp() uint32 { return c.regs().esp } +func (c *sigctxt) eip() uint32 { return c.regs().eip } +func (c *sigctxt) eflags() uint32 { return c.regs().eflags } +func (c *sigctxt) cs() uint32 { return ^uint32(0) } +func (c *sigctxt) fs() uint32 { return ^uint32(0) } +func (c *sigctxt) gs() uint32 { return ^uint32(0) } +func (c *sigctxt) sigcode() uint32 { return ^uint32(0) } +func (c *sigctxt) sigaddr() uint32 { return 0 } + +func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x } +func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x } +func (c *sigctxt) set_sigcode(x uint32) {} +func (c *sigctxt) set_sigaddr(x uint32) {} diff --git a/src/runtime/signal_nacl_386.h b/src/runtime/signal_nacl_386.h deleted file mode 100644 index c9481b5f4f..0000000000 --- a/src/runtime/signal_nacl_386.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 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. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs) - -#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax) -#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx) -#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx) -#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx) -#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi) -#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi) -#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp) -#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp) -#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip) -#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags) - -#define SIG_CS(info, ctxt) (~0) -#define SIG_FS(info, ctxt) (~0) -#define SIG_GS(info, ctxt) (~0) - -#define SIG_CODE0(info, ctxt) (~0) -#define SIG_CODE1(info, ctxt) (0) diff --git a/src/runtime/signal_nacl_amd64p32.go b/src/runtime/signal_nacl_amd64p32.go new file mode 100644 index 0000000000..024cebaddd --- /dev/null +++ b/src/runtime/signal_nacl_amd64p32.go @@ -0,0 +1,44 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregsamd64 { + return &(*exccontext)(c.ctxt).regs +} +func (c *sigctxt) rax() uint64 { return c.regs().rax } +func (c *sigctxt) rbx() uint64 { return c.regs().rbx } +func (c *sigctxt) rcx() uint64 { return c.regs().rcx } +func (c *sigctxt) rdx() uint64 { return c.regs().rdx } +func (c *sigctxt) rdi() uint64 { return c.regs().rdi } +func (c *sigctxt) rsi() uint64 { return c.regs().rsi } +func (c *sigctxt) rbp() uint64 { return c.regs().rbp } +func (c *sigctxt) rsp() uint64 { return c.regs().rsp } +func (c *sigctxt) r8() uint64 { return c.regs().r8 } +func (c *sigctxt) r9() uint64 { return c.regs().r9 } +func (c *sigctxt) r10() uint64 { return c.regs().r10 } +func (c *sigctxt) r11() uint64 { return c.regs().r11 } +func (c *sigctxt) r12() uint64 { return c.regs().r12 } +func (c *sigctxt) r13() uint64 { return c.regs().r13 } +func (c *sigctxt) r14() uint64 { return c.regs().r14 } +func (c *sigctxt) r15() uint64 { return c.regs().r15 } +func (c *sigctxt) rip() uint64 { return c.regs().rip } +func (c *sigctxt) rflags() uint64 { return uint64(c.regs().rflags) } +func (c *sigctxt) cs() uint64 { return ^uint64(0) } +func (c *sigctxt) fs() uint64 { return ^uint64(0) } +func (c *sigctxt) gs() uint64 { return ^uint64(0) } +func (c *sigctxt) sigcode() uint64 { return ^uint64(0) } +func (c *sigctxt) sigaddr() uint64 { return 0 } + +func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x } +func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x } +func (c *sigctxt) set_sigcode(x uint64) {} +func (c *sigctxt) set_sigaddr(x uint64) {} diff --git a/src/runtime/signal_nacl_amd64p32.h b/src/runtime/signal_nacl_amd64p32.h deleted file mode 100644 index f62305cb52..0000000000 --- a/src/runtime/signal_nacl_amd64p32.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 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. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs.regs64) - -#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax) -#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx) -#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx) -#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx) -#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi) -#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi) -#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp) -#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15) -#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip) -#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags) - -#define SIG_CS(info, ctxt) (~0) -#define SIG_FS(info, ctxt) (~0) -#define SIG_GS(info, ctxt) (~0) - -#define SIG_CODE0(info, ctxt) (~0) -#define SIG_CODE1(info, ctxt) (0) diff --git a/src/runtime/signal_nacl_arm.go b/src/runtime/signal_nacl_arm.go new file mode 100644 index 0000000000..1aeaa4e428 --- /dev/null +++ b/src/runtime/signal_nacl_arm.go @@ -0,0 +1,47 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregsarm { return &(*exccontext)(c.ctxt).regs } + +func (c *sigctxt) r0() uint32 { return c.regs().r0 } +func (c *sigctxt) r1() uint32 { return c.regs().r1 } +func (c *sigctxt) r2() uint32 { return c.regs().r2 } +func (c *sigctxt) r3() uint32 { return c.regs().r3 } +func (c *sigctxt) r4() uint32 { return c.regs().r4 } +func (c *sigctxt) r5() uint32 { return c.regs().r5 } +func (c *sigctxt) r6() uint32 { return c.regs().r6 } +func (c *sigctxt) r7() uint32 { return c.regs().r7 } +func (c *sigctxt) r8() uint32 { return c.regs().r8 } +func (c *sigctxt) r9() uint32 { return c.regs().r9 } +func (c *sigctxt) r10() uint32 { return c.regs().r10 } +func (c *sigctxt) fp() uint32 { return c.regs().r11 } +func (c *sigctxt) ip() uint32 { return c.regs().r12 } +func (c *sigctxt) sp() uint32 { return c.regs().sp } +func (c *sigctxt) lr() uint32 { return c.regs().lr } +func (c *sigctxt) pc() uint32 { return c.regs().pc } +func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr } +func (c *sigctxt) fault() uint32 { return ^uint32(0) } +func (c *sigctxt) trap() uint32 { return ^uint32(0) } +func (c *sigctxt) error() uint32 { return ^uint32(0) } +func (c *sigctxt) oldmask() uint32 { return ^uint32(0) } + +func (c *sigctxt) sigcode() uint32 { return 0 } +func (c *sigctxt) sigaddr() uint32 { return 0 } + +func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x } +func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x } +func (c *sigctxt) set_lr(x uint32) { c.regs().lr = x } +func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x } + +func (c *sigctxt) set_sigcode(x uint32) {} +func (c *sigctxt) set_sigaddr(x uint32) {} diff --git a/src/runtime/signal_nacl_arm.h b/src/runtime/signal_nacl_arm.h deleted file mode 100644 index e5bbb211dd..0000000000 --- a/src/runtime/signal_nacl_arm.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).r0) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).r1) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).r2) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).r3) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).r4) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).r5) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).r6) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).r7) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) -#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).r11) -#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).r12) -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).sp) -#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).lr) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).pc) -#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).cpsr) -#define SIG_FAULT(info, ctxt) (~0) -#define SIG_TRAP(info, ctxt) (~0) -#define SIG_ERROR(info, ctxt) (~0) -#define SIG_OLDMASK(info, ctxt) (~0) -#define SIG_CODE0(info, ctxt) (~0) diff --git a/src/runtime/signals_nacl.h b/src/runtime/signals_nacl.h deleted file mode 100644 index 8761e1bd94..0000000000 --- a/src/runtime/signals_nacl.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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. - -#include "textflag.h" - -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define D SigDefault - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ N+K, "SIGHUP: terminal line hangup", - /* 2 */ N+K, "SIGINT: interrupt", - /* 3 */ N+T, "SIGQUIT: quit", - /* 4 */ T, "SIGILL: illegal instruction", - /* 5 */ T, "SIGTRAP: trace trap", - /* 6 */ N+T, "SIGABRT: abort", - /* 7 */ T, "SIGEMT: emulate instruction executed", - /* 8 */ P, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ P, "SIGBUS: bus error", - /* 11 */ P, "SIGSEGV: segmentation violation", - /* 12 */ T, "SIGSYS: bad system call", - /* 13 */ N, "SIGPIPE: write to broken pipe", - /* 14 */ N, "SIGALRM: alarm clock", - /* 15 */ N+K, "SIGTERM: termination", - /* 16 */ N, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ N+D, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ N, "SIGCHLD: child status has changed", - /* 21 */ N+D, "SIGTTIN: background read from tty", - /* 22 */ N+D, "SIGTTOU: background write to tty", - /* 23 */ N, "SIGIO: i/o now possible", - /* 24 */ N, "SIGXCPU: cpu limit exceeded", - /* 25 */ N, "SIGXFSZ: file size limit exceeded", - /* 26 */ N, "SIGVTALRM: virtual alarm clock", - /* 27 */ N, "SIGPROF: profiling alarm clock", - /* 28 */ N, "SIGWINCH: window size change", - /* 29 */ N, "SIGINFO: status request from keyboard", - /* 30 */ N, "SIGUSR1: user-defined signal 1", - /* 31 */ N, "SIGUSR2: user-defined signal 2", -}; - -#undef N -#undef K -#undef T -#undef P -#undef D diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index cb0b0f0ed5..74cc5c6a7c 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -4,6 +4,7 @@ // +build !solaris // +build !windows +// +build !nacl package runtime -- cgit v1.3-5-g9baa From e9c57d8a2d7833a66a511888c4744e058bc68967 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 21 Nov 2014 19:39:01 +0100 Subject: [dev.cc] runtime: convert Plan 9 port to Go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Aram Hăvărneanu, Nick Owens and Russ Cox for the early reviews. LGTM=aram, rsc R=rsc, lucio.dere, aram, ality CC=golang-codereviews, mischief https://golang.org/cl/175370043 --- src/runtime/defs_plan9_386.go | 2 + src/runtime/defs_plan9_amd64.go | 2 + src/runtime/env_plan9.go | 3 + src/runtime/mem_plan9.c | 121 -------------- src/runtime/mem_plan9.go | 70 ++++++++ src/runtime/netpoll_stub.c | 18 -- src/runtime/netpoll_stub.go | 15 ++ src/runtime/os1_plan9.go | 270 ++++++++++++++++++++++++++++++ src/runtime/os2_plan9.go | 72 ++++++++ src/runtime/os_plan9.c | 362 ---------------------------------------- src/runtime/os_plan9.go | 27 +++ src/runtime/os_plan9.h | 93 ----------- src/runtime/os_plan9_386.c | 150 ----------------- src/runtime/os_plan9_386.go | 131 +++++++++++++++ src/runtime/os_plan9_amd64.c | 158 ------------------ src/runtime/os_plan9_amd64.go | 139 +++++++++++++++ src/runtime/signal_plan9.go | 54 ++++++ src/runtime/signals_plan9.h | 63 ------- src/runtime/stubs2.go | 1 + src/runtime/stubs3.go | 12 ++ 20 files changed, 798 insertions(+), 965 deletions(-) delete mode 100644 src/runtime/mem_plan9.c create mode 100644 src/runtime/mem_plan9.go delete mode 100644 src/runtime/netpoll_stub.c create mode 100644 src/runtime/netpoll_stub.go create mode 100644 src/runtime/os1_plan9.go create mode 100644 src/runtime/os2_plan9.go delete mode 100644 src/runtime/os_plan9.c delete mode 100644 src/runtime/os_plan9.h delete mode 100644 src/runtime/os_plan9_386.c create mode 100644 src/runtime/os_plan9_386.go delete mode 100644 src/runtime/os_plan9_amd64.c create mode 100644 src/runtime/os_plan9_amd64.go create mode 100644 src/runtime/signal_plan9.go delete mode 100644 src/runtime/signals_plan9.h create mode 100644 src/runtime/stubs3.go (limited to 'src/runtime') diff --git a/src/runtime/defs_plan9_386.go b/src/runtime/defs_plan9_386.go index 170506b230..212ecdf14a 100644 --- a/src/runtime/defs_plan9_386.go +++ b/src/runtime/defs_plan9_386.go @@ -1,5 +1,7 @@ package runtime +const _PAGESIZE = 0x1000 + type ureg struct { di uint32 /* general registers */ si uint32 /* ... */ diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go index 17becfb66f..510da0e994 100644 --- a/src/runtime/defs_plan9_amd64.go +++ b/src/runtime/defs_plan9_amd64.go @@ -1,5 +1,7 @@ package runtime +const _PAGESIZE = 0x1000 + type ureg struct { ax uint64 bx uint64 diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go index e442c34835..ec50cac484 100644 --- a/src/runtime/env_plan9.go +++ b/src/runtime/env_plan9.go @@ -54,3 +54,6 @@ func gogetenv(key string) string { sp.len = int(r) return s } + +var _cgo_setenv unsafe.Pointer // pointer to C function +var _cgo_unsetenv unsafe.Pointer // pointer to C function diff --git a/src/runtime/mem_plan9.c b/src/runtime/mem_plan9.c deleted file mode 100644 index d673d6f830..0000000000 --- a/src/runtime/mem_plan9.c +++ /dev/null @@ -1,121 +0,0 @@ -// 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "arch_GOARCH.h" -#include "malloc.h" -#include "os_GOOS.h" -#include "textflag.h" - -extern byte runtime·end[]; -#pragma dataflag NOPTR -static byte *bloc = { runtime·end }; -static Mutex memlock; - -enum -{ - Round = PAGESIZE-1 -}; - -static void* -brk(uintptr nbytes) -{ - uintptr bl; - - runtime·lock(&memlock); - // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c - bl = ((uintptr)bloc + Round) & ~Round; - if(runtime·brk_((void*)(bl + nbytes)) < 0) { - runtime·unlock(&memlock); - return nil; - } - bloc = (byte*)bl + nbytes; - runtime·unlock(&memlock); - return (void*)bl; -} - -static void -sysalloc(void) -{ - uintptr nbytes; - uint64 *stat; - void *p; - - nbytes = g->m->scalararg[0]; - stat = g->m->ptrarg[0]; - g->m->scalararg[0] = 0; - g->m->ptrarg[0] = nil; - - p = brk(nbytes); - if(p != nil) - runtime·xadd64(stat, nbytes); - - g->m->ptrarg[0] = p; -} - -#pragma textflag NOSPLIT -void* -runtime·sysAlloc(uintptr nbytes, uint64 *stat) -{ - void (*fn)(void); - void *p; - - g->m->scalararg[0] = nbytes; - g->m->ptrarg[0] = stat; - fn = sysalloc; - runtime·onM(&fn); - p = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - return p; -} - -void -runtime·SysFree(void *v, uintptr nbytes, uint64 *stat) -{ - runtime·xadd64(stat, -(uint64)nbytes); - runtime·lock(&memlock); - // from tiny/mem.c - // Push pointer back if this is a free - // of the most recent sysAlloc. - nbytes += (nbytes + Round) & ~Round; - if(bloc == (byte*)v+nbytes) - bloc -= nbytes; - runtime·unlock(&memlock); -} - -void -runtime·SysUnused(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void -runtime·SysUsed(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void -runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat) -{ - // SysReserve has already allocated all heap memory, - // but has not adjusted stats. - USED(v, reserved); - runtime·xadd64(stat, nbytes); -} - -void -runtime·SysFault(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void* -runtime·SysReserve(void *v, uintptr nbytes, bool *reserved) -{ - USED(v); - *reserved = true; - return brk(nbytes); -} diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go new file mode 100644 index 0000000000..a5d7c1a4cf --- /dev/null +++ b/src/runtime/mem_plan9.go @@ -0,0 +1,70 @@ +// 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. + +package runtime + +import "unsafe" + +var bloc uintptr +var memlock mutex + +const memRound = _PAGESIZE - 1 + +func initBloc() { + bloc = uintptr(unsafe.Pointer(&end)) +} + +func sbrk(n uintptr) unsafe.Pointer { + lock(&memlock) + // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c + bl := (bloc + memRound) &^ memRound + if brk_(unsafe.Pointer(bl+n)) < 0 { + unlock(&memlock) + return nil + } + bloc = bl + n + unlock(&memlock) + return unsafe.Pointer(bl) +} + +func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer { + p := sbrk(n) + if p != nil { + xadd64(stat, int64(n)) + } + return p +} + +func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) { + xadd64(stat, -int64(n)) + lock(&memlock) + // from tiny/mem.c + // Push pointer back if this is a free + // of the most recent sysAlloc. + n += (n + memRound) &^ memRound + if bloc == uintptr(v)+n { + bloc -= n + } + unlock(&memlock) +} + +func sysUnused(v unsafe.Pointer, n uintptr) { +} + +func sysUsed(v unsafe.Pointer, n uintptr) { +} + +func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) { + // sysReserve has already allocated all heap memory, + // but has not adjusted stats. + xadd64(stat, int64(n)) +} + +func sysFault(v unsafe.Pointer, n uintptr) { +} + +func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { + *reserved = true + return sbrk(n) +} diff --git a/src/runtime/netpoll_stub.c b/src/runtime/netpoll_stub.c deleted file mode 100644 index b7a8f2944c..0000000000 --- a/src/runtime/netpoll_stub.c +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2013 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. - -// +build plan9 - -#include "runtime.h" - -// Polls for ready network connections. -// Returns list of goroutines that become runnable. -G* -runtime·netpoll(bool block) -{ - // Implementation for platforms that do not support - // integrated network poller. - USED(block); - return nil; -} diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go new file mode 100644 index 0000000000..6c7e79ea37 --- /dev/null +++ b/src/runtime/netpoll_stub.go @@ -0,0 +1,15 @@ +// Copyright 2013 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. + +// +build plan9 + +package runtime + +// Polls for ready network connections. +// Returns list of goroutines that become runnable. +func netpoll(block bool) (gp *g) { + // Implementation for platforms that do not support + // integrated network poller. + return +} diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go new file mode 100644 index 0000000000..0f8da03f2b --- /dev/null +++ b/src/runtime/os1_plan9.go @@ -0,0 +1,270 @@ +// 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. + +package runtime + +import "unsafe" + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + // Initialize stack and goroutine for note handling. + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp + mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, _FlagNoScan)) + // Initialize stack for handling strings from the + // errstr system call, as used in package syscall. + mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan)) +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + // Mask all SSE floating-point exceptions + // when running on the 64-bit kernel. + setfpmasks() +} + +// Called from dropm to undo the effect of an minit. +func unminit() { +} + +var sysstat = []byte("/dev/sysstat\x00") + +func getproccount() int32 { + var buf [2048]byte + fd := open(&sysstat[0], _OREAD, 0) + if fd < 0 { + return 1 + } + ncpu := int32(0) + for { + n := read(fd, unsafe.Pointer(&buf), int32(len(buf))) + if n <= 0 { + break + } + for i := int32(0); i < n; i++ { + if buf[i] == '\n' { + ncpu++ + } + } + } + close(fd) + if ncpu == 0 { + ncpu = 1 + } + return ncpu +} + +var pid = []byte("#c/pid\x00") + +func getpid() uint64 { + var b [20]byte + fd := open(&pid[0], 0, 0) + if fd >= 0 { + read(fd, unsafe.Pointer(&b), int32(len(b))) + close(fd) + } + c := b[:] + for c[0] == ' ' || c[0] == '\t' { + c = c[1:] + } + return uint64(atoi(c)) +} + +func osinit() { + initBloc() + ncpu = getproccount() + getg().m.procid = getpid() + notify(unsafe.Pointer(funcPC(sigtramp))) +} + +func crash() { + notify(nil) + *(*int)(nil) = 0 +} + +var random_data [_HashRandomBytes]byte +var random_dev = []byte("/dev/random\x00") + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + fd := open(&random_dev[0], 0 /* O_RDONLY */, 0) + if read(fd, unsafe.Pointer(&random_data), _HashRandomBytes) == _HashRandomBytes { + *rnd = unsafe.Pointer(&random_data[0]) + *rnd_len = _HashRandomBytes + } else { + *rnd = nil + *rnd_len = 0 + } + close(fd) +} + +func goenvs() { +} + +func initsig() { +} + +//go:nosplit +func osyield() { + sleep(0) +} + +//go:nosplit +func usleep(µs uint32) { + ms := int32(µs / 1000) + if ms == 0 { + ms = 1 + } + sleep(ms) +} + +//go:nosplit +func nanotime() int64 { + var scratch int64 + ns := nsec(&scratch) + // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. + if ns == 0 { + return scratch + } + return ns +} + +//go:nosplit +func itoa(buf []byte, val uint64) []byte { + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return buf[i:] +} + +var goexits = []byte("go: exit ") + +func goexitsall(status *byte) { + var buf [_ERRMAX]byte + n := copy(buf[:], goexits) + n = copy(buf[n:], gostringnocopy(status)) + pid := getpid() + for mp := (*m)(atomicloadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { + if mp.procid != pid { + postnote(mp.procid, buf[:]) + } + } +} + +var procdir = []byte("/proc/") +var notefile = []byte("/note\x00") + +func postnote(pid uint64, msg []byte) int { + var buf [128]byte + var tmp [32]byte + n := copy(buf[:], procdir) + n += copy(buf[n:], itoa(tmp[:], pid)) + copy(buf[n:], notefile) + fd := open(&buf[0], _OWRITE, 0) + if fd < 0 { + return -1 + } + len := findnull(&msg[0]) + if write(uintptr(fd), (unsafe.Pointer)(&msg[0]), int32(len)) != int64(len) { + close(fd) + return -1 + } + close(fd) + return 0 +} + +//go:nosplit +func exit(e int) { + var status []byte + if e == 0 { + status = []byte("\x00") + } else { + // build error string + var tmp [32]byte + status = []byte(gostringnocopy(&itoa(tmp[:], uint64(e))[0]) + "\x00") + } + goexitsall(&status[0]) + exits(&status[0]) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + if false { + print("newosproc mp=", mp, " ostk=", &mp, "\n") + } + pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT) + if pid < 0 { + gothrow("newosproc: rfork failed") + } + if pid == 0 { + tstart_plan9(mp) + } +} + +//go:nosplit +func semacreate() uintptr { + return 1 +} + +//go:nosplit +func semasleep(ns int64) int { + _g_ := getg() + if ns >= 0 { + ms := timediv(ns, 1000000, nil) + if ms == 0 { + ms = 1 + } + ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms) + if ret == 1 { + return 0 // success + } + return -1 // timeout or interrupted + } + for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 { + // interrupted; try again (c.f. lock_sema.go) + } + return 0 // success +} + +//go:nosplit +func semawakeup(mp *m) { + plan9_semrelease(&mp.waitsemacount, 1) +} + +//go:nosplit +func read(fd int32, buf unsafe.Pointer, n int32) int32 { + return pread(fd, buf, n, -1) +} + +//go:nosplit +func write(fd uintptr, buf unsafe.Pointer, n int32) int64 { + return int64(pwrite(int32(fd), buf, n, -1)) +} + +func memlimit() uint64 { + return 0 +} + +var _badsignal = []byte("runtime: signal received on thread not created by Go.\n") + +// This runs on a foreign stack, without an m or a g. No stack split. +//go:nosplit +func badsignal2() { + pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1) + exits(&_badsignal[0]) +} + +func atoi(b []byte) int { + n := 0 + for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { + n = n*10 + int(b[0]) - '0' + b = b[1:] + } + return n +} diff --git a/src/runtime/os2_plan9.go b/src/runtime/os2_plan9.go new file mode 100644 index 0000000000..f64f4c8dab --- /dev/null +++ b/src/runtime/os2_plan9.go @@ -0,0 +1,72 @@ +// 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. + +// Plan 9-specific system calls + +package runtime + +// open +const ( + _OREAD = 0 + _OWRITE = 1 + _ORDWR = 2 + _OEXEC = 3 + _OTRUNC = 16 + _OCEXEC = 32 + _ORCLOSE = 64 + _OEXCL = 0x1000 +) + +// rfork +const ( + _RFNAMEG = 1 << 0 + _RFENVG = 1 << 1 + _RFFDG = 1 << 2 + _RFNOTEG = 1 << 3 + _RFPROC = 1 << 4 + _RFMEM = 1 << 5 + _RFNOWAIT = 1 << 6 + _RFCNAMEG = 1 << 10 + _RFCENVG = 1 << 11 + _RFCFDG = 1 << 12 + _RFREND = 1 << 13 + _RFNOMNT = 1 << 14 +) + +// notify +const ( + _NCONT = 0 + _NDFLT = 1 +) + +type uinptr _Plink + +type tos struct { + prof struct { // Per process profiling + pp *_Plink // known to be 0(ptr) + next *_Plink // known to be 4(ptr) + last *_Plink + first *_Plink + pid uint32 + what uint32 + } + cyclefreq uint64 // cycle clock frequency if there is one, 0 otherwise + kcycles int64 // cycles spent in kernel + pcycles int64 // cycles spent in process (kernel + user) + pid uint32 // might as well put the pid here + clock uint32 + // top of stack is here +} + +const ( + _NSIG = 14 // number of signals in sigtable array + _ERRMAX = 128 // max length of note string + + // Notes in runtime·sigtab that are handled by runtime·sigpanic. + _SIGRFAULT = 2 + _SIGWFAULT = 3 + _SIGINTDIV = 4 + _SIGFLOAT = 5 + _SIGTRAP = 6 +) diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c deleted file mode 100644 index f8c543f6f6..0000000000 --- a/src/runtime/os_plan9.c +++ /dev/null @@ -1,362 +0,0 @@ -// 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. - -#include "runtime.h" -#include "os_GOOS.h" -#include "arch_GOARCH.h" -#include "textflag.h" -#include "malloc.h" - -int8 *goos = "plan9"; -extern SigTab runtime·sigtab[]; - -int32 runtime·postnote(int32, int8*); - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - // Initialize stack and goroutine for note handling. - mp->gsignal = runtime·malg(32*1024); - mp->gsignal->m = mp; - mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, FlagNoScan); - - // Initialize stack for handling strings from the - // errstr system call, as used in package syscall. - mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, FlagNoScan); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Mask all SSE floating-point exceptions - // when running on the 64-bit kernel. - runtime·setfpmasks(); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ -} - - -static int32 -getproccount(void) -{ - int32 fd, i, n, ncpu; - byte buf[2048]; - - fd = runtime·open("/dev/sysstat", OREAD, 0); - if(fd < 0) - return 1; - ncpu = 0; - for(;;) { - n = runtime·read(fd, buf, sizeof buf); - if(n <= 0) - break; - for(i = 0; i < n; i++) { - if(buf[i] == '\n') - ncpu++; - } - } - runtime·close(fd); - return ncpu > 0 ? ncpu : 1; -} - -static int32 -getpid(void) -{ - byte b[20], *c; - int32 fd; - - runtime·memclr(b, sizeof(b)); - fd = runtime·open("#c/pid", 0, 0); - if(fd >= 0) { - runtime·read(fd, b, sizeof(b)); - runtime·close(fd); - } - c = b; - while(*c == ' ' || *c == '\t') - c++; - return runtime·atoi(c); -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getproccount(); - g->m->procid = getpid(); - runtime·notify(runtime·sigtramp); -} - -void -runtime·crash(void) -{ - runtime·notify(nil); - *(int32*)0 = 0; -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - static byte random_data[HashRandomBytes]; - int32 fd; - - fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) { - *rnd = random_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ -} - -void -runtime·initsig(void) -{ -} - -#pragma textflag NOSPLIT -void -runtime·osyield(void) -{ - runtime·sleep(0); -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 µs) -{ - uint32 ms; - - ms = µs/1000; - if(ms == 0) - ms = 1; - runtime·sleep(ms); -} - -#pragma textflag NOSPLIT -int64 -runtime·nanotime(void) -{ - int64 ns, scratch; - - ns = runtime·nsec(&scratch); - // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. - if(ns == 0) - return scratch; - return ns; -} - -#pragma textflag NOSPLIT -void -runtime·itoa(int32 n, byte *p, uint32 len) -{ - byte *q, c; - uint32 i; - - if(len <= 1) - return; - - runtime·memclr(p, len); - q = p; - - if(n==0) { - *q++ = '0'; - USED(q); - return; - } - if(n < 0) { - *q++ = '-'; - p++; - n = -n; - } - for(i=0; n > 0 && i < len; i++) { - *q++ = '0' + (n%10); - n = n/10; - } - for(q--; q >= p; ) { - c = *p; - *p++ = *q; - *q-- = c; - } -} - -void -runtime·goexitsall(int8 *status) -{ - int8 buf[ERRMAX]; - M *mp; - int32 pid; - - runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status); - pid = getpid(); - for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink) - if(mp->procid != pid) - runtime·postnote(mp->procid, buf); -} - -int32 -runtime·postnote(int32 pid, int8* msg) -{ - int32 fd; - intgo len; - uint8 buf[128]; - uint8 tmp[16]; - uint8 *p, *q; - - runtime·memclr(buf, sizeof buf); - - /* build path string /proc/pid/note */ - q = tmp; - p = buf; - runtime·itoa(pid, tmp, sizeof tmp); - runtime·memmove((void*)p, (void*)"/proc/", 6); - for(p += 6; *p++ = *q++; ); - p--; - runtime·memmove((void*)p, (void*)"/note", 5); - - fd = runtime·open((int8*)buf, OWRITE, 0); - if(fd < 0) - return -1; - - len = runtime·findnull((byte*)msg); - if(runtime·write(fd, msg, len) != len) { - runtime·close(fd); - return -1; - } - runtime·close(fd); - return 0; -} - -static void exit(void); - -#pragma textflag NOSPLIT -void -runtime·exit(int32 e) -{ - void (*fn)(void); - - g->m->scalararg[0] = e; - fn = exit; - runtime·onM(&fn); -} - -static void -exit(void) -{ - int32 e; - byte tmp[16]; - int8 *status; - - e = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - - if(e == 0) - status = ""; - else { - /* build error string */ - runtime·itoa(e, tmp, sizeof tmp); - status = (int8*)tmp; - } - - runtime·goexitsall(status); - runtime·exits(status); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 pid; - - if(0) - runtime·printf("newosproc mp=%p ostk=%p\n", mp, &mp); - - USED(stk); - if((pid = runtime·rfork(RFPROC|RFMEM|RFNOWAIT)) < 0) - runtime·throw("newosproc: rfork failed\n"); - if(pid == 0) - runtime·tstart_plan9(mp); -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return 1; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 ret; - int32 ms; - - if(ns >= 0) { - ms = runtime·timediv(ns, 1000000, nil); - if(ms == 0) - ms = 1; - ret = runtime·plan9_tsemacquire(&g->m->waitsemacount, ms); - if(ret == 1) - return 0; // success - return -1; // timeout or interrupted - } - - while(runtime·plan9_semacquire(&g->m->waitsemacount, 1) < 0) { - /* interrupted; try again (c.f. lock_sema.c) */ - } - return 0; // success -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - runtime·plan9_semrelease(&mp->waitsemacount, 1); -} - -#pragma textflag NOSPLIT -int32 -runtime·read(int32 fd, void *buf, int32 nbytes) -{ - return runtime·pread(fd, buf, nbytes, -1LL); -} - -#pragma textflag NOSPLIT -int32 -runtime·write(uintptr fd, void *buf, int32 nbytes) -{ - return runtime·pwrite((int32)fd, buf, nbytes, -1LL); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -#pragma dataflag NOPTR -static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag NOSPLIT -void -runtime·badsignal2(void) -{ - runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL); - runtime·exits(badsignal); -} diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 20e47bf42e..2dcdfc009a 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -6,22 +6,49 @@ package runtime import "unsafe" +//go:noescape func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + +//go:noescape func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + func seek(fd int32, offset int64, whence int32) int64 + +//go:noescape func exits(msg *byte) + +//go:noescape func brk_(addr unsafe.Pointer) uintptr + func sleep(ms int32) int32 + func rfork(flags int32) int32 + +//go:noescape func plan9_semacquire(addr *uint32, block int32) int32 + +//go:noescape func plan9_tsemacquire(addr *uint32, ms int32) int32 + +//go:noescape func plan9_semrelease(addr *uint32, count int32) int32 + +//go:noescape func notify(fn unsafe.Pointer) int32 + func noted(mode int32) int32 + +//go:noescape func nsec(*int64) int64 + +//go:noescape func sigtramp(ureg, msg unsafe.Pointer) + func setfpmasks() + +//go:noescape func tstart_plan9(newm *m) + func errstr() string type _Plink uintptr diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h deleted file mode 100644 index 6d18024834..0000000000 --- a/src/runtime/os_plan9.h +++ /dev/null @@ -1,93 +0,0 @@ -// 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. - -// Plan 9-specific system calls -int32 runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset); -int32 runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset); -int64 runtime·seek(int32 fd, int64 offset, int32 whence); -void runtime·exits(int8* msg); -intptr runtime·brk_(void*); -int32 runtime·sleep(int32 ms); -int32 runtime·rfork(int32 flags); -int32 runtime·plan9_semacquire(uint32 *addr, int32 block); -int32 runtime·plan9_tsemacquire(uint32 *addr, int32 ms); -int32 runtime·plan9_semrelease(uint32 *addr, int32 count); -int32 runtime·notify(void (*fn)(void*, int8*)); -int32 runtime·noted(int32); -int64 runtime·nsec(int64*); -void runtime·sigtramp(void*, int8*); -void runtime·sigpanic(void); -void runtime·goexitsall(int8*); -void runtime·setfpmasks(void); -void runtime·tstart_plan9(M *newm); - -/* open */ -enum -{ - OREAD = 0, - OWRITE = 1, - ORDWR = 2, - OEXEC = 3, - OTRUNC = 16, - OCEXEC = 32, - ORCLOSE = 64, - OEXCL = 0x1000 -}; - -/* rfork */ -enum -{ - RFNAMEG = (1<<0), - RFENVG = (1<<1), - RFFDG = (1<<2), - RFNOTEG = (1<<3), - RFPROC = (1<<4), - RFMEM = (1<<5), - RFNOWAIT = (1<<6), - RFCNAMEG = (1<<10), - RFCENVG = (1<<11), - RFCFDG = (1<<12), - RFREND = (1<<13), - RFNOMNT = (1<<14) -}; - -/* notify */ -enum -{ - NCONT = 0, - NDFLT = 1 -}; - -typedef struct Tos Tos; -typedef intptr _Plink; - -struct Tos { - struct TosProf /* Per process profiling */ - { - _Plink *pp; /* known to be 0(ptr) */ - _Plink *next; /* known to be 4(ptr) */ - _Plink *last; - _Plink *first; - uint32 pid; - uint32 what; - } prof; - uint64 cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */ - int64 kcycles; /* cycles spent in kernel */ - int64 pcycles; /* cycles spent in process (kernel + user) */ - uint32 pid; /* might as well put the pid here */ - uint32 clock; - /* top of stack is here */ -}; - -enum { - NSIG = 14, /* number of signals in runtime·SigTab array */ - ERRMAX = 128, /* max length of note string */ - - /* Notes in runtime·sigtab that are handled by runtime·sigpanic. */ - SIGRFAULT = 2, - SIGWFAULT = 3, - SIGINTDIV = 4, - SIGFLOAT = 5, - SIGTRAP = 6, -}; diff --git a/src/runtime/os_plan9_386.c b/src/runtime/os_plan9_386.c deleted file mode 100644 index 42c6d161c7..0000000000 --- a/src/runtime/os_plan9_386.c +++ /dev/null @@ -1,150 +0,0 @@ -// 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %x\n", u->ax); - runtime·printf("bx %x\n", u->bx); - runtime·printf("cx %x\n", u->cx); - runtime·printf("dx %x\n", u->dx); - runtime·printf("di %x\n", u->di); - runtime·printf("si %x\n", u->si); - runtime·printf("bp %x\n", u->bp); - runtime·printf("sp %x\n", u->sp); - runtime·printf("pc %x\n", u->pc); - runtime·printf("flags %x\n", u->flags); - runtime·printf("cs %x\n", u->cs); - runtime·printf("fs %x\n", u->fs); - runtime·printf("gs %x\n", u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *note, G *gp) -{ - uintptr *sp; - SigTab *t; - bool crash; - Ureg *ureg; - intgo len, n; - int32 sig, flags; - - ureg = (Ureg*)v; - - // The kernel will never pass us a nil note or ureg so we probably - // made a mistake somewhere in runtime·sigtramp. - if(ureg == nil || note == nil) { - runtime·printf("sighandler: ureg %p note %p\n", ureg, note); - goto Throw; - } - - // Check that the note is no more than ERRMAX bytes (including - // the trailing NUL). We should never receive a longer note. - len = runtime·findnull((byte*)note); - if(len > ERRMAX-1) { - runtime·printf("sighandler: note is longer than ERRMAX\n"); - goto Throw; - } - - // See if the note matches one of the patterns in runtime·sigtab. - // Notes that do not match any pattern can be handled at a higher - // level by the program but will otherwise be ignored. - flags = SigNotify; - for(sig = 0; sig < nelem(runtime·sigtab); sig++) { - t = &runtime·sigtab[sig]; - n = runtime·findnull((byte*)t->name); - if(len < n) - continue; - if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) { - flags = t->flags; - break; - } - } - - if(flags & SigGoExit) - runtime·exits(note+9); // Strip "go: exit " prefix. - - if(flags & SigPanic) { - // Copy the error string from sigtramp's stack into m->notesig so - // we can reliably access it from the panic routines. - runtime·memmove(g->m->notesig, note, len+1); - - gp->sig = sig; - gp->sigpc = ureg->pc; - - // Only push runtime·sigpanic if PC != 0. - // - // If PC == 0, probably panicked because of a call to a nil func. - // Not pushing that onto SP will make the trace look like a call - // to runtime·sigpanic instead. (Otherwise the trace will end at - // runtime·sigpanic and we won't get to see who faulted). - if(ureg->pc != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->pc; - ureg->sp = (uint32)sp; - } - ureg->pc = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(flags & SigNotify) { - // TODO(ality): See if os/signal wants it. - //if(runtime·sigsend(...)) - // return NCONT; - } - if(flags & SigKill) - goto Exit; - if(!(flags & SigThrow)) - return NCONT; - -Throw: - g->m->throwing = 1; - g->m->caughtsig = gp; - runtime·startpanic(); - - runtime·printf("%s\n", note); - runtime·printf("PC=%x\n", ureg->pc); - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)) { - runtime·goroutineheader(gp); - runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(ureg); - } - - if(crash) - runtime·crash(); - -Exit: - runtime·goexitsall(note); - runtime·exits(note); - return NDFLT; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - g->m->profilehz = hz; -} diff --git a/src/runtime/os_plan9_386.go b/src/runtime/os_plan9_386.go new file mode 100644 index 0000000000..7dda13931e --- /dev/null +++ b/src/runtime/os_plan9_386.go @@ -0,0 +1,131 @@ +// 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. + +package runtime + +import "unsafe" + +func dumpregs(u *ureg) { + print("ax ", hex(u.ax), "\n") + print("bx ", hex(u.bx), "\n") + print("cx ", hex(u.cx), "\n") + print("dx ", hex(u.dx), "\n") + print("di ", hex(u.di), "\n") + print("si ", hex(u.si), "\n") + print("bp ", hex(u.bp), "\n") + print("sp ", hex(u.sp), "\n") + print("pc ", hex(u.pc), "\n") + print("flags ", hex(u.flags), "\n") + print("cs ", hex(u.cs), "\n") + print("fs ", hex(u.fs), "\n") + print("gs ", hex(u.gs), "\n") +} + +func sighandler(_ureg *ureg, note *byte, gp *g) int { + _g_ := getg() + var t sigTabT + var docrash bool + var length int + var sig int + var flags int + + // The kernel will never pass us a nil note or ureg so we probably + // made a mistake somewhere in sigtramp. + if _ureg == nil || note == nil { + print("sighandler: ureg ", _ureg, " note ", note, "\n") + goto Throw + } + // Check that the note is no more than ERRMAX bytes (including + // the trailing NUL). We should never receive a longer note. + length = findnull(note) + if length > _ERRMAX-1 { + print("sighandler: note is longer than ERRMAX\n") + goto Throw + } + // See if the note matches one of the patterns in sigtab. + // Notes that do not match any pattern can be handled at a higher + // level by the program but will otherwise be ignored. + flags = _SigNotify + for sig, t = range sigtable { + n := len(t.name) + if length < n { + continue + } + if strncmp(note, &t.name[0], uintptr(n)) == 0 { + flags = t.flags + break + } + } + if flags&_SigGoExit != 0 { + exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix. + } + if flags&_SigPanic != 0 { + // Copy the error string from sigtramp's stack into m->notesig so + // we can reliably access it from the panic routines. + memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1)) + gp.sig = uint32(sig) + gp.sigpc = uintptr(_ureg.pc) + // Only push sigpanic if PC != 0. + // + // If PC == 0, probably panicked because of a call to a nil func. + // Not pushing that onto SP will make the trace look like a call + // to sigpanic instead. (Otherwise the trace will end at + // sigpanic and we won't get to see who faulted). + if _ureg.pc != 0 { + sp := _ureg.sp + if regSize > ptrSize { + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0 + } + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.pc) + _ureg.sp = sp + } + _ureg.pc = uint32(funcPC(sigpanic)) + return _NCONT + } + if flags&_SigNotify != 0 { + // TODO(ality): See if os/signal wants it. + //if(sigsend(...)) + // return _NCONT; + } + if flags&_SigKill != 0 { + goto Exit + } + if flags&_SigThrow == 0 { + return _NCONT + } +Throw: + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + print(gostringnocopy(note), "\n") + print("PC=", hex(_ureg.pc), "\n") + print("\n") + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(_ureg.pc), uintptr(_ureg.sp), 0, gp) + tracebackothers(gp) + print("\n") + dumpregs(_ureg) + } + if docrash { + crash() + } +Exit: + goexitsall(note) + exits(note) + return _NDFLT // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func resetcpuprofiler(hz int32) { + // TODO: Enable profiling interrupts. + getg().m.profilehz = hz +} diff --git a/src/runtime/os_plan9_amd64.c b/src/runtime/os_plan9_amd64.c deleted file mode 100644 index a9dc0eb966..0000000000 --- a/src/runtime/os_plan9_amd64.c +++ /dev/null @@ -1,158 +0,0 @@ -// 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %X\n", u->ax); - runtime·printf("bx %X\n", u->bx); - runtime·printf("cx %X\n", u->cx); - runtime·printf("dx %X\n", u->dx); - runtime·printf("di %X\n", u->di); - runtime·printf("si %X\n", u->si); - runtime·printf("bp %X\n", u->bp); - runtime·printf("sp %X\n", u->sp); - runtime·printf("r8 %X\n", u->r8); - runtime·printf("r9 %X\n", u->r9); - runtime·printf("r10 %X\n", u->r10); - runtime·printf("r11 %X\n", u->r11); - runtime·printf("r12 %X\n", u->r12); - runtime·printf("r13 %X\n", u->r13); - runtime·printf("r14 %X\n", u->r14); - runtime·printf("r15 %X\n", u->r15); - runtime·printf("ip %X\n", u->ip); - runtime·printf("flags %X\n", u->flags); - runtime·printf("cs %X\n", (uint64)u->cs); - runtime·printf("fs %X\n", (uint64)u->fs); - runtime·printf("gs %X\n", (uint64)u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *note, G *gp) -{ - uintptr *sp; - SigTab *t; - bool crash; - Ureg *ureg; - intgo len, n; - int32 sig, flags; - - ureg = (Ureg*)v; - - // The kernel will never pass us a nil note or ureg so we probably - // made a mistake somewhere in runtime·sigtramp. - if(ureg == nil || note == nil) { - runtime·printf("sighandler: ureg %p note %p\n", ureg, note); - goto Throw; - } - - // Check that the note is no more than ERRMAX bytes (including - // the trailing NUL). We should never receive a longer note. - len = runtime·findnull((byte*)note); - if(len > ERRMAX-1) { - runtime·printf("sighandler: note is longer than ERRMAX\n"); - goto Throw; - } - - // See if the note matches one of the patterns in runtime·sigtab. - // Notes that do not match any pattern can be handled at a higher - // level by the program but will otherwise be ignored. - flags = SigNotify; - for(sig = 0; sig < nelem(runtime·sigtab); sig++) { - t = &runtime·sigtab[sig]; - n = runtime·findnull((byte*)t->name); - if(len < n) - continue; - if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) { - flags = t->flags; - break; - } - } - - if(flags & SigGoExit) - runtime·exits(note+9); // Strip "go: exit " prefix. - - if(flags & SigPanic) { - // Copy the error string from sigtramp's stack into m->notesig so - // we can reliably access it from the panic routines. - runtime·memmove(g->m->notesig, note, len+1); - - gp->sig = sig; - gp->sigpc = ureg->ip; - - // Only push runtime·sigpanic if PC != 0. - // - // If PC == 0, probably panicked because of a call to a nil func. - // Not pushing that onto SP will make the trace look like a call - // to runtime·sigpanic instead. (Otherwise the trace will end at - // runtime·sigpanic and we won't get to see who faulted). - if(ureg->ip != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->ip; - ureg->sp = (uint64)sp; - } - ureg->ip = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(flags & SigNotify) { - // TODO(ality): See if os/signal wants it. - //if(runtime·sigsend(...)) - // return NCONT; - } - if(flags & SigKill) - goto Exit; - if(!(flags & SigThrow)) - return NCONT; - -Throw: - g->m->throwing = 1; - g->m->caughtsig = gp; - runtime·startpanic(); - - runtime·printf("%s\n", note); - runtime·printf("PC=%X\n", ureg->ip); - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)) { - runtime·goroutineheader(gp); - runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(ureg); - } - - if(crash) - runtime·crash(); - -Exit: - runtime·goexitsall(note); - runtime·exits(note); - return NDFLT; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - g->m->profilehz = hz; -} diff --git a/src/runtime/os_plan9_amd64.go b/src/runtime/os_plan9_amd64.go new file mode 100644 index 0000000000..8727dcc20f --- /dev/null +++ b/src/runtime/os_plan9_amd64.go @@ -0,0 +1,139 @@ +// 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. + +package runtime + +import "unsafe" + +func dumpregs(u *ureg) { + print("ax ", hex(u.ax), "\n") + print("bx ", hex(u.bx), "\n") + print("cx ", hex(u.cx), "\n") + print("dx ", hex(u.dx), "\n") + print("di ", hex(u.di), "\n") + print("si ", hex(u.si), "\n") + print("bp ", hex(u.bp), "\n") + print("sp ", hex(u.sp), "\n") + print("r8 ", hex(u.r8), "\n") + print("r9 ", hex(u.r9), "\n") + print("r10 ", hex(u.r10), "\n") + print("r11 ", hex(u.r11), "\n") + print("r12 ", hex(u.r12), "\n") + print("r13 ", hex(u.r13), "\n") + print("r14 ", hex(u.r14), "\n") + print("r15 ", hex(u.r15), "\n") + print("ip ", hex(u.ip), "\n") + print("flags ", hex(u.flags), "\n") + print("cs ", hex(uint64(u.cs)), "\n") + print("fs ", hex(uint64(u.fs)), "\n") + print("gs ", hex(uint64(u.gs)), "\n") +} + +func sighandler(_ureg *ureg, note *byte, gp *g) int { + _g_ := getg() + var t sigTabT + var docrash bool + var length int + var sig int + var flags int + + // The kernel will never pass us a nil note or ureg so we probably + // made a mistake somewhere in sigtramp. + if _ureg == nil || note == nil { + print("sighandler: ureg ", _ureg, " note ", note, "\n") + goto Throw + } + // Check that the note is no more than ERRMAX bytes (including + // the trailing NUL). We should never receive a longer note. + length = findnull(note) + if length > _ERRMAX-1 { + print("sighandler: note is longer than ERRMAX\n") + goto Throw + } + // See if the note matches one of the patterns in sigtab. + // Notes that do not match any pattern can be handled at a higher + // level by the program but will otherwise be ignored. + flags = _SigNotify + for sig, t = range sigtable { + n := len(t.name) + if length < n { + continue + } + if strncmp(note, &t.name[0], uintptr(n)) == 0 { + flags = t.flags + break + } + } + if flags&_SigGoExit != 0 { + exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix. + } + if flags&_SigPanic != 0 { + // Copy the error string from sigtramp's stack into m->notesig so + // we can reliably access it from the panic routines. + memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1)) + gp.sig = uint32(sig) + gp.sigpc = uintptr(_ureg.ip) + // Only push sigpanic if PC != 0. + // + // If PC == 0, probably panicked because of a call to a nil func. + // Not pushing that onto SP will make the trace look like a call + // to sigpanic instead. (Otherwise the trace will end at + // sigpanic and we won't get to see who faulted). + if _ureg.ip != 0 { + sp := _ureg.sp + if regSize > ptrSize { + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0 + } + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.ip) + _ureg.sp = sp + } + _ureg.ip = uint64(funcPC(sigpanic)) + return _NCONT + } + if flags&_SigNotify != 0 { + // TODO(ality): See if os/signal wants it. + //if(sigsend(...)) + // return _NCONT; + } + if flags&_SigKill != 0 { + goto Exit + } + if flags&_SigThrow == 0 { + return _NCONT + } +Throw: + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + print(gostringnocopy(note), "\n") + print("PC=", hex(_ureg.ip), "\n") + print("\n") + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(_ureg.ip), uintptr(_ureg.sp), 0, gp) + tracebackothers(gp) + print("\n") + dumpregs(_ureg) + } + if docrash { + crash() + } +Exit: + goexitsall(note) + exits(note) + return _NDFLT // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func resetcpuprofiler(hz int32) { + // TODO: Enable profiling interrupts. + getg().m.profilehz = hz +} diff --git a/src/runtime/signal_plan9.go b/src/runtime/signal_plan9.go new file mode 100644 index 0000000000..37d24359bf --- /dev/null +++ b/src/runtime/signal_plan9.go @@ -0,0 +1,54 @@ +// Copyright 2011 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 + +type sigTabT struct { + flags int + name []byte +} + +// Incoming notes are compared against this table using strncmp, so the +// order matters: longer patterns must appear before their prefixes. +// There are _SIG constants in os2_plan9.go for the table index of some +// of these. +// +// If you add entries to this table, you must respect the prefix ordering +// and also update the constant values is os2_plan9.go. +var sigtable = [...]sigTabT{ + // Traps that we cannot be recovered. + {_SigThrow, []byte("sys: trap: debug exception")}, + {_SigThrow, []byte("sys: trap: invalid opcode")}, + + // We can recover from some memory errors in runtime·sigpanic. + {_SigPanic, []byte("sys: trap: fault read addr")}, // SIGRFAULT + {_SigPanic, []byte("sys: trap: fault write addr")}, // SIGWFAULT + + // We can also recover from math errors. + {_SigPanic, []byte("sys: trap: divide error")}, // SIGINTDIV + {_SigPanic, []byte("sys: fp:")}, // SIGFLOAT + + // All other traps are normally handled as if they were marked SigThrow. + // We mark them SigPanic here so that debug.SetPanicOnFault will work. + {_SigPanic, []byte("sys: trap:")}, // SIGTRAP + + // Writes to a closed pipe can be handled if desired, otherwise they're ignored. + {_SigNotify, []byte("sys: write on closed pipe")}, + + // Other system notes are more serious and cannot be recovered. + {_SigThrow, []byte("sys:")}, + + // Issued to all other procs when calling runtime·exit. + {_SigGoExit, []byte("go: exit ")}, + + // Kill is sent by external programs to cause an exit. + {_SigKill, []byte("kill")}, + + // Interrupts can be handled if desired, otherwise they cause an exit. + {_SigNotify + _SigKill, []byte("interrupt")}, + {_SigNotify + _SigKill, []byte("hangup")}, + + // Alarms can be handled if desired, otherwise they're ignored. + {_SigNotify, []byte("alarm")}, +} diff --git a/src/runtime/signals_plan9.h b/src/runtime/signals_plan9.h deleted file mode 100644 index 4ee8e542c9..0000000000 --- a/src/runtime/signals_plan9.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2011 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. - -#include "textflag.h" - -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define E SigGoExit - -// Incoming notes are compared against this table using strncmp, so the -// order matters: longer patterns must appear before their prefixes. -// There are #defined SIG constants in os_plan9.h for the table index of -// some of these. -// -// If you add entries to this table, you must respect the prefix ordering -// and also update the constant values is os_plan9.h. - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { - // Traps that we cannot be recovered. - T, "sys: trap: debug exception", - T, "sys: trap: invalid opcode", - - // We can recover from some memory errors in runtime·sigpanic. - P, "sys: trap: fault read addr", // SIGRFAULT - P, "sys: trap: fault write addr", // SIGWFAULT - - // We can also recover from math errors. - P, "sys: trap: divide error", // SIGINTDIV - P, "sys: fp:", // SIGFLOAT - - // All other traps are normally handled as if they were marked SigThrow. - // We mark them SigPanic here so that debug.SetPanicOnFault will work. - P, "sys: trap:", // SIGTRAP - - // Writes to a closed pipe can be handled if desired, otherwise they're ignored. - N, "sys: write on closed pipe", - - // Other system notes are more serious and cannot be recovered. - T, "sys:", - - // Issued to all other procs when calling runtime·exit. - E, "go: exit ", - - // Kill is sent by external programs to cause an exit. - K, "kill", - - // Interrupts can be handled if desired, otherwise they cause an exit. - N+K, "interrupt", - N+K, "hangup", - - // Alarms can be handled if desired, otherwise they're ignored. - N, "alarm", -}; - -#undef N -#undef K -#undef T -#undef P -#undef E diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index 74cc5c6a7c..60751dd343 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !plan9 // +build !solaris // +build !windows // +build !nacl diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go new file mode 100644 index 0000000000..ffaa28775d --- /dev/null +++ b/src/runtime/stubs3.go @@ -0,0 +1,12 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build plan9 + +package runtime + +func close(fd int32) int32 + +//go:noescape +func open(name *byte, mode, perm int32) int32 -- cgit v1.3-5-g9baa From adbca13cb36489651ac5b989b6361d81c358d91e Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 21 Nov 2014 18:13:59 -0500 Subject: [dev.cc] runtime: explicitly exclude android in zgoos_linux.go Otherwise both zgoos_linux.go and zgoos_android.go will be compiled for GOOS=android. LGTM=crawshaw, rsc R=rsc, crawshaw CC=golang-codereviews https://golang.org/cl/178110043 --- src/runtime/gengoos.go | 4 +++- src/runtime/zgoos_android.go | 2 -- src/runtime/zgoos_darwin.go | 2 -- src/runtime/zgoos_dragonfly.go | 2 -- src/runtime/zgoos_freebsd.go | 2 -- src/runtime/zgoos_linux.go | 2 +- src/runtime/zgoos_nacl.go | 2 -- src/runtime/zgoos_netbsd.go | 2 -- src/runtime/zgoos_openbsd.go | 2 -- src/runtime/zgoos_plan9.go | 2 -- src/runtime/zgoos_solaris.go | 2 -- src/runtime/zgoos_windows.go | 2 -- 12 files changed, 4 insertions(+), 22 deletions(-) (limited to 'src/runtime') diff --git a/src/runtime/gengoos.go b/src/runtime/gengoos.go index 029575bee2..06621c8dba 100644 --- a/src/runtime/gengoos.go +++ b/src/runtime/gengoos.go @@ -46,7 +46,9 @@ func main() { for _, target := range gooses { var buf bytes.Buffer fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") - fmt.Fprintf(&buf, "// +build %s\n\n", target) // usually redundant, but not always; see linux vs android + if target == "linux" { + fmt.Fprintf(&buf, "// +build !android\n\n") // must explicitly exclude android for linux + } fmt.Fprintf(&buf, "package runtime\n\n") fmt.Fprintf(&buf, "const theGoos = `%s`\n\n", target) for _, goos := range gooses { diff --git a/src/runtime/zgoos_android.go b/src/runtime/zgoos_android.go index abfba808ba..0590bd9ab7 100644 --- a/src/runtime/zgoos_android.go +++ b/src/runtime/zgoos_android.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build android - package runtime const theGoos = `android` diff --git a/src/runtime/zgoos_darwin.go b/src/runtime/zgoos_darwin.go index eb39b53dd4..c0a7cd6e74 100644 --- a/src/runtime/zgoos_darwin.go +++ b/src/runtime/zgoos_darwin.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build darwin - package runtime const theGoos = `darwin` diff --git a/src/runtime/zgoos_dragonfly.go b/src/runtime/zgoos_dragonfly.go index f6e839d3d8..008d6de811 100644 --- a/src/runtime/zgoos_dragonfly.go +++ b/src/runtime/zgoos_dragonfly.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build dragonfly - package runtime const theGoos = `dragonfly` diff --git a/src/runtime/zgoos_freebsd.go b/src/runtime/zgoos_freebsd.go index 3c47aef2ab..2478940353 100644 --- a/src/runtime/zgoos_freebsd.go +++ b/src/runtime/zgoos_freebsd.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build freebsd - package runtime const theGoos = `freebsd` diff --git a/src/runtime/zgoos_linux.go b/src/runtime/zgoos_linux.go index 5d899e3db6..c775ab538d 100644 --- a/src/runtime/zgoos_linux.go +++ b/src/runtime/zgoos_linux.go @@ -1,6 +1,6 @@ // generated by gengoos.go using 'go generate' -// +build linux +// +build !android package runtime diff --git a/src/runtime/zgoos_nacl.go b/src/runtime/zgoos_nacl.go index b5c4281fb5..d9d88f4508 100644 --- a/src/runtime/zgoos_nacl.go +++ b/src/runtime/zgoos_nacl.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build nacl - package runtime const theGoos = `nacl` diff --git a/src/runtime/zgoos_netbsd.go b/src/runtime/zgoos_netbsd.go index b2e45222ae..ff2c5cb8f4 100644 --- a/src/runtime/zgoos_netbsd.go +++ b/src/runtime/zgoos_netbsd.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build netbsd - package runtime const theGoos = `netbsd` diff --git a/src/runtime/zgoos_openbsd.go b/src/runtime/zgoos_openbsd.go index 331c96dd66..b071dc63ab 100644 --- a/src/runtime/zgoos_openbsd.go +++ b/src/runtime/zgoos_openbsd.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build openbsd - package runtime const theGoos = `openbsd` diff --git a/src/runtime/zgoos_plan9.go b/src/runtime/zgoos_plan9.go index f29eb45230..4306b0f1ef 100644 --- a/src/runtime/zgoos_plan9.go +++ b/src/runtime/zgoos_plan9.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build plan9 - package runtime const theGoos = `plan9` diff --git a/src/runtime/zgoos_solaris.go b/src/runtime/zgoos_solaris.go index ac613db33c..10f9537d05 100644 --- a/src/runtime/zgoos_solaris.go +++ b/src/runtime/zgoos_solaris.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build solaris - package runtime const theGoos = `solaris` diff --git a/src/runtime/zgoos_windows.go b/src/runtime/zgoos_windows.go index 43710d862f..56f5c58ce6 100644 --- a/src/runtime/zgoos_windows.go +++ b/src/runtime/zgoos_windows.go @@ -1,7 +1,5 @@ // generated by gengoos.go using 'go generate' -// +build windows - package runtime const theGoos = `windows` -- cgit v1.3-5-g9baa From d3526ea0f6ff6775794ebce22192f48eec20aca0 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 21 Nov 2014 18:15:30 -0500 Subject: [dev.cc] runtime: migrate Android/ARM port to Go. I tested building Go itself, but not any of go.mobile tests. LGTM=crawshaw R=crawshaw, rsc CC=golang-codereviews https://golang.org/cl/179110043 --- src/runtime/os_android.c | 16 ---------------- src/runtime/os_android.h | 1 - src/runtime/os_android_arm.go | 15 +++++++++++++++ src/runtime/signal_android_386.h | 1 - src/runtime/signal_android_arm.h | 1 - src/runtime/signals_android.h | 1 - 6 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 src/runtime/os_android.c delete mode 100644 src/runtime/os_android.h create mode 100644 src/runtime/os_android_arm.go delete mode 100644 src/runtime/signal_android_386.h delete mode 100644 src/runtime/signal_android_arm.h delete mode 100644 src/runtime/signals_android.h (limited to 'src/runtime') diff --git a/src/runtime/os_android.c b/src/runtime/os_android.c deleted file mode 100644 index 5805f68713..0000000000 --- a/src/runtime/os_android.c +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -// Export the runtime entry point symbol. -// -// Used by the app package to start the Go runtime after loading -// a shared library via JNI. See golang.org/x/mobile/app. - -void _rt0_arm_linux1(); -#pragma cgo_export_static _rt0_arm_linux1 -#pragma cgo_export_dynamic _rt0_arm_linux1 diff --git a/src/runtime/os_android.h b/src/runtime/os_android.h deleted file mode 100644 index c7c1098e8d..0000000000 --- a/src/runtime/os_android.h +++ /dev/null @@ -1 +0,0 @@ -#include "os_linux.h" diff --git a/src/runtime/os_android_arm.go b/src/runtime/os_android_arm.go new file mode 100644 index 0000000000..132832236a --- /dev/null +++ b/src/runtime/os_android_arm.go @@ -0,0 +1,15 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import _ "unsafe" + +// Export the runtime entry point symbol. +// +// Used by the app package to start the Go runtime after loading +// a shared library via JNI. See golang.org/x/mobile/app. + +//go:cgo_export_static _rt0_arm_linux1 +//go:cgo_export_dynamic _rt0_arm_linux1 diff --git a/src/runtime/signal_android_386.h b/src/runtime/signal_android_386.h deleted file mode 100644 index 2a1bb4b3e4..0000000000 --- a/src/runtime/signal_android_386.h +++ /dev/null @@ -1 +0,0 @@ -#include "signal_linux_386.h" diff --git a/src/runtime/signal_android_arm.h b/src/runtime/signal_android_arm.h deleted file mode 100644 index 8a05e21e59..0000000000 --- a/src/runtime/signal_android_arm.h +++ /dev/null @@ -1 +0,0 @@ -#include "signal_linux_arm.h" diff --git a/src/runtime/signals_android.h b/src/runtime/signals_android.h deleted file mode 100644 index 5140d8a184..0000000000 --- a/src/runtime/signals_android.h +++ /dev/null @@ -1 +0,0 @@ -#include "signals_linux.h" -- cgit v1.3-5-g9baa From cfc8099a9a71bbcdd8b3259be2f50578872c9626 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 22 Nov 2014 16:05:31 +1100 Subject: [dev.cc] runtime: convert netbsd/amd64 port to Go LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/169620043 --- src/runtime/defs1_netbsd_amd64.go | 20 +- src/runtime/os1_netbsd.go | 265 ++++++++++++++++++++++++++ src/runtime/os1_netbsd_amd64.go | 16 ++ src/runtime/os2_netbsd.go | 18 ++ src/runtime/os_netbsd.c | 368 ------------------------------------- src/runtime/os_netbsd.go | 32 +++- src/runtime/os_netbsd.h | 31 ---- src/runtime/os_netbsd_amd64.c | 18 -- src/runtime/signal_netbsd.go | 46 +++++ src/runtime/signal_netbsd_amd64.go | 48 +++++ src/runtime/signal_netbsd_amd64.h | 31 ---- src/runtime/signals_netbsd.h | 54 ------ 12 files changed, 436 insertions(+), 511 deletions(-) create mode 100644 src/runtime/os1_netbsd.go create mode 100644 src/runtime/os1_netbsd_amd64.go create mode 100644 src/runtime/os2_netbsd.go delete mode 100644 src/runtime/os_netbsd.c delete mode 100644 src/runtime/os_netbsd.h delete mode 100644 src/runtime/os_netbsd_amd64.c create mode 100644 src/runtime/signal_netbsd.go create mode 100644 src/runtime/signal_netbsd_amd64.go delete mode 100644 src/runtime/signal_netbsd_amd64.h delete mode 100644 src/runtime/signals_netbsd.h (limited to 'src/runtime') diff --git a/src/runtime/defs1_netbsd_amd64.go b/src/runtime/defs1_netbsd_amd64.go index cca701e5bc..c2bde4dabe 100644 --- a/src/runtime/defs1_netbsd_amd64.go +++ b/src/runtime/defs1_netbsd_amd64.go @@ -84,8 +84,8 @@ const ( ) type sigaltstackt struct { - ss_sp *byte - ss_size uint64 + ss_sp uintptr + ss_size uintptr ss_flags int32 pad_cgo_0 [4]byte } @@ -103,8 +103,8 @@ type siginfo struct { } type stackt struct { - ss_sp *byte - ss_size uint64 + ss_sp uintptr + ss_size uintptr ss_flags int32 pad_cgo_0 [4]byte } @@ -114,12 +114,24 @@ type timespec struct { tv_nsec int64 } +func (ts *timespec) set_sec(x int32) { + ts.tv_sec = int64(x) +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + type timeval struct { tv_sec int64 tv_usec int32 pad_cgo_0 [4]byte } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + type itimerval struct { it_interval timeval it_value timeval diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go new file mode 100644 index 0000000000..493be30fa5 --- /dev/null +++ b/src/runtime/os1_netbsd.go @@ -0,0 +1,265 @@ +// Copyright 2011 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" + +const ( + _ESRCH = 3 + _ENOTSUP = 91 + + // From NetBSD's + _CLOCK_REALTIME = 0 + _CLOCK_VIRTUAL = 1 + _CLOCK_PROF = 2 + _CLOCK_MONOTONIC = 3 +) + +var sigset_none = sigset{} +var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} + +// From NetBSD's +const ( + _CTL_HW = 6 + _HW_NCPU = 3 +) + +func getncpu() int32 { + mib := [2]uint32{_CTL_HW, _HW_NCPU} + out := uint32(0) + nout := unsafe.Sizeof(out) + ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) + if ret >= 0 { + return int32(out) + } + return 1 +} + +//go:nosplit +func semacreate() uintptr { + return 1 +} + +//go:nosplit +func semasleep(ns int64) int32 { + _g_ := getg() + + // spin-mutex lock + for { + if xchg(&_g_.m.waitsemalock, 1) == 0 { + break + } + osyield() + } + + for { + // lock held + if _g_.m.waitsemacount == 0 { + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m.waitsemalock. + if ns < 0 { + // TODO(jsing) - potential deadlock! + // + // There is a potential deadlock here since we + // have to release the waitsemalock mutex + // before we call lwp_park() to suspend the + // thread. This allows another thread to + // release the lock and call lwp_unpark() + // before the thread is actually suspended. + // If this occurs the current thread will end + // up sleeping indefinitely. Unfortunately + // the NetBSD kernel does not appear to provide + // a mechanism for unlocking the userspace + // mutex once the thread is actually parked. + atomicstore(&_g_.m.waitsemalock, 0) + lwp_park(nil, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) + } else { + var ts timespec + var nsec int32 + ns += nanotime() + ts.set_sec(timediv(ns, 1000000000, &nsec)) + ts.set_nsec(nsec) + // TODO(jsing) - potential deadlock! + // See above for details. + atomicstore(&_g_.m.waitsemalock, 0) + lwp_park(&ts, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) + } + // reacquire lock + for { + if xchg(&_g_.m.waitsemalock, 1) == 0 { + break + } + osyield() + } + } + + // lock held (again) + if _g_.m.waitsemacount != 0 { + // semaphore is available. + _g_.m.waitsemacount-- + // spin-mutex unlock + atomicstore(&_g_.m.waitsemalock, 0) + return 0 + } + + // semaphore not available. + // if there is a timeout, stop now. + // otherwise keep trying. + if ns >= 0 { + break + } + } + + // lock held but giving up + // spin-mutex unlock + atomicstore(&_g_.m.waitsemalock, 0) + return -1 +} + +//go:nosplit +func semawakeup(mp *m) { + // spin-mutex lock + for { + if xchg(&mp.waitsemalock, 1) == 0 { + break + } + osyield() + } + + mp.waitsemacount++ + // TODO(jsing) - potential deadlock, see semasleep() for details. + // Confirm that LWP is parked before unparking... + ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) + if ret != 0 && ret != _ESRCH { + // semawakeup can be called on signal stack. + systemstack(func() { + print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") + }) + } + + // spin-mutex unlock + atomicstore(&mp.waitsemalock, 0) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + if false { + print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n") + } + + mp.tls[0] = uintptr(mp.id) // so 386 asm can find it + + var uc ucontextt + getcontext(unsafe.Pointer(&uc)) + + uc.uc_flags = _UC_SIGMASK | _UC_CPU + uc.uc_link = nil + uc.uc_sigmask = sigset_all + + lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(mstart)) + + ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid)) + if ret < 0 { + print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") + gothrow("runtime.newosproc") + } +} + +func osinit() { + ncpu = getncpu() +} + +var urandom_data [_HashRandomBytes]byte +var urandom_dev = []byte("/dev/urandom\x00") + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) + if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes { + *rnd = unsafe.Pointer(&urandom_data[0]) + *rnd_len = _HashRandomBytes + } else { + *rnd = nil + *rnd_len = 0 + } + close(fd) +} + +func goenvs() { + goenvs_unix() +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + _g_ := getg() + _g_.m.procid = uint64(lwp_self()) + + // Initialize signal handling + signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) + sigprocmask(_SIG_SETMASK, &sigset_none, nil) +} + +// Called from dropm to undo the effect of an minit. +func unminit() { + signalstack(nil, 0) +} + +func memlimit() uintptr { + return 0 +} + +func sigtramp() + +type sigactiont struct { + sa_sigaction uintptr + sa_mask sigset + sa_flags int32 +} + +func setsig(i int32, fn uintptr, restart bool) { + var sa sigactiont + sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK + if restart { + sa.sa_flags |= _SA_RESTART + } + sa.sa_mask = sigset_all + if fn == funcPC(sighandler) { + fn = funcPC(sigtramp) + } + sa.sa_sigaction = fn + sigaction(i, &sa, nil) +} + +func getsig(i int32) uintptr { + var sa sigactiont + sigaction(i, nil, &sa) + if sa.sa_sigaction == funcPC(sigtramp) { + return funcPC(sighandler) + } + return sa.sa_sigaction +} + +func signalstack(p *byte, n int32) { + var st sigaltstackt + + st.ss_sp = uintptr(unsafe.Pointer(p)) + st.ss_size = uintptr(n) + st.ss_flags = 0 + if p == nil { + st.ss_flags = _SS_DISABLE + } + sigaltstack(&st, nil) +} + +func unblocksignals() { + sigprocmask(_SIG_SETMASK, &sigset_none, nil) +} diff --git a/src/runtime/os1_netbsd_amd64.go b/src/runtime/os1_netbsd_amd64.go new file mode 100644 index 0000000000..5118b0c4ff --- /dev/null +++ b/src/runtime/os1_netbsd_amd64.go @@ -0,0 +1,16 @@ +// 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" + +func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { + // Machine dependent mcontext initialisation for LWP. + mc.__gregs[_REG_RIP] = uint64(funcPC(lwp_tramp)) + mc.__gregs[_REG_RSP] = uint64(uintptr(stk)) + mc.__gregs[_REG_R8] = uint64(uintptr(unsafe.Pointer(mp))) + mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp))) + mc.__gregs[_REG_R12] = uint64(fn) +} diff --git a/src/runtime/os2_netbsd.go b/src/runtime/os2_netbsd.go new file mode 100644 index 0000000000..46576b9bc3 --- /dev/null +++ b/src/runtime/os2_netbsd.go @@ -0,0 +1,18 @@ +// 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. + +package runtime + +const ( + _SS_DISABLE = 4 + _SIG_BLOCK = 1 + _SIG_UNBLOCK = 2 + _SIG_SETMASK = 3 + _NSIG = 33 + _SI_USER = 0 + + // From NetBSD's + _UC_SIGMASK = 0x01 + _UC_CPU = 0x04 +) diff --git a/src/runtime/os_netbsd.c b/src/runtime/os_netbsd.c deleted file mode 100644 index 58e5bedf2f..0000000000 --- a/src/runtime/os_netbsd.c +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2011 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signal_unix.h" -#include "stack.h" -#include "textflag.h" - -enum -{ - ESRCH = 3, - ENOTSUP = 91, - - // From NetBSD's - CLOCK_REALTIME = 0, - CLOCK_VIRTUAL = 1, - CLOCK_PROF = 2, - CLOCK_MONOTONIC = 3 -}; - -extern SigTab runtime·sigtab[]; - -static Sigset sigset_none; -static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, }; - -extern void runtime·getcontext(UcontextT *context); -extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid); -extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void)); -extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint); -extern int32 runtime·lwp_unpark(int32 lwp, void *hint); -extern int32 runtime·lwp_self(void); - -// From NetBSD's -#define CTL_HW 6 -#define HW_NCPU 3 - -static int32 -getncpu(void) -{ - uint32 mib[2]; - uint32 out; - int32 ret; - uintptr nout; - - // Fetch hw.ncpu via sysctl. - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - nout = sizeof out; - out = 0; - ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); - if(ret >= 0) - return out; - else - return 1; -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return 1; -} - -static void -semasleep(void) -{ - int64 ns; - Timespec ts; - - ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; - g->m->scalararg[0] = 0; - g->m->scalararg[1] = 0; - - // spin-mutex lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); - - for(;;) { - // lock held - if(g->m->waitsemacount == 0) { - // sleep until semaphore != 0 or timeout. - // thrsleep unlocks m->waitsemalock. - if(ns < 0) { - // TODO(jsing) - potential deadlock! - // - // There is a potential deadlock here since we - // have to release the waitsemalock mutex - // before we call lwp_park() to suspend the - // thread. This allows another thread to - // release the lock and call lwp_unpark() - // before the thread is actually suspended. - // If this occurs the current thread will end - // up sleeping indefinitely. Unfortunately - // the NetBSD kernel does not appear to provide - // a mechanism for unlocking the userspace - // mutex once the thread is actually parked. - runtime·atomicstore(&g->m->waitsemalock, 0); - runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil); - } else { - ns = ns + runtime·nanotime(); - // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system. - ts.tv_nsec = 0; - ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); - // TODO(jsing) - potential deadlock! - // See above for details. - runtime·atomicstore(&g->m->waitsemalock, 0); - runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil); - } - // reacquire lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); - } - - // lock held (again) - if(g->m->waitsemacount != 0) { - // semaphore is available. - g->m->waitsemacount--; - // spin-mutex unlock - runtime·atomicstore(&g->m->waitsemalock, 0); - g->m->scalararg[0] = 0; // semaphore acquired - return; - } - - // semaphore not available. - // if there is a timeout, stop now. - // otherwise keep trying. - if(ns >= 0) - break; - } - - // lock held but giving up - // spin-mutex unlock - runtime·atomicstore(&g->m->waitsemalock, 0); - g->m->scalararg[0] = -1; - return; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 r; - void (*fn)(void); - - g->m->scalararg[0] = (uint32)ns; - g->m->scalararg[1] = (uint32)(ns>>32); - fn = semasleep; - runtime·onM(&fn); - r = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return r; -} - -static void badsemawakeup(void); - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - uint32 ret; - void (*fn)(void); - void *oldptr; - uintptr oldscalar; - - // spin-mutex lock - while(runtime·xchg(&mp->waitsemalock, 1)) - runtime·osyield(); - mp->waitsemacount++; - // TODO(jsing) - potential deadlock, see semasleep() for details. - // Confirm that LWP is parked before unparking... - ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount); - if(ret != 0 && ret != ESRCH) { - // semawakeup can be called on signal stack. - // Save old ptrarg/scalararg so we can restore them. - oldptr = g->m->ptrarg[0]; - oldscalar = g->m->scalararg[0]; - g->m->ptrarg[0] = mp; - g->m->scalararg[0] = ret; - fn = badsemawakeup; - if(g == g->m->gsignal) - fn(); - else - runtime·onM(&fn); - g->m->ptrarg[0] = oldptr; - g->m->scalararg[0] = oldscalar; - } - // spin-mutex unlock - runtime·atomicstore(&mp->waitsemalock, 0); -} - -static void -badsemawakeup(void) -{ - M *mp; - int32 ret; - - mp = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - ret = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - - runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - UcontextT uc; - int32 ret; - - if(0) { - runtime·printf( - "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); - } - - mp->tls[0] = mp->id; // so 386 asm can find it - - runtime·getcontext(&uc); - - uc.uc_flags = _UC_SIGMASK | _UC_CPU; - uc.uc_link = nil; - uc.uc_sigmask = sigset_all; - - runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart); - - ret = runtime·lwp_create(&uc, 0, &mp->procid); - - if(ret < 0) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); - runtime·throw("runtime.newosproc"); - } -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getncpu(); -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - #pragma dataflag NOPTR - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); - mp->gsignal->m = mp; -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - g->m->procid = runtime·lwp_self(); - - // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*_sa_handler)(int32); - void (*_sa_sigaction)(int32, Siginfo*, void *); - } _sa_u; /* signal handler */ - uint32 sa_mask[4]; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} SigactionT; - -void -runtime·setsig(int32 i, GoSighandler *fn, bool restart) -{ - SigactionT sa; - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask[0] = ~0U; - sa.sa_mask[1] = ~0U; - sa.sa_mask[2] = ~0U; - sa.sa_mask[3] = ~0U; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa._sa_u._sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} - -GoSighandler* -runtime·getsig(int32 i) -{ - SigactionT sa; - - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp) - return runtime·sighandler; - return (void*)sa._sa_u._sa_sigaction; -} - -void -runtime·signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = (void*)p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·unblocksignals(void) -{ - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); -} - -#pragma textflag NOSPLIT -int8* -runtime·signame(int32 sig) -{ - return runtime·sigtab[sig].name; -} diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index f000c5e9f6..a153bf2ebc 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -6,15 +6,37 @@ package runtime import "unsafe" -func setitimer(mode int32, new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigaltstack(new, old unsafe.Pointer) -func sigprocmask(mode int32, new, old unsafe.Pointer) +//go:noescape +func setitimer(mode int32, new, old *itimerval) + +//go:noescape +func sigaction(sig int32, new, old *sigactiont) + +//go:noescape +func sigaltstack(new, old *sigaltstackt) + +//go:noescape +func sigprocmask(mode int32, new, old *sigset) + +//go:noescape func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 + func lwp_tramp() + func raise(sig int32) + +//go:noescape func getcontext(ctxt unsafe.Pointer) + +//go:noescape func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32 -func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32 + +//go:noescape +func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 + +//go:noescape func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 + func lwp_self() int32 + +func osyield() diff --git a/src/runtime/os_netbsd.h b/src/runtime/os_netbsd.h deleted file mode 100644 index f95db325f0..0000000000 --- a/src/runtime/os_netbsd.h +++ /dev/null @@ -1,31 +0,0 @@ -// 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. - - -typedef uintptr kevent_udata; - -struct sigaction; - -void runtime·sigpanic(void); - -void runtime·setitimer(int32, Itimerval*, Itimerval*); -void runtime·sigaction(int32, struct sigaction*, struct sigaction*); -void runtime·sigaltstack(SigaltstackT*, SigaltstackT*); -void runtime·sigprocmask(int32, Sigset*, Sigset*); -void runtime·unblocksignals(void); -int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); -extern void runtime·lwp_tramp(void); - -enum { - SS_DISABLE = 4, - SIG_BLOCK = 1, - SIG_UNBLOCK = 2, - SIG_SETMASK = 3, - NSIG = 33, - SI_USER = 0, - - // From NetBSD's - _UC_SIGMASK = 0x01, - _UC_CPU = 0x04, -}; diff --git a/src/runtime/os_netbsd_amd64.c b/src/runtime/os_netbsd_amd64.c deleted file mode 100644 index 226846cbb0..0000000000 --- a/src/runtime/os_netbsd_amd64.c +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - // Machine dependent mcontext initialisation for LWP. - mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp; - mc->__gregs[REG_RSP] = (uint64)stack; - mc->__gregs[REG_R8] = (uint64)mp; - mc->__gregs[REG_R9] = (uint64)gp; - mc->__gregs[REG_R12] = (uint64)fn; -} diff --git a/src/runtime/signal_netbsd.go b/src/runtime/signal_netbsd.go new file mode 100644 index 0000000000..78afc59efa --- /dev/null +++ b/src/runtime/signal_netbsd.go @@ -0,0 +1,46 @@ +// 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 + +type sigTabT struct { + flags int32 + name string +} + +var sigtable = [...]sigTabT{ + /* 0 */ {0, "SIGNONE: no trap"}, + /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, + /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, + /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, + /* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, + /* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, + /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, + /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, + /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, + /* 9 */ {0, "SIGKILL: kill"}, + /* 10 */ {_SigPanic, "SIGBUS: bus error"}, + /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, + /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, + /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, + /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, + /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, + /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"}, + /* 17 */ {0, "SIGSTOP: stop"}, + /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, + /* 19 */ {0, "SIGCONT: continue after stop"}, + /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, + /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, + /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, + /* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, + /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, + /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, + /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, + /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, + /* 28 */ {_SigNotify, "SIGWINCH: window size change"}, + /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, + /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, + /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, + /* 32 */ {_SigNotify, "SIGTHR: reserved"}, +} diff --git a/src/runtime/signal_netbsd_amd64.go b/src/runtime/signal_netbsd_amd64.go new file mode 100644 index 0000000000..e22f4a724a --- /dev/null +++ b/src/runtime/signal_netbsd_amd64.go @@ -0,0 +1,48 @@ +// Copyright 2013 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" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *mcontextt { + return (*mcontextt)(unsafe.Pointer(&(*ucontextt)(c.ctxt).uc_mcontext)) +} +func (c *sigctxt) rax() uint64 { return c.regs().__gregs[_REG_RAX] } +func (c *sigctxt) rbx() uint64 { return c.regs().__gregs[_REG_RBX] } +func (c *sigctxt) rcx() uint64 { return c.regs().__gregs[_REG_RCX] } +func (c *sigctxt) rdx() uint64 { return c.regs().__gregs[_REG_RDX] } +func (c *sigctxt) rdi() uint64 { return c.regs().__gregs[_REG_RDI] } +func (c *sigctxt) rsi() uint64 { return c.regs().__gregs[_REG_RSI] } +func (c *sigctxt) rbp() uint64 { return c.regs().__gregs[_REG_RBP] } +func (c *sigctxt) rsp() uint64 { return c.regs().__gregs[_REG_RSP] } +func (c *sigctxt) r8() uint64 { return c.regs().__gregs[_REG_R8] } +func (c *sigctxt) r9() uint64 { return c.regs().__gregs[_REG_R8] } +func (c *sigctxt) r10() uint64 { return c.regs().__gregs[_REG_R10] } +func (c *sigctxt) r11() uint64 { return c.regs().__gregs[_REG_R11] } +func (c *sigctxt) r12() uint64 { return c.regs().__gregs[_REG_R12] } +func (c *sigctxt) r13() uint64 { return c.regs().__gregs[_REG_R13] } +func (c *sigctxt) r14() uint64 { return c.regs().__gregs[_REG_R14] } +func (c *sigctxt) r15() uint64 { return c.regs().__gregs[_REG_R15] } +func (c *sigctxt) rip() uint64 { return c.regs().__gregs[_REG_RIP] } +func (c *sigctxt) rflags() uint64 { return c.regs().__gregs[_REG_RFLAGS] } +func (c *sigctxt) cs() uint64 { return c.regs().__gregs[_REG_CS] } +func (c *sigctxt) fs() uint64 { return c.regs().__gregs[_REG_FS] } +func (c *sigctxt) gs() uint64 { return c.regs().__gregs[_REG_GS] } +func (c *sigctxt) sigcode() uint64 { return uint64(c.info._code) } +func (c *sigctxt) sigaddr() uint64 { + return uint64(*(*uint64)(unsafe.Pointer(&c.info._reason[0]))) +} + +func (c *sigctxt) set_rip(x uint64) { c.regs().__gregs[_REG_RIP] = x } +func (c *sigctxt) set_rsp(x uint64) { c.regs().__gregs[_REG_RSP] = x } +func (c *sigctxt) set_sigcode(x uint64) { c.info._code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint64) { + *(*uint64)(unsafe.Pointer(&c.info._reason[0])) = x +} diff --git a/src/runtime/signal_netbsd_amd64.h b/src/runtime/signal_netbsd_amd64.h deleted file mode 100644 index 7ec4cd98cd..0000000000 --- a/src/runtime/signal_netbsd_amd64.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 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. - -#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext) - -#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RAX]) -#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBX]) -#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RCX]) -#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDX]) -#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDI]) -#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSI]) -#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBP]) -#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSP]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15]) -#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RIP]) -#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RFLAGS]) - -#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) -#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) -#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) - -#define SIG_CODE0(info, ctxt) ((info)->_code) -#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) diff --git a/src/runtime/signals_netbsd.h b/src/runtime/signals_netbsd.h deleted file mode 100644 index 950a2fe62c..0000000000 --- a/src/runtime/signals_netbsd.h +++ /dev/null @@ -1,54 +0,0 @@ -// 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. - -#include "textflag.h" - -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define D SigDefault - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ N+K, "SIGHUP: terminal line hangup", - /* 2 */ N+K, "SIGINT: interrupt", - /* 3 */ N+T, "SIGQUIT: quit", - /* 4 */ T, "SIGILL: illegal instruction", - /* 5 */ T, "SIGTRAP: trace trap", - /* 6 */ N+T, "SIGABRT: abort", - /* 7 */ T, "SIGEMT: emulate instruction executed", - /* 8 */ P, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ P, "SIGBUS: bus error", - /* 11 */ P, "SIGSEGV: segmentation violation", - /* 12 */ T, "SIGSYS: bad system call", - /* 13 */ N, "SIGPIPE: write to broken pipe", - /* 14 */ N, "SIGALRM: alarm clock", - /* 15 */ N+K, "SIGTERM: termination", - /* 16 */ N, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ N+D, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ N, "SIGCHLD: child status has changed", - /* 21 */ N+D, "SIGTTIN: background read from tty", - /* 22 */ N+D, "SIGTTOU: background write to tty", - /* 23 */ N, "SIGIO: i/o now possible", - /* 24 */ N, "SIGXCPU: cpu limit exceeded", - /* 25 */ N, "SIGXFSZ: file size limit exceeded", - /* 26 */ N, "SIGVTALRM: virtual alarm clock", - /* 27 */ N, "SIGPROF: profiling alarm clock", - /* 28 */ N, "SIGWINCH: window size change", - /* 29 */ N, "SIGINFO: status request from keyboard", - /* 30 */ N, "SIGUSR1: user-defined signal 1", - /* 31 */ N, "SIGUSR2: user-defined signal 2", - /* 32 */ N, "SIGTHR: reserved", -}; - -#undef N -#undef K -#undef T -#undef P -#undef D -- cgit v1.3-5-g9baa From 0d76887433b3034c4dfd8b909f3a4b76b0eabefb Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 22 Nov 2014 22:09:11 +1100 Subject: [dev.cc] runtime: convert netbsd/386 port to Go LGTM=minux R=rsc, minux CC=golang-codereviews https://golang.org/cl/177170043 --- src/runtime/defs1_netbsd_386.go | 22 +++++++++++++++++----- src/runtime/os1_netbsd_386.go | 16 ++++++++++++++++ src/runtime/os_netbsd_386.c | 17 ----------------- src/runtime/signal_netbsd_386.go | 38 ++++++++++++++++++++++++++++++++++++++ src/runtime/signal_netbsd_386.h | 23 ----------------------- 5 files changed, 71 insertions(+), 45 deletions(-) create mode 100644 src/runtime/os1_netbsd_386.go delete mode 100644 src/runtime/os_netbsd_386.c create mode 100644 src/runtime/signal_netbsd_386.go delete mode 100644 src/runtime/signal_netbsd_386.h (limited to 'src/runtime') diff --git a/src/runtime/defs1_netbsd_386.go b/src/runtime/defs1_netbsd_386.go index e39fd04c7a..f222bed996 100644 --- a/src/runtime/defs1_netbsd_386.go +++ b/src/runtime/defs1_netbsd_386.go @@ -84,8 +84,8 @@ const ( ) type sigaltstackt struct { - ss_sp *byte - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -101,8 +101,8 @@ type siginfo struct { } type stackt struct { - ss_sp *byte - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -111,18 +111,30 @@ type timespec struct { tv_nsec int32 } +func (ts *timespec) set_sec(x int32) { + ts.tv_sec = int64(x) +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = x +} + type timeval struct { tv_sec int64 tv_usec int32 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + type itimerval struct { it_interval timeval it_value timeval } type mcontextt struct { - __gregs [19]int32 + __gregs [19]uint32 __fpregs [644]byte _mc_tlsbase int32 } diff --git a/src/runtime/os1_netbsd_386.go b/src/runtime/os1_netbsd_386.go new file mode 100644 index 0000000000..037f7e36dc --- /dev/null +++ b/src/runtime/os1_netbsd_386.go @@ -0,0 +1,16 @@ +// 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" + +func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { + // Machine dependent mcontext initialisation for LWP. + mc.__gregs[_REG_EIP] = uint32(funcPC(lwp_tramp)) + mc.__gregs[_REG_UESP] = uint32(uintptr(stk)) + mc.__gregs[_REG_EBX] = uint32(uintptr(unsafe.Pointer(mp))) + mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp))) + mc.__gregs[_REG_ESI] = uint32(fn) +} diff --git a/src/runtime/os_netbsd_386.c b/src/runtime/os_netbsd_386.c deleted file mode 100644 index 23e9db3c1c..0000000000 --- a/src/runtime/os_netbsd_386.c +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp; - mc->__gregs[REG_UESP] = (uint32)stack; - mc->__gregs[REG_EBX] = (uint32)mp; - mc->__gregs[REG_EDX] = (uint32)gp; - mc->__gregs[REG_ESI] = (uint32)fn; -} diff --git a/src/runtime/signal_netbsd_386.go b/src/runtime/signal_netbsd_386.go new file mode 100644 index 0000000000..6702336abe --- /dev/null +++ b/src/runtime/signal_netbsd_386.go @@ -0,0 +1,38 @@ +// Copyright 2013 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" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext } +func (c *sigctxt) eax() uint32 { return c.regs().__gregs[_REG_EAX] } +func (c *sigctxt) ebx() uint32 { return c.regs().__gregs[_REG_EBX] } +func (c *sigctxt) ecx() uint32 { return c.regs().__gregs[_REG_ECX] } +func (c *sigctxt) edx() uint32 { return c.regs().__gregs[_REG_EDX] } +func (c *sigctxt) edi() uint32 { return c.regs().__gregs[_REG_EDI] } +func (c *sigctxt) esi() uint32 { return c.regs().__gregs[_REG_ESI] } +func (c *sigctxt) ebp() uint32 { return c.regs().__gregs[_REG_EBP] } +func (c *sigctxt) esp() uint32 { return c.regs().__gregs[_REG_UESP] } +func (c *sigctxt) eip() uint32 { return c.regs().__gregs[_REG_EIP] } +func (c *sigctxt) eflags() uint32 { return c.regs().__gregs[_REG_EFL] } +func (c *sigctxt) cs() uint32 { return uint32(c.regs().__gregs[_REG_CS]) } +func (c *sigctxt) fs() uint32 { return uint32(c.regs().__gregs[_REG_FS]) } +func (c *sigctxt) gs() uint32 { return uint32(c.regs().__gregs[_REG_GS]) } +func (c *sigctxt) sigcode() uint32 { return uint32(c.info._code) } +func (c *sigctxt) sigaddr() uint32 { + return uint32(*(*uint32)(unsafe.Pointer(&c.info._reason[0]))) +} + +func (c *sigctxt) set_eip(x uint32) { c.regs().__gregs[_REG_EIP] = x } +func (c *sigctxt) set_esp(x uint32) { c.regs().__gregs[_REG_UESP] = x } +func (c *sigctxt) set_sigcode(x uint32) { c.info._code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint32) { + *(*uint32)(unsafe.Pointer(&c.info._reason[0])) = x +} diff --git a/src/runtime/signal_netbsd_386.h b/src/runtime/signal_netbsd_386.h deleted file mode 100644 index d5a8a0c4bc..0000000000 --- a/src/runtime/signal_netbsd_386.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 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. - -#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext) - -#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX]) -#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX]) -#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX]) -#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX]) -#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI]) -#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI]) -#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP]) -#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_UESP]) -#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP]) -#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFL]) - -#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) -#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) -#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) - -#define SIG_CODE0(info, ctxt) ((info)->_code) -#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) -- cgit v1.3-5-g9baa