Rename USE_THREADS to ENABLE_THREAD_SAFETY to avoid name clash with Perl.
authorPeter Eisentraut <peter_e@gmx.net>
Mon, 24 Nov 2003 13:11:27 +0000 (13:11 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Mon, 24 Nov 2003 13:11:27 +0000 (13:11 +0000)
Fixes compliation failure with --enable-thread-safety --with-perl and Perl
5.6.1.

configure
configure.in
src/include/pg_config.h.in
src/interfaces/ecpg/ecpglib/connect.c
src/interfaces/ecpg/ecpglib/misc.c
src/port/thread.c [new file with mode: 0644]
src/tools/thread/thread_test.c [new file with mode: 0644]

index 14fcc499168e06f7e372a8071065bd86c4691f15..c4cd0ec594ff818b5c5be176a8c645dfe5ff7684 100755 (executable)
--- a/configure
+++ b/configure
@@ -2909,7 +2909,7 @@ if test "${enable_thread_safety+set}" = set; then
     yes)
 
 cat >>confdefs.h <<\_ACEOF
-#define USE_THREADS 1
+#define ENABLE_THREAD_SAFETY 1
 _ACEOF
 
       ;;
index 3b40440787c315ca314966c8e5affacc2592796a..639f1f96959c54a09eae33e4f1af86fb2810635a 100644 (file)
@@ -351,7 +351,7 @@ IFS=$ac_save_IFS
 #
 AC_MSG_CHECKING([allow thread-safe client libraries])
 PGAC_ARG_BOOL(enable, thread-safety, no, [  --enable-thread-safety  make client libraries thread-safe],
-              [AC_DEFINE([USE_THREADS], 1,
+              [AC_DEFINE([ENABLE_THREAD_SAFETY], 1,
                          [Define to 1 to build client libraries as thread-safe code. (--enable-thread-safety)])])
 AC_MSG_RESULT([$enable_thread_safety])
 AC_SUBST(enable_thread_safety)
index cce536adb2d8d5a9caac761b02e42efef1a08160..b53fed22572ed85e0490530b6bd650c0457ad0e2 100644 (file)
 /* Define to 1 if you want National Language Support. (--enable-nls) */
 #undef ENABLE_NLS
 
+/* Define to 1 to build client libraries as thread-safe code.
+   (--enable-thread-safety) */
+#undef ENABLE_THREAD_SAFETY
+
 /* Define to 1 if gettimeofday() takes only 1 argument. */
 #undef GETTIMEOFDAY_1ARG
 
 /* Define to select SysV-style shared memory. */
 #undef USE_SYSV_SHARED_MEMORY
 
-/* Define to 1 to build client libraries as thread-safe code.
-   (--enable-thread-safety) */
-#undef USE_THREADS
-
 /* Define to select unnamed POSIX semaphores. */
 #undef USE_UNNAMED_POSIX_SEMAPHORES
 
index 7a76a2f56a8792c6d2a598bb85205fc0f4ed9987..6c37aed4c1a9fa975983ca162293d9562dcfbc22 100644 (file)
@@ -3,7 +3,7 @@
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
 #include <pthread.h>
 #endif
 #include "ecpgtype.h"
@@ -12,7 +12,7 @@
 #include "extern.h"
 #include "sqlca.h"
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
 static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
 #endif
 static struct connection *all_connections = NULL;
@@ -45,13 +45,13 @@ ECPGget_connection(const char *connection_name)
 {
        struct connection *ret = NULL;
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_lock(&connections_mutex);
 #endif
 
        ret = ecpg_get_connection_nr(connection_name);
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_unlock(&connections_mutex);
 #endif
 
@@ -355,7 +355,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
                realname = strdup(dbname);
 
        /* add connection to our list */
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_lock(&connections_mutex);
 #endif
        if (connection_name != NULL)
@@ -387,7 +387,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
                char       *db = realname ? realname : "<DEFAULT>";
 
                ecpg_finish(this);
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
                pthread_mutex_unlock(&connections_mutex);
 #endif
                ECPGlog("connect: could not open database %s on %s port %s %s%s%s%s in line %d\n\t%s\n",
@@ -411,7 +411,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
                        ECPGfree(dbname);
                return false;
        }
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_unlock(&connections_mutex);
 #endif
 
@@ -440,7 +440,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
        struct sqlca_t *sqlca = ECPGget_sqlca();
        struct connection *con;
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_lock(&connections_mutex);
 #endif
 
@@ -461,7 +461,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
 
                if (!ECPGinit(con, connection_name, lineno))
                {
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
                        pthread_mutex_unlock(&connections_mutex);
 #endif
                        return (false);
@@ -470,7 +470,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
                        ecpg_finish(con);
        }
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_unlock(&connections_mutex);
 #endif
 
index ffca6327d94ca6f0b700d92efec346736007204c..0a50f50961883c6b8fdc5ae42a43d0267d56dc73 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <limits.h>
 #include <unistd.h>
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
 #include <pthread.h>
 #endif
 #include "ecpgtype.h"
@@ -55,7 +55,7 @@ static struct sqlca_t sqlca_init =
        }
 };
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
 static pthread_key_t sqlca_key;
 static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
 
@@ -88,7 +88,7 @@ static struct sqlca_t sqlca =
 };
 #endif
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
 static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
 #endif
