PostgreSQL Source Code  git master
thread_test.c File Reference
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <pwd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
Include dependency graph for thread_test.c:

Go to the source code of this file.

Macros

#define TEMP_FILENAME_1   "thread_test.1"
 
#define TEMP_FILENAME_2   "thread_test.2"
 

Functions

int sigwait (const sigset_t *set, int *sig)
 
static void func_call_1 (void)
 
static void func_call_2 (void)
 
int main (int argc, char *argv[])
 

Variables

static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER
 
static volatile int thread1_done = 0
 
static volatile int thread2_done = 0
 
static volatile int errno1_set = 0
 
static volatile int errno2_set = 0
 
static char * strerror_p1
 
static char * strerror_p2
 
static int strerror_threadsafe = 0
 
static struct passwd * passwd_p1
 
static struct passwd * passwd_p2
 
static int getpwuid_threadsafe = 0
 
static struct hostent * hostent_p1
 
static struct hostent * hostent_p2
 
static char myhostname [MAXHOSTNAMELEN]
 
static int gethostbyname_threadsafe = 0
 
static int platform_is_threadsafe = 1
 

Macro Definition Documentation

◆ TEMP_FILENAME_1

#define TEMP_FILENAME_1   "thread_test.1"

Definition at line 51 of file thread_test.c.

Referenced by func_call_1().

◆ TEMP_FILENAME_2

#define TEMP_FILENAME_2   "thread_test.2"

Definition at line 52 of file thread_test.c.

Referenced by func_call_2().

Function Documentation

◆ func_call_1()

static void func_call_1 ( void  )
static

Definition at line 242 of file thread_test.c.

References close, errno1_set, errno2_set, fd(), fprintf, hostent_p1, init_mutex, myhostname, passwd_p1, printf, pthread_mutex_lock(), pthread_mutex_unlock(), strerror, strerror_p1, TEMP_FILENAME_1, and thread1_done.

Referenced by main().

