From c9b7fc640756b6c2894024b1f8918ac91c68fd6d Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@openldap.org>
Date: Sat, 7 Sep 2002 14:09:09 +0000
Subject: [PATCH] New POSIX threads version support. Detects Draft 4,5,6,7,10
 (final). Should eliminate individual checks for pthread_yield, sched_yield,
 and pthread_detach, but they're left in for now as a redundant check.

---
 build/openldap.m4               | 118 ++++++++++----------
 configure.in                    |  22 ++--
 libraries/libldap_r/thr_posix.c | 190 ++++++++++++++++++++++----------
 3 files changed, 206 insertions(+), 124 deletions(-)

diff --git a/build/openldap.m4 b/build/openldap.m4
index c50acd4a96..9a565db8b3 100644
--- a/build/openldap.m4
+++ b/build/openldap.m4
@@ -621,36 +621,56 @@ dnl
 dnl ====================================================================
 dnl Check POSIX Thread version 
 dnl
-dnl defines ol_cv_posix_version to 'final' or 'draft' or 'unknown'
-dnl 	'unknown' implies that the version could not be detected
-dnl		or that pthreads.h does exist.  Existance of pthreads.h
+dnl defines ol_cv_pthread_version to 0, 4, 5, 6, 7, 10, depending on the
+dnl	version of the POSIX.4a Draft that is implemented.
+dnl	10 == POSIX.4a Final == POSIX.1c-1996 for our purposes.
+dnl 	0 implies that the version could not be detected
+dnl		or that pthreads.h does exist.  Existence of pthreads.h
 dnl		should be tested separately.
 dnl
+dnl tests:
+dnl	pthread_yield() was renamed to sched_yield() in Draft 10, so
+dnl		only a Draft 10 library will define this
+dnl	PTHREAD_INTR_ENABLE was introduced in Draft 6, and renamed to
+dnl		PTHREAD_CANCEL_ENABLE in Draft 7. Draft 7-10 has _CANCEL_,
+dnl		only Draft 6 has _INTR_
+dnl	PTHREAD_MUTEX_INITIALIZER was introduced in Draft 5. It's not
+dnl		interesting to us because we don't try to statically
+dnl		initialize mutexes. 5-10 has it.
+dnl	pthread_attr_create was renamed to pthread_attr_init after Draft 4.
+dnl		Draft 6-10 has _init, Draft 4 has _create. (dunno about 5)
+dnl
+dnl Besides the use of sched_yield vs pthread_yield, differences from
+dnl Draft 7 thru Draft 10 don't appear significant for our purposes.
+dnl
 AC_DEFUN([OL_POSIX_THREAD_VERSION],
 [AC_CACHE_CHECK([POSIX thread version],[ol_cv_pthread_version],[
-	AC_EGREP_CPP(pthread_version_final,[
+	AC_EGREP_HEADER(sched_yield,pthread.h,
+	ol_cv_pthread_version=10, [
+	
+	AC_EGREP_CPP(draft7,[
 #		include <pthread.h>
-		/* this check could be improved */
-#		ifdef PTHREAD_ONCE_INIT
-			pthread_version_final;
+#		ifdef PTHREAD_CANCEL_ENABLE
+		draft7
 #		endif
-	], ol_pthread_final=yes, ol_pthread_final=no)
+	], ol_cv_pthread_version=7, [
 
-	AC_EGREP_CPP(pthread_version_draft4,[
+	AC_EGREP_CPP(draft6,[
 #		include <pthread.h>
-		/* this check could be improved */
-#		ifdef pthread_once_init
-			pthread_version_draft4;
-#		endif
-	], ol_pthread_draft4=yes, ol_pthread_draft4=no)
+#ifdef		PTHREAD_INTR_ENABLE
+		draft6
+#endif
+	], ol_cv_pthread_version=6, [
 
-	if test $ol_pthread_final = yes -a $ol_pthread_draft4 = no; then
-		ol_cv_pthread_version=final
-	elif test $ol_pthread_final = no -a $ol_pthread_draft4 = yes; then
-		ol_cv_pthread_version=draft4
-	else
-		ol_cv_pthread_version=unknown
-	fi
+	AC_EGREP_CPP(draft5,[
+#		include <pthread.h>
+#ifdef		PTHREAD_MUTEX_INITIALIZER
+		draft5
+#endif
+	], ol_cv_pthread_version=5, [
+
+	AC_EGREP_HEADER(pthread_attr_create,pthread.h,
+	ol_cv_pthread_version=4, ol_cv_pthread_version=0) ]) ]) ]) ])
 ])
 ])dnl
 dnl
