1
0
mirror of https://github.com/golang/go synced 2024-11-22 02:14:40 -07:00

runtime(windows): make sure scheduler runs on os stack and new stdcall implementation

R=rsc
CC=golang-dev
https://golang.org/cl/2009045
This commit is contained in:
Alex Brainman 2010-09-12 11:45:16 +10:00
parent 0acb63769c
commit f95a2f2b97
6 changed files with 123 additions and 109 deletions

View File

@ -434,7 +434,11 @@ matchmg(void)
ts.fn = mstart; ts.fn = mstart;
runcgo(libcgo_thread_start, &ts); runcgo(libcgo_thread_start, &ts);
} else { } 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); newosproc(m, m->g0, m->g0->stackbase, mstart);
} }
} }

View File

@ -232,9 +232,7 @@ struct M
G* lockedg; G* lockedg;
uint64 freg[8]; // Floating point register storage used by ARM software fp routines uint64 freg[8]; // Floating point register storage used by ARM software fp routines
#ifdef __WINDOWS__ #ifdef __WINDOWS__
void* return_address; // saved return address and stack void* gostack; // bookmark to keep track of go stack during stdcall
void* stack_pointer; // pointer for Windows stdcall
void* os_stack_pointer;
#endif #endif
}; };
struct Stktop struct Stktop
@ -289,6 +287,16 @@ struct Func
int32 locals; // number of 32-bit locals int32 locals; // number of 32-bit locals
}; };
#ifdef __WINDOWS__
enum {
Windows = 1
};
#else
enum {
Windows = 0
};
#endif
/* /*
* defined macros * defined macros
* you need super-goru privilege * you need super-goru privilege

View File

@ -12,87 +12,102 @@ TEXT get_kernel_module(SB),7,$0
MOVL 0x08(AX), AX // get base of module MOVL 0x08(AX), AX // get base of module
RET RET
// void *stdcall_raw(void *fn, ...); // void *stdcall_raw(void *fn, int32 count, uintptr *args)
// Call fn with stdcall calling convention. TEXT stdcall_raw(SB),7,$4
// fn parameters are on stack. // Copy arguments from stack.
TEXT stdcall_raw(SB),7,$0 MOVL fn+0(FP), AX
get_tls(CX) MOVL count+4(FP), CX // words
MOVL m(CX), CX MOVL args+8(FP), BP
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 syscall(StdcallParams *p); // Switch to m->g0 if needed.
// 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.
get_tls(DI) get_tls(DI)
MOVL m(DI), DX 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 MOVL m_g0(DX), SI
CMPL g(DI), SI CMPL g(DI), SI
JEQ 2(PC) JEQ 3(PC)
MOVL (m_sched+gobuf_sp)(DX), SP 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 SI, g(DI)
MOVL CX, 4(SP)
MOVL AX, 0(SP) // Copy args to new stack.
CALL call_syscall(SB) SUBL $(10*4), SP // padding
MOVL CX, BX
// Back; switch to original g and stack, re-establish SALL $2, BX
// "DF is clear" invariant. SUBL BX, SP // room for args
MOVL SP, DI
MOVL BP, SI
CLD CLD
REP; MOVSL
// Call stdcall function.
CALL AX
// Restore original SP, g.
get_tls(DI) 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 SI, g(DI)
MOVL 4(SP), SP
RET
TEXT threadstart(SB),7,$0 // Someday the convention will be D is always cleared.
MOVL 4(SP), AX // threadstart param CLD
MOVL 0(AX), BX // newosproc arg stack
MOVL 0(BX), CX // m
MOVL 4(BX), DX // g
// 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 LEAL m_tls(CX), SI
MOVL SI, 0x2c(FS) MOVL SI, 0x2c(FS)
MOVL CX, m(SI) MOVL CX, m(SI)
MOVL DX, g(SI) MOVL DX, g(SI)
MOVL SP, m_os_stack_pointer(CX)
PUSHL 8(BX) // stk // Use scheduler stack now.
PUSHL 12(BX) // fn MOVL g_stackbase(DX), SP
PUSHL 4(AX) // event_handle
// signal that we're done with thread args // Someday the convention will be D is always cleared.
MOVL SetEvent(SB), BX CLD
CALL BX // SetEvent(event_handle)
POPL BX // fn PUSHL DI // original stack
POPL SP // stk
CALL stackcheck(SB) // clobbers AX,CX CALL stackcheck(SB) // clobbers AX,CX
CALL BX // fn()
// cleanup stack before returning as we are stdcall CALL mstart(SB)
get_tls(CX)
MOVL m(CX), CX POPL DI // original stack
MOVL m_os_stack_pointer(CX), SP MOVL DI, SP
POPL AX // return address
MOVL AX, (SP) RET
XORL AX, AX
// 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 RET
// setldt(int entry, int address, int limit) // setldt(int entry, int address, int limit)

View File

@ -19,13 +19,15 @@ void windows_goargs(void);
// Get start address of symbol data in memory. // Get start address of symbol data in memory.
void *get_symdat_addr(void); void *get_symdat_addr(void);
// Call a Windows function with stdcall conventions.
void *stdcall_raw(void *fn, ...);
// Call a Windows function with stdcall conventions, // Call a Windows function with stdcall conventions,
// and switch to os stack during the call. // and switch to os stack during the call.
void *stdcall_raw(void *fn, int32 count, uintptr *args);
void *stdcall(void *fn, int32 count, ...); 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 // Call stdcall Windows function StdcallParams.fn
// with params StdcallParams.args, // with params StdcallParams.args,
// followed immediately by GetLastError call. // followed immediately by GetLastError call.
@ -36,8 +38,9 @@ struct StdcallParams
{ {
void *fn; void *fn;
uintptr args[12]; uintptr args[12];
int32 n;
uintptr r; uintptr r;
uintptr err; uintptr err;
}; };
void call_syscall(void *args);
void syscall(StdcallParams *p); void syscall(StdcallParams *p);

View File

@ -12,9 +12,8 @@ func loadlibraryex(filename uintptr) (handle uint32) {
p.args[0] = filename; p.args[0] = filename;
p.args[1] = 0; p.args[1] = 0;
p.args[2] = 0; p.args[2] = 0;
·entersyscall(); p.n = 3;
syscall(&p); syscall(&p);
·exitsyscall();
handle = p.r; handle = p.r;
} }
@ -23,9 +22,8 @@ func getprocaddress(handle uint32, procname uintptr) (proc uintptr) {
p.fn = (void*)GetProcAddress; p.fn = (void*)GetProcAddress;
p.args[0] = handle; p.args[0] = handle;
p.args[1] = procname; p.args[1] = procname;
·entersyscall(); p.n = 2;
syscall(&p); syscall(&p);
·exitsyscall();
proc = p.r; 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[0] = a1;
p.args[1] = a2; p.args[1] = a2;
p.args[2] = a3; p.args[2] = a3;
·entersyscall(); p.n = 3;
syscall(&p); syscall(&p);
·exitsyscall();
r1 = p.r; r1 = p.r;
r2 = 0; r2 = 0;
err = p.err; 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[3] = a4;
p.args[4] = a5; p.args[4] = a5;
p.args[5] = a6; p.args[5] = a6;
·entersyscall(); p.n = 6;
syscall(&p); syscall(&p);
·exitsyscall();
r1 = p.r; r1 = p.r;
r2 = 0; r2 = 0;
err = p.err; 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[6] = a7;
p.args[7] = a8; p.args[7] = a8;
p.args[8] = a9; p.args[8] = a9;
·entersyscall(); p.n = 9;
syscall(&p); syscall(&p);
·exitsyscall();
r1 = p.r; r1 = p.r;
r2 = 0; r2 = 0;
lasterr = p.err; 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[9] = a10;
p.args[10] = a11; p.args[10] = a11;
p.args[11] = a12; p.args[11] = a12;
·entersyscall(); p.n = 12;
syscall(&p); syscall(&p);
·exitsyscall();
r1 = p.r; r1 = p.r;
r2 = 0; r2 = 0;
lasterr = p.err; 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[0] = a1;
p.args[1] = a2; p.args[1] = a2;
p.args[2] = a3; p.args[2] = a3;
p.n = 3;
syscall(&p); syscall(&p);
r1 = p.r; r1 = p.r;
r2 = 0; r2 = 0;

View File

@ -77,8 +77,8 @@ get_proc_addr(void *library, void *name)
{ {
void *base; void *base;
base = stdcall_raw(LoadLibraryEx, library, 0, 0); base = stdcall(LoadLibraryEx, 3, library, 0, 0);
return stdcall_raw(GetProcAddress, base, name); return stdcall(GetProcAddress, 2, base, name);
} }
void void
@ -251,17 +251,11 @@ notesleep(Note *n)
void void
newosproc(M *m, G *g, void *stk, void (*fn)(void)) newosproc(M *m, G *g, void *stk, void (*fn)(void))
{ {
struct { USED(stk);
void *args; USED(g); // assuming g = m->g0
void *event_handle; USED(fn); // assuming fn = mstart
} param = { &m };
extern uint32 threadstart(void *p);
USED(g, stk, fn); stdcall(CreateThread, 6, 0, 0, tstart_stdcall, m, 0, 0);
param.event_handle = stdcall(CreateEvent, 4, 0, 0, 0, 0);
stdcall(CreateThread, 6, 0, 0, threadstart, &param, 0, 0);
stdcall(WaitForSingleObject, 2, param.event_handle, -1);
stdcall(CloseHandle, 1, param.event_handle);
} }
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).
@ -275,25 +269,20 @@ minit(void)
void * void *
stdcall(void *fn, int32 count, ...) stdcall(void *fn, int32 count, ...)
{ {
uintptr *a; return stdcall_raw(fn, count, (uintptr*)(&count + 1));
StdcallParams p;
p.fn = fn;
a = (uintptr*)(&count + 1);
while(count > 0) {
count--;
p.args[count] = a[count];
}
syscall(&p);
return (void*)(p.r);
} }
void void
call_syscall(void *args) syscall(StdcallParams *p)
{ {
StdcallParams *p = (StdcallParams*)args; uintptr a;
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]); ·entersyscall();
p->err = (uintptr)stdcall_raw(GetLastError); // TODO(brainman): Move calls to SetLastError and GetLastError
return; // 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();
} }