From b041d3e3a17331f9fc76509a577c6ed63067aded Mon Sep 17 00:00:00 2001 From: Bruce Momjian <bruce@momjian.us> Date: Sat, 13 Sep 2003 14:49:51 +0000 Subject: [PATCH] Attempt 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 New to this patch is the last option. --- configure.in | 11 +-- src/include/port.h | 10 +-- src/port/thread.c | 173 +++++++++++++++++++++++++++++++++++++----- src/template/bsdi | 2 +- src/template/freebsd | 4 +- src/template/linux | 2 +- src/template/netbsd | 2 +- src/template/osf | 2 +- src/template/solaris | 5 ++ src/template/unixware | 2 +- 10 files changed, 176 insertions(+), 37 deletions(-) diff --git a/configure.in b/configure.in index 62c14eeb286..9ca208f5f3f 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -dnl $Header: /cvsroot/pgsql/configure.in,v 1.287 2003/09/12 16:10:26 momjian Exp $ +dnl $Header: /cvsroot/pgsql/configure.in,v 1.288 2003/09/13 14:49:51 momjian Exp $ dnl dnl Developers, please strive to achieve this order: dnl @@ -1031,17 +1031,12 @@ AC_SUBST(THREAD_LIBS) # One trick here is that if we don't call AC_CHECK_FUNCS, the # functions are marked "not found", which is perfect. # -if test "$enable_thread_safety" = yes -a "$NEED_REENTRANT_FUNC_NAMES" = yes ; then +if test "$enable_thread_safety" = yes -a "$NEED_REENTRANT_FUNCS" = yes ; then _CFLAGS="$CFLAGS" _LIBS="$LIBS" CFLAGS="$CFLAGS $THREAD_CFLAGS" LIBS="$LIBS $THREAD_LIBS" -AC_CHECK_FUNC(strerror_r, - [], [AC_MSG_ERROR([strerror_r not found, required on this platform for --enable-thread-safety])]) -AC_CHECK_FUNC(getpwuid_r, - [], [AC_MSG_ERROR([getpwuid_r not found, required on this platform for --enable-thread-safety])]) -AC_CHECK_FUNC(gethostbyname_r, - [], [AC_MSG_ERROR([gethostbyname_r not found, required on this platform for --enable-thread-safety])]) +AC_CHECK_FUNCS([strerror_r getpwuid_r gethostbyname_r]) CFLAGS="$_CFLAGS" LIBS="$_LIBS" fi diff --git a/src/include/port.h b/src/include/port.h index 6b801ba424a..d77dd652f15 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: port.h,v 1.13 2003/09/05 17:43:39 momjian Exp $ + * $Id: port.h,v 1.14 2003/09/13 14:49:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -114,11 +114,11 @@ extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen); #ifndef WIN32 extern int pqGetpwuid(uid_t uid, struct passwd * resultbuf, char *buffer, - size_t buflen, struct passwd ** result); + size_t buflen, struct passwd **result); #endif extern int pqGethostbyname(const char *name, - struct hostent * resbuf, - char *buf, size_t buflen, - struct hostent ** result, + struct hostent *resultbuf, + char *buffer, size_t buflen, + struct hostent **result, int *herrno); diff --git a/src/port/thread.c b/src/port/thread.c index c00202a0631..193b2e0808b 100644 --- a/src/port/thread.c +++ b/src/port/thread.c @@ -7,19 +7,24 @@ * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * - * $Id: thread.c,v 1.6 2003/09/05 17:43:40 momjian Exp $ + * $Id: thread.c,v 1.7 2003/09/13 14:49:51 momjian Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include <pthread.h> +#include <sys/types.h> +#include <pwd.h> + /* * 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. + * 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 @@ -36,11 +41,15 @@ * doesn't have strerror_r(), so we can't fall back to only using *_r * functions for threaded programs. * - * The current setup is to assume either all standard functions are - * thread-safe (NEED_REENTRANT_FUNC_NAMES=no), or the operating system - * requires reentrant function names (NEED_REENTRANT_FUNC_NAMES=yes). + * 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 + * * Compile and run src/tools/test_thread_funcs.c to see if your operating - * system requires reentrant function names. + * system has thread-safe non-*_r functions. */ @@ -51,14 +60,27 @@ char * pqStrerror(int errnum, char *strerrbuf, size_t buflen) { -#if defined(USE_THREADS) && defined(NEED_REENTRANT_FUNC_NAMES) +#if defined(FRONTEND) && defined(USE_THREADS) && 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); + return strerrbuf; + #else + +#if defined(FRONTEND) && defined(USE_THREADS) && 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 */ - return strerror(errnum); + StrNCpy(strerrbuf, strerror(errnum), buflen); + +#if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_STRERROR_R) + pthread_mutex_unlock(&strerror_lock); +#endif + + return strerrbuf; #endif } @@ -71,7 +93,7 @@ int pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result) { -#if defined(USE_THREADS) && defined(NEED_REENTRANT_FUNC_NAMES) +#if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_GETPWUID_R) /* * Early POSIX draft of getpwuid_r() returns 'struct passwd *'. * getpwuid_r(uid, resultbuf, buffer, buflen) @@ -79,9 +101,52 @@ pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer, */ /* POSIX version */ getpwuid_r(uid, resultbuf, buffer, buflen, result); + #else + +#if defined(FRONTEND) && defined(USE_THREADS) && 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(USE_THREADS) && 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; + + pthread_mutex_unlock(&getpwuid_lock); +#endif #endif return (*result == NULL) ? -1 : 0; } @@ -93,27 +158,101 @@ pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer, */ int pqGethostbyname(const char *name, - struct hostent *resbuf, - char *buf, size_t buflen, + struct hostent *resultbuf, + char *buffer, size_t buflen, struct hostent **result, int *herrno) { -#if defined(USE_THREADS) && defined(NEED_REENTRANT_FUNC_NAMES) +#if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && defined(HAVE_GETHOSTBYNAME_R) /* * broken (well early POSIX draft) gethostbyname_r() which returns * 'struct hostent *' */ - *result = gethostbyname_r(name, resbuf, buf, buflen, herrno); + *result = gethostbyname_r(name, resbuf, buffer, buflen, herrno); return (*result == NULL) ? -1 : 0; + #else + +#if defined(FRONTEND) && defined(USE_THREADS) && 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(USE_THREADS) && 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 (MAXALIGN(len) + pointers * sizeof(char *) + 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 */ + strcpy(buffer, (*result)->h_name); + resultbuf->h_name = buffer; + buffer += strlen(resultbuf->h_name) + 1; + + *result = resultbuf; + } + else + *result = NULL; + } +#endif + + if (*result != NULL) + *herrno = h_errno; + +#if defined(FRONTEND) && defined(USE_THREADS) && defined(NEED_REENTRANT_FUNCS) && !defined(HAVE_GETHOSTBYNAME_R) + pthread_mutex_unlock(&gethostbyname_lock); +#endif + if (*result != NULL) return 0; else - { - *herrno = h_errno; return -1; - } #endif } diff --git a/src/template/bsdi b/src/template/bsdi index ba2d27247e4..d6b16a2417d 100644 --- a/src/template/bsdi +++ b/src/template/bsdi @@ -11,4 +11,4 @@ case $host_os in esac SUPPORTS_THREADS=yes -NEED_REENTRANT_FUNC_NAMES=no # verified 4.3 2003-09-03 +NEED_REENTRANT_FUNCS=no # verified 4.3 2003-09-03 diff --git a/src/template/freebsd b/src/template/freebsd index 9e5cc6d0128..71e50140660 100644 --- a/src/template/freebsd +++ b/src/template/freebsd @@ -4,8 +4,8 @@ case $host_cpu in alpha*) CFLAGS="$CFLAGS -O" ;; esac -SUPPORTS_THREADS=no # 4.8, 5.1 2003-09-12 -NEED_REENTRANT_FUNC_NAMES=no +SUPPORTS_THREADS=yes +NEED_REENTRANT_FUNCS=yes # 4.8, 5.1 2003-09-12 case $host_os in freebsd2*|freebsd3*|freebsd4*) diff --git a/src/template/linux b/src/template/linux index db13803710e..0aab11631f5 100644 --- a/src/template/linux +++ b/src/template/linux @@ -1,7 +1,7 @@ CFLAGS=-O2 SUPPORTS_THREADS=yes -NEED_REENTRANT_FUNC_NAMES=yes # verified glibc 2.1 2003-09-03 +NEED_REENTRANT_FUNCS=yes # verified glibc 2.1 2003-09-03 THREAD_CFLAGS="-D_REENTRANT -D_THREAD_SAFE -D_POSIX_PTHREAD_SEMANTICS" THREAD_LIBS="-lpthread" diff --git a/src/template/netbsd b/src/template/netbsd index 9a3869dfe77..72e1d624c4a 100644 --- a/src/template/netbsd +++ b/src/template/netbsd @@ -1,4 +1,4 @@ CFLAGS='-O2 -pipe' SUPPORTS_THREADS=yes -NEED_REENTRANT_FUNC_NAMES=no +NEED_REENTRANT_FUNCS=no diff --git a/src/template/osf b/src/template/osf index a930bf4e08e..7305395a0b2 100644 --- a/src/template/osf +++ b/src/template/osf @@ -6,5 +6,5 @@ else fi SUPPORTS_THREADS=yes -NEED_REENTRANT_FUNC_NAMES=no +NEED_REENTRANT_FUNCS=no # 4.0 2003-09-13 THREAD_CFLAGS="-pthread" diff --git a/src/template/solaris b/src/template/solaris index 33d40cfb87c..d839f935ccb 100644 --- a/src/template/solaris +++ b/src/template/solaris @@ -4,3 +4,8 @@ else CC="$CC -Xa" # relaxed ISO C mode CFLAGS=-v # -v is like gcc -Wall fi + +SUPPORTS_THREADS=yes +NEED_REENTRANT_FUNCS=yes # 5.6 2003-09-13 +THREAD_CFLAGS="-pthread" + diff --git a/src/template/unixware b/src/template/unixware index 9cfde833c92..21d4314d87d 100644 --- a/src/template/unixware +++ b/src/template/unixware @@ -10,5 +10,5 @@ else fi SUPPORTS_THREADS=yes -NEED_REENTRANT_FUNC_NAMES=no # verified 7.1.3 2003-09-03 +NEED_REENTRANT_FUNCS=no # verified 7.1.3 2003-09-03 THREAD_CFLAGS="$THREAD_CFLAGS -D_REENTRANT" -- GitLab