1 /* Multithread-safety test for setlocale_null_r (LC_xxx, ...).
2    Copyright (C) 2019-2020 Free Software Foundation, Inc.
3 
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
16 
17 /* Written by Bruno Haible <bruno@clisp.org>, 2019.  */
18 
19 #include <config.h>
20 
21 #if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS
22 
23 /* Specification.  */
24 #include <locale.h>
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 
31 #include "glthread/thread.h"
32 
33 /* We want to use the system's setlocale() function here, not the gnulib
34    override.  */
35 #undef setlocale
36 
37 
38 /* Some common locale names.  */
39 
40 #if defined _WIN32 && !defined __CYGWIN__
41 # define ENGLISH "English_United States"
42 # define GERMAN  "German_Germany"
43 # define FRENCH  "French_France"
44 # define ENCODING ".1252"
45 #else
46 # define ENGLISH "en_US"
47 # define GERMAN  "de_DE"
48 # define FRENCH  "fr_FR"
49 # if defined __sgi
50 #  define ENCODING ".ISO8859-15"
51 # elif defined __hpux
52 #  define ENCODING ".utf8"
53 # else
54 #  define ENCODING ".UTF-8"
55 # endif
56 #endif
57 
58 static const char LOCALE1[] = ENGLISH ENCODING;
59 static const char LOCALE2[] = GERMAN ENCODING;
60 static const char LOCALE3[] = FRENCH ENCODING;
61 
62 static char *expected;
63 
64 static void *
thread1_func(void * arg)65 thread1_func (void *arg)
66 {
67   for (;;)
68     {
69       char buf[SETLOCALE_NULL_MAX];
70 
71       if (setlocale_null_r (LC_NUMERIC, buf, sizeof (buf)))
72         abort ();
73       if (strcmp (expected, buf) != 0)
74         {
75           fprintf (stderr, "thread1 disturbed by thread2!\n"); fflush (stderr);
76           abort ();
77         }
78     }
79 
80   /*NOTREACHED*/
81   return NULL;
82 }
83 
84 static void *
thread2_func(void * arg)85 thread2_func (void *arg)
86 {
87   for (;;)
88     {
89       char buf[SETLOCALE_NULL_MAX];
90 
91       setlocale_null_r (LC_NUMERIC, buf, sizeof (buf));
92       setlocale_null_r (LC_TIME, buf, sizeof (buf));
93     }
94 
95   /*NOTREACHED*/
96   return NULL;
97 }
98 
99 int
main(int argc,char * argv[])100 main (int argc, char *argv[])
101 {
102   if (setlocale (LC_ALL, LOCALE1) == NULL)
103     {
104       fprintf (stderr, "Skipping test: LOCALE1 not recognized\n");
105       return 77;
106     }
107   if (setlocale (LC_NUMERIC, LOCALE2) == NULL)
108     {
109       fprintf (stderr, "Skipping test: LOCALE2 not recognized\n");
110       return 77;
111     }
112   if (setlocale (LC_TIME, LOCALE3) == NULL)
113     {
114       fprintf (stderr, "Skipping test: LOCALE3 not recognized\n");
115       return 77;
116     }
117 
118   expected = strdup (setlocale (LC_NUMERIC, NULL));
119 
120   /* Create the two threads.  */
121   gl_thread_create (thread1_func, NULL);
122   gl_thread_create (thread2_func, NULL);
123 
124   /* Let them run for 2 seconds.  */
125   {
126     struct timespec duration;
127     duration.tv_sec = 2;
128     duration.tv_nsec = 0;
129 
130     nanosleep (&duration, NULL);
131   }
132 
133   return 0;
134 }
135 
136 #else
137 
138 /* No multithreading available.  */
139 
140 #include <stdio.h>
141 
142 int
main()143 main ()
144 {
145   fputs ("Skipping test: multithreading not enabled\n", stderr);
146   return 77;
147 }
148 
149 #endif
150 
151 /* Without locking, the results of this test would be:
152 glibc                OK
153 musl libc            OK
154 macOS                OK
155 FreeBSD              OK
156 NetBSD               OK
157 OpenBSD              crash < 1 sec
158 AIX                  crash < 2 sec
159 HP-UX                OK
160 IRIX                 OK
161 Solaris 10           OK
162 Solaris 11.0         OK
163 Solaris 11.4         OK
164 Solaris OpenIndiana  OK
165 Haiku                OK
166 Cygwin               OK
167 mingw                OK
168 MSVC                 OK (assuming compiler option /MD !)
169 */
170