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
merge done from the gofrontend repository.
......@@ -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 <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.
type traceback struct {
......
......@@ -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 = &mp;
#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 = &mp;
#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);
......
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