Commit 428062da authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

ld: increase default stack size on Windows for cgo

Fixes #2437.

R=rsc, hectorchu, mattn.jp, alex.brainman, jdpoirier, snaury, n13m3y3r
CC=golang-dev
https://golang.org/cl/5371049
parent 5e435273
......@@ -274,6 +274,7 @@ loadlib(void)
for(i=0; i<libraryp; i++) {
if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0;
objfile(library[i].file, library[i].pkg);
}
......
......@@ -125,6 +125,7 @@ EXTERN int32 nsymbol;
EXTERN char* thestring;
EXTERN int ndynexp;
EXTERN int havedynamic;
EXTERN int iscgo;
EXTERN Segment segtext;
EXTERN Segment segdata;
......
......@@ -650,8 +650,21 @@ asmbpe(void)
// Commit size must be strictly less than reserve
// size otherwise reserve will be rounded up to a
// larger size, as verified with VMMap.
set(SizeOfStackReserve, 0x00010000);
set(SizeOfStackCommit, 0x0000ffff);
// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
// That default stack reserve size affects only the main thread,
// for other threads we specify stack size in runtime explicitly
// (runtime knows whether cgo is enabled or not).
// If you change stack reserve sizes here,
// change them in runtime/cgo/windows_386/amd64.c as well.
if(!iscgo) {
set(SizeOfStackReserve, 0x00010000);
set(SizeOfStackCommit, 0x0000ffff);
} else {
set(SizeOfStackReserve, pe64 ? 0x00200000 : 0x00100000);
// account for 2 guard pages
set(SizeOfStackCommit, (pe64 ? 0x00200000 : 0x00100000) - 0x2000);
}
set(SizeOfHeapReserve, 0x00100000);
set(SizeOfHeapCommit, 0x00001000);
set(NumberOfRvaAndSizes, 16);
......
......@@ -21,15 +21,22 @@ TEXT _rt0_386(SB),7,$0
MOVL AX, 120(SP) // save argc, argv away
MOVL BX, 124(SP)
// set default stack bounds.
// initcgo may update stackguard.
MOVL $runtime·g0(SB), BP
LEAL (-64*1024+104)(SP), BX
MOVL BX, g_stackguard(BP)
MOVL SP, g_stackbase(BP)
// if there is an initcgo, call it to let it
// initialize and to set up GS. if not,
// we set up GS ourselves.
MOVL initcgo(SB), AX
TESTL AX, AX
JZ needtls
PUSHL $runtime·g0(SB)
PUSHL BP
CALL AX
POPL AX
POPL BP
// skip runtime·ldt0setup(SB) and tls test after initcgo for non-windows
CMPL runtime·iswindows(SB), $0
JEQ ok
......@@ -59,16 +66,6 @@ ok:
// save m->g0 = g0
MOVL CX, m_g0(AX)
// create istack out of the OS stack
// if there is an initcgo, it had setup stackguard for us
MOVL initcgo(SB), AX
TESTL AX, AX
JNZ stackok
LEAL (-64*1024+104)(SP), AX // TODO: 104?
MOVL AX, g_stackguard(CX)
stackok:
MOVL SP, g_stackbase(CX)
CALL runtime·emptyfunc(SB) // fault if stack check is wrong
// convention is D is always cleared
......
......@@ -12,13 +12,19 @@ TEXT _rt0_amd64(SB),7,$-8
ANDQ $~15, SP
MOVQ AX, 16(SP)
MOVQ BX, 24(SP)
// create istack out of the given (operating system) stack.
// initcgo may update stackguard.
MOVQ $runtime·g0(SB), DI
LEAQ (-8192+104)(SP), BX
MOVQ BX, g_stackguard(DI)
MOVQ SP, g_stackbase(DI)
// if there is an initcgo, call it.
MOVQ initcgo(SB), AX
TESTQ AX, AX
JZ needtls
LEAQ runtime·g0(SB), DI
CALL AX
CALL AX // g0 already in DI
CMPL runtime·iswindows(SB), $0
JEQ ok
......@@ -44,16 +50,6 @@ ok:
// save m->g0 = g0
MOVQ CX, m_g0(AX)
// create istack out of the given (operating system) stack
// if there is an initcgo, it had setup stackguard for us
MOVQ initcgo(SB), AX
TESTQ AX, AX
JNZ stackok
LEAQ (-8192+104)(SP), AX
MOVQ AX, g_stackguard(CX)
stackok:
MOVQ SP, g_stackbase(CX)
CLD // convention is D is always left cleared
CALL runtime·check(SB)
......
......@@ -8,15 +8,16 @@
static void *threadentry(void*);
/* From what I've read 1MB is default for 32-bit Linux.
Allocation granularity on Windows is typically 64 KB. */
/* 1MB is default stack size for 32-bit Windows.
Allocation granularity on Windows is typically 64 KB.
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (1*1024*1024)
static void
xinitcgo(G *g)
{
int tmp;
g->stackguard = (uintptr)&tmp - STACKSIZE + 4096;
g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
}
void (*initcgo)(G*) = xinitcgo;
......@@ -24,8 +25,7 @@ void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
ts->g->stackguard = STACKSIZE;
_beginthread(threadentry, STACKSIZE, ts);
_beginthread(threadentry, 0, ts);
}
static void*
......@@ -38,12 +38,7 @@ threadentry(void *v)
free(v);
ts.g->stackbase = (uintptr)&ts;
/*
* libcgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024;
/*
* Set specific keys in thread local storage.
......
......@@ -8,15 +8,16 @@
static void *threadentry(void*);
/* From what I've read 2MB is default for 64-bit Linux.
Allocation granularity on Windows is typically 64 KB. */
/* 2MB is default stack size for 64-bit Windows.
Allocation granularity on Windows is typically 64 KB.
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (2*1024*1024)
static void
xinitcgo(G *g)
{
int tmp;
g->stackguard = (uintptr)&tmp - STACKSIZE + 4096;
g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
}
void (*initcgo)(G*) = xinitcgo;
......@@ -24,8 +25,7 @@ void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
ts->g->stackguard = STACKSIZE;
_beginthread(threadentry, STACKSIZE, ts);
_beginthread(threadentry, 0, ts);
}
static void*
......@@ -38,12 +38,7 @@ threadentry(void *v)
free(v);
ts.g->stackbase = (uintptr)&ts;
/*
* libcgo_sys_thread_start set stackguard to stack size;
* change to actual guard pointer.
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024;
/*
* Set specific keys in thread local storage.
......
......@@ -183,6 +183,8 @@ runtime·semacreate(void)
return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
}
#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
void
runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
......@@ -193,7 +195,8 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
USED(fn); // assuming fn = mstart
thandle = runtime·stdcall(runtime·CreateThread, 6,
nil, nil, runtime·tstart_stdcall, m, nil, nil);
nil, (uintptr)0x20000, runtime·tstart_stdcall, m,
STACK_SIZE_PARAM_IS_A_RESERVATION, nil);
if(thandle == nil) {
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
runtime·throw("runtime.newosproc");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment