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