Patchwork libgo patch committed: Use getcontext, not setjmp, to save regs for GC

login
register
mail settings
Submitter Ian Taylor
Date May 22, 2012, 4:57 p.m.
Message ID <mcrbolg17cq.fsf@dhcp-172-18-216-180.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/160690/
State New
Headers show

Comments

Ian Taylor - May 22, 2012, 4:57 p.m.
When starting a system call, the libgo library needs to save the
registers in a place where the garbage collector can see them, so that
if the registers happen to be pointers the objects to which they point
will not be collected.  I thought that I could simply use setjmp for
that.  Unfortunately, I just managed to uncover the fact that setjmp
mangles the register values, so that the garbage collector does not
understand them.  This means that a particularly poorly timed garbage
collection can discard values used by a system call.  This patch changes
libgo to use getcontext as well, which should work at least until
getcontext also gets pointer mangling.  It appears that in the long run
we will need processor-specific context save and restore routines in
libgo.  Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline and 4.7 branch.

Ian

Patch

diff -r edb476bbcabd libgo/runtime/proc.c
--- a/libgo/runtime/proc.c	Fri May 18 13:14:19 2012 -0700
+++ b/libgo/runtime/proc.c	Tue May 22 09:51:13 2012 -0700
@@ -1239,9 +1239,7 @@ 
 
 	// Save the registers in the g structure so that any pointers
 	// held in registers will be seen by the garbage collector.
-	// We could use getcontext here, but setjmp is more efficient
-	// because it doesn't need to save the signal mask.
-	setjmp(g->gcregs);
+	getcontext(&g->gcregs);
 
 	g->status = Gsyscall;
 
@@ -1299,7 +1297,7 @@ 
 		gp->gcstack = nil;
 #endif
 		gp->gcnext_sp = nil;
-		runtime_memclr(gp->gcregs, sizeof gp->gcregs);
+		runtime_memclr(&gp->gcregs, sizeof gp->gcregs);
 
 		if(m->profilehz > 0)
 			runtime_setprof(true);
@@ -1328,7 +1326,7 @@ 
 	gp->gcstack = nil;
 #endif
 	gp->gcnext_sp = nil;
-	runtime_memclr(gp->gcregs, sizeof gp->gcregs);
+	runtime_memclr(&gp->gcregs, sizeof gp->gcregs);
 }
 
 // Allocate a new g, with a stack big enough for stacksize bytes.
diff -r edb476bbcabd libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Fri May 18 13:14:19 2012 -0700
+++ b/libgo/runtime/runtime.h	Tue May 22 09:51:13 2012 -0700
@@ -7,7 +7,6 @@ 
 #include "config.h"
 
 #include "go-assert.h"
-#include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -128,7 +127,7 @@ 
 	void*	gcnext_segment;
 	void*	gcnext_sp;
 	void*	gcinitial_sp;
-	jmp_buf	gcregs;
+	ucontext_t gcregs;
 	byte*	entry;		// initial function
 	G*	alllink;	// on allg
 	void*	param;		// passed parameter on wakeup