mirror of
https://github.com/golang/go
synced 2024-11-22 08: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:
parent
0acb63769c
commit
f95a2f2b97
@ -434,6 +434,10 @@ matchmg(void)
|
|||||||
ts.fn = mstart;
|
ts.fn = mstart;
|
||||||
runcgo(libcgo_thread_start, &ts);
|
runcgo(libcgo_thread_start, &ts);
|
||||||
} else {
|
} else {
|
||||||
|
if(Windows)
|
||||||
|
// windows will layout sched stack on os stack
|
||||||
|
m->g0 = malg(-1);
|
||||||
|
else
|
||||||
m->g0 = malg(8192);
|
m->g0 = malg(8192);
|
||||||
newosproc(m, m->g0, m->g0->stackbase, mstart);
|
newosproc(m, m->g0, m->g0->stackbase, mstart);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
|
||||||
CALL call_syscall(SB)
|
|
||||||
|
|
||||||
// Back; switch to original g and stack, re-establish
|
// Copy args to new stack.
|
||||||
// "DF is clear" invariant.
|
SUBL $(10*4), SP // padding
|
||||||
|
MOVL CX, BX
|
||||||
|
SALL $2, BX
|
||||||
|
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
|
|
||||||
|
// Someday the convention will be D is always cleared.
|
||||||
|
CLD
|
||||||
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
TEXT threadstart(SB),7,$0
|
// void tstart(M *newm);
|
||||||
MOVL 4(SP), AX // threadstart param
|
TEXT tstart(SB),7,$0
|
||||||
MOVL 0(AX), BX // newosproc arg stack
|
MOVL newm+4(SP), CX // m
|
||||||
MOVL 0(BX), CX // m
|
MOVL m_g0(CX), DX // g
|
||||||
MOVL 4(BX), DX // g
|
|
||||||
|
|
||||||
// set up tls
|
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)
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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, ¶m, 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();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user