1 /* Test floating-point environment is thread-local.
2    Copyright (C) 2013-2021 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 *
test_round(void * arg)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 *
test_raise(void * arg)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 *
test_enable(void * arg)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
do_test(void)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"
209