runtime: add stackguard0 to G
This is part of preemptive scheduler.
stackguard0 is checked in split stack checks and can be set to StackPreempt.
stackguard is not set to StackPreempt (holds the original value).

R=golang-dev, daniel.morsing, iant
CC=golang-dev
https://golang.org/cl/9875043
diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s
index 58fa6d6..85b5008 100644
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -18,6 +18,7 @@
 	MOVL	$runtime·g0(SB), BP
 	LEAL	(-64*1024+104)(SP), BX
 	MOVL	BX, g_stackguard(BP)
+	MOVL	BX, g_stackguard0(BP)
 	MOVL	SP, g_stackbase(BP)
 	
 	// find out information about the processor we're on
@@ -41,6 +42,10 @@
 	MOVL	BX, 4(SP)
 	MOVL	BP, 0(SP)
 	CALL	AX
+	// update stackguard after _cgo_init
+	MOVL	$runtime·g0(SB), CX
+	MOVL	g_stackguard0(CX), AX
+	MOVL	AX, g_stackguard(CX)
 	// skip runtime·ldt0setup(SB) and tls test after _cgo_init for non-windows
 	CMPL runtime·iswindows(SB), $0
 	JEQ ok
diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s
index f779b94..af83c03 100644
--- a/src/pkg/runtime/asm_amd64.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -18,6 +18,7 @@
 	MOVQ	$runtime·g0(SB), DI
 	LEAQ	(-64*1024+104)(SP), BX
 	MOVQ	BX, g_stackguard(DI)
+	MOVQ	BX, g_stackguard0(DI)
 	MOVQ	SP, g_stackbase(DI)
 
 	// find out information about the processor we're on
@@ -39,6 +40,10 @@
 	MOVQ	DI, CX	// Win64 uses CX for first parameter
 	MOVQ	$setmg_gcc<>(SB), SI
 	CALL	AX
+	// update stackguard after _cgo_init
+	MOVQ	$runtime·g0(SB), CX
+	MOVQ	g_stackguard0(CX), AX
+	MOVQ	AX, g_stackguard(CX)
 	CMPL	runtime·iswindows(SB), $0
 	JEQ ok
 
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index fed9b30..d4bcbd5 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -28,6 +28,7 @@
 	// create istack out of the OS stack
 	MOVW	$(-8192+104)(R13), R0
 	MOVW	R0, g_stackguard(g)	// (w 104b guard)
+	MOVW	R0, g_stackguard0(g)
 	MOVW	R13, g_stackbase(g)
 	BL	runtime·emptyfunc(SB)	// fault if stack check is wrong
 
@@ -36,6 +37,9 @@
 	CMP	$0, R2
 	MOVW.NE	g, R0 // first argument of _cgo_init is g
 	BL.NE	(R2) // will clobber R0-R3
+	// update stackguard after _cgo_init
+	MOVW	g_stackguard0(g), R0
+	MOVW	R0, g_stackguard(g)
 
 	BL	runtime·checkgoarm(SB)
 	BL	runtime·check(SB)
diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c
index ecce93f..18e4779 100644
--- a/src/pkg/runtime/panic.c
+++ b/src/pkg/runtime/panic.c
@@ -298,6 +298,7 @@
 			break;
 		gp->stackbase = (uintptr)top->stackbase;
 		gp->stackguard = (uintptr)top->stackguard;
+		gp->stackguard0 = gp->stackguard;
 		if(top->free != 0)
 			runtime·stackfree(stk, top->free);
 	}
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index c7a8d24..206a3cb 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -468,6 +468,7 @@
 	// so other calls can reuse this stack space.
 	runtime·gosave(&m->g0->sched);
 	m->g0->sched.pc = (void*)-1;  // make sure it is never used
+	m->g0->stackguard = m->g0->stackguard0;  // cgo sets only stackguard0, copy it to stackguard
 	m->seh = &seh;
 	runtime·asminit();
 	runtime·minit();
@@ -615,6 +616,7 @@
 	runtime·setmg(mp, mp->g0);
 	g->stackbase = (uintptr)(&x + 1024);
 	g->stackguard = (uintptr)(&x - 32*1024);
+	g->stackguard0 = g->stackguard;
 
 	// On windows/386, we need to put an SEH frame (two words)
 	// somewhere on the current stack. We are called
@@ -979,6 +981,7 @@
 		runtime·throw("execute: bad g status");
 	}
 	gp->status = Grunning;
+	gp->stackguard0 = gp->stackguard;
 	m->p->tick++;
 	m->curg = gp;
 	gp->m = m;
@@ -1465,6 +1468,7 @@
 		}
 		newg->stack0 = (uintptr)stk;
 		newg->stackguard = (uintptr)stk + StackGuard;
+		newg->stackguard0 = newg->stackguard;
 		newg->stackbase = (uintptr)stk + StackSystem + stacksize - sizeof(Stktop);
 		runtime·memclr((byte*)newg->stackbase, sizeof(Stktop));
 	}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 2d918f4..e616990 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -226,7 +226,8 @@
 };
 struct	G
 {
-	uintptr	stackguard;	// cannot move - also known to linker, libmach, runtime/cgo
+	// stackguard0 can be set to StackPreempt as opposed to stackguard
+	uintptr	stackguard0;	// cannot move - also known to linker, libmach, runtime/cgo
 	uintptr	stackbase;	// cannot move - also known to libmach, runtime/cgo
 	Defer*	defer;
 	Panic*	panic;
@@ -235,6 +236,7 @@
 	uintptr	gcsp;		// if status==Gsyscall, gcsp = sched.sp to use during gc
 	byte*	gcpc;		// if status==Gsyscall, gcpc = sched.pc to use during gc
 	uintptr	gcguard;		// if status==Gsyscall, gcguard = stackguard to use during gc
+	uintptr	stackguard;	// same as stackguard0, but not set to StackPreempt
 	uintptr	stack0;
 	FuncVal*	fnstart;		// initial function
 	G*	alllink;	// on allg
diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c
index b6f64aa..a033d6b 100644
--- a/src/pkg/runtime/stack.c
+++ b/src/pkg/runtime/stack.c
@@ -157,6 +157,7 @@
 	label = top->gobuf;
 	gp->stackbase = (uintptr)top->stackbase;
 	gp->stackguard = (uintptr)top->stackguard;
+	gp->stackguard0 = gp->stackguard;
 	if(top->free != 0)
 		runtime·stackfree(old, top->free);
 
@@ -249,6 +250,7 @@
 
 	gp->stackbase = (uintptr)top;
 	gp->stackguard = (uintptr)stk + StackGuard;
+	gp->stackguard0 = gp->stackguard;
 
 	sp = (byte*)top;
 	if(argsize > 0) {