runtime: System-specific hack fix for x86_64 Solaris 10.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 8 Feb 2012 05:30:12 +0000 (05:30 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 8 Feb 2012 05:30:12 +0000 (05:30 +0000)
Fixes problem in which setcontext changes all thread-specific
information.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@183993 138bc75d-0d04-0410-961f-82ee72b054a4

libgo/config.h.in
libgo/configure
libgo/configure.ac
libgo/runtime/proc.c

index c9f497d..bd19873 100644 (file)
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
+/* Define if setcontext clobbers TLS variables */
+#undef SETCONTEXT_CLOBBERS_TLS
+
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
index 94bf268..9b65c25 100755 (executable)
@@ -14756,6 +14756,104 @@ $as_echo "$libgo_cv_c_epoll_event_fd_offset" >&6; }
 STRUCT_EPOLL_EVENT_FD_OFFSET=${libgo_cv_c_epoll_event_fd_offset}
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether setcontext clobbers TLS variables" >&5
+$as_echo_n "checking whether setcontext clobbers TLS variables... " >&6; }
+if test "${libgo_cv_lib_setcontext_clobbers_tls+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  LIBS_hold="$LIBS"
+LIBS="$LIBS $PTHREAD_LIBS"
+if test "$cross_compiling" = yes; then :
+  case "$target" in
+  x86_64*-*-solaris2.10) libgo_cv_lib_setcontext_clobbers_tls=yes ;;
+  *) libgo_cv_lib_setcontext_clobbers_tls=no ;;
+ esac
+
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+__thread int tls;
+
+static char stack[10 * 1024 * 1024];
+static ucontext_t c;
+
+/* Called via makecontext/setcontext.  */
+
+static void
+cfn (void)
+{
+  exit (tls);
+}
+
+/* Called via pthread_create.  */
+
+static void *
+tfn (void *dummy)
+{
+  /* The thread should still see this value after calling
+     setcontext.  */
+  tls = 0;
+
+  setcontext (&c);
+
+  /* The call to setcontext should not return.  */
+  abort ();
+}
+
+int
+main ()
+{
+  pthread_t tid;
+
+  /* The thread should not see this value.  */
+  tls = 1;
+
+  if (getcontext (&c) < 0)
+    abort ();
+
+  c.uc_stack.ss_sp = stack;
+  c.uc_stack.ss_flags = 0;
+  c.uc_stack.ss_size = sizeof stack;
+  c.uc_link = NULL;
+  makecontext (&c, cfn, 0);
+
+  if (pthread_create (&tid, NULL, tfn, NULL) != 0)
+    abort ();
+
+  if (pthread_join (tid, NULL) != 0)
+    abort ();
+
+  /* The thread should have called exit.  */
+  abort ();
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  libgo_cv_lib_setcontext_clobbers_tls=no
+else
+  libgo_cv_lib_setcontext_clobbers_tls=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+LIBS="$LIBS_hold"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_lib_setcontext_clobbers_tls" >&5
+$as_echo "$libgo_cv_lib_setcontext_clobbers_tls" >&6; }
+if test "$libgo_cv_lib_setcontext_clobbers_tls" = "yes"; then
+
+$as_echo "#define SETCONTEXT_CLOBBERS_TLS 1" >>confdefs.h
+
+fi
+
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
index e815887..3de5b4a 100644 (file)
@@ -549,6 +549,87 @@ AC_CACHE_CHECK([epoll_event data.fd offset],
 STRUCT_EPOLL_EVENT_FD_OFFSET=${libgo_cv_c_epoll_event_fd_offset}
 AC_SUBST(STRUCT_EPOLL_EVENT_FD_OFFSET)
 
+dnl See whether setcontext changes the value of TLS variables.
+AC_CACHE_CHECK([whether setcontext clobbers TLS variables],
+[libgo_cv_lib_setcontext_clobbers_tls],
+[LIBS_hold="$LIBS"
+LIBS="$LIBS $PTHREAD_LIBS"
+AC_RUN_IFELSE(
+  [AC_LANG_SOURCE([
+#include <pthread.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+__thread int tls;
+
+static char stack[[10 * 1024 * 1024]];
+static ucontext_t c;
+
+/* Called via makecontext/setcontext.  */
+
+static void
+cfn (void)
+{
+  exit (tls);
+}
+
+/* Called via pthread_create.  */
+
+static void *
+tfn (void *dummy)
+{
+  /* The thread should still see this value after calling
+     setcontext.  */
+  tls = 0;
+
+  setcontext (&c);
+
+  /* The call to setcontext should not return.  */
+  abort ();
+}
+
+int
+main ()
+{
+  pthread_t tid;
+
+  /* The thread should not see this value.  */
+  tls = 1;
+
+  if (getcontext (&c) < 0)
+    abort ();
+
+  c.uc_stack.ss_sp = stack;
+  c.uc_stack.ss_flags = 0;
+  c.uc_stack.ss_size = sizeof stack;
+  c.uc_link = NULL;
+  makecontext (&c, cfn, 0);
+
+  if (pthread_create (&tid, NULL, tfn, NULL) != 0)
+    abort ();
+
+  if (pthread_join (tid, NULL) != 0)
+    abort ();
+
+  /* The thread should have called exit.  */
+  abort ();
+}
+])],
+[libgo_cv_lib_setcontext_clobbers_tls=no],
+[libgo_cv_lib_setcontext_clobbers_tls=yes],
+[case "$target" in
+  x86_64*-*-solaris2.10) libgo_cv_lib_setcontext_clobbers_tls=yes ;;
+  *) libgo_cv_lib_setcontext_clobbers_tls=no ;;
+ esac
+])
+LIBS="$LIBS_hold"
+])
+if test "$libgo_cv_lib_setcontext_clobbers_tls" = "yes"; then
+  AC_DEFINE(SETCONTEXT_CLOBBERS_TLS, 1,
+           [Define if setcontext clobbers TLS variables])
+fi
+
 AC_CACHE_SAVE
 
 if test ${multilib} = yes; then
