1  /* Test floating-point environment is thread-local.
       2     Copyright (C) 2013-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <fenv.h>
      20  #include <pthread.h>
      21  #include <stdio.h>
      22  #include <stdint.h>
      23  
      24  #define TEST_ONE_RM(RM)						\
      25    do								\
      26      {								\
      27        if (fesetround (RM) == 0)					\
      28  	{							\
      29  	  rm = fegetround ();					\
      30  	  if (rm != RM)						\
      31  	    {							\
      32  	      printf ("expected " #RM ", got %d\n", rm);	\
      33  	      ret = 1;						\
      34  	    }							\
      35  	}							\
      36      }								\
      37    while (0)
      38  
      39  static void *
      40  test_round (void *arg)
      41  {
      42    intptr_t ret = 0;
      43    for (int i = 0; i < 10000; i++)
      44      {
      45        int rm;
      46  #ifdef FE_DOWNWARD
      47        TEST_ONE_RM (FE_DOWNWARD);
      48  #endif
      49  #ifdef FE_TONEAREST
      50        TEST_ONE_RM (FE_TONEAREST);
      51  #endif
      52  #ifdef FE_TOWARDZERO
      53        TEST_ONE_RM (FE_TOWARDZERO);
      54  #endif
      55  #ifdef FE_UPWARD
      56        TEST_ONE_RM (FE_UPWARD);
      57  #endif
      58      }
      59    return (void *) ret;
      60  }
      61  
      62  #define TEST_ONE_RAISE(EX)				\
      63    do							\
      64      {							\
      65        if (feraiseexcept (EX) == 0)			\
      66  	if (fetestexcept (EX) != EX)			\
      67  	  {						\
      68  	    printf (#EX " not raised\n");		\
      69  	    ret = 1;					\
      70  	  }						\
      71        if (feclearexcept (FE_ALL_EXCEPT) == 0)		\
      72  	if (fetestexcept (FE_ALL_EXCEPT) != 0)		\
      73  	  {						\
      74  	    printf ("exceptions not all cleared\n");	\
      75  	    ret = 1;					\
      76  	  }						\
      77      }							\
      78    while (0)
      79  
      80  static void *
      81  test_raise (void *arg)
      82  {
      83    intptr_t ret = 0;
      84    for (int i = 0; i < 10000; i++)
      85      {
      86  #ifdef FE_DIVBYZERO
      87        TEST_ONE_RAISE (FE_DIVBYZERO);
      88  #endif
      89  #ifdef FE_INEXACT
      90        TEST_ONE_RAISE (FE_INEXACT);
      91  #endif
      92  #ifdef FE_INVALID
      93        TEST_ONE_RAISE (FE_INVALID);
      94  #endif
      95  #ifdef FE_OVERFLOW
      96        TEST_ONE_RAISE (FE_OVERFLOW);
      97  #endif
      98  #ifdef UNDERFLOW
      99        TEST_ONE_RAISE (FE_UNDERFLOW);
     100  #endif
     101      }
     102    return (void *) ret;
     103  }
     104  
     105  #define TEST_ONE_ENABLE(EX)				\
     106    do							\
     107      {							\
     108        if (feenableexcept (EX) != -1)			\
     109  	if (fegetexcept () != EX)			\
     110  	  {						\
     111  	    printf (#EX " not enabled\n");		\
     112  	    ret = 1;					\
     113  	  }						\
     114        if (fedisableexcept (EX) != -1)			\
     115  	if (fegetexcept () != 0)			\
     116  	  {						\
     117  	    printf ("exceptions not all disabled\n");	\
     118  	    ret = 1;					\
     119  	  }						\
     120      }							\
     121    while (0)
     122  
     123  static void *
     124  test_enable (void *arg)
     125  {
     126    intptr_t ret = 0;
     127    for (int i = 0; i < 10000; i++)
     128      {
     129  #ifdef FE_DIVBYZERO
     130        TEST_ONE_ENABLE (FE_DIVBYZERO);
     131  #endif
     132  #ifdef FE_INEXACT
     133        TEST_ONE_ENABLE (FE_INEXACT);
     134  #endif
     135  #ifdef FE_INVALID
     136        TEST_ONE_ENABLE (FE_INVALID);
     137  #endif
     138  #ifdef FE_OVERFLOW
     139        TEST_ONE_ENABLE (FE_OVERFLOW);
     140  #endif
     141  #ifdef UNDERFLOW
     142        TEST_ONE_ENABLE (FE_UNDERFLOW);
     143  #endif
     144      }
     145    return (void *) ret;
     146  }
     147  
     148  static int
     149  do_test (void)
     150  {
     151    int ret = 0;
     152    void *vret;
     153    pthread_t thread_id;
     154    int pret;
     155  
     156    pret = pthread_create (&thread_id, NULL, test_round, NULL);
     157    if (pret != 0)
     158      {
     159        printf ("pthread_create failed: %d\n", pret);
     160        return 1;
     161      }
     162    vret = test_round (NULL);
     163    ret |= (intptr_t) vret;
     164    pret = pthread_join (thread_id, &vret);
     165    if (pret != 0)
     166      {
     167        printf ("pthread_join failed: %d\n", pret);
     168        return 1;
     169      }
     170    ret |= (intptr_t) vret;
     171  
     172    pret = pthread_create (&thread_id, NULL, test_raise, NULL);
     173    if (pret != 0)
     174      {
     175        printf ("pthread_create failed: %d\n", pret);
     176        return 1;
     177      }
     178    vret = test_raise (NULL);
     179    ret |= (intptr_t) vret;
     180    pret = pthread_join (thread_id, &vret);
     181    if (pret != 0)
     182      {
     183        printf ("pthread_join failed: %d\n", pret);
     184        return 1;
     185      }
     186    ret |= (intptr_t) vret;
     187  
     188    pret = pthread_create (&thread_id, NULL, test_enable, NULL);
     189    if (pret != 0)
     190      {
     191        printf ("pthread_create failed: %d\n", pret);
     192        return 1;
     193      }
     194    vret = test_enable (NULL);
     195    ret |= (intptr_t) vret;
     196    pret = pthread_join (thread_id, &vret);
     197    if (pret != 0)
     198      {
     199        printf ("pthread_join failed: %d\n", pret);
     200        return 1;
     201      }
     202    ret |= (intptr_t) vret;
     203  
     204    return ret;
     205  }
     206  
     207  #define TEST_FUNCTION do_test ()
     208  #include "../test-skeleton.c"