1 /*-------------------------------------------------------------------------
4 * libc thread test program
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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>
55 /******************************************************************
57 *****************************************************************/
60 #define MAXHOSTNAMELEN 63
63 int mkstemp(char *template);
66 mkstemp(char *template)
71 foo
= fopen(template, "rw");
79 /******************************************************************
81 *****************************************************************/
84 /* Test for POSIX.1c 2-arg sigwait() and fail on single-arg version */
86 int sigwait(const sigset_t
*set
, int *sig
);
89 #if !defined(ENABLE_THREAD_SAFETY) && !defined(IN_CONFIGURE) && !(defined(WIN32))
91 main(int argc
, char *argv
[])
93 fprintf(stderr
, "This PostgreSQL build does not support threads.\n");
94 fprintf(stderr
, "Perhaps rerun 'configure' using '--enable-thread-safety'.\n");
99 /* This must be down here because this is the code that uses threads. */
102 static void func_call_1(void);
103 static void func_call_2(void);
106 #define TEMP_FILENAME_1 "thread_test.1.XXXXXX"
107 #define TEMP_FILENAME_2 "thread_test.2.XXXXXX"
109 #define TEMP_FILENAME_1 "/tmp/thread_test.1.XXXXXX"
110 #define TEMP_FILENAME_2 "/tmp/thread_test.2.XXXXXX"
113 static char *temp_filename_1
;
114 static char *temp_filename_2
;
116 static pthread_mutex_t init_mutex
= PTHREAD_MUTEX_INITIALIZER
;
118 static volatile int thread1_done
= 0;
119 static volatile int thread2_done
= 0;
121 static volatile int errno1_set
= 0;
122 static volatile int errno2_set
= 0;
124 #ifndef HAVE_STRERROR_R
125 static char *strerror_p1
;
126 static char *strerror_p2
;
127 static bool strerror_threadsafe
= false;
131 #ifndef HAVE_GETPWUID_R
132 static struct passwd
*passwd_p1
;
133 static struct passwd
*passwd_p2
;
134 static bool getpwuid_threadsafe
= false;
138 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
139 static struct hostent
*hostent_p1
;
140 static struct hostent
*hostent_p2
;
141 static char myhostname
[MAXHOSTNAMELEN
];
142 static bool gethostbyname_threadsafe
= false;
145 static bool platform_is_threadsafe
= true;
148 main(int argc
, char *argv
[])
161 fprintf(stderr
, "Usage: %s\n", argv
[0]);
166 /* Send stdout to 'config.log' */
172 err
= WSAStartup(MAKEWORD(1, 1), &wsaData
);
175 fprintf(stderr
, "Cannot start the network subsystem - %d**\nexiting\n", err
);
180 /* Make temp filenames, might not have strdup() */
181 temp_filename_1
= malloc(strlen(TEMP_FILENAME_1
) + 1);
182 strcpy(temp_filename_1
, TEMP_FILENAME_1
);
183 fd
= mkstemp(temp_filename_1
);
186 temp_filename_2
= malloc(strlen(TEMP_FILENAME_2
) + 1);
187 strcpy(temp_filename_2
, TEMP_FILENAME_2
);
188 fd
= mkstemp(temp_filename_2
);
191 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
192 if (gethostname(myhostname
, MAXHOSTNAMELEN
) != 0)
194 fprintf(stderr
, "Cannot get local hostname **\nexiting\n");
199 /* Hold lock until we are ready for the child threads to exit. */
200 pthread_mutex_lock(&init_mutex
);
202 pthread_create(&thread1
, NULL
, (void *(*) (void *)) func_call_1
, NULL
);
203 pthread_create(&thread2
, NULL
, (void *(*) (void *)) func_call_2
, NULL
);
205 while (thread1_done
== 0 || thread2_done
== 0)
206 sched_yield(); /* if this is a portability problem, remove it */
208 printf("Your GetLastError() is thread-safe.\n");
210 printf("Your errno is thread-safe.\n");
213 #ifndef HAVE_STRERROR_R
214 if (strerror_p1
!= strerror_p2
)
215 strerror_threadsafe
= true;
219 #ifndef HAVE_GETPWUID_R
220 if (passwd_p1
!= passwd_p2
)
221 getpwuid_threadsafe
= true;
225 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
226 if (hostent_p1
!= hostent_p2
)
227 gethostbyname_threadsafe
= true;
230 pthread_mutex_unlock(&init_mutex
); /* let children exit */
232 pthread_join(thread1
, NULL
); /* clean up children */
233 pthread_join(thread2
, NULL
);
235 #ifdef HAVE_STRERROR_R
236 printf("Your system has sterror_r(); it does not need strerror().\n");
238 printf("Your system uses strerror() which is ");
239 if (strerror_threadsafe
)
240 printf("thread-safe.\n");
243 printf("not thread-safe. **\n");
244 platform_is_threadsafe
= false;
249 #ifdef HAVE_GETPWUID_R
250 printf("Your system has getpwuid_r(); it does not need getpwuid().\n");
252 printf("Your system uses getpwuid() which is ");
253 if (getpwuid_threadsafe
)
254 printf("thread-safe.\n");
257 printf("not thread-safe. **\n");
258 platform_is_threadsafe
= false;
262 printf("getpwuid_r()/getpwuid() are not applicable to Win32 platforms.\n");
265 #ifdef HAVE_GETADDRINFO
266 printf("Your system has getaddrinfo(); it does not need gethostbyname()\n"
267 " or gethostbyname_r().\n");
269 #ifdef HAVE_GETHOSTBYNAME_R
270 printf("Your system has gethostbyname_r(); it does not need gethostbyname().\n");
272 printf("Your system uses gethostbyname which is ");
273 if (gethostbyname_threadsafe
)
274 printf("thread-safe.\n");
277 printf("not thread-safe. **\n");
278 platform_is_threadsafe
= false;
283 if (platform_is_threadsafe
)
285 printf("\nYour platform is thread-safe.\n");
290 printf("\n** YOUR PLATFORM IS NOT THREAD-SAFE. **\n");
298 #if !defined(HAVE_GETPWUID_R) || \
299 (!defined(HAVE_GETADDRINFO) && \
300 !defined(HAVE_GETHOSTBYNAME_R))
307 unlink(temp_filename_1
);
310 /* create, then try to fail on exclusive create open */
312 h1
= CreateFile(temp_filename_1
, GENERIC_WRITE
, 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
313 h2
= CreateFile(temp_filename_1
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
314 if (h1
== INVALID_HANDLE_VALUE
|| GetLastError() != ERROR_FILE_EXISTS
)
316 if (open(temp_filename_1
, O_RDWR
| O_CREAT
, 0600) < 0 ||
317 open(temp_filename_1
, O_RDWR
| O_CREAT
| O_EXCL
, 0600) >= 0)
321 fprintf(stderr
, "Could not create file in current directory or\n");
322 fprintf(stderr
, "Could not generate failure for create file in current directory **\nexiting\n");
324 fprintf(stderr
, "Could not create file in /tmp or\n");
325 fprintf(stderr
, "Could not generate failure for create file in /tmp **\nexiting\n");
331 * Wait for other thread to set errno. We can't use thread-specific
332 * locking here because it might affect errno.
335 while (errno2_set
== 0)
338 if (GetLastError() != ERROR_FILE_EXISTS
)
344 fprintf(stderr
, "GetLastError() not thread-safe **\nexiting\n");
346 fprintf(stderr
, "errno not thread-safe **\nexiting\n");
348 unlink(temp_filename_1
);
351 unlink(temp_filename_1
);
353 #ifndef HAVE_STRERROR_R
354 strerror_p1
= strerror(EACCES
);
357 * If strerror() uses sys_errlist, the pointer might change for different
358 * errno values, so we don't check to see if it varies within the thread.
363 #ifndef HAVE_GETPWUID_R
364 passwd_p1
= getpwuid(0);
368 printf("Your getpwuid() changes the static memory area between calls\n");
369 passwd_p1
= NULL
; /* force thread-safe failure report */
374 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
375 /* threads do this in opposite order */
376 hostent_p1
= gethostbyname(myhostname
);
377 p
= gethostbyname("localhost");
380 printf("Your gethostbyname() changes the static memory area between calls\n");
381 hostent_p1
= NULL
; /* force thread-safe failure report */
386 pthread_mutex_lock(&init_mutex
); /* wait for parent to test */
387 pthread_mutex_unlock(&init_mutex
);
394 #if !defined(HAVE_GETPWUID_R) || \
395 (!defined(HAVE_GETADDRINFO) && \
396 !defined(HAVE_GETHOSTBYNAME_R))
400 unlink(temp_filename_2
);
401 /* open non-existant file */
403 CreateFile(temp_filename_2
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
404 if (GetLastError() != ERROR_FILE_NOT_FOUND
)
406 if (open(temp_filename_2
, O_RDONLY
, 0600) >= 0)
409 fprintf(stderr
, "Read-only open succeeded without create **\nexiting\n");
414 * Wait for other thread to set errno. We can't use thread-specific
415 * locking here because it might affect errno.
418 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");
431 unlink(temp_filename_2
);
434 unlink(temp_filename_2
);
436 #ifndef HAVE_STRERROR_R
437 strerror_p2
= strerror(EINVAL
);
440 * If strerror() uses sys_errlist, the pointer might change for different
441 * errno values, so we don't check to see if it varies within the thread.
446 #ifndef HAVE_GETPWUID_R
447 passwd_p2
= getpwuid(2);
451 printf("Your getpwuid() changes the static memory area between calls\n");
452 passwd_p2
= NULL
; /* force thread-safe failure report */
457 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
458 /* threads do this in opposite order */
459 hostent_p2
= gethostbyname("localhost");
460 p
= gethostbyname(myhostname
);
463 printf("Your gethostbyname() changes the static memory area between calls\n");
464 hostent_p2
= NULL
; /* force thread-safe failure report */
469 pthread_mutex_lock(&init_mutex
); /* wait for parent to test */
470 pthread_mutex_unlock(&init_mutex
);
473 #endif /* !ENABLE_THREAD_SAFETY && !IN_CONFIGURE */