77 *
88 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
99 *
10- * $Id: thread.c,v 1.6 2003/09/05 17:43:40 momjian Exp $
10+ * $Id: thread.c,v 1.7 2003/09/13 14:49:51 momjian Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
1414
1515#include "postgres.h"
1616
17+ #include <pthread.h>
18+ #include <sys/types.h>
19+ #include <pwd.h>
20+
1721/*
1822 *Threading sometimes requires specially-named versions of functions
1923 *that return data in static buffers, like strerror_r() instead of
2024 *strerror(). Other operating systems use pthread_setspecific()
2125 *and pthread_getspecific() internally to allow standard library
22- *functions to return static data to threaded applications.
26+ *functions to return static data to threaded applications. And some
27+ *operating systems have neither, meaning we have to do our own locking.
2328 *
2429 *Additional confusion exists because many operating systems that
2530 *use pthread_setspecific/pthread_getspecific() also have *_r versions
3641 *doesn't have strerror_r(), so we can't fall back to only using *_r
3742 *functions for threaded programs.
3843 *
39- *The current setup is to assume either all standard functions are
40- *thread-safe (NEED_REENTRANT_FUNC_NAMES=no), or the operating system
41- *requires reentrant function names (NEED_REENTRANT_FUNC_NAMES=yes).
44+ *The current setup is to try threading in this order:
45+ *
46+ *use non-*_r function names if they are all thread-safe
47+ *(NEED_REENTRANT_FUNCS=no)
48+ *use *_r functions if they exist (configure test)
49+ *do our own locking and copying of non-threadsafe functions
50+ *
4251 *Compile and run src/tools/test_thread_funcs.c to see if your operating
43- *systemrequires reentrant function names .
52+ *systemhas thread-safe non-*_r functions .
4453 */
4554
4655
5160char *
5261pqStrerror (int errnum ,char * strerrbuf ,size_t buflen )
5362{
54- #if defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNC_NAMES )
63+ #if defined(FRONTEND ) && defined( USE_THREADS )&& defined(NEED_REENTRANT_FUNCS ) && defined( HAVE_STRERROR_R )
5564/* reentrant strerror_r is available */
5665/* some early standards had strerror_r returning char * */
5766strerror_r (errnum ,strerrbuf ,buflen );
58- return (strerrbuf );
67+ return strerrbuf ;
68+
5969#else
70+
71+ #if defined(FRONTEND )&& defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNCS )&& !defined(HAVE_STRERROR_R )
72+ static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER ;
73+ pthread_mutex_lock (& strerror_lock );
74+ #endif
75+
6076/* no strerror_r() available, just use strerror */
61- return strerror (errnum );
77+ StrNCpy (strerrbuf ,strerror (errnum ),buflen );
78+
79+ #if defined(FRONTEND )&& defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNCS )&& !defined(HAVE_STRERROR_R )
80+ pthread_mutex_unlock (& strerror_lock );
81+ #endif
82+
83+ return strerrbuf ;
6284#endif
6385}
6486
7193pqGetpwuid (uid_t uid ,struct passwd * resultbuf ,char * buffer ,
7294size_t buflen ,struct passwd * * result )
7395{
74- #if defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNC_NAMES )
96+ #if defined(FRONTEND ) && defined( USE_THREADS )&& defined(NEED_REENTRANT_FUNCS ) && defined( HAVE_GETPWUID_R )
7597/*
7698 * Early POSIX draft of getpwuid_r() returns 'struct passwd *'.
7799 * getpwuid_r(uid, resultbuf, buffer, buflen)
78100 * Do we need to support it? bjm 2003-08-14
79101 */
80102/* POSIX version */
81103getpwuid_r (uid ,resultbuf ,buffer ,buflen ,result );
104+
82105#else
106+
107+ #if defined(FRONTEND )&& defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNCS )&& !defined(HAVE_GETPWUID_R )
108+ static pthread_mutex_t getpwuid_lock = PTHREAD_MUTEX_INITIALIZER ;
109+ pthread_mutex_lock (& getpwuid_lock );
110+ #endif
111+
83112/* no getpwuid_r() available, just use getpwuid() */
84113* result = getpwuid (uid );
114+
115+ #if defined(FRONTEND )&& defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNCS )&& !defined(HAVE_GETPWUID_R )
116+
117+ /* Use 'buffer' memory for storage of strings used by struct passwd */
118+ if (* result &&
119+ strlen ((* result )-> pw_name )+ 1 +
120+ strlen ((* result )-> pw_passwd )+ 1 +
121+ strlen ((* result )-> pw_gecos )+ 1 +
122+ /* skip class if it exists */
123+ strlen ((* result )-> pw_dir )+ 1 +
124+ strlen ((* result )-> pw_shell )+ 1 <=buflen )
125+ {
126+ memcpy (resultbuf ,* result ,sizeof (struct passwd ));
127+ strcpy (buffer , (* result )-> pw_name );
128+ resultbuf -> pw_name = buffer ;
129+ buffer += strlen (resultbuf -> pw_name )+ 1 ;
130+ strcpy (buffer , (* result )-> pw_passwd );
131+ resultbuf -> pw_passwd = buffer ;
132+ buffer += strlen (resultbuf -> pw_passwd )+ 1 ;
133+ strcpy (buffer , (* result )-> pw_gecos );
134+ resultbuf -> pw_gecos = buffer ;
135+ buffer += strlen (resultbuf -> pw_gecos )+ 1 ;
136+ strcpy (buffer , (* result )-> pw_dir );
137+ resultbuf -> pw_dir = buffer ;
138+ buffer += strlen (resultbuf -> pw_dir )+ 1 ;
139+ strcpy (buffer , (* result )-> pw_shell );
140+ resultbuf -> pw_shell = buffer ;
141+ buffer += strlen (resultbuf -> pw_shell )+ 1 ;
142+
143+ * result = resultbuf ;
144+ }
145+ else
146+ * result = NULL ;
147+
148+ pthread_mutex_unlock (& getpwuid_lock );
149+ #endif
85150#endif
86151return (* result == NULL ) ?-1 :0 ;
87152}
@@ -93,27 +158,101 @@ pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
93158 */
94159int
95160pqGethostbyname (const char * name ,
96- struct hostent * resbuf ,
97- char * buf ,size_t buflen ,
161+ struct hostent * resultbuf ,
162+ char * buffer ,size_t buflen ,
98163struct hostent * * result ,
99164int * herrno )
100165{
101- #if defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNC_NAMES )
166+ #if defined(FRONTEND ) && defined( USE_THREADS )&& defined(NEED_REENTRANT_FUNCS ) && defined( HAVE_GETHOSTBYNAME_R )
102167/*
103168 * broken (well early POSIX draft) gethostbyname_r() which returns
104169 * 'struct hostent *'
105170 */
106- * result = gethostbyname_r (name ,resbuf ,buf ,buflen ,herrno );
171+ * result = gethostbyname_r (name ,resbuf ,buffer ,buflen ,herrno );
107172return (* result == NULL ) ?-1 :0 ;
173+
108174#else
175+
176+ #if defined(FRONTEND )&& defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNCS )&& !defined(HAVE_GETHOSTBYNAME_R )
177+ static pthread_mutex_t gethostbyname_lock = PTHREAD_MUTEX_INITIALIZER ;
178+ pthread_mutex_lock (& gethostbyname_lock );
179+ #endif
180+
109181/* no gethostbyname_r(), just use gethostbyname() */
110182* result = gethostbyname (name );
183+
184+ #if defined(FRONTEND )&& defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNCS )&& !defined(HAVE_GETHOSTBYNAME_R )
185+
186+ /*
187+ *Use 'buffer' memory for storage of structures used by struct hostent.
188+ *The layout is:
189+ *
190+ *addr pointers
191+ *alias pointers
192+ *addr structures
193+ *alias structures
194+ *name
195+ */
196+ if (* result )
197+ {
198+ int i ,pointers = 2 /* for nulls */ ,len = 0 ;
199+ char * * pbuffer ;
200+
201+ for (i = 0 ; (* result )-> h_addr_list [i ];i ++ ,pointers ++ )
202+ len += (* result )-> h_length ;
203+ for (i = 0 ; (* result )-> h_aliases [i ];i ++ ,pointers ++ )
204+ len += (* result )-> h_length ;
205+
206+ if (MAXALIGN (len )+ pointers * sizeof (char * )+ strlen ((* result )-> h_name )+ 1 <=buflen )
207+ {
208+ memcpy (resultbuf ,* result ,sizeof (struct hostent ));
209+
210+ pbuffer = (char * * )buffer ;
211+ resultbuf -> h_addr_list = pbuffer ;
212+ buffer += pointers * sizeof (char * );
213+
214+ for (i = 0 ; (* result )-> h_addr_list [i ];i ++ ,pbuffer ++ )
215+ {
216+ memcpy (buffer , (* result )-> h_addr_list [i ], (* result )-> h_length );
217+ resultbuf -> h_addr_list [i ]= buffer ;
218+ buffer += (* result )-> h_length ;
219+ }
220+ resultbuf -> h_addr_list [i ]= NULL ;
221+ pbuffer ++ ;
222+
223+ resultbuf -> h_aliases = pbuffer ;
224+
225+ for (i = 0 ; (* result )-> h_aliases [i ];i ++ ,pbuffer ++ )
226+ {
227+ memcpy (buffer , (* result )-> h_aliases [i ], (* result )-> h_length );
228+ resultbuf -> h_aliases [i ]= buffer ;
229+ buffer += (* result )-> h_length ;
230+ }
231+ resultbuf -> h_aliases [i ]= NULL ;
232+ pbuffer ++ ;
233+
234+ /* Place at end for cleaner alignment */
235+ strcpy (buffer , (* result )-> h_name );
236+ resultbuf -> h_name = buffer ;
237+ buffer += strlen (resultbuf -> h_name )+ 1 ;
238+
239+ * result = resultbuf ;
240+ }
241+ else
242+ * result = NULL ;
243+ }
244+ #endif
245+
246+ if (* result != NULL )
247+ * herrno = h_errno ;
248+
249+ #if defined(FRONTEND )&& defined(USE_THREADS )&& defined(NEED_REENTRANT_FUNCS )&& !defined(HAVE_GETHOSTBYNAME_R )
250+ pthread_mutex_unlock (& gethostbyname_lock );
251+ #endif
252+
111253if (* result != NULL )
112254return 0 ;
113255else
114- {
115- * herrno = h_errno ;
116256return -1 ;
117- }
118257#endif
119258}