diff options
Diffstat (limited to 'src/port/thread.c')
-rw-r--r-- | src/port/thread.c | 173 |
1 files changed, 156 insertions, 17 deletions
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 } |