From 73c1ce4fdbdf117b4d91b6e894686228155bd702 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Tue, 19 Nov 2013 13:39:56 +0000 Subject: Make powerpc-nofpu floating-point state thread-local (bug 15483). --- math/Makefile | 3 +- math/test-fenv-tls.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 math/test-fenv-tls.c (limited to 'math') diff --git a/math/Makefile b/math/Makefile index a9bd49baee..fcccab2051 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 0000000000..879c9f9518 --- /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 + . */ + +#include +#include +#include +#include + +#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" -- cgit v1.2.3