Skip to content
Snippets Groups Projects
Commit 66b42d30 authored by Bruce Momjian's avatar Bruce Momjian
Browse files

Improve thread test program. Test only functions that need testing.

parent fc7fd501
No related branches found
No related tags found
No related merge requests found
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# #
# Copyright (C) 2003 by PostgreSQL Global Development Team # Copyright (C) 2003 by PostgreSQL Global Development Team
# #
# $PostgreSQL: pgsql/src/tools/thread/Makefile,v 1.4 2004/04/23 18:15:55 momjian Exp $ # $PostgreSQL: pgsql/src/tools/thread/Makefile,v 1.5 2004/04/23 20:35:50 momjian Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -12,13 +12,6 @@ subdir = tools/thread ...@@ -12,13 +12,6 @@ subdir = tools/thread
top_builddir = ../../.. top_builddir = ../../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
ifeq ($(THREAD_SUPPORT), no)
$(error Your platform does not support threads)
endif
ifeq ($(THREAD_SUPPORT), )
$(error You have not configured your template/$$port file. See the README)
endif
override CFLAGS += $(PTHREAD_CFLAGS) override CFLAGS += $(PTHREAD_CFLAGS)
LDFLAGS += $(PTHREAD_LIBS) LDFLAGS += $(PTHREAD_LIBS)
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* test_thread_funcs.c * test_thread_funcs.c
* libc thread test program * libc thread test program
* *
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/tools/thread/thread_test.c,v 1.20 2004/04/23 18:15:55 momjian Exp $ * $PostgreSQL: pgsql/src/tools/thread/thread_test.c,v 1.21 2004/04/23 20:35:50 momjian Exp $
* *
* This program tests to see if your standard libc functions use * This program tests to see if your standard libc functions use
* pthread_setspecific()/pthread_getspecific() to be thread-safe. * pthread_setspecific()/pthread_getspecific() to be thread-safe.
...@@ -33,188 +33,210 @@ ...@@ -33,188 +33,210 @@
#include "postgres.h" #include "postgres.h"
void func_call_1(void); void func_call_1(void);
void func_call_2(void); void func_call_2(void);
char myhostname[MAXHOSTNAMELEN]; pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
volatile int errno1_set = 0;
volatile int errno2_set = 0;
volatile int thread1_done = 0; volatile int thread1_done = 0;
volatile int thread2_done = 0; volatile int thread2_done = 0;
char *strerror_p1; volatile int errno1_set = 0;
char *strerror_p2; volatile int errno2_set = 0;
#ifndef HAVE_STRERROR_R
char *strerror_p1;
char *strerror_p2;
bool strerror_threadsafe = false;
#endif
#ifndef HAVE_GETPWUID_R
struct passwd *passwd_p1; struct passwd *passwd_p1;
struct passwd *passwd_p2; struct passwd *passwd_p2;
bool getpwuid_threadsafe = false;
#endif
#if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
struct hostent *hostent_p1; struct hostent *hostent_p1;
struct hostent *hostent_p2; struct hostent *hostent_p2;
char myhostname[MAXHOSTNAMELEN];
bool gethostbyname_threadsafe = false;
#endif
bool gethostbyname_threadsafe = false; bool platform_is_threadsafe = true;
bool getpwuid_threadsafe = false;
bool strerror_threadsafe = false;
bool platform_is_threadsafe = true;
pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
int main(int argc, char *argv[]) int
main(int argc, char *argv[])
{ {
pthread_t thread1, pthread_t thread1,
thread2; thread2;
if (argc > 1) if (argc > 1)
{ {
fprintf(stderr, "Usage: %s\n", argv[0]); fprintf(stderr, "Usage: %s\n", argv[0]);
return 1; return 1;
} }
#if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
if (gethostname(myhostname, MAXHOSTNAMELEN) != 0) if (gethostname(myhostname, MAXHOSTNAMELEN) != 0)
{ {
fprintf(stderr, "can not get local hostname, exiting\n"); fprintf(stderr, "can not get local hostname, exiting\n");
exit(1); exit(1);
} }
#endif
printf("\
Make sure you have added any needed 'PTHREAD_CFLAGS' and 'PTHREAD_LIBS'\n\
defines to your template/$port file before compiling this program.\n\n"
);
/* Hold lock until we are ready for the child threads to exit. */ /* Hold lock until we are ready for the child threads to exit. */
pthread_mutex_lock(&init_mutex); pthread_mutex_lock(&init_mutex);
pthread_create(&thread1, NULL, (void * (*)(void *)) func_call_1, NULL); pthread_create(&thread1, NULL, (void *(*) (void *)) func_call_1, NULL);
pthread_create(&thread2, NULL, (void * (*)(void *)) func_call_2, NULL); pthread_create(&thread2, NULL, (void *(*) (void *)) func_call_2, NULL);
while (thread1_done == 0 || thread2_done == 0) while (thread1_done == 0 || thread2_done == 0)
sched_yield(); /* if this is a portability problem, remove it */ sched_yield(); /* if this is a portability problem,
* remove it */
fprintf(stderr, "errno is thread-safe\n"); fprintf(stderr, "Your errno is thread-safe.\n");
#ifndef HAVE_STRERROR_R
if (strerror_p1 != strerror_p2) if (strerror_p1 != strerror_p2)
strerror_threadsafe = true; strerror_threadsafe = true;
#endif
#ifndef HAVE_GETPWUID_R
if (passwd_p1 != passwd_p2) if (passwd_p1 != passwd_p2)
getpwuid_threadsafe = true; getpwuid_threadsafe = true;
#endif
#if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
if (hostent_p1 != hostent_p2) if (hostent_p1 != hostent_p2)
gethostbyname_threadsafe = true; gethostbyname_threadsafe = true;
#endif
pthread_mutex_unlock(&init_mutex); /* let children exit */ pthread_mutex_unlock(&init_mutex); /* let children exit */
pthread_join(thread1, NULL); /* clean up children */ pthread_join(thread1, NULL); /* clean up children */
pthread_join(thread2, NULL); pthread_join(thread2, NULL);
printf("\n");
#ifdef HAVE_STRERROR_R #ifdef HAVE_STRERROR_R
printf("Your system has sterror_r(), so it doesn't use strerror().\n"); printf("Your system has sterror_r(); it does not need strerror().\n");
#else #else
printf("Your system uses strerror() which is "); printf("Your system uses strerror() which is ");
if (strerror_threadsafe) if (strerror_threadsafe)
printf("thread-safe.\n"); printf("thread-safe.\n");
else else
{ {
platform_is_threadsafe = false;
printf("not thread-safe.\n"); printf("not thread-safe.\n");
platform_is_threadsafe = false;
} }
#endif #endif
#ifdef HAVE_GETPWUID_R #ifdef HAVE_GETPWUID_R
printf("Your system has getpwuid_r(), so it doesn't use getpwuid().\n"); printf("Your system has getpwuid_r(); it does not need getpwuid().\n");
#else #else
printf("Your system uses getpwuid() which is "); printf("Your system uses getpwuid() which is ");
if (getpwuid_threadsafe) if (getpwuid_threadsafe)
printf("thread-safe.\n"); printf("thread-safe.\n");
else else
{ {
platform_is_threadsafe = false;
printf("not thread-safe.\n"); printf("not thread-safe.\n");
platform_is_threadsafe = false;
} }
#endif #endif
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
printf("Your system has getaddrinfo(), so it doesn't use gethostbyname()\n" printf("Your system has getaddrinfo(); it does not need gethostbyname()\n"
" or gethostbyname_r().\n"); " or gethostbyname_r().\n");
#else #else
#ifdef HAVE_GETHOSTBYNAME_R #ifdef HAVE_GETHOSTBYNAME_R
printf("Your system has gethostbyname_r(), so it doesn't use gethostbyname().\n"); printf("Your system has gethostbyname_r(); it does not need gethostbyname().\n");
#else #else
printf("Your system uses gethostbyname which is "); printf("Your system uses gethostbyname which is ");
if (gethostbyname_threadsafe) if (gethostbyname_threadsafe)
printf("thread-safe.\n"); printf("thread-safe.\n");
else else
{ {
platform_is_threadsafe = false;
printf("not thread-safe.\n"); printf("not thread-safe.\n");
platform_is_threadsafe = false;
} }
#endif #endif
#endif #endif
if (!platform_is_threadsafe) if (platform_is_threadsafe)
{ {
printf("\n** YOUR PLATFORM IS NOT THREADSAFE **\n"); printf("\nYour platform is thread-safe.\n");
return 1; return 0;
} }
else else
{ {
printf("\nYOUR PLATFORM IS THREADSAFE\n"); printf("\n** YOUR PLATFORM IS NOT THREAD-SAFE. **\n");
return 0; return 1;
} }
} }
void func_call_1(void) { void
void *p; func_call_1(void)
{
#if !defined(HAVE_GETPWUID_R) || \
(!defined(HAVE_GETADDRINFO) && \
!defined(HAVE_GETHOSTBYNAME_R))
void *p;
#endif
unlink("/tmp/thread_test.1"); unlink("/tmp/thread_test.1");
/* create, then try to fail on exclusive create open */ /* create, then try to fail on exclusive create open */
if (open("/tmp/thread_test.1", O_RDWR | O_CREAT, 0600) < 0 || if (open("/tmp/thread_test.1", O_RDWR | O_CREAT, 0600) < 0 ||
open("/tmp/thread_test.1", O_RDWR | O_CREAT | O_EXCL, 0600) >= 0) open("/tmp/thread_test.1", O_RDWR | O_CREAT | O_EXCL, 0600) >= 0)
{ {
fprintf(stderr, "Could not create file in /tmp or\n"); fprintf(stderr, "Could not create file in /tmp or\n");
fprintf(stderr, "could not generate failure for create file in /tmp, exiting\n"); fprintf(stderr, "could not generate failure for create file in /tmp, exiting\n");
exit(1); exit(1);
} }
/* /*
* Wait for other thread to set errno. * Wait for other thread to set errno. We can't use thread-specific
* We can't use thread-specific locking here because it might * locking here because it might affect errno.
* affect errno.
*/ */
errno1_set = 1; errno1_set = 1;
while (errno2_set == 0) while (errno2_set == 0)
sched_yield(); sched_yield();
if (errno != EEXIST) if (errno != EEXIST)
{ {
fprintf(stderr, "errno not thread-safe; exiting\n"); fprintf(stderr, "errno not thread-safe; exiting\n");
unlink("/tmp/thread_test.1"); unlink("/tmp/thread_test.1");
exit(1); exit(1);
} }
unlink("/tmp/thread_test.1"); unlink("/tmp/thread_test.1");
#ifndef HAVE_STRERROR_R
strerror_p1 = strerror(EACCES); strerror_p1 = strerror(EACCES);
/* /*
* If strerror() uses sys_errlist, the pointer might change for different * If strerror() uses sys_errlist, the pointer might change for
* errno values, so we don't check to see if it varies within the thread. * different errno values, so we don't check to see if it varies
* within the thread.
*/ */
#endif
#ifndef HAVE_GETPWUID_R
passwd_p1 = getpwuid(0); passwd_p1 = getpwuid(0);
p = getpwuid(1); p = getpwuid(1);
if (passwd_p1 != p) if (passwd_p1 != p)
{ {
printf("Your getpwuid() changes the static memory area between calls\n"); printf("Your getpwuid() changes the static memory area between calls\n");
passwd_p1 = NULL; /* force thread-safe failure report */ passwd_p1 = NULL; /* force thread-safe failure report */
} }
#endif
#if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
/* threads do this in opposite order */ /* threads do this in opposite order */
hostent_p1 = gethostbyname(myhostname); hostent_p1 = gethostbyname(myhostname);
p = gethostbyname("localhost"); p = gethostbyname("localhost");
if (hostent_p1 != p) if (hostent_p1 != p)
{ {
printf("Your gethostbyname() changes the static memory area between calls\n"); printf("Your gethostbyname() changes the static memory area between calls\n");
hostent_p1 = NULL; /* force thread-safe failure report */ hostent_p1 = NULL; /* force thread-safe failure report */
} }
#endif
thread1_done = 1; thread1_done = 1;
pthread_mutex_lock(&init_mutex); /* wait for parent to test */ pthread_mutex_lock(&init_mutex); /* wait for parent to test */
...@@ -222,54 +244,68 @@ void func_call_1(void) { ...@@ -222,54 +244,68 @@ void func_call_1(void) {
} }
void func_call_2(void) { void
void *p; func_call_2(void)
{
#if !defined(HAVE_GETPWUID_R) || \
(!defined(HAVE_GETADDRINFO) && \
!defined(HAVE_GETHOSTBYNAME_R))
void *p;
#endif
unlink("/tmp/thread_test.2"); unlink("/tmp/thread_test.2");
/* open non-existant file */ /* open non-existant file */
if (open("/tmp/thread_test.2", O_RDONLY, 0600) >= 0) if (open("/tmp/thread_test.2", O_RDONLY, 0600) >= 0)
{ {
fprintf(stderr, "Read-only open succeeded without create, exiting\n"); fprintf(stderr, "Read-only open succeeded without create, exiting\n");
exit(1); exit(1);
} }
/* /*
* Wait for other thread to set errno. * Wait for other thread to set errno. We can't use thread-specific
* We can't use thread-specific locking here because it might * locking here because it might affect errno.
* affect errno.
*/ */
errno2_set = 1; errno2_set = 1;
while (errno1_set == 0) while (errno1_set == 0)
sched_yield(); sched_yield();
if (errno != ENOENT) if (errno != ENOENT)
{ {
fprintf(stderr, "errno not thread-safe; exiting\n"); fprintf(stderr, "errno not thread-safe; exiting\n");
unlink("/tmp/thread_test.A"); unlink("/tmp/thread_test.A");
exit(1); exit(1);
} }
unlink("/tmp/thread_test.2"); unlink("/tmp/thread_test.2");
#ifndef HAVE_STRERROR_R
strerror_p2 = strerror(EINVAL); strerror_p2 = strerror(EINVAL);
/* /*
* If strerror() uses sys_errlist, the pointer might change for different * If strerror() uses sys_errlist, the pointer might change for
* errno values, so we don't check to see if it varies within the thread. * different errno values, so we don't check to see if it varies
* within the thread.
*/ */
#endif
#ifndef HAVE_GETPWUID_R
passwd_p2 = getpwuid(2); passwd_p2 = getpwuid(2);
p = getpwuid(3); p = getpwuid(3);
if (passwd_p2 != p) if (passwd_p2 != p)
{ {
printf("Your getpwuid() changes the static memory area between calls\n"); printf("Your getpwuid() changes the static memory area between calls\n");
passwd_p2 = NULL; /* force thread-safe failure report */ passwd_p2 = NULL; /* force thread-safe failure report */
} }
#endif
#if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
/* threads do this in opposite order */ /* threads do this in opposite order */
hostent_p2 = gethostbyname("localhost"); hostent_p2 = gethostbyname("localhost");
p = gethostbyname(myhostname); p = gethostbyname(myhostname);
if (hostent_p2 != p) if (hostent_p2 != p)
{ {
printf("Your gethostbyname() changes the static memory area between calls\n"); printf("Your gethostbyname() changes the static memory area between calls\n");
hostent_p2 = NULL; /* force thread-safe failure report */ hostent_p2 = NULL; /* force thread-safe failure report */
} }
#endif
thread2_done = 1; thread2_done = 1;
pthread_mutex_lock(&init_mutex); /* wait for parent to test */ pthread_mutex_lock(&init_mutex); /* wait for parent to test */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment