From 6f02c138136e54ec525d81e604427782cacec378 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 9 Sep 2016 13:31:49 +0000 Subject: [PATCH] runtime: align ucontext_t argument to 16 byte boundary Some systems, such as ia64 and PPC, require that a ucontext_t pointer passed to getcontext and friends be aligned to a 16-byte boundary. Currently the ucontext_t fields in the g structure are defined in Go, and Go has no way to ensure a 16-byte alignment for a struct field. The fields are currently represented by an array of unsafe.Pointer. Enforce the alignment by making the array larger, and picking an offset into the array that is 16-byte aligned. Reviewed-on: https://go-review.googlesource.com/28910 From-SVN: r240044 --- gcc/go/gofrontend/MERGE | 2 +- libgo/go/runtime/runtime2.go | 6 ++++- libgo/runtime/proc.c | 58 +++++++++++++++++++++++++++++--------------- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 71a9f5b..26f36ec 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -c8cf90f2daf62428ca6aa0b5674572cd99f25fe3 +4f033f29553655ad90493d55059a7bbc6cd63108 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go index 05ce513..468d11e 100644 --- a/libgo/go/runtime/runtime2.go +++ b/libgo/go/runtime/runtime2.go @@ -805,7 +805,11 @@ var ( // _ucontext_t is a Go version of the C ucontext_t type, used by getcontext. // _sizeof_ucontext_t is defined by the Makefile from . -type _ucontext_t [_sizeof_ucontext_t / unsafe.Sizeof(uintptr(0))]unsafe.Pointer +// On some systems getcontext and friends require a value that is +// aligned to a 16-byte boundary. We implement this by increasing the +// required size and picking an appropriate offset when we use the +// array. +type _ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer // traceback is used to collect stack traces from other goroutines. type traceback struct { diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 1ac03a4..59dfc09 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -156,6 +156,20 @@ fixcontext(ucontext_t *c) #endif +// ucontext_arg returns a properly aligned ucontext_t value. On some +// systems a ucontext_t value must be aligned to a 16-byte boundary. +// The g structure that has fields of type ucontext_t is defined in +// Go, and Go has no simple way to align a field to such a boundary. +// So we make the field larger in runtime2.go and pick an appropriate +// offset within the field here. +static ucontext_t* +ucontext_arg(void** go_ucontext) +{ + uintptr_t p = (uintptr_t)go_ucontext; + p = (p + 15) &~ (uintptr_t)0xf; + return (ucontext_t*)p; +} + // We can not always refer to the TLS variables directly. The // compiler will call tls_get_addr to get the address of the variable, // and it may hold it in a register across a call to schedule. When @@ -245,8 +259,8 @@ runtime_gogo(G* newg) #endif g = newg; newg->fromgogo = true; - fixcontext((ucontext_t*)&newg->context[0]); - setcontext((ucontext_t*)&newg->context[0]); + fixcontext(ucontext_arg(&newg->context[0])); + setcontext(ucontext_arg(&newg->context[0])); runtime_throw("gogo setcontext returned"); } @@ -278,7 +292,7 @@ runtime_mcall(void (*pfn)(G*)) gp->gcnextsp = &pfn; #endif gp->fromgogo = false; - getcontext((ucontext_t*)&gp->context[0]); + getcontext(ucontext_arg(&gp->context[0])); // When we return from getcontext, we may be running // in a new thread. That means that g may have @@ -305,8 +319,8 @@ runtime_mcall(void (*pfn)(G*)) // the getcontext call just above. g = mp->g0; - fixcontext((ucontext_t*)&mp->g0->context[0]); - setcontext((ucontext_t*)&mp->g0->context[0]); + fixcontext(ucontext_arg(&mp->g0->context[0])); + setcontext(ucontext_arg(&mp->g0->context[0])); runtime_throw("runtime: mcall function returned"); } } @@ -709,7 +723,7 @@ runtime_tracebackothers(G * volatile me) #ifdef USING_SPLIT_STACK __splitstack_getcontext(&me->stackcontext[0]); #endif - getcontext((ucontext_t*)&me->context[0]); + getcontext(ucontext_arg(&me->context[0])); if(gp->traceback != nil) { runtime_gogo(gp); @@ -750,7 +764,7 @@ runtime_tracebackothers(G * volatile me) #ifdef USING_SPLIT_STACK __splitstack_getcontext(&me->stackcontext[0]); #endif - getcontext((ucontext_t*)&me->context[0]); + getcontext(ucontext_arg(&me->context[0])); if(gp->traceback != nil) { runtime_gogo(gp); @@ -1063,7 +1077,7 @@ runtime_mstart(void* mp) g->gcstacksize = 0; g->gcnextsp = ∓ #endif - getcontext((ucontext_t*)&g->context[0]); + getcontext(ucontext_arg(&g->context[0])); if(g->entry != nil) { // Got here from mcall. @@ -1251,7 +1265,7 @@ runtime_needm(void) g->gcstacksize = 0; g->gcnextsp = ∓ #endif - getcontext((ucontext_t*)&g->context[0]); + getcontext(ucontext_arg(&g->context[0])); if(g->entry != nil) { // Got here from mcall. @@ -1282,6 +1296,7 @@ runtime_newextram(void) G *gp; byte *g0_sp, *sp; uintptr g0_spsize, spsize; + ucontext_t *uc; // Create extra goroutine locked to extra m. // The goroutine is the context in which the cgo callback will run. @@ -1302,10 +1317,11 @@ runtime_newextram(void) // The context for gp will be set up in runtime_needm. But // here we need to set up the context for g0. - getcontext((ucontext_t*)&mp->g0->context[0]); - ((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_sp = g0_sp; - ((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_size = (size_t)g0_spsize; - makecontext((ucontext_t*)&mp->g0->context[0], kickoff, 0); + uc = ucontext_arg(&mp->g0->context[0]); + getcontext(uc); + uc->uc_stack.ss_sp = g0_sp; + uc->uc_stack.ss_size = (size_t)g0_spsize; + makecontext(uc, kickoff, 0); // Add m to the extra list. mnext = lockextra(true); @@ -2007,7 +2023,7 @@ runtime_entersyscall() { // Save the registers in the g structure so that any pointers // held in registers will be seen by the garbage collector. - getcontext((ucontext_t*)&g->gcregs[0]); + getcontext(ucontext_arg(&g->gcregs[0])); // Do the work in a separate function, so that this function // doesn't save any registers on its own stack. If this @@ -2086,7 +2102,7 @@ runtime_entersyscallblock(void) // Save the registers in the g structure so that any pointers // held in registers will be seen by the garbage collector. - getcontext((ucontext_t*)&g->gcregs[0]); + getcontext(ucontext_arg(&g->gcregs[0])); g->atomicstatus = _Gsyscall; @@ -2375,14 +2391,16 @@ __go_go(void (*fn)(void*), void* arg) byte * volatile vsp = sp; size_t volatile vspsize = spsize; G * volatile vnewg = newg; + ucontext_t * volatile uc; - getcontext((ucontext_t*)&vnewg->context[0]); - ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp = vsp; + uc = ucontext_arg(&vnewg->context[0]); + getcontext(uc); + uc->uc_stack.ss_sp = vsp; #ifdef MAKECONTEXT_STACK_TOP - ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp += vspsize; + uc->uc_stack.ss_sp += vspsize; #endif - ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_size = vspsize; - makecontext((ucontext_t*)&vnewg->context[0], kickoff, 0); + uc->uc_stack.ss_size = vspsize; + makecontext(uc, kickoff, 0); runqput(p, vnewg); -- 2.7.4