This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Make powerpc-nofpu floating-point state thread-local (bug 15483)


This patch fixes bug 15483, powerpc-nofpu floating-point state being
wrongly global instead of thread-local.  The relevant state is moved
to TLS variables, with the old global variables becoming compat
symbols not available for new links, and being updated when the TLS
variables are updated, but never read by libc; I think this is the
most ABI-compatible option available for making this data
thread-local.  (Static libc doesn't have the old global variables at
all.)  An architecture-independent test is added for this data being
thread-local.

This patch depends on my previous patch
<https://sourceware.org/ml/libc-alpha/2013-11/msg00180.html> to add
libc_hidden_tls_proto.

Tested for powerpc-nofpu, and the new test also tested for x86_64.

There are legitimate uses for compiler-generated code to access some
of this state without introducing a libm dependency.  To facilitate
those, I intend in a future patch to add new interfaces __flt_rounds,
__atomic_feholdexcept, __atomic_feclearexcept and __atomic_feupdateenv
to powerpc-nofpu libc.  The first could be used in fixing GCC bug
30569 (for most platforms, inline code examining FPU state can
determine the rounding mode, but not where the rounding mode is a
variable in libc as here) and the remaining three in implementing the
new TARGET_ATOMIC_ASSIGN_EXPAND_FENV target hook (in the latter case,
e500 GCC will need them as well as pure soft-float, because of the
prctl syscalls involved in environment manipulation - of course all
four functions will be implemented for both soft-float and e500 to
keep the ABIs the same).

