1 /*-------------------------------------------------------------------------
4 * libc thread test program
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * src/test/thread/thread_test.c
11 * This program tests to see if your standard libc functions use
12 * pthread_setspecific()/pthread_getspecific() to be thread-safe.
13 * See src/port/thread.c for more details.
15 * This program first tests to see if each function returns a constant
16 * memory pointer within the same thread, then, assuming it does, tests
17 * to see if the pointers are different for different threads. If they
18 * are, the function is thread-safe.
20 *-------------------------------------------------------------------------
23 #if !defined(IN_CONFIGURE) && !defined(WIN32)
26 /* From src/include/c.h" */
32 #define true ((bool) 1)
36 #define false ((bool) 0)
44 #include <sys/types.h>
50 /* CYGWIN requires this for MAXHOSTNAMELEN */
52 #include <sys/param.h>
56 #define MAXHOSTNAMELEN 63
61 /* Test for POSIX.1c 2-arg sigwait() and fail on single-arg version */
63 int sigwait(const sigset_t *set, int *sig);
66 #if !defined(ENABLE_THREAD_SAFETY) && !defined(IN_CONFIGURE) && !defined(WIN32)
68 main(int argc, char *argv[])
70 fprintf(stderr, "This PostgreSQL build does not support threads.\n");
71 fprintf(stderr, "Perhaps rerun 'configure' using '--enable-thread-safety'.\n");
76 /* This must be down here because this is the code that uses threads. */
79 #define TEMP_FILENAME_1 "thread_test.1"
80 #define TEMP_FILENAME_2 "thread_test.2"
82 static void func_call_1(void);
83 static void func_call_2(void);
85 static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
87 static volatile int thread1_done = 0;
88 static volatile int thread2_done = 0;
90 static volatile int errno1_set = 0;
91 static volatile int errno2_set = 0;
93 #ifndef HAVE_STRERROR_R
94 static char *strerror_p1;
95 static char *strerror_p2;
96 static bool strerror_threadsafe = false;
99 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
100 static struct passwd *passwd_p1;
101 static struct passwd *passwd_p2;
102 static bool getpwuid_threadsafe = false;
105 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
106 static struct hostent *hostent_p1;
107 static struct hostent *hostent_p2;
108 static char myhostname[MAXHOSTNAMELEN];
109 static bool gethostbyname_threadsafe = false;
112 static bool platform_is_threadsafe = true;
115 main(int argc, char *argv[])
128 fprintf(stderr, "Usage: %s\n", argv[0]);
133 /* Send stdout to 'config.log' */
139 err = WSAStartup(MAKEWORD(1, 1), &wsaData);
142 fprintf(stderr, "Cannot start the network subsystem - %d**\nexiting\n", err);
147 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
148 if (gethostname(myhostname, MAXHOSTNAMELEN) != 0)
150 fprintf(stderr, "Cannot get local hostname **\nexiting\n");
155 /* Hold lock until we are ready for the child threads to exit. */
156 pthread_mutex_lock(&init_mutex);
158 rc = pthread_create(&thread1, NULL, (void *(*) (void *)) func_call_1, NULL);
161 fprintf(stderr, "Failed to create thread 1: %s **\nexiting\n",
165 rc = pthread_create(&thread2, NULL, (void *(*) (void *)) func_call_2, NULL);
169 * strerror() might not be thread-safe, and we already spawned thread
170 * 1 that uses it, so avoid using it.
172 fprintf(stderr, "Failed to create thread 2 **\nexiting\n");
176 while (thread1_done == 0 || thread2_done == 0)
177 sched_yield(); /* if this is a portability problem, remove it */
179 /* Test things while we have thread-local storage */
181 /* If we got here, we didn't exit() from a thread */
183 printf("Your GetLastError() is thread-safe.\n");
185 printf("Your errno is thread-safe.\n");
188 #ifndef HAVE_STRERROR_R
189 if (strerror_p1 != strerror_p2)
190 strerror_threadsafe = true;
193 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
194 if (passwd_p1 != passwd_p2)
195 getpwuid_threadsafe = true;
198 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
199 if (hostent_p1 != hostent_p2)
200 gethostbyname_threadsafe = true;
203 /* close down threads */
205 pthread_mutex_unlock(&init_mutex); /* let children exit */
207 pthread_join(thread1, NULL); /* clean up children */
208 pthread_join(thread2, NULL);
212 #ifdef HAVE_STRERROR_R
213 printf("Your system has sterror_r(); it does not need strerror().\n");
215 printf("Your system uses strerror() which is ");
216 if (strerror_threadsafe)
217 printf("thread-safe.\n");
220 printf("not thread-safe. **\n");
221 platform_is_threadsafe = false;
226 printf("getpwuid_r()/getpwuid() are not applicable to Win32 platforms.\n");
227 #elif defined(HAVE_GETPWUID_R)
228 printf("Your system has getpwuid_r(); it does not need getpwuid().\n");
230 printf("Your system uses getpwuid() which is ");
231 if (getpwuid_threadsafe)
232 printf("thread-safe.\n");
235 printf("not thread-safe. **\n");
236 platform_is_threadsafe = false;
240 #ifdef HAVE_GETADDRINFO
241 printf("Your system has getaddrinfo(); it does not need gethostbyname()\n"
242 " or gethostbyname_r().\n");
243 #elif defined(HAVE_GETHOSTBYNAME_R)
244 printf("Your system has gethostbyname_r(); it does not need gethostbyname().\n");
246 printf("Your system uses gethostbyname which is ");
247 if (gethostbyname_threadsafe)
248 printf("thread-safe.\n");
251 printf("not thread-safe. **\n");
252 platform_is_threadsafe = false;
256 if (platform_is_threadsafe)
258 printf("\nYour platform is thread-safe.\n");
263 printf("\n** YOUR PLATFORM IS NOT THREAD-SAFE. **\n");
274 #if !defined(HAVE_GETPWUID_R) || \
275 (!defined(HAVE_GETADDRINFO) && \
276 !defined(HAVE_GETHOSTBYNAME_R))
285 unlink(TEMP_FILENAME_1);
287 /* Set errno = EEXIST */
289 /* create, then try to fail on exclusive create open */
292 * It would be great to check errno here but if errno is not thread-safe
293 * we might get a value from the other thread and mis-report the cause of
297 if ((h1 = CreateFile(TEMP_FILENAME_1, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL)) ==
298 INVALID_HANDLE_VALUE)
300 if ((fd = open(TEMP_FILENAME_1, O_RDWR | O_CREAT, 0600)) < 0)
303 fprintf(stderr, "Could not create file %s in current directory\n",
309 if (CreateFile(TEMP_FILENAME_1, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL)
310 != INVALID_HANDLE_VALUE)
312 if (open(TEMP_FILENAME_1, O_RDWR | O_CREAT | O_EXCL, 0600) >= 0)
316 "Could not generate failure for exclusive file create of %s in current directory **\nexiting\n",
322 * Wait for other thread to set errno. We can't use thread-specific
323 * locking here because it might affect errno.
326 while (errno2_set == 0)
330 if (GetLastError() != ERROR_FILE_EXISTS)
336 fprintf(stderr, "GetLastError() not thread-safe **\nexiting\n");
338 fprintf(stderr, "errno not thread-safe **\nexiting\n");
340 unlink(TEMP_FILENAME_1);
349 unlink(TEMP_FILENAME_1);
351 #ifndef HAVE_STRERROR_R
354 * If strerror() uses sys_errlist, the pointer might change for different
355 * errno values, so we don't check to see if it varies within the thread.
357 strerror_p1 = strerror(EACCES);
360 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
361 passwd_p1 = getpwuid(0);
365 printf("Your getpwuid() changes the static memory area between calls\n");
366 passwd_p1 = NULL; /* force thread-safe failure report */
370 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
371 /* threads do this in opposite order */
372 hostent_p1 = gethostbyname(myhostname);
373 p = gethostbyname("localhost");
376 printf("Your gethostbyname() changes the static memory area between calls\n");
377 hostent_p1 = NULL; /* force thread-safe failure report */
382 pthread_mutex_lock(&init_mutex); /* wait for parent to test */
383 pthread_mutex_unlock(&init_mutex);
393 #if !defined(HAVE_GETPWUID_R) || \
394 (!defined(HAVE_GETADDRINFO) && \
395 !defined(HAVE_GETHOSTBYNAME_R))
399 unlink(TEMP_FILENAME_2);
401 /* Set errno = ENOENT */
403 /* This will fail, but we can't check errno yet */
404 if (unlink(TEMP_FILENAME_2) != -1)
407 "Could not generate failure for unlink of %s in current directory **\nexiting\n",
413 * Wait for other thread to set errno. We can't use thread-specific
414 * locking here because it might affect errno.
417 while (errno1_set == 0)
421 if (GetLastError() != ENOENT)
427 fprintf(stderr, "GetLastError() not thread-safe **\nexiting\n");
429 fprintf(stderr, "errno not thread-safe **\nexiting\n");
434 #ifndef HAVE_STRERROR_R
437 * If strerror() uses sys_errlist, the pointer might change for different
438 * errno values, so we don't check to see if it varies within the thread.
440 strerror_p2 = strerror(EINVAL);
443 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
444 passwd_p2 = getpwuid(2);
448 printf("Your getpwuid() changes the static memory area between calls\n");
449 passwd_p2 = NULL; /* force thread-safe failure report */
453 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
454 /* threads do this in opposite order */
455 hostent_p2 = gethostbyname("localhost");
456 p = gethostbyname(myhostname);
459 printf("Your gethostbyname() changes the static memory area between calls\n");
460 hostent_p2 = NULL; /* force thread-safe failure report */
465 pthread_mutex_lock(&init_mutex); /* wait for parent to test */
466 pthread_mutex_unlock(&init_mutex);
469 #endif /* !ENABLE_THREAD_SAFETY && !IN_CONFIGURE */