1 /*-------------------------------------------------------------------------
4 * libc thread test program
6 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * $PostgreSQL: pgsql/src/tools/thread/thread_test.c,v 1.29 2004/04/27 19:51:12 momjian Exp $
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 *-------------------------------------------------------------------------
26 /* From src/include/c.h" */
32 #define true ((bool) 1)
36 #define false ((bool) 0)
44 #include <sys/types.h>
50 #if !defined(ENABLE_THREAD_SAFETY) && !defined(IN_CONFIGURE)
52 main(int argc, char *argv[])
54 fprintf(stderr, "This PostgreSQL build does not support threads.\n");
55 fprintf(stderr, "Perhaps rerun 'configure' using '--enable-thread-safety'.\n");
61 /* This must be down here because this is the code that uses threads. */
64 void func_call_1(void);
65 void func_call_2(void);
67 #define TEMP_FILENAME_1 "/tmp/thread_test.1.XXXXX"
68 #define TEMP_FILENAME_2 "/tmp/thread_test.2.XXXXX"
70 char *temp_filename_1;
71 char *temp_filename_2;
73 pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
75 volatile int thread1_done = 0;
76 volatile int thread2_done = 0;
78 volatile int errno1_set = 0;
79 volatile int errno2_set = 0;
81 #ifndef HAVE_STRERROR_R
84 bool strerror_threadsafe = false;
87 #ifndef HAVE_GETPWUID_R
88 struct passwd *passwd_p1;
89 struct passwd *passwd_p2;
90 bool getpwuid_threadsafe = false;
93 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
94 struct hostent *hostent_p1;
95 struct hostent *hostent_p2;
96 char myhostname[MAXHOSTNAMELEN];
97 bool gethostbyname_threadsafe = false;
100 bool platform_is_threadsafe = true;
103 main(int argc, char *argv[])
110 fprintf(stderr, "Usage: %s\n", argv[0]);
115 /* Send stdout to 'config.log' */
120 /* Make temp filenames, might not have strdup() */
121 temp_filename_1 = malloc(strlen(TEMP_FILENAME_1) + 1);
122 strcpy(temp_filename_1, TEMP_FILENAME_1);
123 mktemp(temp_filename_1);
125 temp_filename_2 = malloc(strlen(TEMP_FILENAME_2) + 1);
126 strcpy(temp_filename_2, TEMP_FILENAME_2);
127 mktemp(temp_filename_2);
129 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
130 if (gethostname(myhostname, MAXHOSTNAMELEN) != 0)
132 fprintf(stderr, "Can not get local hostname **\nexiting\n");
137 /* Hold lock until we are ready for the child threads to exit. */
138 pthread_mutex_lock(&init_mutex);
140 pthread_create(&thread1, NULL, (void *(*) (void *)) func_call_1, NULL);
141 pthread_create(&thread2, NULL, (void *(*) (void *)) func_call_2, NULL);
143 while (thread1_done == 0 || thread2_done == 0)
144 sched_yield(); /* if this is a portability problem,
147 printf("Your errno is thread-safe.\n");
149 #ifndef HAVE_STRERROR_R
150 if (strerror_p1 != strerror_p2)
151 strerror_threadsafe = true;
154 #ifndef HAVE_GETPWUID_R
155 if (passwd_p1 != passwd_p2)
156 getpwuid_threadsafe = true;
159 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
160 if (hostent_p1 != hostent_p2)
161 gethostbyname_threadsafe = true;
164 pthread_mutex_unlock(&init_mutex); /* let children exit */
166 pthread_join(thread1, NULL); /* clean up children */
167 pthread_join(thread2, NULL);
169 #ifdef HAVE_STRERROR_R
170 printf("Your system has sterror_r(); it does not need strerror().\n");
172 printf("Your system uses strerror() which is ");
173 if (strerror_threadsafe)
174 printf("thread-safe.\n");
177 printf("not thread-safe. **\n");
178 platform_is_threadsafe = false;
182 #ifdef HAVE_GETPWUID_R
183 printf("Your system has getpwuid_r(); it does not need getpwuid().\n");
185 printf("Your system uses getpwuid() which is ");
186 if (getpwuid_threadsafe)
187 printf("thread-safe.\n");
190 printf("not thread-safe. **\n");
191 platform_is_threadsafe = false;
195 #ifdef HAVE_GETADDRINFO
196 printf("Your system has getaddrinfo(); it does not need gethostbyname()\n"
197 " or gethostbyname_r().\n");
199 #ifdef HAVE_GETHOSTBYNAME_R
200 printf("Your system has gethostbyname_r(); it does not need gethostbyname().\n");
202 printf("Your system uses gethostbyname which is ");
203 if (gethostbyname_threadsafe)
204 printf("thread-safe.\n");
207 printf("not thread-safe. **\n");
208 platform_is_threadsafe = false;
213 if (platform_is_threadsafe)
215 printf("\nYour platform is thread-safe.\n");
220 printf("\n** YOUR PLATFORM IS NOT THREAD-SAFE. **\n");
228 #if !defined(HAVE_GETPWUID_R) || \
229 (!defined(HAVE_GETADDRINFO) && \
230 !defined(HAVE_GETHOSTBYNAME_R))
234 unlink(temp_filename_1);
235 /* create, then try to fail on exclusive create open */
236 if (open(temp_filename_1, O_RDWR | O_CREAT, 0600) < 0 ||
237 open(temp_filename_1, O_RDWR | O_CREAT | O_EXCL, 0600) >= 0)
239 fprintf(stderr, "Could not create file in /tmp or\n");
240 fprintf(stderr, "Could not generate failure for create file in /tmp **\nexiting\n");
245 * Wait for other thread to set errno. We can't use thread-specific
246 * locking here because it might affect errno.
249 while (errno2_set == 0)
253 fprintf(stderr, "errno not thread-safe **\nexiting\n");
254 unlink(temp_filename_1);
257 unlink(temp_filename_1);
259 #ifndef HAVE_STRERROR_R
260 strerror_p1 = strerror(EACCES);
263 * If strerror() uses sys_errlist, the pointer might change for
264 * different errno values, so we don't check to see if it varies
269 #ifndef HAVE_GETPWUID_R
270 passwd_p1 = getpwuid(0);
274 printf("Your getpwuid() changes the static memory area between calls\n");
275 passwd_p1 = NULL; /* force thread-safe failure report */
279 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
280 /* threads do this in opposite order */
281 hostent_p1 = gethostbyname(myhostname);
282 p = gethostbyname("localhost");
285 printf("Your gethostbyname() changes the static memory area between calls\n");
286 hostent_p1 = NULL; /* force thread-safe failure report */
291 pthread_mutex_lock(&init_mutex); /* wait for parent to test */
292 pthread_mutex_unlock(&init_mutex);
299 #if !defined(HAVE_GETPWUID_R) || \
300 (!defined(HAVE_GETADDRINFO) && \
301 !defined(HAVE_GETHOSTBYNAME_R))
305 unlink(temp_filename_2);
306 /* open non-existant file */
307 if (open(temp_filename_2, O_RDONLY, 0600) >= 0)
309 fprintf(stderr, "Read-only open succeeded without create **\nexiting\n");
314 * Wait for other thread to set errno. We can't use thread-specific
315 * locking here because it might affect errno.
318 while (errno1_set == 0)
322 fprintf(stderr, "errno not thread-safe **\nexiting\n");
323 unlink(temp_filename_2);
326 unlink(temp_filename_2);
328 #ifndef HAVE_STRERROR_R
329 strerror_p2 = strerror(EINVAL);
332 * If strerror() uses sys_errlist, the pointer might change for
333 * different errno values, so we don't check to see if it varies
338 #ifndef HAVE_GETPWUID_R
339 passwd_p2 = getpwuid(2);
343 printf("Your getpwuid() changes the static memory area between calls\n");
344 passwd_p2 = NULL; /* force thread-safe failure report */
348 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
349 /* threads do this in opposite order */
350 hostent_p2 = gethostbyname("localhost");
351 p = gethostbyname(myhostname);
354 printf("Your gethostbyname() changes the static memory area between calls\n");
355 hostent_p2 = NULL; /* force thread-safe failure report */
360 pthread_mutex_lock(&init_mutex); /* wait for parent to test */
361 pthread_mutex_unlock(&init_mutex);
363 #endif /* !ENABLE_THREAD_SAFETY && !IN_CONFIGURE */