2013-11-07  Joseph Myers  <joseph@codesourcery.com>

	[BZ #15483]
	* sysdeps/powerpc/nofpu/sim-full.c (__sim_exceptions): Change to
	thread-local __sim_exceptions_thread and global
	__sim_exceptions_global.
	(__sim_disabled_exceptions): Change to thread-local
	__sim_disabled_exceptions_thread and global
	__sim_disabled_exceptions_global.
	(__sim_round_mode): Change to thread-local __sim_round_mode_thread
	and global __sim_round_mode_global.
	(__simulate_exceptions): Use thread-local floating-point state and
	set global state from it as needed.
	* sysdeps/powerpc/nofpu/Versions (GLIBC_PRIVATE): Add
	__sim_exceptions_thread, __sim_disabled_exceptions_thread and
	__sim_round_mode_thread.
	* sysdeps/powerpc/nofpu/soft-supp.h: Include <shlib-compat.h>.
	(__sim_exceptions): Change to thread-local __sim_exceptions_thread
	and global __sim_exceptions_global.
	(__sim_disabled_exceptions): Change to thread-local
	__sim_disabled_exceptions_thread and global
	__sim_disabled_exceptions_global.
	(__sim_round_mode): Change to thread-local __sim_round_mode_thread
	and global __sim_round_mode_global.
	[SIM_GLOBAL_COMPAT] (SIM_COMPAT_SYMBOL): New macro.
	(SIM_SET_GLOBAL): Likewise.
	* sysdeps/powerpc/soft-fp/sfp-machine.h
	[!(__NO_FPRS__ && !_SOFT_FLOAT)] (FP_ROUNDMODE): Use
	__sim_round_mode_thread.
	[!(__NO_FPRS__ && !_SOFT_FLOAT)] (FP_TRAPPING_EXCEPTIONS): Use
	__sim_disabled_exceptions_thread.
	(__sim_exceptions): Change to __sim_exceptions_thread.
	(__sim_disabled_exceptions): Change to
	__sim_disabled_exceptions_thread.
	(__sim_round_mode): Change to __sim_round_mode_thread.
	* sysdeps/powerpc/nofpu/fclrexcpt.c (__feclearexcept): Use
	thread-local floating-point state and set global state from it as
	needed.
	* sysdeps/powerpc/nofpu/fedisblxcpt.c (fedisableexcept): Likewise.
	* sysdeps/powerpc/nofpu/feenablxcpt.c: Include "soft-supp.h".
	(__sim_disabled_exceptions): Remove extern declaration.
	(feenableexcept): Use thread-local floating-point state and set
	global state from it as needed.
	* sysdeps/powerpc/nofpu/fegetenv.c (__sim_exceptions): Remove
	extern declaration.
	(__sim_disabled_exceptions): Likewise.
	(__sim_round_mode): Likewise.
	(__fegetenv): Use thread-local floating-point state.
	* sysdeps/powerpc/nofpu/fegetexcept.c (fegetexcept): Likewise.
	* sysdeps/powerpc/nofpu/fegetround.c (fegetround): Likewise.
	* sysdeps/powerpc/nofpu/fesetenv.c (__fesetenv): Use thread-local
	floating-point state and set global state from it as needed.
	* sysdeps/powerpc/nofpu/fesetround.c (fesetround): Likewise.
	* sysdeps/powerpc/nofpu/feupdateenv.c (__feupdateenv): Likewise.
	* sysdeps/powerpc/nofpu/fgetexcptflg.c (__fegetexceptflag):
	Likewise.
	* sysdeps/powerpc/nofpu/fraiseexcpt.c (__feraiseexcept): Likewise.
	* sysdeps/powerpc/nofpu/fsetexcptflg.c (__fesetexceptflag):
	Likewise.
	sysdeps/powerpc/nofpu/ftestexcept.c (fetestexcept): Likewise.
	* sysdeps/powerpc/nofpu/get-rounding-mode.h (get_rounding_mode):
	Use __sim_round_mode_thread.
	* math/test-fenv-tls.c: New file.
	* math/Makefile (tests): Add test-fenv-tls.
	($(objpfx)test-fenv-tls): Depend on
	$(common-objpfx)nptl/libpthread.so.

diff --git a/math/Makefile b/math/Makefile
index a9bd49b..fcccab2 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -90,7 +90,7 @@ tests = test-matherr test-fenv atest-exp atest-sincos atest-exp2 basic-test \
 	test-misc test-fpucw test-fpucw-ieee tst-definitions test-tgmath \
 	test-tgmath-ret bug-nextafter bug-nexttoward bug-tgmath1 \
 	test-tgmath-int test-tgmath2 test-powl tst-CMPLX tst-CMPLX2 test-snan \
-	$(tests-static)
+	test-fenv-tls $(tests-static)
 tests-static = test-fpucw-static test-fpucw-ieee-static
 # We do the `long double' tests only if this data type is available and
 # distinct from `double'.
@@ -232,3 +232,4 @@ gmp-objs = $(patsubst %,$(common-objpfx)stdlib/%.o,\
 $(objpfx)atest-exp: $(gmp-objs)
 $(objpfx)atest-sincos: $(gmp-objs)
 $(objpfx)atest-exp2: $(gmp-objs)
+$(objpfx)test-fenv-tls: $(common-objpfx)nptl/libpthread.so
diff --git a/math/test-fenv-tls.c b/math/test-fenv-tls.c
new file mode 100644
index 0000000..879c9f9
--- /dev/null
+++ b/math/test-fenv-tls.c
@@ -0,0 +1,208 @@
+/* Test floating-point environment is thread-local.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#define TEST_ONE_RM(RM)						\
+  do								\
+    {								\
+      if (fesetround (RM) == 0)					\
+	{							\
+	  rm = fegetround ();					\
+	  if (rm != RM)						\
+	    {							\
+	      printf ("expected " #RM ", got %d\n", rm);	\
+	      ret = 1;						\
+	    }							\
+	}							\
+    }								\
+  while (0)
+
+static void *
+test_round (void *arg)
+{
+  intptr_t ret = 0;
+  for (int i = 0; i < 10000; i++)
+    {
+      int rm;
+#ifdef FE_DOWNWARD
+      TEST_ONE_RM (FE_DOWNWARD);
+#endif
+#ifdef FE_TONEAREST
+      TEST_ONE_RM (FE_TONEAREST);
+#endif
+#ifdef FE_TOWARDZERO
+      TEST_ONE_RM (FE_TOWARDZERO);
+#endif
+#ifdef FE_UPWARD
+      TEST_ONE_RM (FE_UPWARD);
+#endif
+    }
+  return (void *) ret;
+}
+
+#define TEST_ONE_RAISE(EX)				\
+  do							\
+    {							\
+      if (feraiseexcept (EX) == 0)			\
+	if (fetestexcept (EX) != EX)			\
+	  {						\
+	    printf (#EX " not raised\n");		\
+	    ret = 1;					\
+	  }						\
+      if (feclearexcept (FE_ALL_EXCEPT) == 0)		\
+	if (fetestexcept (FE_ALL_EXCEPT) != 0)		\
+	  {						\
+	    printf ("exceptions not all cleared\n");	\
+	    ret = 1;					\
+	  }						\
+    }							\
+  while (0)
+
+static void *
+test_raise (void *arg)
+{
+  intptr_t ret = 0;
+  for (int i = 0; i < 10000; i++)
+    {
+#ifdef FE_DIVBYZERO
+      TEST_ONE_RAISE (FE_DIVBYZERO);
+#endif
+#ifdef FE_INEXACT
+      TEST_ONE_RAISE (FE_INEXACT);
+#endif
+#ifdef FE_INVALID
+      TEST_ONE_RAISE (FE_INVALID);
+#endif
+#ifdef FE_OVERFLOW
+      TEST_ONE_RAISE (FE_OVERFLOW);
+#endif
+#ifdef UNDERFLOW
+      TEST_ONE_RAISE (FE_UNDERFLOW);
+#endif
+    }
+  return (void *) ret;
+}
+
+#define TEST_ONE_ENABLE(EX)				\
+  do							\
+    {							\
+      if (feenableexcept (EX) != -1)			\
+	if (fegetexcept () != EX)			\
+	  {						\
+	    printf (#EX " not enabled\n");		\
+	    ret = 1;					\
+	  }						\
+      if (fedisableexcept (EX) != -1)			\
+	if (fegetexcept () != 0)			\
+	  {						\
+	    printf ("exceptions not all disabled\n");	\
+	    ret = 1;					\
+	  }						\
+    }							\
+  while (0)
+
+static void *
+test_enable (void *arg)
+{
+  intptr_t ret = 0;
+  for (int i = 0; i < 10000; i++)
+    {
+#ifdef FE_DIVBYZERO
+      TEST_ONE_ENABLE (FE_DIVBYZERO);
+#endif
+#ifdef FE_INEXACT
+      TEST_ONE_ENABLE (FE_INEXACT);
+#endif
+#ifdef FE_INVALID
+      TEST_ONE_ENABLE (FE_INVALID);
+#endif
+#ifdef FE_OVERFLOW
+      TEST_ONE_ENABLE (FE_OVERFLOW);
+#endif
+#ifdef UNDERFLOW
+      TEST_ONE_ENABLE (FE_UNDERFLOW);
+#endif
+    }
+  return (void *) ret;
+}
+
+static int
+do_test (void)
+{
+  int ret = 0;
+  void *vret;
+  pthread_t thread_id;
+  int pret;
+
+  pret = pthread_create (&thread_id, NULL, test_round, NULL);
+  if (pret != 0)
+    {
+      printf ("pthread_create failed: %d\n", pret);
+      return 1;
+    }
+  vret = test_round (NULL);
+  ret |= (intptr_t) vret;
+  pret = pthread_join (thread_id, &vret);
+  if (pret != 0)
+    {
+      printf ("pthread_join failed: %d\n", pret);
+      return 1;
+    }
+  ret |= (intptr_t) vret;
+
+  pret = pthread_create (&thread_id, NULL, test_raise, NULL);
+  if (pret != 0)
+    {
+      printf ("pthread_create failed: %d\n", pret);
+      return 1;
+    }
+  vret = test_raise (NULL);
+  ret |= (intptr_t) vret;
+  pret = pthread_join (thread_id, &vret);
+  if (pret != 0)
+    {
+      printf ("pthread_join failed: %d\n", pret);
+      return 1;
+    }
+  ret |= (intptr_t) vret;
+
+  pret = pthread_create (&thread_id, NULL, test_enable, NULL);
+  if (pret != 0)
+    {
+      printf ("pthread_create failed: %d\n", pret);
+      return 1;
+    }
+  vret = test_enable (NULL);
+  ret |= (intptr_t) vret;
+  pret = pthread_join (thread_id, &vret);
+  if (pret != 0)
+    {
+      printf ("pthread_join failed: %d\n", pret);
+      return 1;
+    }
+  ret |= (intptr_t) vret;
+
+  return ret;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/powerpc/nofpu/Versions b/sysdeps/powerpc/nofpu/Versions
index 1a29319..8ba6021 100644
--- a/sysdeps/powerpc/nofpu/Versions
+++ b/sysdeps/powerpc/nofpu/Versions
@@ -17,4 +17,9 @@ libc {
     __gtdf2; __gtsf2;
     __ltdf2; __ltsf2;
   }
+  GLIBC_PRIVATE {
+    __sim_exceptions_thread;
+    __sim_disabled_exceptions_thread;
+    __sim_round_mode_thread;
+  }
 }
diff --git a/sysdeps/powerpc/nofpu/fclrexcpt.c b/sysdeps/powerpc/nofpu/fclrexcpt.c
index fabda0a..da0b61a 100644
--- a/sysdeps/powerpc/nofpu/fclrexcpt.c
+++ b/sysdeps/powerpc/nofpu/fclrexcpt.c
@@ -23,7 +23,8 @@
 int
 __feclearexcept (int x)
 {
-  __sim_exceptions &= ~x;
+  __sim_exceptions_thread &= ~x;
+  SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
   return 0;
 }
 
diff --git a/sysdeps/powerpc/nofpu/fedisblxcpt.c b/sysdeps/powerpc/nofpu/fedisblxcpt.c
index e06c8f7..00490fd 100644
--- a/sysdeps/powerpc/nofpu/fedisblxcpt.c
+++ b/sysdeps/powerpc/nofpu/fedisblxcpt.c
@@ -24,9 +24,11 @@
 int
 fedisableexcept (int x)
 {
-  int old_exceptions = ~__sim_disabled_exceptions & FE_ALL_EXCEPT;
+  int old_exceptions = ~__sim_disabled_exceptions_thread & FE_ALL_EXCEPT;
 
-  __sim_disabled_exceptions |= x;
+  __sim_disabled_exceptions_thread |= x;
+  SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
+		  __sim_disabled_exceptions_thread);
 
   return old_exceptions;
 }
diff --git a/sysdeps/powerpc/nofpu/feenablxcpt.c b/sysdeps/powerpc/nofpu/feenablxcpt.c
index 93249ab..09eb823 100644
--- a/sysdeps/powerpc/nofpu/feenablxcpt.c
+++ b/sysdeps/powerpc/nofpu/feenablxcpt.c
@@ -17,16 +17,17 @@
    License along with the GNU C Library.  If not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include "soft-supp.h"
 #include <fenv.h>
 
-extern int __sim_disabled_exceptions;
-
 int
 feenableexcept (int exceptions)
 {
-  int old_exceptions = ~__sim_disabled_exceptions & FE_ALL_EXCEPT;
+  int old_exceptions = ~__sim_disabled_exceptions_thread & FE_ALL_EXCEPT;
 
-  __sim_disabled_exceptions &= ~exceptions;
+  __sim_disabled_exceptions_thread &= ~exceptions;
+  SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
+		  __sim_disabled_exceptions_thread);
 
   return old_exceptions;
 }
diff --git a/sysdeps/powerpc/nofpu/fegetenv.c b/sysdeps/powerpc/nofpu/fegetenv.c
index 51bcef3..351e552 100644
--- a/sysdeps/powerpc/nofpu/fegetenv.c
+++ b/sysdeps/powerpc/nofpu/fegetenv.c
@@ -20,18 +20,14 @@
 #include "soft-fp.h"
 #include "soft-supp.h"
 
-extern int __sim_exceptions;
-extern int __sim_disabled_exceptions;
-extern int __sim_round_mode;
-
 int
 __fegetenv (fenv_t *envp)
 {
   fenv_union_t u;
 
-  u.l[0] = __sim_exceptions;
-  u.l[0] |= __sim_round_mode;
-  u.l[1] = __sim_disabled_exceptions;
+  u.l[0] = __sim_exceptions_thread;
+  u.l[0] |= __sim_round_mode_thread;
+  u.l[1] = __sim_disabled_exceptions_thread;
 
   *envp = u.fenv;
 
diff --git a/sysdeps/powerpc/nofpu/fegetexcept.c b/sysdeps/powerpc/nofpu/fegetexcept.c
index ea39a82..d907555 100644
--- a/sysdeps/powerpc/nofpu/fegetexcept.c
+++ b/sysdeps/powerpc/nofpu/fegetexcept.c
@@ -23,5 +23,5 @@
 int
 fegetexcept (void)
 {
-  return (__sim_disabled_exceptions ^ FE_ALL_EXCEPT) & FE_ALL_EXCEPT;
+  return (__sim_disabled_exceptions_thread ^ FE_ALL_EXCEPT) & FE_ALL_EXCEPT;
 }
diff --git a/sysdeps/powerpc/nofpu/fegetround.c b/sysdeps/powerpc/nofpu/fegetround.c
index c232ae3..016602f 100644
--- a/sysdeps/powerpc/nofpu/fegetround.c
+++ b/sysdeps/powerpc/nofpu/fegetround.c
@@ -24,5 +24,5 @@
 int
 fegetround (void)
 {
-  return __sim_round_mode;
+  return __sim_round_mode_thread;
 }
diff --git a/sysdeps/powerpc/nofpu/fesetenv.c b/sysdeps/powerpc/nofpu/fesetenv.c
index 3f35909..fa84169 100644
--- a/sysdeps/powerpc/nofpu/fesetenv.c
+++ b/sysdeps/powerpc/nofpu/fesetenv.c
@@ -26,9 +26,13 @@ __fesetenv (const fenv_t *envp)
   fenv_union_t u;
 
   u.fenv = *envp;
-  __sim_exceptions = u.l[0] & FE_ALL_EXCEPT;
-  __sim_round_mode = u.l[0] & 0x3;
-  __sim_disabled_exceptions = u.l[1];
+  __sim_exceptions_thread = u.l[0] & FE_ALL_EXCEPT;
+  SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
+  __sim_round_mode_thread = u.l[0] & 0x3;
+  SIM_SET_GLOBAL (__sim_round_mode_global, __sim_round_mode_thread);
+  __sim_disabled_exceptions_thread = u.l[1];
+  SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
+		  __sim_disabled_exceptions_thread);
   return 0;
 }
 
diff --git a/sysdeps/powerpc/nofpu/fesetround.c b/sysdeps/powerpc/nofpu/fesetround.c
index 028c130..ab0d52f 100644
--- a/sysdeps/powerpc/nofpu/fesetround.c
+++ b/sysdeps/powerpc/nofpu/fesetround.c
@@ -26,7 +26,8 @@ fesetround (int round)
   if ((unsigned int) round > FE_DOWNWARD)
     return 1;
 
-  __sim_round_mode = round;
+  __sim_round_mode_thread = round;
+  SIM_SET_GLOBAL (__sim_round_mode_global, __sim_round_mode_thread);
 
   return 0;
 }
diff --git a/sysdeps/powerpc/nofpu/feupdateenv.c b/sysdeps/powerpc/nofpu/feupdateenv.c
index 163f673..8a26cb8 100644
--- a/sysdeps/powerpc/nofpu/feupdateenv.c
+++ b/sysdeps/powerpc/nofpu/feupdateenv.c
@@ -28,14 +28,15 @@ __feupdateenv (const fenv_t *envp)
   int saved_exceptions;
 
   /* Save currently set exceptions.  */
-  saved_exceptions = __sim_exceptions;
+  saved_exceptions = __sim_exceptions_thread;
 
   /* Set environment.  */
   fesetenv (envp);
 
   /* Raise old exceptions.  */
-  __sim_exceptions |= saved_exceptions;
-  if (saved_exceptions & ~__sim_disabled_exceptions)
+  __sim_exceptions_thread |= saved_exceptions;
+  SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
+  if (saved_exceptions & ~__sim_disabled_exceptions_thread)
     raise (SIGFPE);
 
   return 0;
diff --git a/sysdeps/powerpc/nofpu/fgetexcptflg.c b/sysdeps/powerpc/nofpu/fgetexcptflg.c
index 2373fa4..b7fd90d 100644
--- a/sysdeps/powerpc/nofpu/fgetexcptflg.c
+++ b/sysdeps/powerpc/nofpu/fgetexcptflg.c
@@ -23,7 +23,7 @@
 int
 __fegetexceptflag (fexcept_t *flagp, int excepts)
 {
-  *flagp = (fexcept_t) __sim_exceptions  & excepts & FE_ALL_EXCEPT;
+  *flagp = (fexcept_t) __sim_exceptions_thread & excepts & FE_ALL_EXCEPT;
 
   return 0;
 }
diff --git a/sysdeps/powerpc/nofpu/fraiseexcpt.c b/sysdeps/powerpc/nofpu/fraiseexcpt.c
index cd142b6..215a70b 100644
--- a/sysdeps/powerpc/nofpu/fraiseexcpt.c
+++ b/sysdeps/powerpc/nofpu/fraiseexcpt.c
@@ -25,8 +25,9 @@
 int
 __feraiseexcept (int x)
 {
-  __sim_exceptions |= x;
-  if (x & ~__sim_disabled_exceptions)
+  __sim_exceptions_thread |= x;
+  SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
+  if (x & ~__sim_disabled_exceptions_thread)
     raise (SIGFPE);
   return 0;
 }
diff --git a/sysdeps/powerpc/nofpu/fsetexcptflg.c b/sysdeps/powerpc/nofpu/fsetexcptflg.c
index 3dc368f..ee2aa81 100644
--- a/sysdeps/powerpc/nofpu/fsetexcptflg.c
+++ b/sysdeps/powerpc/nofpu/fsetexcptflg.c
@@ -24,7 +24,9 @@ int
 __fesetexceptflag(const fexcept_t *flagp, int excepts)
 {
   /* Ignore exceptions not listed in 'excepts'.  */
-  __sim_exceptions = (__sim_exceptions & ~excepts) | (*flagp & excepts);
+  __sim_exceptions_thread
+    = (__sim_exceptions_thread & ~excepts) | (*flagp & excepts);
+  SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
 
   return 0;
 }
diff --git a/sysdeps/powerpc/nofpu/ftestexcept.c b/sysdeps/powerpc/nofpu/ftestexcept.c
index f5d01e8..42e861d 100644
--- a/sysdeps/powerpc/nofpu/ftestexcept.c
+++ b/sysdeps/powerpc/nofpu/ftestexcept.c
@@ -23,6 +23,6 @@
 int
 fetestexcept (int x)
 {
-  return __sim_exceptions & x;
+  return __sim_exceptions_thread & x;
 }
 libm_hidden_def (fetestexcept)
diff --git a/sysdeps/powerpc/nofpu/get-rounding-mode.h b/sysdeps/powerpc/nofpu/get-rounding-mode.h
index 20eb810..6d327f5 100644
--- a/sysdeps/powerpc/nofpu/get-rounding-mode.h
+++ b/sysdeps/powerpc/nofpu/get-rounding-mode.h
@@ -29,7 +29,7 @@
 static inline int
 get_rounding_mode (void)
 {
-  return __sim_round_mode;
+  return __sim_round_mode_thread;
 }
 
 #endif /* get-rounding-mode.h */
diff --git a/sysdeps/powerpc/nofpu/sim-full.c b/sysdeps/powerpc/nofpu/sim-full.c
index e167033..fb09d1b 100644
--- a/sysdeps/powerpc/nofpu/sim-full.c
+++ b/sysdeps/powerpc/nofpu/sim-full.c
@@ -21,26 +21,37 @@
 #include "soft-fp.h"
 #include "soft-supp.h"
 
-/* FIXME: these variables should be thread specific (see bugzilla bug
-   15483) and ideally preserved across signal handlers, like hardware
-   FP status words, but the latter is quite difficult to accomplish in
-   userland.  */
-
-/* Global to store sticky exceptions.  */
-int __sim_exceptions __attribute__ ((nocommon));
-libc_hidden_data_def (__sim_exceptions);
+/* Thread-local to store sticky exceptions.  */
+__thread int __sim_exceptions_thread __attribute__ ((nocommon));
+libc_hidden_data_def (__sim_exceptions_thread);
 
 /* By default, no exceptions should trap.  */
-int __sim_disabled_exceptions = 0xffffffff;
-libc_hidden_data_def (__sim_disabled_exceptions);
+__thread int __sim_disabled_exceptions_thread = 0xffffffff;
+libc_hidden_data_def (__sim_disabled_exceptions_thread);
+
+__thread int __sim_round_mode_thread __attribute__ ((nocommon));
+libc_hidden_data_def (__sim_round_mode_thread);
+
+#if SIM_GLOBAL_COMPAT
+int __sim_exceptions_global __attribute__ ((nocommon));
+libc_hidden_data_def (__sim_exceptions_global);
+SIM_COMPAT_SYMBOL (__sim_exceptions_global, __sim_exceptions);
+
+int __sim_disabled_exceptions_global = 0xffffffff;
+libc_hidden_data_def (__sim_disabled_exceptions_global);
+SIM_COMPAT_SYMBOL (__sim_disabled_exceptions_global,
+		   __sim_disabled_exceptions);
 
-int __sim_round_mode __attribute__ ((nocommon));
-libc_hidden_data_def (__sim_round_mode);
+int __sim_round_mode_global __attribute__ ((nocommon));
+libc_hidden_data_def (__sim_round_mode_global);
+SIM_COMPAT_SYMBOL (__sim_round_mode_global, __sim_round_mode);
+#endif
 
 void
 __simulate_exceptions (int x)
 {
-  __sim_exceptions |= x;
-  if (x & ~__sim_disabled_exceptions)
+  __sim_exceptions_thread |= x;
+  SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
+  if (x & ~__sim_disabled_exceptions_thread)
     raise (SIGFPE);
 }
diff --git a/sysdeps/powerpc/nofpu/soft-supp.h b/sysdeps/powerpc/nofpu/soft-supp.h
index 18b4550..0a0614a 100644
--- a/sysdeps/powerpc/nofpu/soft-supp.h
+++ b/sysdeps/powerpc/nofpu/soft-supp.h
@@ -33,16 +33,31 @@ typedef union
 
 #endif
 
-/* FIXME: these variables should be thread specific (see bugzilla bug
-   15483) and ideally preserved across signal handlers, like hardware
-   FP status words, but the latter is quite difficult to accomplish in
-   userland.  */
-
-extern int __sim_exceptions;
-libc_hidden_proto (__sim_exceptions);
-extern int __sim_disabled_exceptions;
-libc_hidden_proto (__sim_disabled_exceptions);
-extern int __sim_round_mode;
-libc_hidden_proto (__sim_round_mode);
+extern __thread int __sim_exceptions_thread attribute_tls_model_ie;
+libc_hidden_tls_proto (__sim_exceptions_thread, tls_model ("initial-exec"));
+extern __thread int __sim_disabled_exceptions_thread attribute_tls_model_ie;
+libc_hidden_tls_proto (__sim_disabled_exceptions_thread,
+		       tls_model ("initial-exec"));
+extern __thread int __sim_round_mode_thread attribute_tls_model_ie;
+libc_hidden_tls_proto (__sim_round_mode_thread, tls_model ("initial-exec"));
+
+/* These variables were formerly global, so there are compat symbols
+   for global versions as well.  */
+
+#include <shlib-compat.h>
+#define SIM_GLOBAL_COMPAT SHLIB_COMPAT (libc, GLIBC_2_3_2, GLIBC_2_19)
+#if SIM_GLOBAL_COMPAT
+extern int __sim_exceptions_global;
+libc_hidden_proto (__sim_exceptions_global);
+extern int __sim_disabled_exceptions_global ;
+libc_hidden_proto (__sim_disabled_exceptions_global);
+extern int __sim_round_mode_global;
+libc_hidden_proto (__sim_round_mode_global);
+# define SIM_COMPAT_SYMBOL(GLOBAL_NAME, NAME) \
+  compat_symbol (libc, GLOBAL_NAME, NAME, GLIBC_2_3_2)
+# define SIM_SET_GLOBAL(GLOBAL_VAR, THREAD_VAR) ((GLOBAL_VAR) = (THREAD_VAR))
+#else
+# define SIM_SET_GLOBAL(GLOBAL_VAR, THREAD_VAR) ((void) 0)
+#endif
 
 extern void __simulate_exceptions (int x) attribute_hidden;
diff --git a/sysdeps/powerpc/soft-fp/sfp-machine.h b/sysdeps/powerpc/soft-fp/sfp-machine.h
index 0411878..35a38b0 100644
--- a/sysdeps/powerpc/soft-fp/sfp-machine.h
+++ b/sysdeps/powerpc/soft-fp/sfp-machine.h
@@ -95,21 +95,18 @@ libc_hidden_proto (__feraiseexcept_soft)
 # define FP_EX_INEXACT         (1 << (31 - 6))
 
 # define FP_HANDLE_EXCEPTIONS  __simulate_exceptions (_fex)
-# define FP_ROUNDMODE          __sim_round_mode
-# define FP_TRAPPING_EXCEPTIONS (~__sim_disabled_exceptions & 0x3e000000)
+# define FP_ROUNDMODE          __sim_round_mode_thread
+# define FP_TRAPPING_EXCEPTIONS \
+  (~__sim_disabled_exceptions_thread & 0x3e000000)
 
 #endif
 
-/* FIXME: these variables should be thread specific (see bugzilla bug
-   15483) and ideally preserved across signal handlers, like hardware
-   FP status words, but the latter is quite difficult to accomplish in
-   userland.  */
-
-extern int __sim_exceptions;
-libc_hidden_proto (__sim_exceptions);
-extern int __sim_disabled_exceptions;
-libc_hidden_proto (__sim_disabled_exceptions);
-extern int __sim_round_mode;
-libc_hidden_proto (__sim_round_mode);
+extern __thread int __sim_exceptions_thread attribute_tls_model_ie;
+libc_hidden_tls_proto (__sim_exceptions_thread, tls_model ("initial-exec"));
+extern __thread int __sim_disabled_exceptions_thread attribute_tls_model_ie;
+libc_hidden_tls_proto (__sim_disabled_exceptions_thread,
+		       tls_model ("initial-exec"));
+extern __thread int __sim_round_mode_thread attribute_tls_model_ie;
+libc_hidden_tls_proto (__sim_round_mode_thread, tls_model ("initial-exec"));
 
 extern void __simulate_exceptions (int x) attribute_hidden;

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]