re PR go/50654 (Many Go tests fail on emutls targets)
[gcc.git] / libgo / runtime / proc.c
index 94c2a51730e944e93f0e976c878057819f8afd67..609920a561971cda3dfbae75ddf50c9fea951ab5 100644 (file)
@@ -309,6 +309,8 @@ static void runtime_mcall(void (*)(G*)) __attribute__ ((noinline));
 static void
 runtime_mcall(void (*pfn)(G*))
 {
+       M *mp;
+       G *gp;
 #ifndef USING_SPLIT_STACK
        int i;
 #endif
@@ -317,28 +319,45 @@ runtime_mcall(void (*pfn)(G*))
        // collector.
        __builtin_unwind_init();
 
-       if(g == m->g0)
+       mp = m;
+       gp = g;
+       if(gp == mp->g0)
                runtime_throw("runtime: mcall called on m->g0 stack");
 
-       if(g != nil) {
+       if(gp != nil) {
 
 #ifdef USING_SPLIT_STACK
                __splitstack_getcontext(&g->stack_context[0]);
 #else
-               g->gcnext_sp = &i;
+               gp->gcnext_sp = &i;
 #endif
-               g->fromgogo = false;
-               getcontext(&g->context);
+               gp->fromgogo = false;
+               getcontext(&gp->context);
+
+               // When we return from getcontext, we may be running
+               // in a new thread.  That means that m and g may have
+               // changed.  They are global variables so we will
+               // reload them, but the addresses of m and g may be
+               // cached in our local stack frame, and those
+               // addresses may be wrong.  Call functions to reload
+               // the values for this thread.
+               mp = runtime_m();
+               gp = runtime_g();
        }
-       if (g == nil || !g->fromgogo) {
+       if (gp == nil || !gp->fromgogo) {
 #ifdef USING_SPLIT_STACK
-               __splitstack_setcontext(&m->g0->stack_context[0]);
+               __splitstack_setcontext(&mp->g0->stack_context[0]);
 #endif
-               m->g0->entry = (byte*)pfn;
-               m->g0->param = g;
-               g = m->g0;
-               fixcontext(&m->g0->context);
-               setcontext(&m->g0->context);
+               mp->g0->entry = (byte*)pfn;
+               mp->g0->param = gp;
+
+               // It's OK to set g directly here because this case
+               // can not occur if we got here via a setcontext to
+               // the getcontext call just above.
+               g = mp->g0;
+
+               fixcontext(&mp->g0->context);
+               setcontext(&mp->g0->context);
                runtime_throw("runtime: mcall function returned");
        }
 }