Header And Logo

PostgreSQL
| The world's most advanced open source database.

thread.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * thread.c
00004  *
00005  *        Prototypes and macros around system calls, used to help make
00006  *        threaded libraries reentrant and safe to use from threaded applications.
00007  *
00008  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00009  *
00010  * src/port/thread.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 
00015 #include "c.h"
00016 
00017 #include <pwd.h>
00018 
00019 
00020 /*
00021  *  Threading sometimes requires specially-named versions of functions
00022  *  that return data in static buffers, like strerror_r() instead of
00023  *  strerror().  Other operating systems use pthread_setspecific()
00024  *  and pthread_getspecific() internally to allow standard library
00025  *  functions to return static data to threaded applications. And some
00026  *  operating systems have neither.
00027  *
00028  *  Additional confusion exists because many operating systems that
00029  *  use pthread_setspecific/pthread_getspecific() also have *_r versions
00030  *  of standard library functions for compatibility with operating systems
00031  *  that require them.  However, internally, these *_r functions merely
00032  *  call the thread-safe standard library functions.
00033  *
00034  *  For example, BSD/OS 4.3 uses Bind 8.2.3 for getpwuid().  Internally,
00035  *  getpwuid() calls pthread_setspecific/pthread_getspecific() to return
00036  *  static data to the caller in a thread-safe manner.  However, BSD/OS
00037  *  also has getpwuid_r(), which merely calls getpwuid() and shifts
00038  *  around the arguments to match the getpwuid_r() function declaration.
00039  *  Therefore, while BSD/OS has getpwuid_r(), it isn't required.  It also
00040  *  doesn't have strerror_r(), so we can't fall back to only using *_r
00041  *  functions for threaded programs.
00042  *
00043  *  The current setup is to try threading in this order:
00044  *
00045  *      use *_r function names if they exit
00046  *          (*_THREADSAFE=yes)
00047  *      use non-*_r functions if they are thread-safe
00048  *
00049  *  One thread-safe solution for gethostbyname() might be to use getaddrinfo().
00050  *
00051  *  Run src/test/thread to test if your operating system has thread-safe
00052  *  non-*_r functions.
00053  */
00054 
00055 
00056 /*
00057  * Wrapper around strerror and strerror_r to use the former if it is
00058  * available and also return a more useful value (the error string).
00059  */
00060 char *
00061 pqStrerror(int errnum, char *strerrbuf, size_t buflen)
00062 {
00063 #if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_STRERROR_R)
00064     /* reentrant strerror_r is available */
00065 #ifdef STRERROR_R_INT
00066     /* SUSv3 version */
00067     if (strerror_r(errnum, strerrbuf, buflen) == 0)
00068         return strerrbuf;
00069     else
00070         return "Unknown error";
00071 #else
00072     /* GNU libc */
00073     return strerror_r(errnum, strerrbuf, buflen);
00074 #endif
00075 #else
00076     /* no strerror_r() available, just use strerror */
00077     strlcpy(strerrbuf, strerror(errnum), buflen);
00078 
00079     return strerrbuf;
00080 #endif
00081 }
00082 
00083 /*
00084  * Wrapper around getpwuid() or getpwuid_r() to mimic POSIX getpwuid_r()
00085  * behaviour, if it is not available or required.
00086  */
00087 #ifndef WIN32
00088 int
00089 pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer,
00090            size_t buflen, struct passwd ** result)
00091 {
00092 #if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETPWUID_R)
00093 
00094 #ifdef GETPWUID_R_5ARG
00095     /* POSIX version */
00096     getpwuid_r(uid, resultbuf, buffer, buflen, result);
00097 #else
00098 
00099     /*
00100      * Early POSIX draft of getpwuid_r() returns 'struct passwd *'.
00101      * getpwuid_r(uid, resultbuf, buffer, buflen)
00102      */
00103     *result = getpwuid_r(uid, resultbuf, buffer, buflen);
00104 #endif
00105 #else
00106 
00107     /* no getpwuid_r() available, just use getpwuid() */
00108     *result = getpwuid(uid);
00109 #endif
00110 
00111     return (*result == NULL) ? -1 : 0;
00112 }
00113 #endif
00114 
00115 /*
00116  * Wrapper around gethostbyname() or gethostbyname_r() to mimic
00117  * POSIX gethostbyname_r() behaviour, if it is not available or required.
00118  * This function is called _only_ by our getaddinfo() portability function.
00119  */
00120 #ifndef HAVE_GETADDRINFO
00121 int
00122 pqGethostbyname(const char *name,
00123                 struct hostent * resultbuf,
00124                 char *buffer, size_t buflen,
00125                 struct hostent ** result,
00126                 int *herrno)
00127 {
00128 #if defined(FRONTEND) && defined(ENABLE_THREAD_SAFETY) && defined(HAVE_GETHOSTBYNAME_R)
00129 
00130     /*
00131      * broken (well early POSIX draft) gethostbyname_r() which returns 'struct
00132      * hostent *'
00133      */
00134     *result = gethostbyname_r(name, resultbuf, buffer, buflen, herrno);
00135     return (*result == NULL) ? -1 : 0;
00136 #else
00137 
00138     /* no gethostbyname_r(), just use gethostbyname() */
00139     *result = gethostbyname(name);
00140 
00141     if (*result != NULL)
00142         *herrno = h_errno;
00143 
00144     if (*result != NULL)
00145         return 0;
00146     else
00147         return -1;
00148 #endif
00149 }
00150 
00151 #endif