aboutsummaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-02-08 05:30:12 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-02-08 05:30:12 +0000
commit7f57843fbebc7b50cfad7cc5bd3459a2d1077035 (patch)
treec2a0810ed549d7918e5361e32b62c078b9961ff3 /libgo
parent3327318150635df73331b0ebdd7b7bc2628b3b21 (diff)
downloadgcc-7f57843fbebc7b50cfad7cc5bd3459a2d1077035.zip
gcc-7f57843fbebc7b50cfad7cc5bd3459a2d1077035.tar.gz
gcc-7f57843fbebc7b50cfad7cc5bd3459a2d1077035.tar.bz2
runtime: System-specific hack fix for x86_64 Solaris 10.
Fixes problem in which setcontext changes all thread-specific information. From-SVN: r183993
Diffstat (limited to 'libgo')
-rw-r--r--libgo/config.h.in3
-rwxr-xr-xlibgo/configure98
-rw-r--r--libgo/configure.ac81
-rw-r--r--libgo/runtime/proc.c55
4 files changed, 237 insertions, 0 deletions
diff --git a/libgo/config.h.in b/libgo/config.h.in
index c9f497d..bd19873 100644
--- a/libgo/config.h.in
+++ b/libgo/config.h.in
@@ -189,6 +189,9 @@
/* 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
diff --git a/libgo/configure b/libgo/configure
index 94bf268..9b65c25 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -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
diff --git a/libgo/configure.ac b/libgo/configure.ac
index e8158877..3de5b4a 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -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
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 9225f82..04412bd 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -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;