Commit 6f02c138 by Ian Lance Taylor

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
parent 0abcd6cc
c8cf90f2daf62428ca6aa0b5674572cd99f25fe3 4f033f29553655ad90493d55059a7bbc6cd63108
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -805,7 +805,11 @@ var ( ...@@ -805,7 +805,11 @@ var (
// _ucontext_t is a Go version of the C ucontext_t type, used by getcontext. // _ucontext_t is a Go version of the C ucontext_t type, used by getcontext.
// _sizeof_ucontext_t is defined by the Makefile from <ucontext.h>. // _sizeof_ucontext_t is defined by the Makefile from <ucontext.h>.
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. // traceback is used to collect stack traces from other goroutines.
type traceback struct { type traceback struct {
......
...@@ -156,6 +156,20 @@ fixcontext(ucontext_t *c) ...@@ -156,6 +156,20 @@ fixcontext(ucontext_t *c)
#endif #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 // We can not always refer to the TLS variables directly. The
// compiler will call tls_get_addr to get the address of the variable, // 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 // and it may hold it in a register across a call to schedule. When
...@@ -245,8 +259,8 @@ runtime_gogo(G* newg) ...@@ -245,8 +259,8 @@ runtime_gogo(G* newg)
#endif #endif
g = newg; g = newg;
newg->fromgogo = true; newg->fromgogo = true;
fixcontext((ucontext_t*)&newg->context[0]); fixcontext(ucontext_arg(&newg->context[0]));
setcontext((ucontext_t*)&newg->context[0]); setcontext(ucontext_arg(&newg->context[0]));
runtime_throw("gogo setcontext returned"); runtime_throw("gogo setcontext returned");
} }
...@@ -278,7 +292,7 @@ runtime_mcall(void (*pfn)(G*)) ...@@ -278,7 +292,7 @@ runtime_mcall(void (*pfn)(G*))
gp->gcnextsp = &pfn; gp->gcnextsp = &pfn;
#endif #endif
gp->fromgogo = false; gp->fromgogo = false;
getcontext((ucontext_t*)&gp->context[0]); getcontext(ucontext_arg(&gp->context[0]));
// When we return from getcontext, we may be running // When we return from getcontext, we may be running
// in a new thread. That means that g may have // in a new thread. That means that g may have
...@@ -305,8 +319,8 @@ runtime_mcall(void (*pfn)(G*)) ...@@ -305,8 +319,8 @@ runtime_mcall(void (*pfn)(G*))
// the getcontext call just above. // the getcontext call just above.
g = mp->g0; g = mp->g0;
fixcontext((ucontext_t*)&mp->g0->context[0]); fixcontext(ucontext_arg(&mp->g0->context[0]));
setcontext((ucontext_t*)&mp->g0->context[0]); setcontext(ucontext_arg(&mp->g0->context[0]));
runtime_throw("runtime: mcall function returned"); runtime_throw("runtime: mcall function returned");
} }
} }
...@@ -709,7 +723,7 @@ runtime_tracebackothers(G * volatile me) ...@@ -709,7 +723,7 @@ runtime_tracebackothers(G * volatile me)
#ifdef USING_SPLIT_STACK #ifdef USING_SPLIT_STACK
__splitstack_getcontext(&me->stackcontext[0]); __splitstack_getcontext(&me->stackcontext[0]);
#endif #endif
getcontext((ucontext_t*)&me->context[0]); getcontext(ucontext_arg(&me->context[0]));
if(gp->traceback != nil) { if(gp->traceback != nil) {
runtime_gogo(gp); runtime_gogo(gp);
...@@ -750,7 +764,7 @@ runtime_tracebackothers(G * volatile me) ...@@ -750,7 +764,7 @@ runtime_tracebackothers(G * volatile me)
#ifdef USING_SPLIT_STACK #ifdef USING_SPLIT_STACK
__splitstack_getcontext(&me->stackcontext[0]); __splitstack_getcontext(&me->stackcontext[0]);
#endif #endif
getcontext((ucontext_t*)&me->context[0]); getcontext(ucontext_arg(&me->context[0]));
if(gp->traceback != nil) { if(gp->traceback != nil) {
runtime_gogo(gp); runtime_gogo(gp);
...@@ -1063,7 +1077,7 @@ runtime_mstart(void* mp) ...@@ -1063,7 +1077,7 @@ runtime_mstart(void* mp)
g->gcstacksize = 0; g->gcstacksize = 0;
g->gcnextsp = &mp; g->gcnextsp = &mp;
#endif #endif
getcontext((ucontext_t*)&g->context[0]); getcontext(ucontext_arg(&g->context[0]));
if(g->entry != nil) { if(g->entry != nil) {
// Got here from mcall. // Got here from mcall.
...@@ -1251,7 +1265,7 @@ runtime_needm(void) ...@@ -1251,7 +1265,7 @@ runtime_needm(void)
g->gcstacksize = 0; g->gcstacksize = 0;
g->gcnextsp = &mp; g->gcnextsp = &mp;
#endif #endif
getcontext((ucontext_t*)&g->context[0]); getcontext(ucontext_arg(&g->context[0]));
if(g->entry != nil) { if(g->entry != nil) {
// Got here from mcall. // Got here from mcall.
...@@ -1282,6 +1296,7 @@ runtime_newextram(void) ...@@ -1282,6 +1296,7 @@ runtime_newextram(void)
G *gp; G *gp;
byte *g0_sp, *sp; byte *g0_sp, *sp;
uintptr g0_spsize, spsize; uintptr g0_spsize, spsize;
ucontext_t *uc;
// Create extra goroutine locked to extra m. // Create extra goroutine locked to extra m.
// The goroutine is the context in which the cgo callback will run. // The goroutine is the context in which the cgo callback will run.
...@@ -1302,10 +1317,11 @@ runtime_newextram(void) ...@@ -1302,10 +1317,11 @@ runtime_newextram(void)
// The context for gp will be set up in runtime_needm. But // The context for gp will be set up in runtime_needm. But
// here we need to set up the context for g0. // here we need to set up the context for g0.
getcontext((ucontext_t*)&mp->g0->context[0]); uc = ucontext_arg(&mp->g0->context[0]);
((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_sp = g0_sp; getcontext(uc);
((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_size = (size_t)g0_spsize; uc->uc_stack.ss_sp = g0_sp;
makecontext((ucontext_t*)&mp->g0->context[0], kickoff, 0); uc->uc_stack.ss_size = (size_t)g0_spsize;
makecontext(uc, kickoff, 0);
// Add m to the extra list. // Add m to the extra list.
mnext = lockextra(true); mnext = lockextra(true);
...@@ -2007,7 +2023,7 @@ runtime_entersyscall() ...@@ -2007,7 +2023,7 @@ runtime_entersyscall()
{ {
// Save the registers in the g structure so that any pointers // Save the registers in the g structure so that any pointers
// held in registers will be seen by the garbage collector. // 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 // Do the work in a separate function, so that this function
// doesn't save any registers on its own stack. If this // doesn't save any registers on its own stack. If this
...@@ -2086,7 +2102,7 @@ runtime_entersyscallblock(void) ...@@ -2086,7 +2102,7 @@ runtime_entersyscallblock(void)
// Save the registers in the g structure so that any pointers // Save the registers in the g structure so that any pointers
// held in registers will be seen by the garbage collector. // 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; g->atomicstatus = _Gsyscall;
...@@ -2375,14 +2391,16 @@ __go_go(void (*fn)(void*), void* arg) ...@@ -2375,14 +2391,16 @@ __go_go(void (*fn)(void*), void* arg)
byte * volatile vsp = sp; byte * volatile vsp = sp;
size_t volatile vspsize = spsize; size_t volatile vspsize = spsize;
G * volatile vnewg = newg; G * volatile vnewg = newg;
ucontext_t * volatile uc;
getcontext((ucontext_t*)&vnewg->context[0]); uc = ucontext_arg(&vnewg->context[0]);
((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp = vsp; getcontext(uc);
uc->uc_stack.ss_sp = vsp;
#ifdef MAKECONTEXT_STACK_TOP #ifdef MAKECONTEXT_STACK_TOP
((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp += vspsize; uc->uc_stack.ss_sp += vspsize;
#endif #endif
((ucontext_t*)&vnewg->context[0])->uc_stack.ss_size = vspsize; uc->uc_stack.ss_size = vspsize;
makecontext((ucontext_t*)&vnewg->context[0], kickoff, 0); makecontext(uc, kickoff, 0);
runqput(p, vnewg); runqput(p, vnewg);
......
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