@@ -658,6 +678,9 @@ dnl --------------------------------------------------------------------
 AC_DEFUN([OL_PTHREAD_TEST_INCLUDES],
 [/* pthread test headers */
 #include <pthread.h>
+#if HAVE_PTHREADS < 7
+#include <errno.h>
+#endif
 #ifndef NULL
 #define NULL (void*)0
 #endif
@@ -670,60 +693,43 @@ static void *task(p)
 ])
 AC_DEFUN([OL_PTHREAD_TEST_FUNCTION],[
 	/* pthread test function */
+#ifndef PTHREAD_CREATE_DETACHED
+#define	PTHREAD_CREATE_DETACHED	1
+#endif
 	pthread_t t;
 	int status;
-	int detach = 1;
+	int detach = PTHREAD_CREATE_DETACHED;
 
-#ifdef HAVE_PTHREADS_FINAL
+#if HAVE_PTHREADS > 4
 	/* Final pthreads */
 	pthread_attr_t attr;
 
 	status = pthread_attr_init(&attr);
 	if( status ) return status;
 
-#if defined( PTHREAD_CREATE_JOINABLE ) || defined( PTHREAD_UNDETACHED )
-	if( !detach ) {
-#if defined( PTHREAD_CREATE_JOINABLE )
-		status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+#if HAVE_PTHREADS < 7
+	status = pthread_attr_setdetachstate(&attr, &detach);
+	if( status < 0 ) status = errno;
 #else
-		status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
+	status = pthread_attr_setdetachstate(&attr, detach);
 #endif
-
-#ifdef PTHREAD_CREATE_DETACHED
-	} else {
-		status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-#endif
-	}
 	if( status ) return status;
-#endif
-
 	status = pthread_create( &t, &attr, task, NULL );
-	if( status ) return status;
-
-#if !defined( PTHREAD_CREATE_JOINABLE ) && !defined( PTHREAD_UNDETACHED )
-	if( detach ) {
-		/* give thread a chance to complete */
-		/* it should remain joinable and hence detachable */
-		sleep( 1 );
-
-		status = pthread_detach( t );
-		if( status ) return status;
-	}
+#if HAVE_PTHREADS < 7
+	if( status < 0 ) status = errno;
 #endif
-
+	if( status ) return status;
 #else
 	/* Draft 4 pthreads */
 	status = pthread_create( &t, pthread_attr_default, task, NULL );
-	if( status ) return status;
+	if( status ) return errno;
 
-	if( detach ) {
-		/* give thread a chance to complete */
-		/* it should remain joinable and hence detachable */
-		sleep( 1 );
+	/* give thread a chance to complete */
+	/* it should remain joinable and hence detachable */
+	sleep( 1 );
 
-		status = pthread_detach( &t );
-		if( status ) return status;
-	}
+	status = pthread_detach( &t );
+	if( status ) return errno;
 #endif
 
 #ifdef HAVE_LINUX_THREADS
diff --git a/configure.in b/configure.in
index 2057f3d8b8..899cd51b84 100644
--- a/configure.in
+++ b/configure.in
@@ -729,6 +729,14 @@ AC_CHECK_LIB(s, afopen, [
 	AC_DEFINE(HAVE_AIX_SECURITY,1,[define if you have AIX security lib])
 ])
 
+dnl ----------------------------------------------------------------
+dnl Check for IBM OS/390
+case "$target" in
+*-ibm-openedition)
+	ac_cv_func_getopt=no
+	AC_DEFINE(BOTH_STRINGS_H,1,[define to use both <string.h> and <strings.h>])
+	;;
+esac
 
 dnl ----------------------------------------------------------------
 dnl Check for module support
@@ -1370,12 +1378,9 @@ if test $ol_with_threads = auto -o $ol_with_threads = yes \
 	if test $ac_cv_header_pthread_h = yes ; then
 		OL_POSIX_THREAD_VERSION
 
-		if test $ol_cv_pthread_version = final ; then
-			AC_DEFINE(HAVE_PTHREADS_FINAL,1,
-				[define if pthreads API compatible with final spec])
-		elif test $ol_cv_pthread_version = draft4 ; then
-			AC_DEFINE(HAVE_PTHREADS_D4,1,
-				[define if pthreads API compatible with draft4 spec])
+		if test $ol_cv_pthread_version != 0 ; then
+			AC_DEFINE_UNQUOTED(HAVE_PTHREADS,$ol_cv_pthread_version,
+				[define to pthreads API spec revision])
 		else
 			AC_MSG_ERROR([unknown pthread version])
 		fi
@@ -1470,9 +1475,6 @@ dnl			[ol_cv_pthread_lpthread_lexc])
 		OL_PTHREAD_TRY([-lpthreads],[ol_cv_pthread_lib_lpthreads])
 
 		if test $ol_link_threads != no ; then