243 {
244 #if !defined(HAVE_GETPWUID_R) || \
245  (!defined(HAVE_GETADDRINFO) && \
246  !defined(HAVE_GETHOSTBYNAME_R))
247  void *p;
248 #endif
249 #ifdef WIN32
250  HANDLE h1;
251 #else
252  int fd;
253 #endif
254 
255  unlink(TEMP_FILENAME_1);
256 
257  /* Set errno = EEXIST */
258 
259  /* create, then try to fail on exclusive create open */
260 
261  /*
262  * It would be great to check errno here but if errno is not thread-safe
263  * we might get a value from the other thread and mis-report the cause of
264  * the failure.
265  */
266 #ifdef WIN32
267  if ((h1 = CreateFile(TEMP_FILENAME_1, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL)) ==
268  INVALID_HANDLE_VALUE)
269 #else
270  if ((fd = open(TEMP_FILENAME_1, O_RDWR | O_CREAT, 0600)) < 0)
271 #endif
272  {
273  fprintf(stderr, "Could not create file %s in current directory\n",
275  exit(1);
276  }
277 
278 #ifdef WIN32
279  if (CreateFile(TEMP_FILENAME_1, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL)
280  != INVALID_HANDLE_VALUE)
281 #else
282  if (open(TEMP_FILENAME_1, O_RDWR | O_CREAT | O_EXCL, 0600) >= 0)
283 #endif
284  {
285  fprintf(stderr,
286  "Could not generate failure for exclusive file create of %s in current directory **\nexiting\n",
288  exit(1);
289  }
290 
291  /*
292  * Wait for other thread to set errno. We can't use thread-specific
293  * locking here because it might affect errno.
294  */
295  errno1_set = 1;
296  while (errno2_set == 0)
297  sched_yield();
298 
299 #ifdef WIN32
300  if (GetLastError() != ERROR_FILE_EXISTS)
301 #else
302  if (errno != EEXIST)
303 #endif
304  {
305 #ifdef WIN32
306  fprintf(stderr, "GetLastError() not thread-safe **\nexiting\n");
307 #else
308  fprintf(stderr, "errno not thread-safe **\nexiting\n");
309 #endif
310  unlink(TEMP_FILENAME_1);
311  exit(1);
312  }
313 
314 #ifdef WIN32
315  CloseHandle(h1);
316 #else
317  close(fd);
318 #endif
319  unlink(TEMP_FILENAME_1);
320 
321 #ifndef HAVE_STRERROR_R
322 
323  /*
324  * If strerror() uses sys_errlist, the pointer might change for different
325  * errno values, so we don't check to see if it varies within the thread.
326  */
327  strerror_p1 = strerror(EACCES);
328 #endif
329 
330 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
331  passwd_p1 = getpwuid(0);
332  p = getpwuid(1);
333  if (passwd_p1 != p)
334  {
335  printf("Your getpwuid() changes the static memory area between calls\n");
336  passwd_p1 = NULL; /* force thread-safe failure report */
337  }
338 #endif
339 
340 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
341  /* threads do this in opposite order */
342  hostent_p1 = gethostbyname(myhostname);
343  p = gethostbyname("localhost");
344  if (hostent_p1 != p)
345  {
346  printf("Your gethostbyname() changes the static memory area between calls\n");
347  hostent_p1 = NULL; /* force thread-safe failure report */
348  }
349 #endif
350 
351  thread1_done = 1;
352  pthread_mutex_lock(&init_mutex); /* wait for parent to test */
354 }
static volatile int errno1_set
Definition: thread_test.c:62
#define printf(...)
Definition: port.h:222
static volatile int errno2_set
Definition: thread_test.c:63
#define fprintf
Definition: port.h:220
static int fd(const char *x, int i)
Definition: preproc-init.c:105
static pthread_mutex_t init_mutex
Definition: thread_test.c:57
static struct hostent * hostent_p1
Definition: thread_test.c:78
int pthread_mutex_lock(pthread_mutex_t *mp)
Definition: pthread-win32.c:45
int pthread_mutex_unlock(pthread_mutex_t *mp)
Definition: pthread-win32.c:54
static struct passwd * passwd_p1
Definition: thread_test.c:72
#define strerror
Definition: port.h:229
static volatile int thread1_done
Definition: thread_test.c:59
#define TEMP_FILENAME_1
Definition: thread_test.c:51
static char * strerror_p1
Definition: thread_test.c:66
#define close(a)
Definition: win32.h:12
static char myhostname[MAXHOSTNAMELEN]
Definition: thread_test.c:80

◆ func_call_2()

static void func_call_2 ( void  )
static

Definition at line 361 of file thread_test.c.

References errno1_set, errno2_set, fprintf, hostent_p2, init_mutex, myhostname, passwd_p2, printf, pthread_mutex_lock(), pthread_mutex_unlock(), strerror, strerror_p2, TEMP_FILENAME_2, and thread2_done.

Referenced by main().

362 {
363 #if !defined(HAVE_GETPWUID_R) || \
364  (!defined(HAVE_GETADDRINFO) && \
365  !defined(HAVE_GETHOSTBYNAME_R))
366  void *p;
367 #endif
368 
369  unlink(TEMP_FILENAME_2);
370 
371  /* Set errno = ENOENT */
372 
373  /* This will fail, but we can't check errno yet */
374  if (unlink(TEMP_FILENAME_2) != -1)
375  {
376  fprintf(stderr,
377  "Could not generate failure for unlink of %s in current directory **\nexiting\n",
379  exit(1);
380  }
381 
382  /*
383  * Wait for other thread to set errno. We can't use thread-specific
384  * locking here because it might affect errno.
385  */
386  errno2_set = 1;
387  while (errno1_set == 0)
388  sched_yield();
389 
390 #ifdef WIN32
391  if (GetLastError() != ENOENT)
392 #else
393  if (errno != ENOENT)
394 #endif
395  {
396 #ifdef WIN32
397  fprintf(stderr, "GetLastError() not thread-safe **\nexiting\n");
398 #else
399  fprintf(stderr, "errno not thread-safe **\nexiting\n");
400 #endif
401  exit(1);
402  }
403 
404 #ifndef HAVE_STRERROR_R
405 
406  /*
407  * If strerror() uses sys_errlist, the pointer might change for different
408  * errno values, so we don't check to see if it varies within the thread.
409  */
410  strerror_p2 = strerror(EINVAL);
411 #endif
412 
413 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
414  passwd_p2 = getpwuid(2);
415  p = getpwuid(3);
416  if (passwd_p2 != p)
417  {
418  printf("Your getpwuid() changes the static memory area between calls\n");
419  passwd_p2 = NULL; /* force thread-safe failure report */
420  }
421 #endif
422 
423 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
424  /* threads do this in opposite order */
425  hostent_p2 = gethostbyname("localhost");
426  p = gethostbyname(myhostname);
427  if (hostent_p2 != p)
428  {
429  printf("Your gethostbyname() changes the static memory area between calls\n");
430  hostent_p2 = NULL; /* force thread-safe failure report */
431  }
432 #endif
433 
434  thread2_done = 1;
435  pthread_mutex_lock(&init_mutex); /* wait for parent to test */
437 }
#define TEMP_FILENAME_2
Definition: thread_test.c:52
static volatile int errno1_set
Definition: thread_test.c:62
static struct passwd * passwd_p2
Definition: thread_test.c:73
static char * strerror_p2
Definition: thread_test.c:67
static volatile int thread2_done
Definition: thread_test.c:60
#define printf(...)
Definition: port.h:222
static volatile int errno2_set
Definition: thread_test.c:63
#define fprintf
Definition: port.h:220
static struct hostent * hostent_p2
Definition: thread_test.c:79
static pthread_mutex_t init_mutex
Definition: thread_test.c:57
int pthread_mutex_lock(pthread_mutex_t *mp)
Definition: pthread-win32.c:45
int pthread_mutex_unlock(pthread_mutex_t *mp)
Definition: pthread-win32.c:54
#define strerror
Definition: port.h:229
static char myhostname[MAXHOSTNAMELEN]
Definition: thread_test.c:80

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 87 of file thread_test.c.

References close, fprintf, func_call_1(), func_call_2(), gethostbyname_threadsafe, getpwuid_threadsafe, hostent_p1, hostent_p2, init_mutex, myhostname, passwd_p1, passwd_p2, platform_is_threadsafe, printf, pthread_mutex_lock(), pthread_mutex_unlock(), strerror, strerror_p1, strerror_p2, strerror_threadsafe, thread1_done, and thread2_done.

Referenced by aes_cbc_decrypt(), DoubleMetaphone(), and update_spins_per_delay().

88 {
89  pthread_t thread1,
90  thread2;
91  int rc;
92 
93 #ifdef WIN32
94  WSADATA wsaData;
95  int err;
96 #endif
97 
98  if (argc > 1)
99  {
100  fprintf(stderr, "Usage: %s\n", argv[0]);
101  return 1;
102  }
103 
104  /* Send stdout to 'config.log' */
105  close(1);
106  dup(5);
107 
108 #ifdef WIN32
109  err = WSAStartup(MAKEWORD(2, 2), &wsaData);
110  if (err != 0)
111  {
112  fprintf(stderr, "Cannot start the network subsystem - %d**\nexiting\n", err);
113  exit(1);
114  }
115 #endif
116 
117 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
118  if (gethostname(myhostname, MAXHOSTNAMELEN) != 0)
119  {
120  fprintf(stderr, "Cannot get local hostname **\nexiting\n");
121  exit(1);
122  }
123 #endif
124 
125  /* Hold lock until we are ready for the child threads to exit. */
127 
128  rc = pthread_create(&thread1, NULL, (void *(*) (void *)) func_call_1, NULL);
129  if (rc != 0)
130  {
131  fprintf(stderr, "Failed to create thread 1: %s **\nexiting\n",
132  strerror(errno));
133  exit(1);
134  }
135  rc = pthread_create(&thread2, NULL, (void *(*) (void *)) func_call_2, NULL);
136  if (rc != 0)
137  {
138  /*
139  * strerror() might not be thread-safe, and we already spawned thread
140  * 1 that uses it, so avoid using it.
141  */
142  fprintf(stderr, "Failed to create thread 2 **\nexiting\n");
143  exit(1);
144  }
145 
146  while (thread1_done == 0 || thread2_done == 0)
147  sched_yield(); /* if this is a portability problem, remove it */
148 
149  /* Test things while we have thread-local storage */
150 
151  /* If we got here, we didn't exit() from a thread */
152 #ifdef WIN32
153  printf("Your GetLastError() is thread-safe.\n");
154 #else
155  printf("Your errno is thread-safe.\n");
156 #endif
157 
158 #ifndef HAVE_STRERROR_R
159  if (strerror_p1 != strerror_p2)
161 #endif
162 
163 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
164  if (passwd_p1 != passwd_p2)
166 #endif
167 
168 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
169  if (hostent_p1 != hostent_p2)
171 #endif
172 
173  /* close down threads */
174 
175  pthread_mutex_unlock(&init_mutex); /* let children exit */
176 
177  pthread_join(thread1, NULL); /* clean up children */
178  pthread_join(thread2, NULL);
179 
180  /* report results */
181 
182 #ifdef HAVE_STRERROR_R
183  printf("Your system has strerror_r(); it does not need strerror().\n");
184 #else
185  printf("Your system uses strerror() which is ");
187  printf("thread-safe.\n");
188  else
189  {
190  printf("not thread-safe. **\n");
192  }
193 #endif
194 
195 #ifdef WIN32
196  printf("getpwuid_r()/getpwuid() are not applicable to Win32 platforms.\n");
197 #elif defined(HAVE_GETPWUID_R)
198  printf("Your system has getpwuid_r(); it does not need getpwuid().\n");
199 #else
200  printf("Your system uses getpwuid() which is ");
202  printf("thread-safe.\n");
203  else
204  {
205  printf("not thread-safe. **\n");
207  }
208 #endif
209 
210 #ifdef HAVE_GETADDRINFO
211  printf("Your system has getaddrinfo(); it does not need gethostbyname()\n"
212  " or gethostbyname_r().\n");
213 #elif defined(HAVE_GETHOSTBYNAME_R)
214  printf("Your system has gethostbyname_r(); it does not need gethostbyname().\n");
215 #else
216  printf("Your system uses gethostbyname which is ");
218  printf("thread-safe.\n");
219  else
220  {
221  printf("not thread-safe. **\n");
223  }
224 #endif
225 
227  {
228  printf("\nYour platform is thread-safe.\n");
229  return 0;
230  }
231  else
232  {
233  printf("\n** YOUR PLATFORM IS NOT THREAD-SAFE. **\n");
234  return 1;
235  }
236 }
static struct passwd * passwd_p2
Definition: thread_test.c:73
static char * strerror_p2
Definition: thread_test.c:67
static int platform_is_threadsafe
Definition: thread_test.c:84
static volatile int thread2_done
Definition: thread_test.c:60
#define printf(...)
Definition: port.h:222
#define fprintf
Definition: port.h:220
static struct hostent * hostent_p2
Definition: thread_test.c:79
static pthread_mutex_t init_mutex
Definition: thread_test.c:57
static struct hostent * hostent_p1
Definition: thread_test.c:78
int pthread_mutex_lock(pthread_mutex_t *mp)
Definition: pthread-win32.c:45
static void func_call_2(void)
Definition: thread_test.c:361
static int strerror_threadsafe
Definition: thread_test.c:68
int pthread_mutex_unlock(pthread_mutex_t *mp)
Definition: pthread-win32.c:54
static struct passwd * passwd_p1
Definition: thread_test.c:72
static void func_call_1(void)
Definition: thread_test.c:242
#define strerror
Definition: port.h:229
static volatile int thread1_done
Definition: thread_test.c:59
static char * strerror_p1
Definition: thread_test.c:66
#define close(a)
Definition: win32.h:12
static int gethostbyname_threadsafe
Definition: thread_test.c:81
static int getpwuid_threadsafe
Definition: thread_test.c:74
static char myhostname[MAXHOSTNAMELEN]
Definition: thread_test.c:80

◆ sigwait()

int sigwait ( const sigset_t *  set,
int *  sig 
)

Referenced by PQgssEncInUse().

Variable Documentation

◆ errno1_set

volatile int errno1_set = 0
static

Definition at line 62 of file thread_test.c.

Referenced by func_call_1(), and func_call_2().

◆ errno2_set

volatile int errno2_set = 0
static

Definition at line 63 of file thread_test.c.

Referenced by func_call_1(), and func_call_2().

◆ gethostbyname_threadsafe

int gethostbyname_threadsafe = 0
static

Definition at line 81 of file thread_test.c.

Referenced by main().

◆ getpwuid_threadsafe

int getpwuid_threadsafe = 0
static

Definition at line 74 of file thread_test.c.

Referenced by main().

◆ hostent_p1

struct hostent* hostent_p1
static

Definition at line 78 of file thread_test.c.

Referenced by func_call_1(), and main().

◆ hostent_p2

struct hostent* hostent_p2
static

Definition at line 79 of file thread_test.c.

Referenced by func_call_2(), and main().

◆ init_mutex

pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER
static

Definition at line 57 of file thread_test.c.

Referenced by func_call_1(), func_call_2(), and main().

◆ myhostname

char myhostname[MAXHOSTNAMELEN]
static

Definition at line 80 of file thread_test.c.

Referenced by func_call_1(), func_call_2(), and main().

◆ passwd_p1

struct passwd* passwd_p1
static

Definition at line 72 of file thread_test.c.

Referenced by func_call_1(), and main().

◆ passwd_p2

struct passwd* passwd_p2
static

Definition at line 73 of file thread_test.c.

Referenced by func_call_2(), and main().

◆ platform_is_threadsafe

int platform_is_threadsafe = 1
static

Definition at line 84 of file thread_test.c.

Referenced by main().

◆ strerror_p1

char* strerror_p1
static

Definition at line 66 of file thread_test.c.

Referenced by func_call_1(), and main().

◆ strerror_p2

char* strerror_p2
static

Definition at line 67 of file thread_test.c.

Referenced by func_call_2(), and main().

◆ strerror_threadsafe

int strerror_threadsafe = 0
static

Definition at line 68 of file thread_test.c.

Referenced by main().

◆ thread1_done

volatile int thread1_done = 0
static

Definition at line 59 of file thread_test.c.

Referenced by func_call_1(), and main().

◆ thread2_done

volatile int thread2_done = 0
static

Definition at line 60 of file thread_test.c.

Referenced by func_call_2(), and main().