From f95a2f2b971411d0abef2c2534d70761dde117b6 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Sun, 12 Sep 2010 11:45:16 +1000 Subject: [PATCH] runtime(windows): make sure scheduler runs on os stack and new stdcall implementation R=rsc CC=golang-dev https://golang.org/cl/2009045 --- src/pkg/runtime/proc.c | 6 +- src/pkg/runtime/runtime.h | 14 ++- src/pkg/runtime/windows/386/sys.s | 135 +++++++++++++++------------- src/pkg/runtime/windows/os.h | 11 ++- src/pkg/runtime/windows/syscall.goc | 19 ++-- src/pkg/runtime/windows/thread.c | 47 ++++------ 6 files changed, 123 insertions(+), 109 deletions(-) diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 3dbc48fd9bc..1d1b05969c6 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -434,7 +434,11 @@ matchmg(void) ts.fn = mstart; runcgo(libcgo_thread_start, &ts); } else { - m->g0 = malg(8192); + if(Windows) + // windows will layout sched stack on os stack + m->g0 = malg(-1); + else + m->g0 = malg(8192); newosproc(m, m->g0, m->g0->stackbase, mstart); } } diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 6e8a79624a7..ca76729ec20 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -232,9 +232,7 @@ struct M G* lockedg; uint64 freg[8]; // Floating point register storage used by ARM software fp routines #ifdef __WINDOWS__ - void* return_address; // saved return address and stack - void* stack_pointer; // pointer for Windows stdcall - void* os_stack_pointer; + void* gostack; // bookmark to keep track of go stack during stdcall #endif }; struct Stktop @@ -289,6 +287,16 @@ struct Func int32 locals; // number of 32-bit locals }; +#ifdef __WINDOWS__ +enum { + Windows = 1 +}; +#else +enum { + Windows = 0 +}; +#endif + /* * defined macros * you need super-goru privilege diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s index e36ef53e0a8..8c43f9bdcf1 100644 --- a/src/pkg/runtime/windows/386/sys.s +++ b/src/pkg/runtime/windows/386/sys.s @@ -12,87 +12,102 @@ TEXT get_kernel_module(SB),7,$0 MOVL 0x08(AX), AX // get base of module RET -// void *stdcall_raw(void *fn, ...); -// Call fn with stdcall calling convention. -// fn parameters are on stack. -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 +// void *stdcall_raw(void *fn, int32 count, uintptr *args) +TEXT stdcall_raw(SB),7,$4 + // Copy arguments from stack. + MOVL fn+0(FP), AX + MOVL count+4(FP), CX // words + MOVL args+8(FP), BP -// void syscall(StdcallParams *p); -// Call p.fn syscall + GetLastError on os stack. -TEXT syscall(SB),7,$16 - MOVL p+0(FP), AX - MOVL SP, CX - - // Figure out if we need to switch to m->g0 stack. + // Switch to m->g0 if needed. get_tls(DI) MOVL m(DI), DX + MOVL g(DI), SI + MOVL SI, 0(SP) // save g + MOVL SP, m_gostack(DX) // save SP MOVL m_g0(DX), SI CMPL g(DI), SI - JEQ 2(PC) + JEQ 3(PC) MOVL (m_sched+gobuf_sp)(DX), SP - - // Now on a scheduling stack (an os stack). - MOVL g(DI), BP - MOVL BP, 8(SP) MOVL SI, g(DI) - MOVL CX, 4(SP) - MOVL AX, 0(SP) - CALL call_syscall(SB) - - // Back; switch to original g and stack, re-establish - // "DF is clear" invariant. + + // Copy args to new stack. + SUBL $(10*4), SP // padding + MOVL CX, BX + SALL $2, BX + SUBL BX, SP // room for args + MOVL SP, DI + MOVL BP, SI CLD + REP; MOVSL + + // Call stdcall function. + CALL AX + + // Restore original SP, g. get_tls(DI) - MOVL 8(SP), SI + MOVL m(DI), DX + MOVL m_gostack(DX), SP // restore SP + MOVL 0(SP), SI // restore g MOVL SI, g(DI) - MOVL 4(SP), SP - 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 + // Someday the convention will be D is always cleared. + CLD - // set up tls + RET + +// void tstart(M *newm); +TEXT tstart(SB),7,$0 + MOVL newm+4(SP), CX // m + MOVL m_g0(CX), DX // g + + MOVL SP, DI // remember stack + + // Layout new m scheduler stack on os stack. + MOVL SP, AX + SUBL $256, AX // just some space for ourselves + MOVL AX, g_stackbase(DX) + SUBL $8192, AX // stack size + MOVL AX, g_stackguard(DX) + + // 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 + // Use scheduler stack now. + MOVL g_stackbase(DX), SP - // signal that we're done with thread args - MOVL SetEvent(SB), BX - CALL BX // SetEvent(event_handle) - POPL BX // fn - POPL SP // stk + // Someday the convention will be D is always cleared. + CLD + + PUSHL DI // original stack 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 + CALL mstart(SB) + + POPL DI // original stack + MOVL DI, SP + + RET + +// uint32 tstart_stdcall(M *newm); +TEXT tstart_stdcall(SB),7,$0 + MOVL newm+4(SP), BX + + PUSHL BX + CALL tstart+0(SB) + POPL BX + + // Adjust stack for stdcall to return properly. + MOVL (SP), AX // save return address + ADDL $4, SP // remove single parameter + MOVL AX, (SP) // restore return address + + XORL AX, AX // return 0 == success + RET // setldt(int entry, int address, int limit) diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h index 68efaa036a7..343ddbccf96 100644 --- a/src/pkg/runtime/windows/os.h +++ b/src/pkg/runtime/windows/os.h @@ -19,13 +19,15 @@ void windows_goargs(void); // Get start address of symbol data in memory. void *get_symdat_addr(void); -// Call a Windows function with stdcall conventions. -void *stdcall_raw(void *fn, ...); - // Call a Windows function with stdcall conventions, // and switch to os stack during the call. +void *stdcall_raw(void *fn, int32 count, uintptr *args); void *stdcall(void *fn, int32 count, ...); +// Function to be called by windows CreateTread +// to start new os thread. +uint32 tstart_stdcall(M *newm); + // Call stdcall Windows function StdcallParams.fn // with params StdcallParams.args, // followed immediately by GetLastError call. @@ -36,8 +38,9 @@ struct StdcallParams { void *fn; uintptr args[12]; + int32 n; uintptr r; uintptr err; }; -void call_syscall(void *args); + void syscall(StdcallParams *p); diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc index 8287e704146..306b7152964 100644 --- a/src/pkg/runtime/windows/syscall.goc +++ b/src/pkg/runtime/windows/syscall.goc @@ -12,9 +12,8 @@ func loadlibraryex(filename uintptr) (handle uint32) { p.args[0] = filename; p.args[1] = 0; p.args[2] = 0; - ·entersyscall(); + p.n = 3; syscall(&p); - ·exitsyscall(); handle = p.r; } @@ -23,9 +22,8 @@ func getprocaddress(handle uint32, procname uintptr) (proc uintptr) { p.fn = (void*)GetProcAddress; p.args[0] = handle; p.args[1] = procname; - ·entersyscall(); + p.n = 2; syscall(&p); - ·exitsyscall(); proc = p.r; } @@ -35,9 +33,8 @@ func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 u p.args[0] = a1; p.args[1] = a2; p.args[2] = a3; - ·entersyscall(); + p.n = 3; syscall(&p); - ·exitsyscall(); r1 = p.r; r2 = 0; err = p.err; @@ -52,9 +49,8 @@ func Syscall6(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 u p.args[3] = a4; p.args[4] = a5; p.args[5] = a6; - ·entersyscall(); + p.n = 6; syscall(&p); - ·exitsyscall(); r1 = p.r; r2 = 0; err = p.err; @@ -72,9 +68,8 @@ func Syscall9(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 u p.args[6] = a7; p.args[7] = a8; p.args[8] = a9; - ·entersyscall(); + p.n = 9; syscall(&p); - ·exitsyscall(); r1 = p.r; r2 = 0; lasterr = p.err; @@ -95,9 +90,8 @@ func Syscall12(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 p.args[9] = a10; p.args[10] = a11; p.args[11] = a12; - ·entersyscall(); + p.n = 12; syscall(&p); - ·exitsyscall(); r1 = p.r; r2 = 0; lasterr = p.err; @@ -109,6 +103,7 @@ func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r p.args[0] = a1; p.args[1] = a2; p.args[2] = a3; + p.n = 3; syscall(&p); r1 = p.r; r2 = 0; diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c index a9062250dc7..82d1fa84e56 100644 --- a/src/pkg/runtime/windows/thread.c +++ b/src/pkg/runtime/windows/thread.c @@ -77,8 +77,8 @@ get_proc_addr(void *library, void *name) { void *base; - base = stdcall_raw(LoadLibraryEx, library, 0, 0); - return stdcall_raw(GetProcAddress, base, name); + base = stdcall(LoadLibraryEx, 3, library, 0, 0); + return stdcall(GetProcAddress, 2, base, name); } void @@ -251,17 +251,11 @@ notesleep(Note *n) 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(stk); + USED(g); // assuming g = m->g0 + USED(fn); // assuming fn = mstart - USED(g, stk, fn); - param.event_handle = stdcall(CreateEvent, 4, 0, 0, 0, 0); - stdcall(CreateThread, 6, 0, 0, threadstart, ¶m, 0, 0); - stdcall(WaitForSingleObject, 2, param.event_handle, -1); - stdcall(CloseHandle, 1, param.event_handle); + stdcall(CreateThread, 6, 0, 0, tstart_stdcall, m, 0, 0); } // Called to initialize a new m (including the bootstrap m). @@ -275,25 +269,20 @@ minit(void) void * stdcall(void *fn, int32 count, ...) { - uintptr *a; - StdcallParams p; - - p.fn = fn; - a = (uintptr*)(&count + 1); - while(count > 0) { - count--; - p.args[count] = a[count]; - } - syscall(&p); - return (void*)(p.r); + return stdcall_raw(fn, count, (uintptr*)(&count + 1)); } void -call_syscall(void *args) +syscall(StdcallParams *p) { - StdcallParams *p = (StdcallParams*)args; - stdcall_raw(SetLastError, 0); - p->r = (uintptr)stdcall_raw((void*)p->fn, p->args[0], p->args[1], p->args[2], p->args[3], p->args[4], p->args[5], p->args[6], p->args[7], p->args[8], p->args[9], p->args[10], p->args[11]); - p->err = (uintptr)stdcall_raw(GetLastError); - return; + uintptr a; + + ·entersyscall(); + // TODO(brainman): Move calls to SetLastError and GetLastError + // to stdcall_raw to speed up syscall. + a = 0; + stdcall_raw(SetLastError, 1, &a); + p->r = (uintptr)stdcall_raw((void*)p->fn, p->n, p->args); + p->err = (uintptr)stdcall_raw(GetLastError, 0, &a); + ·exitsyscall(); }