-			AC_DEFINE(HAVE_PTHREADS,1,
-				[define if you have POSIX Threads])
-
 			LTHREAD_LIBS="$LTHREAD_LIBS $ol_link_pthreads"
 
 			dnl save flags
@@ -1621,7 +1623,7 @@ int main(argc, argv)
 #endif
 #endif
 
-#if HAVE_PTHREADS_D4
+#if HAVE_PTHREADS < 6
 	pthread_create(&t, pthread_attr_default, task, NULL);
 #else
 	pthread_create(&t, NULL, task, NULL);
diff --git a/libraries/libldap_r/thr_posix.c b/libraries/libldap_r/thr_posix.c
index fef18fe9ca..9ca988422e 100644
--- a/libraries/libldap_r/thr_posix.c
+++ b/libraries/libldap_r/thr_posix.c
@@ -21,7 +21,7 @@
 #include "ldap_pvt_thread.h"
 
 
-#if HAVE_PTHREADS_D4
+#if HAVE_PTHREADS == 4
 #  define LDAP_INT_THREAD_ATTR_DEFAULT		pthread_attr_default
 #  define LDAP_INT_THREAD_CONDATTR_DEFAULT	pthread_condattr_default
 #  define LDAP_INT_THREAD_MUTEXATTR_DEFAULT	pthread_mutexattr_default
@@ -76,6 +76,15 @@ ldap_pvt_thread_get_concurrency(void)
 }
 #endif
 
+/* These are first defined in Draft 7 */
+#ifndef PTHREAD_CREATE_JOINABLE
+#define	PTHREAD_CREATE_JOINABLE	0
+#endif
+
+#ifndef PTHREAD_CREATE_DETACHED
+#define	PTHREAD_CREATE_DETACHED	1
+#endif
+
 int 
 ldap_pvt_thread_create( ldap_pvt_thread_t * thread,
 	int detach,
@@ -83,26 +92,11 @@ ldap_pvt_thread_create( ldap_pvt_thread_t * thread,
 	void *arg)
 {
 	int rtn;
-#if defined( HAVE_PTHREADS_FINAL )
 	pthread_attr_t attr;
+#if HAVE_PTHREADS > 4
 	pthread_attr_init(&attr);
-
-#if defined( PTHREAD_CREATE_JOINABLE ) || defined( PTHREAD_UNDETACHED )
-	if (!detach) {
-#if defined( PTHREAD_CREATE_JOINABLE )
-		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 #else
-		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
-#endif
-#ifdef PTHREAD_CREATE_DETACHED
-	} else {
-		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-#elif HAVE_PTHREADS_OS390
-	} else {
-		int st = __DETACHED;
-		pthread_attr_setdetachstate(&attr, &st);
-#endif
-	}
+	pthread_attr_create(&attr);
 #endif
 
 #if defined(LDAP_PVT_THREAD_STACK_SIZE) && LDAP_PVT_THREAD_STACK_SIZE > 0
@@ -110,31 +104,27 @@ ldap_pvt_thread_create( ldap_pvt_thread_t * thread,
 	pthread_attr_setstacksize( &attr, LDAP_PVT_THREAD_STACK_SIZE );
 #endif
 
-	rtn = pthread_create( thread, &attr, start_routine, arg );
-#ifdef HAVE_PTHREADS_OS390
-	if ( rtn == -1 ) rtn = errno;
-#endif
-
-#if !defined( PTHREAD_CREATE_JOINABLE ) && !defined( PTHREAD_UNDETACHED )
-	if( detach ) {
-#ifdef HAVE_PTHREADS_OS390
-		(void) pthread_detach( thread );
+#if HAVE_PTHREADS > 4
+	detach = detach ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE;
+#if HAVE_PTHREADS == 6
+	pthread_attr_setdetachstate(&attr, &detach);
 #else
-		(void) pthread_detach( *thread );
+	pthread_attr_setdetachstate(&attr, detach);
 #endif
-	}
 #endif
+	rtn = pthread_create( thread, &attr, start_routine, arg );
+#if HAVE_PTHREADS > 4
 	pthread_attr_destroy(&attr);
-
 #else
-	rtn = pthread_create( thread, LDAP_INT_THREAD_ATTR_DEFAULT,
-		start_routine, arg );
-
+	pthread_attr_delete(&attr);
 	if( detach ) {
 		pthread_detach( thread );
 	}
 #endif
 
+#if HAVE_PTHREADS < 7
+	if ( rtn < 0 ) rtn = errno;
+#endif
 	return rtn;
 }
 
@@ -147,15 +137,14 @@ ldap_pvt_thread_exit( void *retval )
 int 
 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
 {
-#if !defined( HAVE_PTHREADS_FINAL )
+#if HAVE_PTHREADS < 7
 	void *dummy;
+
 	if (thread_return==NULL)
 	  thread_return=&dummy;
-#endif	
-#ifdef HAVE_PTHREADS_OS390
-	int st = pthread_join( thread, thread_return ); 
-	if ( st == -1 ) st = errno;
-	return st;
+
+	if ( pthread_join( thread, thread_return ) < 0 ) return errno;
+	return 0;
 #else
 	return pthread_join( thread, thread_return );
 #endif
@@ -164,14 +153,11 @@ ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
 int 
 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
 {
-#ifdef HAVE_PTHREAD_KILL
-#ifdef HAVE_PTHREADS_OS390
-	int st = pthread_kill( thread, signo );
-	if ( st == -1 ) st = errno;
-	return st;
-#else
+#if HAVE_PTHREADS > 6
 	return pthread_kill( thread, signo );
-#endif
+#elif HAVE_PTHREADS == 6
+	if ( pthread_kill( thread, signo ) < 0 ) return errno;
+	return 0;
 #else
 	/* pthread package with DCE */
 	if (kill( getpid(), signo )<0)
@@ -183,88 +169,136 @@ ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
 int 
 ldap_pvt_thread_yield( void )
 {
-#ifdef _POSIX_THREAD_IS_GNU_PTH
-	sched_yield();
-	return 0;
-
-#elif HAVE_SCHED_YIELD
+#if HAVE_PTHREADS == 10
 	return sched_yield();
 
-#elif HAVE_PTHREAD_YIELD
-#if HAVE_PTHREADS_OS390
-	pthread_yield(NULL);
-#else
-	pthread_yield();
-#endif
+#elif defined(_POSIX_THREAD_IS_GNU_PTH)
+	sched_yield();
 	return 0;
 
 #elif HAVE_THR_YIELD
 	return thr_yield();
 
+#elif HAVE_PTHREADS == 6
+	pthread_yield(NULL);
+	return 0;
 #else
+	pthread_yield();
 	return 0;
-#endif   
+#endif
 }
 
 int 
 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_cond_init( cond, LDAP_INT_THREAD_CONDATTR_DEFAULT ) < 0 )
+		return errno;
+	return 0;
+#else
 	return pthread_cond_init( cond, LDAP_INT_THREAD_CONDATTR_DEFAULT );
+#endif
 }
 
 int 
 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cond )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_cond_destroy( cond ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_cond_destroy( cond );
+#endif
 }
 	
 int 
 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_cond_signal( cond ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_cond_signal( cond );
+#endif
 }
 
 int
 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cond )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_cond_broadcast( cond ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_cond_broadcast( cond );
+#endif
 }
 
 int 
 ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, 
 		      ldap_pvt_thread_mutex_t *mutex )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_cond_wait( cond, mutex ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_cond_wait( cond, mutex );
+#endif
 }
 
 int 
 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_mutex_init( mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT )<0)
