diff options
| author | Yuval Pavel Zholkover <paulzhol@gmail.com> | 2010-10-18 12:32:55 -0400 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2010-10-18 12:32:55 -0400 |
| commit | 99a10eff16b79cfb8ccf36e586532a40b17a203c (patch) | |
| tree | 30ce7d1c68d3725a0e948a3b3267c6c611f37ee3 /src/pkg/runtime | |
| parent | 6ac08ba6387129d9cf9aef924b252270c407d4c1 (diff) | |
| download | go-99a10eff16b79cfb8ccf36e586532a40b17a203c.tar.xz | |
8l, runtime: initial support for Plan 9
No multiple processes/locks, managed to compile
and run a hello.go (with print not fmt). Also test/sieve.go
seems to run until 439 and stops with a
'throw: all goroutines are asleep - deadlock!'
- just like runtime/tiny.
based on Russ's suggestions at:
http://groups.google.com/group/comp.os.plan9/browse_thread/thread/cfda8b82535d2d68/243777a597ec1612
Build instructions:
cd src/pkg/runtime
make clean && GOOS=plan9 make install
this will build and install the runtime.
When linking with 8l, you should pass -s to suppress symbol
generation in the a.out, otherwise the generated executable will not run.
This is runtime only, the porting of the toolchain has already
been done: http://code.google.com/p/go-plan9/source/browse
in the plan9-quanstro branch.
R=rsc
CC=golang-dev
https://golang.org/cl/2273041
Diffstat (limited to 'src/pkg/runtime')
| -rw-r--r-- | src/pkg/runtime/386/asm.s | 4 | ||||
| -rwxr-xr-x | src/pkg/runtime/mkasmh.sh | 5 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/386/defs.h | 1 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/386/rt0.s | 32 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/386/signal.c | 10 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/386/sys.s | 76 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/mem.c | 49 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/os.h | 27 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/signals.h | 1 | ||||
| -rw-r--r-- | src/pkg/runtime/plan9/thread.c | 135 | ||||
| -rw-r--r-- | src/pkg/runtime/runtime.c | 11 | ||||
| -rw-r--r-- | src/pkg/runtime/runtime.h | 2 |
12 files changed, 348 insertions, 5 deletions
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s index 614c026eaf..5f0d0ed468 100644 --- a/src/pkg/runtime/386/asm.s +++ b/src/pkg/runtime/386/asm.s @@ -26,6 +26,8 @@ TEXT _rt0_386(SB),7,$0 CALL ldt0setup(SB) // store through it, to make sure it works + CMPL isplan9(SB), $1 + JEQ ok get_tls(BX) MOVL $0x123, g(BX) MOVL tls0(SB), AX @@ -414,4 +416,4 @@ GLOBL m0(SB), $1024 GLOBL g0(SB), $1024 GLOBL tls0(SB), $32 GLOBL initcgo(SB), $4 - +GLOBL isplan9(SB), $4 diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh index 8544d15d84..3ed5f74c90 100755 --- a/src/pkg/runtime/mkasmh.sh +++ b/src/pkg/runtime/mkasmh.sh @@ -24,6 +24,11 @@ case "$GOARCH" in echo '#define g(r) 0(r)' echo '#define m(r) 4(r)' ;; + plan9) + echo '#define get_tls(r)' + echo '#define g(r) 0xdfffefc0' + echo '#define m(r) 0xdfffefc4' + ;; linux) # On Linux systems, what we call 0(GS) and 4(GS) for g and m # turn into %gs:-8 and %gs:-4 (using gcc syntax to denote diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/plan9/386/defs.h new file mode 100644 index 0000000000..5df7576133 --- /dev/null +++ b/src/pkg/runtime/plan9/386/defs.h @@ -0,0 +1 @@ +// nothing to see here diff --git a/src/pkg/runtime/plan9/386/rt0.s b/src/pkg/runtime/plan9/386/rt0.s new file mode 100644 index 0000000000..e8d65d367b --- /dev/null +++ b/src/pkg/runtime/plan9/386/rt0.s @@ -0,0 +1,32 @@ +// 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. + +TEXT _rt0_386_plan9(SB),7, $0 + MOVL AX, _tos(SB) + + // move arguments down to make room for + // m and g at top of stack, right before Tos. + MOVL SP, SI + SUBL $8, SP + MOVL SP, DI + + MOVL AX, CX + SUBL SI, CX + CLD + REP; MOVSB + + // adjust argv + SUBL SI, DI + MOVL newargc+0(SP), CX + LEAL newargv+4(SP), BP +argv_fix: + ADDL DI, 0(BP) + ADDL $4, BP + LOOP argv_fix + + JMP _rt0_386(SB) + +DATA isplan9+0(SB)/4, $1 +GLOBL isplan9(SB), $4 +GLOBL _tos(SB), $4 diff --git a/src/pkg/runtime/plan9/386/signal.c b/src/pkg/runtime/plan9/386/signal.c new file mode 100644 index 0000000000..e7c98441e4 --- /dev/null +++ b/src/pkg/runtime/plan9/386/signal.c @@ -0,0 +1,10 @@ +// 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" + +void +gettime(int64*, int32*) +{ +} diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/plan9/386/sys.s new file mode 100644 index 0000000000..8dbacc0623 --- /dev/null +++ b/src/pkg/runtime/plan9/386/sys.s @@ -0,0 +1,76 @@ +// 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 "defs.h" +#include "386/asm.h" + +// setldt(int entry, int address, int limit) +TEXT setldt(SB),7,$0 + RET + +TEXT write(SB),7,$0 + MOVL $20, AX + INT $64 + RET + +TEXT exits(SB),7,$0 + MOVL $8, AX + INT $64 + RET + +TEXT brk_(SB),7,$0 + MOVL $24, AX + INT $64 + RET + +TEXT plan9_semacquire(SB),7,$0 + MOVL $37, AX + INT $64 + RET + +TEXT plan9_semrelease(SB),7,$0 + MOVL $38, AX + INT $64 + RET + +TEXT rfork(SB),7,$0 + MOVL $19, AX // rfork + INT $64 + + // In parent, return. + CMPL AX, $0 + JEQ 2(PC) + RET + + // In child on old stack. + MOVL mm+12(SP), BX // m + MOVL gg+16(SP), DX // g + MOVL fn+20(SP), SI // fn + + // set SP to be on the new child stack + MOVL stack+8(SP), CX + MOVL CX, SP + + // Initialize m, g. + get_tls(AX) + MOVL DX, g(AX) + MOVL BX, m(AX) + + // Initialize AX from _tos->pid + MOVL 0xdfffeff8, AX + MOVL AX, m_procid(BX) // save pid as m->procid + + CALL stackcheck(SB) // smashes AX, CX + + MOVL 0(DX), DX // paranoia; check they are not nil + MOVL 0(BX), BX + + // more paranoia; check that stack splitting code works + PUSHAL + CALL emptyfunc(SB) + POPAL + + CALL SI // fn() + CALL exit(SB) + RET diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/plan9/mem.c new file mode 100644 index 0000000000..7d214c3529 --- /dev/null +++ b/src/pkg/runtime/plan9/mem.c @@ -0,0 +1,49 @@ +// 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 "malloc.h" + +extern byte end[]; +static byte *bloc = { end }; + +enum +{ + Round = 7 +}; + +void* +SysAlloc(uintptr ask) +{ + uintptr bl; + + // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c + bl = ((uintptr)bloc + Round) & ~Round; + if(brk_((void*)(bl + ask)) < 0) + return (void*)-1; + bloc = (byte*)bl + ask; + return (void*)bl; +} + +void +SysFree(void *v, uintptr n) +{ + // from tiny/mem.c + // Push pointer back if this is a free + // of the most recent SysAlloc. + n += (n + Round) & ~Round; + if(bloc == (byte*)v+n) + bloc -= n; +} + +void +SysUnused(void *v, uintptr n) +{ + USED(v, n); +} + +void +SysMemInit(void) +{ +} diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/plan9/os.h new file mode 100644 index 0000000000..748cf7a388 --- /dev/null +++ b/src/pkg/runtime/plan9/os.h @@ -0,0 +1,27 @@ +// 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. + +extern int32 write(int32 fd, void* buffer, int32 nbytes); +extern void exits(int8* msg); +extern int32 brk_(void*); + +/* 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) +}; +extern int32 rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void)); +extern int32 plan9_semacquire(uint32 *addr, int32 block); +extern int32 plan9_semrelease(uint32 *addr, int32 count); diff --git a/src/pkg/runtime/plan9/signals.h b/src/pkg/runtime/plan9/signals.h new file mode 100644 index 0000000000..5df7576133 --- /dev/null +++ b/src/pkg/runtime/plan9/signals.h @@ -0,0 +1 @@ +// nothing to see here diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c new file mode 100644 index 0000000000..96e83fc2b5 --- /dev/null +++ b/src/pkg/runtime/plan9/thread.c @@ -0,0 +1,135 @@ +// 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.h" + +int8 *goos = "plan9"; + +void +minit(void) +{ +} + +void +osinit(void) +{ +} + +void +initsig(int32 queue) +{ +} + +void +exit(int32) +{ + exits(nil); +} + +void +newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + USED(m, g, stk, fn); + + m->tls[0] = m->id; // so 386 asm can find it + if(0){ + printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n", + stk, m, g, fn, rfork, m->id, m->tls[0], &m); + } + + if (rfork(RFPROC | RFMEM, stk, m, g, fn) < 0 ) + throw("newosproc: rfork failed"); +} + +// Blocking locks. + +// Implement Locks, using semaphores. +// l->key is the number of threads who want the lock. +// In a race, one thread increments l->key from 0 to 1 +// and the others increment it from >0 to >1. The thread +// who does the 0->1 increment gets the lock, and the +// others wait on the semaphore. When the 0->1 thread +// releases the lock by decrementing l->key, l->key will +// be >0, so it will increment the semaphore to wake up +// one of the others. This is the same algorithm used +// in Plan 9's user-level locks. + +void +lock(Lock *l) +{ + if(m->locks < 0) + throw("lock count"); + m->locks++; + + if(xadd(&l->key, 1) == 1) + return; // changed from 0 -> 1; we hold lock + // otherwise wait in kernel + while(plan9_semacquire(&l->sema, 1) < 0) { + /* interrupted; try again */ + } +} + +void +unlock(Lock *l) +{ + m->locks--; + if(m->locks < 0) + throw("lock count"); + + if(xadd(&l->key, -1) == 0) + return; // changed from 1 -> 0: no contention + + plan9_semrelease(&l->sema, 1); +} + + +void +destroylock(Lock *l) +{ + // nothing +} + +// User-level semaphore implementation: +// try to do the operations in user space on u, +// but when it's time to block, fall back on the kernel semaphore k. +// This is the same algorithm used in Plan 9. +void +usemacquire(Usema *s) +{ + if((int32)xadd(&s->u, -1) < 0) + while(plan9_semacquire(&s->k, 1) < 0) { + /* interrupted; try again */ + } +} + +void +usemrelease(Usema *s) +{ + if((int32)xadd(&s->u, 1) <= 0) + plan9_semrelease(&s->k, 1); +} + + +// Event notifications. +void +noteclear(Note *n) +{ + n->wakeup = 0; +} + +void +notesleep(Note *n) +{ + while(!n->wakeup) + usemacquire(&n->sema); +} + +void +notewakeup(Note *n) +{ + n->wakeup = 1; + usemrelease(&n->sema); +} + diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c index 4b09f7bcf7..a8f8177331 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -147,15 +147,20 @@ args(int32 c, uint8 **v) argv = v; } +extern int32 isplan9; + void goargs(void) { String *gargv; String *genvv; int32 i, envc; - - for(envc=0; argv[argc+1+envc] != 0; envc++) - ; + + if(isplan9) + envc=0; + else + for(envc=0; argv[argc+1+envc] != 0; envc++) + ; gargv = malloc(argc*sizeof gargv[0]); genvv = malloc(envc*sizeof genvv[0]); diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 88f53e2a2e..92da669d7f 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -76,7 +76,7 @@ typedef struct Complex128 Complex128; * segment register. * * amd64: allocated downwards from R15 - * x86: allocated upwards from 0(FS) + * x86: allocated upwards from 0(GS) * arm: allocated downwards from R10 * * every C file linked into a Go program must include runtime.h |
