]> Cypherpunks repositories - gostls13.git/commitdiff
Ported runtime to Windows.
authorHector Chu <hectorchu@gmail.com>
Thu, 7 Jan 2010 01:58:55 +0000 (17:58 -0800)
committerRuss Cox <rsc@golang.org>
Thu, 7 Jan 2010 01:58:55 +0000 (17:58 -0800)
R=rsc
CC=golang-dev
https://golang.org/cl/176066

20 files changed:
src/pkg/runtime/386/asm.s
src/pkg/runtime/Makefile
src/pkg/runtime/darwin/386/sys.s
src/pkg/runtime/darwin/thread.c
src/pkg/runtime/freebsd/386/sys.s
src/pkg/runtime/linux/386/sys.s
src/pkg/runtime/mgc0.c
src/pkg/runtime/mingw/386/defs.h [new file with mode: 0644]
src/pkg/runtime/mingw/386/rt0.s [new file with mode: 0644]
src/pkg/runtime/mingw/386/signal.c [new file with mode: 0644]
src/pkg/runtime/mingw/386/sys.s [new file with mode: 0644]
src/pkg/runtime/mingw/defs.c [new file with mode: 0644]
src/pkg/runtime/mingw/os.h [new file with mode: 0644]
src/pkg/runtime/mingw/thread.c [new file with mode: 0644]
src/pkg/runtime/mkasmh.sh
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.c
src/pkg/runtime/runtime.h
src/pkg/runtime/string.cgo
src/pkg/runtime/symtab.c

index 7ec62161d93d3f5cf7178ebd1aeba63eaf0a0ccf..11ce3f6b6f0f783f1d798cd8d0e5b0948d5086ff 100644 (file)
@@ -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
index a85c4419049d52fff1f053827107596d202a81bc..80bb521b31a22864533a536c812ce68beee12832 100644 (file)
@@ -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 >$@
index 38459447f89cb83810de62938046e65c2923598c..b18f390709f6fa239e5853db9b73674138a2298a 100644 (file)
@@ -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()
index bf66f8673205bae9403829b5ef4f0162062bc898..f68b63f7ab89f728e76153a53c6980d810c77bd6 100644 (file)
@@ -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.
index 651ccb2348dedb559df57e28cfe707ff5148d209..7328a90467811870abf7c21370cd1bfb4f4c2b31 100644 (file)
@@ -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
 