+		return errno;
+	return 0;
+#else
 	return pthread_mutex_init( mutex, LDAP_INT_THREAD_MUTEXATTR_DEFAULT );
+#endif
 }
 
 int 
 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_mutex_destroy( mutex ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_mutex_destroy( mutex );
+#endif
 }
 
 int 
 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_mutex_lock( mutex ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_mutex_lock( mutex );
+#endif
 }
 
 int 
 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mutex )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_mutex_trylock( mutex ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_mutex_trylock( mutex );
+#endif
 }
 
 int 
 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_mutex_unlock( mutex ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_mutex_unlock( mutex );
+#endif
 }
 
 #ifdef LDAP_THREAD_HAVE_RDWR
@@ -272,43 +306,83 @@ ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
 int 
 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_init( rw, NULL ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_init( rw, NULL );
+#endif
 }
 
 int 
 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_destroy( rw ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_destroy( rw );
+#endif
 }
 
 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_rdlock( rw ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_rdlock( rw );
+#endif
 }
 
 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_tryrdlock( rw ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_tryrdlock( rw );
+#endif
 }
 
 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_unlock( rw ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_unlock( rw );
+#endif
 }
 
 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_wrlock( rw ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_wrlock( rw );
+#endif
 }
 
 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_trywrlock( rw ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_trywrlock( rw );
+#endif
 }
 
 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
 {
+#if HAVE_PTHREADS < 7
+	if ( pthread_rwlock_unlock( rw ) < 0 ) return errno;
+	return 0;
+#else
 	return pthread_rwlock_unlock( rw );
+#endif
 }
 
 #endif /* HAVE_PTHREAD_RDLOCK_DESTROY */
-- 
GitLab