[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: A clean way to detect if a ldap_pvt_thread_mutex is locked (best would be also to know who's the owner of the lock :)



One thing which is missing is pthread_once() to protect init functions.
I'll commit one for pthreads and a default version, unless someone
protests.

Then e.g. ldap_int_initialize() can use that - and if two threads call
it at the same time, one will wait for the other's initialization to
complete.

The default would be something like the code below.
Would also define LDAP_PVT_THREAD_MUTEX_INITIALIZER for the
thread packages I know to define a static initializer for mutexes.

typedef struct {
	volatile sig_atomic_t	done;
#ifndef LDAP_R_COMPILE
#ifndef LDAP_PVT_THREAD_MUTEX_INITIALIZER
	volatile sig_atomic_t	initialized;
#endif
	ldap_pvt_thread_mutex_t	mutex;
#endif
} ldap_pvt_thread_once_t;

/*
 * Run a function only once per unique ONCE argument.  If another
 * thread is running a function with the same ONCE value, wait for it.
 * The function cannot be called recursively with the same ONCE value.
 * Threads can deadlock if A() calls B() once and B() calls A() once.
 *
 * This default version is not quite safe: It can call a function for
 * ONCE twice if the _first_ calls to ldap_pvt_thread_once() happen
 * in parallell before ldap_pvt_thread_initialize() has been called.
 */
void
ldap_pvt_thread_once( ldap_pvt_thread_once_t *once, void (*func)( void ) )
{
	if( !once->done ) {
#ifdef LDAP_R_COMPILE
# ifndef LDAP_PVT_THREAD_MUTEX_INITIALIZER
		/* Initialize ldap_pvt_thread_once(). */
		static volatile sig_atomic_t	once_init_done;
		static ldap_pvt_thread_mutex_t	once_init_mutex;
		if( !once_init_done ) {
			ldap_pvt_thread_mutex_init( &once_init_mutex );
			once_init_done = 1;
		}
		/* Initialize the ONCE parameter if necessary. */
		ldap_pvt_thread_mutex_lock( &once_init_mutex );
		if( !once->initialized ) {
			ldap_pvt_thread_mutex_init( &once->mutex );
			once->initialized = 1;
		}
		ldap_pvt_thread_mutex_unlock( &once_init_mutex );
# endif /* !LDAP_PVT_THREAD_MUTEX_INITIALIZER */
		ldap_pvt_thread_mutex_lock( &once->mutex );
		if( !once->done ) {
			func();
			once->done = 1;
		}
		ldap_pvt_thread_mutex_unlock( &once->mutex );
#else /* !LDAP_R_COMPILE */
		func();
		once->done = 1;
#endif /* !LDAP_R_COMPILE */
	}
}

-- 
Hallvard