1
0
mirror of https://github.com/golang/go synced 2024-11-23 15:50:07 -07:00

[dev.cc] runtime: convert Plan 9 port to Go

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
This commit is contained in:
David du Colombier 2014-11-21 19:39:01 +01:00
parent ad8179281d
commit e9c57d8a2d
18 changed files with 756 additions and 923 deletions

View File

@ -1,5 +1,7 @@
package runtime
const _PAGESIZE = 0x1000
type ureg struct {
di uint32 /* general registers */
si uint32 /* ... */

View File

@ -1,5 +1,7 @@
package runtime
const _PAGESIZE = 0x1000
type ureg struct {
ax uint64
bx uint64

View File

@ -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

View File

@ -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);
}

70
src/runtime/mem_plan9.go Normal file
View File

@ -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)
}

View File

@ -4,15 +4,12 @@
// +build plan9
#include "runtime.h"
package runtime
// Polls for ready network connections.
// Returns list of goroutines that become runnable.
G*
runtime·netpoll(bool block)
{
func netpoll(block bool) (gp *g) {
// Implementation for platforms that do not support
// integrated network poller.
USED(block);
return nil;
return
}

270
src/runtime/os1_plan9.go Normal file
View File

@ -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
}

72
src/runtime/os2_plan9.go Normal file
View File

@ -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
)

View File

@ -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);
}

View File

@ -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

View File

@ -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,
};

View File

@ -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;
}

131
src/runtime/os_plan9_386.go Normal file
View File

@ -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
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -2,62 +2,53 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
package runtime
#define N SigNotify
#define K SigKill
#define T SigThrow
#define P SigPanic
#define E SigGoExit
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 #defined SIG constants in os_plan9.h for the table index of
// some of these.
// 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 os_plan9.h.
#pragma dataflag NOPTR
SigTab runtime·sigtab[] = {
// and also update the constant values is os2_plan9.go.
var sigtable = [...]sigTabT{
// Traps that we cannot be recovered.
T, "sys: trap: debug exception",
T, "sys: trap: invalid opcode",
{_SigThrow, []byte("sys: trap: debug exception")},
{_SigThrow, []byte("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
{_SigPanic, []byte("sys: trap: fault read addr")}, // SIGRFAULT
{_SigPanic, []byte("sys: trap: fault write addr")}, // SIGWFAULT
// We can also recover from math errors.
P, "sys: trap: divide error", // SIGINTDIV
P, "sys: fp:", // SIGFLOAT
{_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.
P, "sys: trap:", // SIGTRAP
{_SigPanic, []byte("sys: trap:")}, // SIGTRAP
// Writes to a closed pipe can be handled if desired, otherwise they're ignored.
N, "sys: write on closed pipe",
{_SigNotify, []byte("sys: write on closed pipe")},
// Other system notes are more serious and cannot be recovered.
T, "sys:",
{_SigThrow, []byte("sys:")},
// Issued to all other procs when calling runtime·exit.
E, "go: exit ",
{_SigGoExit, []byte("go: exit ")},
// Kill is sent by external programs to cause an exit.
K, "kill",
{_SigKill, []byte("kill")},
// Interrupts can be handled if desired, otherwise they cause an exit.
N+K, "interrupt",
N+K, "hangup",
{_SigNotify + _SigKill, []byte("interrupt")},
{_SigNotify + _SigKill, []byte("hangup")},
// Alarms can be handled if desired, otherwise they're ignored.
N, "alarm",
};
#undef N
#undef K
#undef T
#undef P
#undef E
{_SigNotify, []byte("alarm")},
}

View File

@ -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

12
src/runtime/stubs3.go Normal file
View File

@ -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