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
- * system requires reentrant function names .
52
+ * system has 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
}
0 commit comments