7
7
*
8
8
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
9
9
*
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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
14
14
15
15
#include "postgres.h"
16
16
17
+ #include <pthread.h>
18
+ #include <sys/types.h>
19
+ #include <pwd.h>
20
+
17
21
/*
18
22
*Threading sometimes requires specially-named versions of functions
19
23
*that return data in static buffers, like strerror_r() instead of
20
24
*strerror(). Other operating systems use pthread_setspecific()
21
25
*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.
23
28
*
24
29
*Additional confusion exists because many operating systems that
25
30
*use pthread_setspecific/pthread_getspecific() also have *_r versions
36
41
*doesn't have strerror_r(), so we can't fall back to only using *_r
37
42
*functions for threaded programs.
38
43
*
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
+ *
42
51
*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 .
44
53
*/
45
54
46
55
51
60
char *
52
61
pqStrerror (int errnum ,char * strerrbuf ,size_t buflen )
53
62
{
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 )
55
64
/* reentrant strerror_r is available */
56
65
/* some early standards had strerror_r returning char * */
57
66
strerror_r (errnum ,strerrbuf ,buflen );
58
- return (strerrbuf );
67
+ return strerrbuf ;
68
+
59
69
#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
+
60
76
/* 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 ;
62
84
#endif
63
85
}
64
86
71
93
pqGetpwuid (uid_t uid ,struct passwd * resultbuf ,char * buffer ,
72
94
size_t buflen ,struct passwd * * result )
73
95
{
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 )
75
97
/*
76
98
* Early POSIX draft of getpwuid_r() returns 'struct passwd *'.
77
99
* getpwuid_r(uid, resultbuf, buffer, buflen)
78
100
* Do we need to support it? bjm 2003-08-14
79
101
*/
80
102
/* POSIX version */
81
103
getpwuid_r (uid ,resultbuf ,buffer ,buflen ,result );
104
+
82
105
#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
+
83
112
/* no getpwuid_r() available, just use getpwuid() */
84
113
* 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
85
150
#endif
86
151
return (* result == NULL ) ?-1 :0 ;
87
152
}
@@ -93,27 +158,101 @@ pqGetpwuid(uid_t uid, struct passwd *resultbuf, char *buffer,
93
158
*/
94
159
int
95
160
pqGethostbyname (const char * name ,
96
- struct hostent * resbuf ,
97
- char * buf ,size_t buflen ,
161
+ struct hostent * resultbuf ,
162
+ char * buffer ,size_t buflen ,
98
163
struct hostent * * result ,
99
164
int * herrno )
100
165
{
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 )
102
167
/*
103
168
* broken (well early POSIX draft) gethostbyname_r() which returns
104
169
* 'struct hostent *'
105
170
*/
106
- * result = gethostbyname_r (name ,resbuf ,buf ,buflen ,herrno );
171
+ * result = gethostbyname_r (name ,resbuf ,buffer ,buflen ,herrno );
107
172
return (* result == NULL ) ?-1 :0 ;
173
+
108
174
#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
+
109
181
/* no gethostbyname_r(), just use gethostbyname() */
110
182
* 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
+
111
253
if (* result != NULL )
112
254
return 0 ;
113
255
else
114
- {
115
- * herrno = h_errno ;
116
256
return -1 ;
117
- }
118
257
#endif
119
258
}