@@ -117,7 +117,7 @@ ECPGinit(const struct connection * con, const char *connection_name, const int l
        return (true);
 }
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
 static void
 ecpg_sqlca_key_init(void)
 {
@@ -128,7 +128,7 @@ ecpg_sqlca_key_init(void)
 struct sqlca_t *
 ECPGget_sqlca(void)
 {
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        struct sqlca_t *sqlca;
 
        pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
@@ -211,7 +211,7 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction)
 void
 ECPGdebug(int n, FILE *dbgs)
 {
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_lock(&debug_init_mutex);
 #endif
 
@@ -219,7 +219,7 @@ ECPGdebug(int n, FILE *dbgs)
        debugstream = dbgs;
        ECPGlog("ECPGdebug: set to %d\n", simple_debug);
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_unlock(&debug_init_mutex);
 #endif
 }
@@ -229,7 +229,7 @@ ECPGlog(const char *format,...)
 {
        va_list         ap;
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_lock(&debug_mutex);
 #endif
 
@@ -239,7 +239,7 @@ ECPGlog(const char *format,...)
 
                if (f == NULL)
                {
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
                        pthread_mutex_unlock(&debug_mutex);
 #endif
                        return;
@@ -255,7 +255,7 @@ ECPGlog(const char *format,...)
                ECPGfree(f);
        }
 
-#ifdef USE_THREADS
+#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_unlock(&debug_mutex);
 #endif
 }
diff --git a/src/port/thread.c b/src/port/thread.c
new file mode 100644 (file)
index 0000000..962181a
--- /dev/null
@@ -0,0 +1,281 @@
+/*-------------------------------------------------------------------------
+ *
+ * thread.c
+ *
+ *               Prototypes and macros around system calls, used to help make
+ *               threaded libraries reentrant and safe to use from threaded applications.
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ *
+ * $Id$
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <sys/types.h>
+#include <errno.h>
+#if defined(WIN32) && defined(_MSC_VER)
+#undef ERROR
+#else
+#include <pwd.h>
+#endif
+#if defined(ENABLE_THREAD_SAFETY)
+#include <pthread.h>
+#endif
+
+/*
+ *     Threading sometimes requires specially-named versions of functions
+ *     that return data in static buffers, like strerror_r() instead of
+ *     strerror().  Other operating systems use pthread_setspecific()
+ *     and pthread_getspecific() internally to allow standard library
+ *     functions to return static data to threaded applications. And some
+ *     operating systems have neither, meaning we have to do our own locking.
+ *
+ *     Additional confusion exists because many operating systems that
+ *     use pthread_setspecific/pthread_getspecific() also have *_r versions
+ *     of standard library functions for compatibility with operating systems
+ *     that require them.  However, internally, these *_r functions merely
+ *     call the thread-safe standard library functions.
+ *
+ *     For example, BSD/OS 4.3 uses Bind 8.2.3 for getpwuid().  Internally,
+ *     getpwuid() calls pthread_setspecific/pthread_getspecific() to return
+ *     static data to the caller in a thread-safe manner.  However, BSD/OS
+ *     also has getpwuid_r(), which merely calls getpwuid() and shifts
+ *     around the arguments to match the getpwuid_r() function declaration.
+ *     Therefore, while BSD/OS has getpwuid_r(), it isn't required.  It also
+ *     doesn't have strerror_r(), so we can't fall back to only using *_r
+ *     functions for threaded programs.
+ *
+ *     The current setup is to try threading in this order:
+ *
+ *             use non-*_r function names if they are all thread-safe
+ *                     (NEED_REENTRANT_FUNCS=no)
+ *             use *_r functions if they exist (configure test)
+ *             do our own locking and copying of non-threadsafe functions
+ *
+ *     The disadvantage of the last option is not the thread overhead but
+ *     the fact that all function calls are serialized, and with gethostbyname()
+ *     requiring a DNS lookup, that could be slow.
+ *
+ *     One thread-safe solution for gethostbyname() might be to use getaddrinfo().
+ *
+ *     See src/tools/thread to see if your operating system has thread-safe
+ *     non-*_r functions.
+ */
+
+/*
+ * Wrapper around strerror and strerror_r to use the former if it is
+ * available and also return a more useful value (the error string).
+ */
+char *
+pqStrerror(int errnum, char *strerrbuf, size_t buflen)
+{
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_STRERROR_R)
+       /* reentrant strerror_r is available */
+       /* some early standards had strerror_r returning char * */
+       strerror_r(errnum, strerrbuf, buflen);
+       return strerrbuf;
+
+#else
+
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_STRERROR_R)
+       static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
+       pthread_mutex_lock(&strerror_lock);
+#endif
+
+       /* no strerror_r() available, just use strerror */
+       StrNCpy(strerrbuf, strerror(errnum), buflen);
+
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_STRERROR_R)
+       pthread_mutex_unlock(&strerror_lock);
+#endif
+
+       return strerrbuf;
+#endif
+}
+
+/*
+ * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
+ * behaviour, if it is not available or required.
+ */
+#ifndef WIN32
+int
+pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
+                  size_t buflen, struct passwd **result)
+{
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_GETPWUID_R)
+       /*
+        * Early POSIX draft of getpwuid_r() returns 'struct passwd *'.
+        *    getpwuid_r(uid, resultbuf, buffer, buflen)
+        * Do we need to support it?  bjm 2003-08-14
+        */
+       /* POSIX version */
+       getpwuid_r(uid, resultbuf, buffer, buflen, result);
+
+#else
+
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETPWUID_R)
+       static pthread_mutex_t getpwuid_lock = PTHREAD_MUTEX_INITIALIZER;
+       pthread_mutex_lock(&getpwuid_lock);
+#endif
+
+       /* no getpwuid_r() available, just use getpwuid() */
+       *result = getpwuid(uid);
+
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETPWUID_R)
+
+       /* Use 'buffer' memory for storage of strings used by struct passwd */
+       if (*result &&
+               strlen((*result)->pw_name) + 1 +
+               strlen((*result)->pw_passwd) + 1 +
+               strlen((*result)->pw_gecos) + 1 +
+               /* skip class if it exists */
+               strlen((*result)->pw_dir) + 1 +
+               strlen((*result)->pw_shell) + 1 <= buflen)
+       {
+               memcpy(resultbuf, *result, sizeof(struct passwd));
+               strcpy(buffer, (*result)->pw_name);
+               resultbuf->pw_name = buffer;
+               buffer += strlen(resultbuf->pw_name) + 1;
+               strcpy(buffer, (*result)->pw_passwd);
+               resultbuf->pw_passwd = buffer;
+               buffer += strlen(resultbuf->pw_passwd) + 1;
+               strcpy(buffer, (*result)->pw_gecos);
+               resultbuf->pw_gecos = buffer;
+               buffer += strlen(resultbuf->pw_gecos) + 1;
+               strcpy(buffer, (*result)->pw_dir);
+               resultbuf->pw_dir = buffer;
+               buffer += strlen(resultbuf->pw_dir) + 1;
+               strcpy(buffer, (*result)->pw_shell);
+               resultbuf->pw_shell = buffer;
+               buffer += strlen(resultbuf->pw_shell) + 1;
+
+               *result = resultbuf;
+       }
+       else
+       {
+               *result = NULL;
+               errno = ERANGE;
+       }
+
+       pthread_mutex_unlock(&getpwuid_lock);
+#endif
+#endif
+       return (*result == NULL) ? -1 : 0;
+}
+#endif
+
+/*
+ * Wrapper around gethostbyname() or gethostbyname_r() to mimic
+ * POSIX gethostbyname_r() behaviour, if it is not available or required.
+ * This function is called _only_ by our getaddinfo() portability function.
+ */
+#ifndef HAVE_GETADDRINFO
+int
+pqGethostbyname(const char *name,
+                               struct hostent *resultbuf,
+                               char *buffer, size_t buflen,
+                               struct hostent **result,
+                               int *herrno)
+{
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_GETHOSTBYNAME_R)
+       /*
+        * broken (well early POSIX draft) gethostbyname_r() which returns
+        * 'struct hostent *'
+        */
+       *result = gethostbyname_r(name, resbuf, buffer, buflen, herrno);
+       return (*result == NULL) ? -1 : 0;
+
+#else
+
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETHOSTBYNAME_R)
+       static pthread_mutex_t gethostbyname_lock = PTHREAD_MUTEX_INITIALIZER;
+       pthread_mutex_lock(&gethostbyname_lock);
+#endif
+
+       /* no gethostbyname_r(), just use gethostbyname() */
+       *result = gethostbyname(name);
+
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETHOSTBYNAME_R)
+
+       /*
+        *      Use 'buffer' memory for storage of structures used by struct hostent.
+        *      The layout is:
+        *
+        *              addr pointers
+        *              alias pointers
+        *              addr structures
+        *              alias structures
+        *              name
+        */
+       if (*result)
+       {
+               int             i, pointers = 2 /* for nulls */, len = 0;
+               char    **pbuffer;
+
+               for (i = 0; (*result)->h_addr_list[i]; i++, pointers++)
+                       len += (*result)->h_length;
+               for (i = 0; (*result)->h_aliases[i]; i++, pointers++)
+                       len += (*result)->h_length;
+
+               if (pointers * sizeof(char *) + MAXALIGN(len) + strlen((*result)->h_name) + 1 <= buflen)
+               {
+                       memcpy(resultbuf, *result, sizeof(struct hostent));
+
+               pbuffer = (char **)buffer;
+               resultbuf->h_addr_list = pbuffer;
+               buffer += pointers * sizeof(char *);
+
+                       for (i = 0; (*result)->h_addr_list[i]; i++, pbuffer++)
+                       {
+                               memcpy(buffer, (*result)->h_addr_list[i], (*result)->h_length);
+                       resultbuf->h_addr_list[i] = buffer;
+                       buffer += (*result)->h_length;
+               }
+                       resultbuf->h_addr_list[i] = NULL;
+                       pbuffer++;
+                           
+               resultbuf->h_aliases = pbuffer;
+
+                       for (i = 0; (*result)->h_aliases[i]; i++, pbuffer++)
+                       {
+                               memcpy(buffer, (*result)->h_aliases[i], (*result)->h_length);
+                       resultbuf->h_aliases[i] = buffer;
+                       buffer += (*result)->h_length;
+               }
+                       resultbuf->h_aliases[i] = NULL;
+                       pbuffer++;
+
+                       /* Place at end for cleaner alignment */                        
+                       buffer = MAXALIGN(buffer);
+                       strcpy(buffer, (*result)->h_name);
+                       resultbuf->h_name = buffer;
+                       buffer += strlen(resultbuf->h_name) + 1;
+
+                       *result = resultbuf;
+               }
+               else
+               {
+                       *result = NULL;
+                       errno = ERANGE;
+               }
+       }
+#endif
+
+       if (*result != NULL)
+               *herrno = h_errno;
+               
+#if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETHOSTBYNAME_R)
+       pthread_mutex_unlock(&gethostbyname_lock);
+#endif
+
+       if (*result != NULL)
+               return 0;
+       else
+               return -1;
+#endif
+}
+#endif
diff --git a/src/tools/thread/thread_test.c b/src/tools/thread/thread_test.c
new file mode 100644 (file)
index 0000000..20ef112
--- /dev/null
@@ -0,0 +1,155 @@
+/*-------------------------------------------------------------------------
+ *
+ * test_thread_funcs.c
+ *      libc thread test program
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *     $Header$
+ *
+ *     This program tests to see if your standard libc functions use
+ *     pthread_setspecific()/pthread_getspecific() to be thread-safe.
+ *     See src/port/thread.c for more details.
+ *
+ *     This program first tests to see if each function returns a constant
+ *     memory pointer within the same thread, then, assuming it does, tests
+ *     to see if the pointers are different for different threads.  If they
+ *     are, the function is thread-safe.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#ifdef ENABLE_THREAD_SAFETY
+#include <pthread.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <string.h>
+#include <errno.h>
+
+void func_call_1(void);
+void func_call_2(void);
+
+#ifndef HAVE_GETADDRINFO
+struct hostent *hostent_p1;
+struct hostent *hostent_p2;
+#endif
+
+struct passwd *passwd_p1;
+struct passwd *passwd_p2;
+
+char *strerror_p1;
+char *strerror_p2;
+
+int main(int argc, char *argv[])
+{
+       pthread_t               thread1,
+                                       thread2;
+
+       if (argc > 1)
+       {
+                       fprintf(stderr, "Usage: %s\n", argv[0]);
+                       return 1;
+       }
+
+       printf("\
+Make sure you have added any needed 'THREAD_CPPFLAGS' and 'THREAD_LIBS'\n\
+defines to your template/$port file before compiling this program.\n\n"
+);
+       pthread_create(&thread1, NULL, (void * (*)(void *)) func_call_1, NULL);
+       pthread_create(&thread2, NULL, (void * (*)(void *)) func_call_2, NULL);
+       pthread_join(thread1, NULL);
+       pthread_join(thread2, NULL);
+
+#ifndef HAVE_GETADDRINFO
+       if (hostent_p1 == hostent_p2)
+               printf("Your gethostbyname() is _not_ thread-safe\n");
+#endif
+       if (passwd_p1 == passwd_p2)
+               printf("Your getpwuid() is _not_ thread-safe\n");
+       if (strerror_p1 == strerror_p2)
+               printf("Your strerror() is _not_ thread-safe\n");
+
+       if (
+#ifndef HAVE_GETADDRINFO
+               hostent_p1 != hostent_p2 &&
+#endif
+               passwd_p1 != passwd_p2 &&
+               strerror_p1 != strerror_p2)
+       {
+               printf("All your non-*_r functions are thread-safe.\n");
+               printf("Add this to your template/$port file:\n\n");
+               printf("NEED_REENTRANT_FUNCS=no\n");
+       }
+       else
+       {
+               printf("Not all non-*_r functions are thread-safe.\n");
+               printf("Add this to your template/$port file:\n\n");
+               printf("NEED_REENTRANT_FUNCS=yes\n");
+       }
+
+       return 0;
+}
+
+void func_call_1(void) {
+       void *p;
+
+#ifndef HAVE_GETADDRINFO
+       hostent_p1 = gethostbyname("yahoo.com");
+       p = gethostbyname("slashdot.org");
+       if (hostent_p1 != p)
+       {
+               printf("Your gethostbyname() changes the static memory area between calls\n");
+               hostent_p1 = NULL;      /* force thread-safe failure report */
+       }
+#endif
+
+       passwd_p1 = getpwuid(0);
+       p = getpwuid(1);
+       if (passwd_p1 != p)
+       {
+               printf("Your getpwuid() changes the static memory area between calls\n");
+               passwd_p1 = NULL;       /* force thread-safe failure report */
+       }
+
+       strerror_p1 = strerror(EACCES);
+       /*
+        *      If strerror() uses sys_errlist, the pointer might change for different
+        *      errno values, so we don't check to see if it varies within the thread.
+        */
+}
+
+
+void func_call_2(void) {
+       void *p;
+
+#ifndef HAVE_GETADDRINFO
+       hostent_p2 = gethostbyname("google.com");
+       p = gethostbyname("postgresql.org");
+       if (hostent_p2 != p)
+       {
+               printf("Your gethostbyname() changes the static memory area between calls\n");
+               hostent_p2 = NULL;      /* force thread-safe failure report */
+       }
+#endif
+
+       passwd_p2 = getpwuid(2);
+       p = getpwuid(3);
+       if (passwd_p2 != p)
+       {
+               printf("Your getpwuid() changes the static memory area between calls\n");
+               passwd_p2 = NULL;       /* force thread-safe failure report */
+       }
+
+       strerror_p2 = strerror(EINVAL);
+       /*
+        *      If strerror() uses sys_errlist, the pointer might change for different
+        *      errno values, so we don't check to see if it varies within the thread.
+        */
+}