1 /* thr_posix.c - wrapper around posix and posixish thread implementations. */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 1998-2021 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16
17
18 #include "portable.h"
19
20 #if defined( HAVE_PTHREADS )
21
22 #ifdef __GLIBC__
23 #undef _FEATURES_H
24 #define _XOPEN_SOURCE 500 /* For pthread_setconcurrency() on glibc */
25 #endif
26
27 #include <ac/errno.h>
28
29 #ifdef REPLACE_BROKEN_YIELD
30 #ifndef HAVE_NANOSLEEP
31 #include <ac/socket.h>
32 #endif
33 #include <ac/time.h>
34 #endif
35
36 #include "ldap_pvt_thread.h" /* Get the thread interface */
37 #define LDAP_THREAD_IMPLEMENTATION
38 #define LDAP_THREAD_RDWR_IMPLEMENTATION
39 #include "ldap_thr_debug.h" /* May rename the symbols defined below */
40 #include <signal.h> /* For pthread_kill() */
41
42 extern int ldap_int_stackguard;
43
44 #if HAVE_PTHREADS < 6
45 # define LDAP_INT_THREAD_ATTR_DEFAULT pthread_attr_default
46 # define LDAP_INT_THREAD_CONDATTR_DEFAULT pthread_condattr_default
47 # define LDAP_INT_THREAD_MUTEXATTR_DEFAULT pthread_mutexattr_default
48 #else
49 # define LDAP_INT_THREAD_ATTR_DEFAULT NULL
50 # define LDAP_INT_THREAD_CONDATTR_DEFAULT NULL
51 # define LDAP_INT_THREAD_MUTEXATTR_DEFAULT NULL
52 #endif
53
54 #ifdef LDAP_THREAD_DEBUG
55 # if defined LDAP_INT_THREAD_MUTEXATTR /* May be defined in CPPFLAGS */
56 # elif defined HAVE_PTHREAD_KILL_OTHER_THREADS_NP
57 /* LinuxThreads hack */
58 # define LDAP_INT_THREAD_MUTEXATTR PTHREAD_MUTEX_ERRORCHECK_NP
59 # else
60 # define LDAP_INT_THREAD_MUTEXATTR PTHREAD_MUTEX_ERRORCHECK
61 # endif
62 static pthread_mutexattr_t mutex_attr;
63 # undef LDAP_INT_THREAD_MUTEXATTR_DEFAULT
64 # define LDAP_INT_THREAD_MUTEXATTR_DEFAULT &mutex_attr
65 #endif
66
67 static pthread_mutexattr_t mutex_attr_recursive;
68
69 #if HAVE_PTHREADS < 7
70 #define ERRVAL(val) ((val) < 0 ? errno : 0)
71 #else
72 #define ERRVAL(val) (val)
73 #endif
74
75 int
ldap_int_thread_initialize(void)76 ldap_int_thread_initialize( void )
77 {
78 #ifdef LDAP_INT_THREAD_MUTEXATTR
79 pthread_mutexattr_init( &mutex_attr );
80 pthread_mutexattr_settype( &mutex_attr, LDAP_INT_THREAD_MUTEXATTR );
81 #endif
82 if (pthread_mutexattr_init(&mutex_attr_recursive))
83 return -1;
84 if (pthread_mutexattr_settype(&mutex_attr_recursive, PTHREAD_MUTEX_RECURSIVE))
85 return -1;
86 return 0;
87 }
88
89 int
ldap_int_thread_destroy(void)90 ldap_int_thread_destroy( void )
91 {
92 #ifdef HAVE_PTHREAD_KILL_OTHER_THREADS_NP
93 /* LinuxThreads: kill clones */
94 pthread_kill_other_threads_np();
95 #endif
96 #ifdef LDAP_INT_THREAD_MUTEXATTR
97 pthread_mutexattr_destroy( &mutex_attr );
98 #endif
99 pthread_mutexattr_destroy( &mutex_attr_recursive );
100 return 0;
101 }
102
103 #ifdef LDAP_THREAD_HAVE_SETCONCURRENCY
104 int
ldap_pvt_thread_set_concurrency(int n)105 ldap_pvt_thread_set_concurrency(int n)
106 {
107 #ifdef HAVE_PTHREAD_SETCONCURRENCY
108 return pthread_setconcurrency( n );
109 #elif defined(HAVE_THR_SETCONCURRENCY)
110 return thr_setconcurrency( n );
111 #else
112 return 0;
113 #endif
114 }
115 #endif
116
117 #ifdef LDAP_THREAD_HAVE_GETCONCURRENCY
118 int
ldap_pvt_thread_get_concurrency(void)119 ldap_pvt_thread_get_concurrency(void)
120 {
121 #ifdef HAVE_PTHREAD_GETCONCURRENCY
122 return pthread_getconcurrency();
123 #elif defined(HAVE_THR_GETCONCURRENCY)
124 return thr_getconcurrency();
125 #else
126 return 0;
127 #endif
128 }
129 #endif
130
131 /* detachstate appeared in Draft 6, but without manifest constants.
132 * in Draft 7 they were called PTHREAD_CREATE_UNDETACHED and ...DETACHED.
133 * in Draft 8 on, ...UNDETACHED became ...JOINABLE.
134 */
135 #ifndef PTHREAD_CREATE_JOINABLE
136 #ifdef PTHREAD_CREATE_UNDETACHED
137 #define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED
138 #else
139 #define PTHREAD_CREATE_JOINABLE 0
140 #endif
141 #endif
142
143 #ifndef PTHREAD_CREATE_DETACHED
144 #define PTHREAD_CREATE_DETACHED 1
145 #endif
146
147 int
ldap_pvt_thread_create(ldap_pvt_thread_t * thread,int detach,void * (* start_routine)(void *),void * arg)148 ldap_pvt_thread_create( ldap_pvt_thread_t * thread,
149 int detach,
150 void *(*start_routine)( void * ),
151 void *arg)
152 {
153 int rtn;
154 pthread_attr_t attr;
155
156 /* Always create the thread attrs, so we can set stacksize if we need to */
157 #if HAVE_PTHREADS > 5
158 pthread_attr_init(&attr);
159 #else
160 pthread_attr_create(&attr);
161 #endif
162
163 #ifdef LDAP_PVT_THREAD_SET_STACK_SIZE
164 /* this should be tunable */
165 pthread_attr_setstacksize( &attr, LDAP_PVT_THREAD_STACK_SIZE );
166 if ( ldap_int_stackguard )
167 pthread_attr_setguardsize( &attr, LDAP_PVT_THREAD_STACK_SIZE );
168 #endif
169
170 #if HAVE_PTHREADS > 5
171 detach = detach ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;
172 #if HAVE_PTHREADS == 6
173 pthread_attr_setdetachstate(&attr, &detach);
174 #else
175 pthread_attr_setdetachstate(&attr, detach);
176 #endif
177 #endif
178
179 #if HAVE_PTHREADS < 5
180 rtn = pthread_create( thread, attr, start_routine, arg );
181 #else
182 rtn = pthread_create( thread, &attr, start_routine, arg );
183 #endif
184
185 #if HAVE_PTHREADS > 5
186 pthread_attr_destroy(&attr);
187 #else
188 pthread_attr_delete(&attr);
189 if( detach ) {
190 pthread_detach( thread );
191 }
192 #endif
193
194 #if HAVE_PTHREADS < 7
195 if ( rtn < 0 ) rtn = errno;
196 #endif
197 return rtn;
198 }
199
200 void
ldap_pvt_thread_exit(void * retval)201 ldap_pvt_thread_exit( void *retval )
202 {
203 pthread_exit( retval );
204 }
205
206 int
ldap_pvt_thread_join(ldap_pvt_thread_t thread,void ** thread_return)207 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
208 {
209 #if HAVE_PTHREADS < 7
210 void *dummy;
211 if (thread_return==NULL)
212 thread_return=&dummy;
213 #endif
214 return ERRVAL( pthread_join( thread, thread_return ) );
215 }
216
217 int
ldap_pvt_thread_kill(ldap_pvt_thread_t thread,int signo)218 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
219 {
220 #if defined(HAVE_PTHREAD_KILL) && HAVE_PTHREADS > 4
221 /* MacOS 10.1 is detected as v10 but has no pthread_kill() */
222 return ERRVAL( pthread_kill( thread, signo ) );
223 #else
224 /* pthread package with DCE */
225 if (kill( getpid(), signo )<0)
226 return errno;
227 return 0;
228 #endif
229 }
230
231 int
ldap_pvt_thread_yield(void)232 ldap_pvt_thread_yield( void )
233 {
234 #ifdef REPLACE_BROKEN_YIELD
235 #ifdef HAVE_NANOSLEEP
236 struct timespec t = { 0, 0 };
237 nanosleep(&t, NULL);
238 #else
239 struct timeval tv = {0,0};
240 select( 0, NULL, NULL, NULL, &tv );
241 #endif
242 return 0;
243
244 #elif defined(HAVE_THR_YIELD)
245 thr_yield();
246 return 0;
247
248 #elif HAVE_PTHREADS == 10
249 return sched_yield();
250
251 #elif defined(_POSIX_THREAD_IS_GNU_PTH)
252 sched_yield();
253 return 0;
254
255 #elif HAVE_PTHREADS == 6
256 pthread_yield(NULL);
257 return 0;
258
259 #else
260 pthread_yield();
261 return 0;
262 #endif
263 }
264
265 int
ldap_pvt_thread_cond_init(ldap_pvt_thread_cond_t * cond)266 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
267 {
268 return ERRVAL( pthread_cond_init(
269 cond, LDAP_INT_THREAD_CONDATTR_DEFAULT ) );
270 }
271
272 int
ldap_pvt_thread_cond_destroy(ldap_pvt_thread_cond_t * cond)273 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
274 {
275 return ERRVAL( pthread_cond_destroy( cond ) );
276 }
277
278 int
ldap_pvt_thread_cond_signal(ldap_pvt_thread_cond_t * cond)279 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
280 {
281 return ERRVAL( pthread_cond_signal( cond ) );
282 }
283
284 int
ldap_pvt_thread_cond_broadcast(ldap_pvt_thread_cond_t * cond)285 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
286 {
287 return ERRVAL( pthread_cond_broadcast( cond ) );
288 }
289
290 int
ldap_pvt_thread_cond_wait(ldap_pvt_thread_cond_t * cond,ldap_pvt_thread_mutex_t * mutex)291 ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond,
292 ldap_pvt_thread_mutex_t *mutex )
293 {
294 return ERRVAL( pthread_cond_wait( cond, mutex ) );
295 }
296
297 int
ldap_pvt_thread_mutex_init(ldap_pvt_thread_mutex_t * mutex)298 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
299 {
300 return ERRVAL( pthread_mutex_init(
301 mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT ) );
302 }
303
304 int
ldap_pvt_thread_mutex_destroy(ldap_pvt_thread_mutex_t * mutex)305 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
306 {
307 return ERRVAL( pthread_mutex_destroy( mutex ) );
308 }
309
310 int
ldap_pvt_thread_mutex_lock(ldap_pvt_thread_mutex_t * mutex)311 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
312 {
313 return ERRVAL( pthread_mutex_lock( mutex ) );
314 }
315
316 int
ldap_pvt_thread_mutex_trylock(ldap_pvt_thread_mutex_t * mutex)317 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
318 {
319 return ERRVAL( pthread_mutex_trylock( mutex ) );
320 }
321
322 int
ldap_pvt_thread_mutex_unlock(ldap_pvt_thread_mutex_t * mutex)323 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
324 {
325 return ERRVAL( pthread_mutex_unlock( mutex ) );
326 }
327
328 int
ldap_pvt_thread_mutex_recursive_init(ldap_pvt_thread_mutex_t * mutex)329 ldap_pvt_thread_mutex_recursive_init( ldap_pvt_thread_mutex_t *mutex )
330 {
331 return ERRVAL( pthread_mutex_init( mutex, &mutex_attr_recursive ) );
332 }
333
ldap_pvt_thread_self(void)334 ldap_pvt_thread_t ldap_pvt_thread_self( void )
335 {
336 return pthread_self();
337 }
338
339 int
ldap_pvt_thread_key_create(ldap_pvt_thread_key_t * key)340 ldap_pvt_thread_key_create( ldap_pvt_thread_key_t *key )
341 {
342 return pthread_key_create( key, NULL );
343 }
344
345 int
ldap_pvt_thread_key_destroy(ldap_pvt_thread_key_t key)346 ldap_pvt_thread_key_destroy( ldap_pvt_thread_key_t key )
347 {
348 return pthread_key_delete( key );
349 }
350
351 int
ldap_pvt_thread_key_setdata(ldap_pvt_thread_key_t key,void * data)352 ldap_pvt_thread_key_setdata( ldap_pvt_thread_key_t key, void *data )
353 {
354 return pthread_setspecific( key, data );
355 }
356
357 int
ldap_pvt_thread_key_getdata(ldap_pvt_thread_key_t key,void ** data)358 ldap_pvt_thread_key_getdata( ldap_pvt_thread_key_t key, void **data )
359 {
360 *data = pthread_getspecific( key );
361 return 0;
362 }
363
364 #ifdef LDAP_THREAD_HAVE_RDWR
365 #ifdef HAVE_PTHREAD_RWLOCK_DESTROY
366 int
ldap_pvt_thread_rdwr_init(ldap_pvt_thread_rdwr_t * rw)367 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw )
368 {
369 return ERRVAL( pthread_rwlock_init( rw, NULL ) );
370 }
371
372 int
ldap_pvt_thread_rdwr_destroy(ldap_pvt_thread_rdwr_t * rw)373 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw )
374 {
375 return ERRVAL( pthread_rwlock_destroy( rw ) );
376 }
377
ldap_pvt_thread_rdwr_rlock(ldap_pvt_thread_rdwr_t * rw)378 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
379 {
380 return ERRVAL( pthread_rwlock_rdlock( rw ) );
381 }
382
ldap_pvt_thread_rdwr_rtrylock(ldap_pvt_thread_rdwr_t * rw)383 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
384 {
385 return ERRVAL( pthread_rwlock_tryrdlock( rw ) );
386 }
387
ldap_pvt_thread_rdwr_runlock(ldap_pvt_thread_rdwr_t * rw)388 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
389 {
390 return ERRVAL( pthread_rwlock_unlock( rw ) );
391 }
392
ldap_pvt_thread_rdwr_wlock(ldap_pvt_thread_rdwr_t * rw)393 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
394 {
395 return ERRVAL( pthread_rwlock_wrlock( rw ) );
396 }
397
ldap_pvt_thread_rdwr_wtrylock(ldap_pvt_thread_rdwr_t * rw)398 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
399 {
400 return ERRVAL( pthread_rwlock_trywrlock( rw ) );
401 }
402
ldap_pvt_thread_rdwr_wunlock(ldap_pvt_thread_rdwr_t * rw)403 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
404 {
405 return ERRVAL( pthread_rwlock_unlock( rw ) );
406 }
407
408 #endif /* HAVE_PTHREAD_RWLOCK_DESTROY */
409 #endif /* LDAP_THREAD_HAVE_RDWR */
410 #endif /* HAVE_PTHREADS */
411
412