index 72882cb9dccbdd3cf6ec4100bfc4db3ae150d1cc..f734a68338e4b1202e8e114a10088c0956e5e5c7 100644 (file)
@@ -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
index f0eafe3fd6cb8279d13ca351de375b8baec92e5f..91898270d2b8ac08e0397dad8d06e2d2ff71da46 100644 (file)
@@ -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 (file)
index 0000000..f5a1636
--- /dev/null
@@ -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 (file)
index 0000000..efd8ce3
--- /dev/null
@@ -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 (file)
index 0000000..ba38823
--- /dev/null
@@ -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 (file)
index 0000000..9bbafc2
--- /dev/null
@@ -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 (file)
index 0000000..db5f140
--- /dev/null
@@ -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 (file)
index 0000000..8470cc0
--- /dev/null
@@ -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 (file)
index 0000000..979fd42
--- /dev/null
@@ -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; i<entries; i++) {
+               byte *s = base+names[i];
+               if(!strcmp(name, s))
+                       break;
+       }
+       if(i == entries)
+               return 0;
+       return base+addr[ordinals[i]];
+}
+
+void
+osinit(void)
+{
+       void *base;
+
+       base = get_kernel_module();
+       GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress");
+       LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA");
+       CloseHandle = get_proc_addr("kernel32.dll", "CloseHandle");
+       CreateEvent = get_proc_addr("kernel32.dll", "CreateEventA");
+       CreateThread = get_proc_addr("kernel32.dll", "CreateThread");
+       ExitProcess = get_proc_addr("kernel32.dll", "ExitProcess");
+       GetModuleHandle = get_proc_addr("kernel32.dll", "GetModuleHandleA");
+       GetStdHandle = get_proc_addr("kernel32.dll", "GetStdHandle");
+       SetEvent = get_proc_addr("kernel32.dll", "SetEvent");
+       VirtualAlloc = get_proc_addr("kernel32.dll", "VirtualAlloc");
+       WaitForSingleObject = get_proc_addr("kernel32.dll", "WaitForSingleObject");
+       WriteFile = get_proc_addr("kernel32.dll", "WriteFile");
+}
+
+// The arguments are strings.
+void*
+get_proc_addr(void *library, void *name)
+{
+       void *base;
+
+       base = stdcall(LoadLibraryEx, library, 0, 0);
+       return stdcall(GetProcAddress, base, name);
+}
+
+void
+mingw_goargs(void)
+{
+       extern Slice os·Args;
+       extern Slice os·Envs;
+
+       void *gcl, *clta, *ges;
+       uint16 *cmd, *env, **argv;
+       String *gargv;
+       String *genvv;
+       int32 i, argc, envc;
+       uint16 *envp;
+
+       gcl = get_proc_addr("kernel32.dll", "GetCommandLineW");
+       clta = get_proc_addr("shell32.dll", "CommandLineToArgvW");
+       ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
+
+       cmd = stdcall(gcl);
+       env = stdcall(ges);
+       argv = stdcall(clta, cmd, &argc);
+
+       envc = 0;
+       for(envp=env; *envp; envc++)
+               envp += findnullw(envp)+1;
+
+       gargv = malloc(argc*sizeof gargv[0]);
+       genvv = malloc(envc*sizeof genvv[0]);
+
+       for(i=0; i<argc; i++)
+               gargv[i] = gostringw(argv[i]);
+       os·Args.array = (byte*)gargv;
+       os·Args.len = argc;
+       os·Args.cap = argc;
+
+       envp = env;
+       for(i=0; i<envc; i++) {
+               genvv[i] = gostringw(envp);
+               envp += findnullw(envp)+1;
+       }
+       os·Envs.array = (byte*)genvv;
+       os·Envs.len = envc;
+       os·Envs.cap = envc;
+}
+
+void
+exit(int32 code)
+{
+       stdcall(ExitProcess, code);
+}
+
+int32
+write(int32 fd, void *buf, int32 n)
+{
+       void *handle;
+       uint32 written;
+
+       written = 0;
+       switch(fd) {
+       case 1:
+               handle = stdcall(GetStdHandle, -11);
+               break;
+       case 2:
+               handle = stdcall(GetStdHandle, -12);
+               break;
+       default:
+               return -1;
+       }
+       stdcall(WriteFile, handle, buf, n, &written, 0);
+       return written;
+}
+
+uint8*
+runtime_mmap(byte *addr, uint32 len, int32 prot,
+       int32 flags, int32 fd, uint32 off)
+{
+       USED(prot, flags, fd, off);
+       return stdcall(VirtualAlloc, addr, len, 0x3000, 0x40);
+}
+
+void*
+get_symdat_addr(void)
+{
+       byte *mod, *p;
+       uint32 peh, add;
+       uint16 oph;
+
+       mod = stdcall(GetModuleHandle, 0);
+       peh = *(uint32*)(mod+0x3c);
+       p = mod+peh+4;
+       oph = *(uint16*)(p+0x10);
+       p += 0x14+oph;
+       while(strcmp(p, (byte*)".symdat"))
+               p += 40;
+       add = *(uint32*)(p+0x0c);
+       return mod+add;
+}
+
+// Thread-safe allocation of an event.
+static void
+initevent(void **pevent)
+{
+       void *event;
+
+       event = stdcall(CreateEvent, 0, 0, 0, 0);
+       if(!casp(pevent, 0, event)) {
+               // Someone else filled it in.  Use theirs.
+               stdcall(CloseHandle, event);
+       }
+}
+
+static void
+eventlock(Lock *l)
+{
+       // Allocate event if needed.
+       if(l->event == 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, &param, 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)
+{
+}
index cb4b6d214f015214c4fd190bba3b81b4cc535bbc..fdd26684064114715416ee63b3fa8a2f9896109d 100755 (executable)
@@ -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:
index 60d76bc0f7425e70a67601ebb9ab34cf2a671622..8dc9243261990c92c54a331eac896205f5f4d620 100644 (file)
@@ -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);
index 4a0309e0c7e608c9c180a3edf67dc5d17437ea6b..8588894624706385ae5cd50659bf40d13267af45 100644 (file)
@@ -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)
 {
index 8052fd09ca3fbd3d46a47ce02f713f3ac40de357..2d956ea980f211626fcd27f8d9edca9291b8fdf0 100644 (file)
@@ -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*);
index 6e380a1075a2c5b874b8cc57a6d314535fb6c0d5..03b05618d81a52de29c3bc1b4f3c2cce045d8fbc 100644 (file)
@@ -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;
index 0b5499474f4785fadf9068cd506083fb477e119c..1a547f230bfe3694a0a94b1284283c5f470d877b 100644 (file)
@@ -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];