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