index 9225f82..04412bd 100644 (file)
@@ -60,6 +60,54 @@ G    runtime_g0;     // idle goroutine for m0
 static __thread G *g;
 static __thread M *m;
 
+#ifndef SETCONTEXT_CLOBBERS_TLS
+
+static inline void
+initcontext(void)
+{
+}
+
+static inline void
+fixcontext(ucontext_t *c __attribute__ ((unused)))
+{
+}
+
+# else
+
+# if defined(__x86_64__) && defined(__sun__)
+
+// x86_64 Solaris 10 and 11 have a bug: setcontext switches the %fs
+// register to that of the thread which called getcontext.  The effect
+// is that the address of all __thread variables changes.  This bug
+// also affects pthread_self() and pthread_getspecific.  We work
+// around it by clobbering the context field directly to keep %fs the
+// same.
+
+static __thread greg_t fs;
+
+static inline void
+initcontext(void)
+{
+       ucontext_t c;
+
+       getcontext(&c);
+       fs = c.uc_mcontext.gregs[REG_FSBASE];
+}
+
+static inline void
+fixcontext(ucontext_t* c)
+{
+       c->uc_mcontext.gregs[REG_FSBASE] = fs;
+}
+
+# else
+
+#  error unknown case for SETCONTEXT_CLOBBERS_TLS
+
+# endif
+
+#endif
+
 // 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
@@ -248,7 +296,9 @@ runtime_gogo(G* newg)
 #endif
        g = newg;
        newg->fromgogo = true;
+       fixcontext(&newg->context);
        setcontext(&newg->context);
+       runtime_throw("gogo setcontext returned");
 }
 
 // Save context and call fn passing g as a parameter.  This is like
@@ -287,6 +337,7 @@ runtime_mcall(void (*pfn)(G*))
                m->g0->entry = (byte*)pfn;
                m->g0->param = g;
                g = m->g0;
+               fixcontext(&m->g0->context);
                setcontext(&m->g0->context);
                runtime_throw("runtime: mcall function returned");
        }
@@ -312,6 +363,8 @@ runtime_schedinit(void)
        m->curg = g;
        g->m = m;
 
+       initcontext();
+
        m->nomemprof++;
        runtime_mallocinit();
        mcommoninit(m);
@@ -844,6 +897,8 @@ runtime_mstart(void* mp)
        m = (M*)mp;
        g = m->g0;
 
+       initcontext();
+
        g->entry = nil;
        g->param = nil;