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