Make powerpc-nofpu floating-point state thread-local (bug 15483).
authorJoseph Myers <joseph@codesourcery.com>
Tue, 19 Nov 2013 13:39:56 +0000 (13:39 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Tue, 19 Nov 2013 13:39:56 +0000 (13:39 +0000)
22 files changed:
ChangeLog
NEWS
math/Makefile
math/test-fenv-tls.c [new file with mode: 0644]
sysdeps/powerpc/nofpu/Versions
sysdeps/powerpc/nofpu/fclrexcpt.c
sysdeps/powerpc/nofpu/fedisblxcpt.c
sysdeps/powerpc/nofpu/feenablxcpt.c
sysdeps/powerpc/nofpu/fegetenv.c
sysdeps/powerpc/nofpu/fegetexcept.c
sysdeps/powerpc/nofpu/fegetround.c
sysdeps/powerpc/nofpu/fesetenv.c
sysdeps/powerpc/nofpu/fesetround.c
sysdeps/powerpc/nofpu/feupdateenv.c
sysdeps/powerpc/nofpu/fgetexcptflg.c
sysdeps/powerpc/nofpu/fraiseexcpt.c
sysdeps/powerpc/nofpu/fsetexcptflg.c
sysdeps/powerpc/nofpu/ftestexcept.c
sysdeps/powerpc/nofpu/get-rounding-mode.h
sysdeps/powerpc/nofpu/sim-full.c
sysdeps/powerpc/nofpu/soft-supp.h
sysdeps/powerpc/soft-fp/sfp-machine.h

index 9568016..0f03219 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,70 @@
+2013-11-19  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.
+
 2013-11-19  Andreas Schwab  <schwab@suse.de>
 
        * locale/programs/locale.c (show_info): Decode wordarray elements.
diff --git a/NEWS b/NEWS
index 26fdfd4..0fdc535 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,14 +11,15 @@ Version 2.19
 
   156, 387, 431, 832, 2801, 7003, 9954, 10253, 10278, 11087, 13028, 13982,
   13985, 14029, 14143, 14155, 14547, 14699, 14752, 14876, 14910, 15048,
-  15218, 15277, 15308, 15362, 15374, 15400, 15427, 15522, 15531, 15532,
-  15608, 15609, 15610, 15632, 15640, 15670, 15672, 15680, 15681, 15723,
-  15734, 15735, 15736, 15748, 15749, 15754, 15760, 15763, 15764, 15797,
-  15799, 15825, 15844, 15847, 15849, 15855, 15856, 15857, 15859, 15867,
-  15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909, 15917,
-  15919, 15921, 15923, 15939, 15948, 15963, 15966, 15985, 15988, 15997,
-  16032, 16034, 16036, 16037, 16041, 16055, 16071, 16072, 16074, 16078,
-  16103, 16112, 16143, 16144, 16146, 16150, 16151, 16153, 16167, 16172.
+  15218, 15277, 15308, 15362, 15374, 15400, 15427, 15483, 15522, 15531,
+  15532, 15608, 15609, 15610, 15632, 15640, 15670, 15672, 15680, 15681,
+  15723, 15734, 15735, 15736, 15748, 15749, 15754, 15760, 15763, 15764,
+  15797, 15799, 15825, 15844, 15847, 15849, 15855, 15856, 15857, 15859,
+  15867, 15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909,
+  15917, 15919, 15921, 15923, 15939, 15948, 15963, 15966, 15985, 15988,
+  15997, 16032, 16034, 16036, 16037, 16041, 16055, 16071, 16072, 16074,
+  16078, 16103, 16112, 16143, 16144, 16146, 16150, 16151, 16153, 16167,
+  16172.
 
 * CVE-2012-4412 The strcoll implementation caches indices and rules for
   large collation sequences to optimize multiple passes.  This cache
index a9bd49b..fcccab2 100644 (file)
@@ -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 (file)
index 0000000..879c9f9
--- /dev/null
@@ -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"
index 1a29319..8ba6021 100644 (file)
@@ -17,4 +17,9 @@ libc {
     __gtdf2; __gtsf2;
     __ltdf2; __ltsf2;
   }
+  GLIBC_PRIVATE {
+    __sim_exceptions_thread;
+    __sim_disabled_exceptions_thread;
+    __sim_round_mode_thread;
+  }
 }
index fabda0a..da0b61a 100644 (file)
@@ -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;
 }
 
index e06c8f7..00490fd 100644 (file)
 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;
 }
index 93249ab..09eb823 100644 (file)
    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;
 }
index 51bcef3..351e552 100644 (file)
 #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;
 
index ea39a82..d907555 100644 (file)
@@ -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;
 }
index c232ae3..016602f 100644 (file)
@@ -24,5 +24,5 @@
 int
 fegetround (void)
 {
-  return __sim_round_mode;
+  return __sim_round_mode_thread;
 }
index 3f35909..fa84169 100644 (file)
@@ -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;
 }
 
index 028c130..ab0d52f 100644 (file)
@@ -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;
 }
index 163f673..8a26cb8 100644 (file)
@@ -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;
index 2373fa4..b7fd90d 100644 (file)
@@ -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;
 }
index cd142b6..215a70b 100644 (file)
@@ -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;
 }
index 3dc368f..ee2aa81 100644 (file)
@@ -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;
 }
index f5d01e8..42e861d 100644 (file)
@@ -23,6 +23,6 @@
 int
 fetestexcept (int x)
 {
-  return __sim_exceptions & x;
+  return __sim_exceptions_thread & x;
 }
 libm_hidden_def (fetestexcept)
index 20eb810..6d327f5 100644 (file)
@@ -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 */
index e167033..fb09d1b 100644 (file)
 #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);
 }
index 18b4550..0a0614a 100644 (file)
@@ -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;
index 0411878..35a38b0 100644 (file)
@@ -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;