From 6bfe5f55f4dc110ca43a202a6a5eb70ee477916b Mon Sep 17 00:00:00 2001 From: Hector Chu Date: Wed, 6 Jan 2010 17:58:55 -0800 Subject: [PATCH] Ported runtime to Windows. R=rsc CC=golang-dev https://golang.org/cl/176066 --- src/pkg/runtime/386/asm.s | 67 ++++++-- src/pkg/runtime/Makefile | 5 +- src/pkg/runtime/darwin/386/sys.s | 15 +- src/pkg/runtime/darwin/thread.c | 15 -- src/pkg/runtime/freebsd/386/sys.s | 16 +- src/pkg/runtime/linux/386/sys.s | 15 +- src/pkg/runtime/mgc0.c | 14 +- src/pkg/runtime/mingw/386/defs.h | 17 ++ src/pkg/runtime/mingw/386/rt0.s | 6 + src/pkg/runtime/mingw/386/signal.c | 8 + src/pkg/runtime/mingw/386/sys.s | 87 ++++++++++ src/pkg/runtime/mingw/defs.c | 13 ++ src/pkg/runtime/mingw/os.h | 18 ++ src/pkg/runtime/mingw/thread.c | 265 +++++++++++++++++++++++++++++ src/pkg/runtime/mkasmh.sh | 14 +- src/pkg/runtime/proc.c | 16 +- src/pkg/runtime/runtime.c | 14 ++ src/pkg/runtime/runtime.h | 13 ++ src/pkg/runtime/string.cgo | 30 ++++ src/pkg/runtime/symtab.c | 12 ++ 20 files changed, 600 insertions(+), 60 deletions(-) create mode 100644 src/pkg/runtime/mingw/386/defs.h create mode 100644 src/pkg/runtime/mingw/386/rt0.s create mode 100644 src/pkg/runtime/mingw/386/signal.c create mode 100644 src/pkg/runtime/mingw/386/sys.s create mode 100644 src/pkg/runtime/mingw/defs.c create mode 100644 src/pkg/runtime/mingw/os.h create mode 100644 src/pkg/runtime/mingw/thread.c diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s index 7ec62161d9..11ce3f6b6f 100644 --- a/src/pkg/runtime/386/asm.s +++ b/src/pkg/runtime/386/asm.s @@ -26,17 +26,19 @@ TEXT _rt0_386(SB),7,$0 CALL ldt0setup(SB) // store through it, to make sure it works - MOVL $0x123, 0(GS) + get_tls(BX) + MOVL $0x123, g(BX) MOVL tls0(SB), AX CMPL AX, $0x123 JEQ ok MOVL AX, 0 // abort ok: // set up m and g "registers" + get_tls(BX) LEAL g0(SB), CX - MOVL CX, g + MOVL CX, g(BX) LEAL m0(SB), AX - MOVL AX, m + MOVL AX, m(BX) // save m->g0 = g0 MOVL CX, m_g0(AX) @@ -100,7 +102,8 @@ TEXT gosave(SB), 7, $0 MOVL BX, gobuf_sp(AX) MOVL 0(SP), BX // caller's PC MOVL BX, gobuf_pc(AX) - MOVL g, BX + get_tls(CX) + MOVL g(CX), BX MOVL BX, gobuf_g(AX) MOVL $0, AX // return 0 RET @@ -112,7 +115,8 @@ TEXT gogo(SB), 7, $0 MOVL 4(SP), BX // gobuf MOVL gobuf_g(BX), DX MOVL 0(DX), CX // make sure g != nil - MOVL DX, g + get_tls(CX) + MOVL DX, g(CX) MOVL gobuf_sp(BX), SP // restore SP MOVL gobuf_pc(BX), BX JMP BX @@ -124,7 +128,8 @@ TEXT gogocall(SB), 7, $0 MOVL 8(SP), AX // fn MOVL 4(SP), BX // gobuf MOVL gobuf_g(BX), DX - MOVL DX, g + get_tls(CX) + MOVL DX, g(CX) MOVL 0(DX), CX // make sure g != nil MOVL gobuf_sp(BX), SP // restore SP MOVL gobuf_pc(BX), BX @@ -139,9 +144,10 @@ TEXT gogocall(SB), 7, $0 // Called during function prolog when more stack is needed. TEXT runtime·morestack(SB),7,$0 // Cannot grow scheduler stack (m->g0). - MOVL m, BX + get_tls(CX) + MOVL m(CX), BX MOVL m_g0(BX), SI - CMPL g, SI + CMPL g(CX), SI JNE 2(PC) INT $3 @@ -158,7 +164,8 @@ TEXT runtime·morestack(SB),7,$0 LEAL 8(SP), CX // f's caller's SP MOVL CX, (m_morebuf+gobuf_sp)(BX) MOVL CX, (m_morefp)(BX) - MOVL g, SI + get_tls(CX) + MOVL g(CX), SI MOVL SI, (m_morebuf+gobuf_g)(BX) // Set m->morepc to f's PC. @@ -167,7 +174,7 @@ TEXT runtime·morestack(SB),7,$0 // Call newstack on m's scheduling stack. MOVL m_g0(BX), BP - MOVL BP, g + MOVL BP, g(CX) MOVL (m_sched+gobuf_sp)(BX), SP CALL newstack(SB) MOVL $0, 0x1003 // crash if newstack returns @@ -179,7 +186,8 @@ TEXT runtime·morestack(SB),7,$0 // // func call(fn *byte, arg *byte, argsize uint32). TEXT reflect·call(SB), 7, $0 - MOVL m, BX + get_tls(CX) + MOVL m(CX), BX // Save our caller's state as the PC and SP to // restore when returning from f. @@ -187,7 +195,7 @@ TEXT reflect·call(SB), 7, $0 MOVL AX, (m_morebuf+gobuf_pc)(BX) LEAL 4(SP), AX // our caller's SP MOVL AX, (m_morebuf+gobuf_sp)(BX) - MOVL g, AX + MOVL g(CX), AX MOVL AX, (m_morebuf+gobuf_g)(BX) // Set up morestack arguments to call f on a new stack. @@ -207,7 +215,8 @@ TEXT reflect·call(SB), 7, $0 // Call newstack on m's scheduling stack. MOVL m_g0(BX), BP - MOVL BP, g + get_tls(CX) + MOVL BP, g(CX) MOVL (m_sched+gobuf_sp)(BX), SP CALL newstack(SB) MOVL $0, 0x1103 // crash if newstack returns @@ -217,12 +226,13 @@ TEXT reflect·call(SB), 7, $0 // Return point when leaving stack. TEXT runtime·lessstack(SB), 7, $0 // Save return value in m->cret - MOVL m, BX + get_tls(CX) + MOVL m(CX), BX MOVL AX, m_cret(BX) // Call oldstack on m's scheduling stack. MOVL m_g0(BX), DX - MOVL DX, g + MOVL DX, g(CX) MOVL (m_sched+gobuf_sp)(BX), SP CALL oldstack(SB) MOVL $0, 0x1004 // crash if oldstack returns @@ -248,6 +258,25 @@ TEXT cas(SB), 7, $0 MOVL $1, AX RET +// bool casp(void **p, void *old, void *new) +// Atomically: +// if(*p == old){ +// *p = new; +// return 1; +// }else +// return 0; +TEXT casp(SB), 7, $0 + MOVL 4(SP), BX + MOVL 8(SP), AX + MOVL 12(SP), CX + LOCK + CMPXCHGL CX, 0(BX) + JZ 3(PC) + MOVL $0, AX + RET + MOVL $1, AX + RET + // void jmpdefer(fn, sp); // called from deferreturn. // 1. pop the caller @@ -308,9 +337,10 @@ TEXT runcgo(SB),7,$16 MOVL SP, CX // Figure out if we need to switch to m->g0 stack. - MOVL m, DX + get_tls(DI) + MOVL m(DI), DX MOVL m_g0(DX), SI - CMPL g, SI + CMPL g(DI), SI JEQ 2(PC) MOVL (m_sched+gobuf_sp)(DX), SP @@ -325,7 +355,8 @@ TEXT runcgo(SB),7,$16 // check that SP is in range [g->stackbase, g->stackguard) TEXT stackcheck(SB), 7, $0 - MOVL g, AX + get_tls(CX) + MOVL g(CX), AX CMPL g_stackbase(AX), SP JHI 2(PC) INT $3 diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile index a85c441904..80bb521b31 100644 --- a/src/pkg/runtime/Makefile +++ b/src/pkg/runtime/Makefile @@ -17,7 +17,8 @@ CFLAGS_64=-D_64BIT # TODO(kaib): fix register allocation to honor extern register so we # can enable optimizations again. CFLAGS_arm=-N -CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) $(CFLAGS_$(GOARCH)) +CFLAGS_mingw=-D__MINGW__ +CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS)) GOFILES=\ extern.go\ @@ -118,4 +119,4 @@ cgo2c: cgo2c.c # for discovering offsets inside structs when debugging runtime.acid.$(GOARCH): runtime.h proc.c - $(QUOTED_GOBIN)/$(CC) -a proc.c >$@ + $(QUOTED_GOBIN)/$(CC) $(CFLAGS) -a proc.c >$@ diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s index 38459447f8..b18f390709 100644 --- a/src/pkg/runtime/darwin/386/sys.s +++ b/src/pkg/runtime/darwin/386/sys.s @@ -64,9 +64,10 @@ TEXT sigtramp(SB),7,$40 MOVW BX, GS // g = m->gsignal - MOVL m, BP + get_tls(CX) + MOVL m(CX), BP MOVL m_gsignal(BP), BP - MOVL BP, g + MOVL BP, g(CX) MOVL handler+0(FP), DI // 4(FP) is sigstyle @@ -80,9 +81,10 @@ TEXT sigtramp(SB),7,$40 CALL DI // g = m->curg - MOVL m, BP + get_tls(CX) + MOVL m(CX), BP MOVL m_curg(BP), BP - MOVL BP, g + MOVL BP, g(CX) MOVL context+16(FP), CX MOVL style+4(FP), BX @@ -150,8 +152,9 @@ TEXT bsdthread_start(SB),7,$0 POPAL // Now segment is established. Initialize m, g. - MOVL AX, g - MOVL DX, m + get_tls(BP) + MOVL AX, g(BP) + MOVL DX, m(BP) MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers) CALL stackcheck(SB) // smashes AX CALL CX // fn() diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c index bf66f86732..f68b63f7ab 100644 --- a/src/pkg/runtime/darwin/thread.c +++ b/src/pkg/runtime/darwin/thread.c @@ -36,21 +36,6 @@ initsema(uint32 *psema) } -// Atomic add and return new value. -static uint32 -xadd(uint32 volatile *val, int32 delta) -{ - uint32 oval, nval; - - for(;;){ - oval = *val; - nval = oval + delta; - if(cas(val, oval, nval)) - return nval; - } -} - - // Blocking locks. // Implement Locks, using semaphores. diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s index 651ccb2348..7328a90467 100644 --- a/src/pkg/runtime/freebsd/386/sys.s +++ b/src/pkg/runtime/freebsd/386/sys.s @@ -33,8 +33,10 @@ TEXT thr_start(SB),7,$0 POPL AX POPL AX POPAL - MOVL BX, g - MOVL AX, m + get_tls(CX) + MOVL BX, g(CX) + + MOVL AX, m(CX) CALL stackcheck(SB) // smashes AX CALL mstart(SB) MOVL 0, AX // crash (not reached) @@ -80,9 +82,10 @@ TEXT sigaction(SB),7,$-4 TEXT sigtramp(SB),7,$40 // g = m->gsignal - MOVL m, BP + get_tls(DX) + MOVL m(DX), BP MOVL m_gsignal(BP), BP - MOVL BP, g + MOVL BP, g(DX) MOVL signo+0(FP), AX MOVL siginfo+4(FP), BX @@ -94,9 +97,10 @@ TEXT sigtramp(SB),7,$40 CALL sighandler(SB) // g = m->curg - MOVL m, BP + get_tls(DX) + MOVL m(DX), BP MOVL m_curg(BP), BP - MOVL BP, g + MOVL BP, g(DX) MOVL context+8(FP), AX diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s index 72882cb9dc..f734a68338 100644 --- a/src/pkg/runtime/linux/386/sys.s +++ b/src/pkg/runtime/linux/386/sys.s @@ -40,9 +40,10 @@ TEXT rt_sigaction(SB),7,$0 RET TEXT sigtramp(SB),7,$0 - MOVL m, BP + get_tls(CX) + MOVL m(CX), BP MOVL m_gsignal(BP), AX - MOVL AX, g + MOVL AX, g(CX) JMP sighandler(SB) TEXT sigignore(SB),7,$0 @@ -50,9 +51,10 @@ TEXT sigignore(SB),7,$0 TEXT sigreturn(SB),7,$0 // g = m->curg - MOVL m, BP + get_tls(CX) + MOVL m(CX), BP MOVL m_curg(BP), BP - MOVL BP, g + MOVL BP, g(CX) MOVL $173, AX // rt_sigreturn INT $0x80 INT $3 // not reached @@ -149,8 +151,9 @@ TEXT clone(SB),7,$0 MOVW DI, GS // Now segment is established. Initialize m, g. - MOVL DX, g - MOVL BX, m + get_tls(AX) + MOVL DX, g(AX) + MOVL BX, m(AX) CALL stackcheck(SB) // smashes AX MOVL 0(DX), DX // paranoia; check they are not nil diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index f0eafe3fd6..91898270d2 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -73,8 +73,12 @@ scanstack(G *gp) { Stktop *stk; byte *sp; + // TODO(rsc): Change 8g not to assume that extern register + // variables are directly addressable. Declaring the + // local variable here works around the bug. + G* gg = g; - if(gp == g) + if(gp == gg) sp = (byte*)&gp; else sp = gp->sched.sp; @@ -89,7 +93,11 @@ scanstack(G *gp) static void mark(void) { - G *gp; + G* gp; + // TODO(rsc): Change 8g not to assume that extern register + // variables are directly addressable. Declaring the + // local variable here works around the bug. + G* gg = g; // mark data+bss. // skip mheap itself, which has no interesting pointers @@ -106,7 +114,7 @@ mark(void) case Gdead: break; case Grunning: - if(gp != g) + if(gp != gg) throw("mark - world not stopped"); scanstack(gp); break; diff --git a/src/pkg/runtime/mingw/386/defs.h b/src/pkg/runtime/mingw/386/defs.h new file mode 100644 index 0000000000..f5a16367eb --- /dev/null +++ b/src/pkg/runtime/mingw/386/defs.h @@ -0,0 +1,17 @@ +// c:\Users\Hector\Code\go\bin\godefs.exe defs.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants +enum { + PROT_NONE = 0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + MAP_ANON = 0x1, + MAP_PRIVATE = 0x2, +}; + +// Types +#pragma pack on +#pragma pack off diff --git a/src/pkg/runtime/mingw/386/rt0.s b/src/pkg/runtime/mingw/386/rt0.s new file mode 100644 index 0000000000..efd8ce3e68 --- /dev/null +++ b/src/pkg/runtime/mingw/386/rt0.s @@ -0,0 +1,6 @@ +// 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. + +TEXT _rt0_386_mingw(SB),7,$0 + JMP _rt0_386(SB) diff --git a/src/pkg/runtime/mingw/386/signal.c b/src/pkg/runtime/mingw/386/signal.c new file mode 100644 index 0000000000..ba38823911 --- /dev/null +++ b/src/pkg/runtime/mingw/386/signal.c @@ -0,0 +1,8 @@ +// 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. + +void +initsig(void) +{ +} diff --git a/src/pkg/runtime/mingw/386/sys.s b/src/pkg/runtime/mingw/386/sys.s new file mode 100644 index 0000000000..9bbafc2785 --- /dev/null +++ b/src/pkg/runtime/mingw/386/sys.s @@ -0,0 +1,87 @@ +// 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 "386/asm.h" + +TEXT get_kernel_module(SB),7,$0 + MOVL 0x30(FS), AX // get PEB + MOVL 0x0c(AX), AX // get PEB_LDR_DATA + MOVL 0x1c(AX), AX // get init order module list + MOVL (AX), AX // get next entry (kernel module) + MOVL 0x08(AX), AX // get base of module + RET + +// TODO(rsc,hectorchu): Switch to m stack before call. +TEXT stdcall(SB),7,$0 + CALL runtime·entersyscall(SB) + get_tls(CX) + MOVL m(CX), CX + POPL m_return_address(CX) // save return address + POPL AX // first arg is function pointer + MOVL SP, m_stack_pointer(CX) // save stack pointer + CALL AX + get_tls(CX) + MOVL m(CX), CX + MOVL m_stack_pointer(CX), SP + PUSHL AX + PUSHL m_return_address(CX) + CALL runtime·exitsyscall(SB) + MOVL 4(SP), AX + RET + +// TODO(rsc,hectorchu): Switch to m stack before call. +TEXT stdcall_raw(SB),7,$0 + get_tls(CX) + MOVL m(CX), CX + POPL m_return_address(CX) // save return address + POPL AX // first arg is function pointer + MOVL SP, m_stack_pointer(CX) // save stack pointer + CALL AX + get_tls(CX) + MOVL m(CX), CX + MOVL m_stack_pointer(CX), SP + PUSHL AX + PUSHL m_return_address(CX) + RET + +TEXT threadstart(SB),7,$0 + MOVL 4(SP), AX // threadstart param + MOVL 0(AX), BX // newosproc arg stack + MOVL 0(BX), CX // m + MOVL 4(BX), DX // g + + // set up tls + LEAL m_tls(CX), SI + MOVL SI, 0x2c(FS) + MOVL CX, m(SI) + MOVL DX, g(SI) + MOVL SP, m_os_stack_pointer(CX) + + PUSHL 8(BX) // stk + PUSHL 12(BX) // fn + PUSHL 4(AX) // event_handle + + // signal that we're done with thread args + MOVL SetEvent(SB), BX + CALL BX // SetEvent(event_handle) + POPL BX // fn + POPL SP // stk + + CALL stackcheck(SB) // clobbers AX,CX + CALL BX // fn() + + // cleanup stack before returning as we are stdcall + get_tls(CX) + MOVL m(CX), CX + MOVL m_os_stack_pointer(CX), SP + POPL AX // return address + MOVL AX, (SP) + XORL AX, AX + RET + +// setldt(int entry, int address, int limit) +TEXT setldt(SB),7,$0 + MOVL address+4(FP), CX + MOVL CX, 0x2c(FS) + RET diff --git a/src/pkg/runtime/mingw/defs.c b/src/pkg/runtime/mingw/defs.c new file mode 100644 index 0000000000..db5f1400ef --- /dev/null +++ b/src/pkg/runtime/mingw/defs.c @@ -0,0 +1,13 @@ +// 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. + +enum { + $PROT_NONE = 0, + $PROT_READ = 1, + $PROT_WRITE = 2, + $PROT_EXEC = 4, + + $MAP_ANON = 1, + $MAP_PRIVATE = 2, +}; diff --git a/src/pkg/runtime/mingw/os.h b/src/pkg/runtime/mingw/os.h new file mode 100644 index 0000000000..8470cc0e58 --- /dev/null +++ b/src/pkg/runtime/mingw/os.h @@ -0,0 +1,18 @@ +// 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. + +// The following function allows one to dynamically +// resolve DLL function names. +// The arguments are strings. +void *get_proc_addr(void *library, void *name); + +// Call a Windows function with stdcall conventions. +void *stdcall(void *fn, ...); +void *stdcall_raw(void *fn, ...); + +#define goargs mingw_goargs +void mingw_goargs(void); + +// Get start address of symbol data in memory. +void *get_symdat_addr(void); diff --git a/src/pkg/runtime/mingw/thread.c b/src/pkg/runtime/mingw/thread.c new file mode 100644 index 0000000000..979fd42247 --- /dev/null +++ b/src/pkg/runtime/mingw/thread.c @@ -0,0 +1,265 @@ +// 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 "os.h" + +#define stdcall stdcall_raw + +extern void *get_kernel_module(void); + +// Also referenced by external packages +void *CloseHandle; +void *ExitProcess; +void *GetStdHandle; +void *SetEvent; +void *WriteFile; + +static void *CreateEvent; +static void *CreateThread; +static void *GetModuleHandle; +static void *GetProcAddress; +static void *LoadLibraryEx; +static void *VirtualAlloc; +static void *WaitForSingleObject; + +static void* +get_proc_addr2(byte *base, byte *name) +{ + byte *pe_header, *exports; + uint32 entries, *addr, *names, i; + uint16 *ordinals; + + pe_header = base+*(uint32*)(base+0x3c); + exports = base+*(uint32*)(pe_header+0x78); + entries = *(uint32*)(exports+0x18); + addr = (uint32*)(base+*(uint32*)(exports+0x1c)); + names = (uint32*)(base+*(uint32*)(exports+0x20)); + ordinals = (uint16*)(base+*(uint32*)(exports+0x24)); + for(i=0; ievent == 0) + initevent(&l->event); + + if(xadd(&l->key, 1) > 1) // someone else has it; wait + stdcall(WaitForSingleObject, l->event, -1); +} + +static void +eventunlock(Lock *l) +{ + if(xadd(&l->key, -1) > 0) // someone else is waiting + stdcall(SetEvent, l->event); +} + +void +lock(Lock *l) +{ + if(m->locks < 0) + throw("lock count"); + m->locks++; + eventlock(l); +} + +void +unlock(Lock *l) +{ + m->locks--; + if(m->locks < 0) + throw("lock count"); + eventunlock(l); +} + +void +noteclear(Note *n) +{ + eventlock(&n->lock); +} + +void +notewakeup(Note *n) +{ + eventunlock(&n->lock); +} + +void +notesleep(Note *n) +{ + eventlock(&n->lock); + eventunlock(&n->lock); // Let other sleepers find out too. +} + +void +newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + struct { + void *args; + void *event_handle; + } param = { &m }; + extern uint32 threadstart(void *p); + + USED(g, stk, fn); + param.event_handle = stdcall(CreateEvent, 0, 0, 0, 0); + stdcall(CreateThread, 0, 0, threadstart, ¶m, 0, 0); + stdcall(WaitForSingleObject, param.event_handle, -1); + stdcall(CloseHandle, param.event_handle); +} + +// Called to initialize a new m (including the bootstrap m). +void +minit(void) +{ +} diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh index cb4b6d214f..fdd2668406 100755 --- a/src/pkg/runtime/mkasmh.sh +++ b/src/pkg/runtime/mkasmh.sh @@ -18,8 +18,18 @@ case "$GOARCH" in # ../../cmd/8l/pass.c:/D_GS # ../../libcgo/linux_386.c:/^start # ../../libcgo/darwin_386.c:/^start - echo '#define g 0(GS)' - echo '#define m 4(GS)' + case "$GOOS" in + mingw) + echo '#define get_tls(r) MOVL 0x2c(FS), r' + echo '#define g(r) 0(r)' + echo '#define m(r) 4(r)' + ;; + *) + echo '#define get_tls(r)' + echo '#define g(r) 0(GS)' + echo '#define m(r) 4(GS)' + ;; + esac ;; amd64) # These registers are also known to: diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 60d76bc0f7..8dc9243261 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -3,7 +3,9 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "defs.h" #include "malloc.h" +#include "os.h" typedef struct Sched Sched; @@ -386,7 +388,12 @@ starttheworld(void) void mstart(void) { - if(g != m->g0) + // TODO(rsc): Change 8g not to assume that extern register + // variables are directly addressable. Declaring the + // local variable here works around the bug. + G* gg = g; + + if(gg != m->g0) throw("bad mstart"); if(m->mcache == nil) m->mcache = allocmcache(); @@ -517,7 +524,12 @@ scheduler(void) void gosched(void) { - if(g == m->g0) + // TODO(rsc): Change 8g not to assume that extern register + // variables are directly addressable. Declaring the + // local variable here works around the bug. + G* gg = g; + + if(gg == m->g0) throw("gosched of g0"); if(gosave(&g->sched) == 0) gogo(&m->sched, 1); diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c index 4a0309e0c7..8588894624 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -165,6 +165,20 @@ goargs(void) os·Envs.cap = envc; } +// Atomic add and return new value. +uint32 +xadd(uint32 volatile *val, int32 delta) +{ + uint32 oval, nval; + + for(;;){ + oval = *val; + nval = oval + delta; + if(cas(val, oval, nval)) + return nval; + } +} + byte* getenv(int8 *s) { diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 8052fd09ca..2d956ea980 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -109,7 +109,11 @@ enum struct Lock { uint32 key; +#ifdef __MINGW__ + void* event; +#else uint32 sema; // for OS X +#endif }; struct Usema { @@ -204,6 +208,11 @@ struct M uint32 machport; // Return address for Mach IPC (OS X) MCache *mcache; G* lockedg; +#ifdef __MINGW__ + void* return_address; // saved return address and stack + void* stack_pointer; // pointer for Windows stdcall + void* os_stack_pointer; +#endif }; struct Stktop { @@ -314,6 +323,7 @@ int8* goos; */ int32 strcmp(byte*, byte*); int32 findnull(byte*); +int32 findnullw(uint16*); void dump(byte*, int32); int32 runetochar(byte*, int32); int32 charntorune(int32*, uint8*, int32); @@ -339,6 +349,7 @@ void memmove(void*, void*, uint32); void* mal(uint32); uint32 cmpstring(String, String); String gostring(byte*); +String gostringw(uint16*); void initsig(void); int32 gotraceback(void); void traceback(uint8 *pc, uint8 *sp, G* gp); @@ -346,6 +357,8 @@ void tracebackothers(G*); int32 open(byte*, int32, ...); int32 write(int32, void*, int32); bool cas(uint32*, uint32, uint32); +bool casp(void**, void*, void*); +uint32 xadd(uint32 volatile*, int32); void jmpdefer(byte*, void*); void exit1(int32); void ready(G*); diff --git a/src/pkg/runtime/string.cgo b/src/pkg/runtime/string.cgo index 6e380a1075..03b05618d8 100644 --- a/src/pkg/runtime/string.cgo +++ b/src/pkg/runtime/string.cgo @@ -19,6 +19,18 @@ findnull(byte *s) return l; } +int32 +findnullw(uint16 *s) +{ + int32 l; + + if(s == nil) + return 0; + for(l=0; s[l]!=0; l++) + ; + return l; +} + int32 maxstring; String @@ -47,6 +59,24 @@ gostring(byte *str) return s; } +String +gostringw(uint16 *str) +{ + int32 n, i; + byte buf[8]; + String s; + + n = 0; + for(i=0; str[i]; i++) + n += runetochar(buf, str[i]); + s = gostringsize(n+4); + n = 0; + for(i=0; str[i]; i++) + n += runetochar(s.str+n, str[i]); + s.len = n; + return s; +} + func catstring(s1 String, s2 String) (s3 String) { if(s1.len == 0) { s3 = s2; diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c index 0b5499474f..1a547f230b 100644 --- a/src/pkg/runtime/symtab.c +++ b/src/pkg/runtime/symtab.c @@ -13,6 +13,8 @@ // and figure out exactly what we want. #include "runtime.h" +#include "defs.h" +#include "os.h" // TODO(rsc): Move this *under* the text segment. // Then define names for these addresses instead of hard-coding magic ones. @@ -45,8 +47,13 @@ walksymtab(void (*fn)(Sym*)) if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0) return; +#ifdef __MINGW__ + v = get_symdat_addr(); + p = (byte*)v+8; +#else v = SYMCOUNTS; p = SYMDATA; +#endif ep = p + v[0]; while(p < ep) { if(p + 7 > ep) @@ -246,8 +253,13 @@ splitpcln(void) return; // pc/ln table bounds +#ifdef __MINGW__ + v = get_symdat_addr(); + p = (byte*)v+8; +#else v = SYMCOUNTS; p = SYMDATA; +#endif p += v[0]; ep = p+v[1];