ldap_pvt_thread_set_concurrency LDAP_P(( int ));
#endif
+#define LDAP_PVT_THREAD_CREATE_JOINABLE 0
+#define LDAP_PVT_THREAD_CREATE_DETACHED 1
+
LDAP_F int
ldap_pvt_thread_create LDAP_P((
ldap_pvt_thread_t * thread,
ldap_pvt_thread_mutex_unlock LDAP_P(( ldap_pvt_thread_mutex_t *mutex ));
typedef struct ldap_pvt_thread_rdwr_var {
- int lt_readers_reading;
- int lt_writer_writing;
- ldap_pvt_thread_mutex_t lt_mutex;
- ldap_pvt_thread_cond_t lt_lock_free;
+ ldap_pvt_thread_mutex_t ltrw_mutex;
+ ldap_pvt_thread_cond_t ltrw_read; /* wait for read */
+ ldap_pvt_thread_cond_t ltrw_write; /* wait for write */
+ int ltrw_valid;
+#define LDAP_PVT_THREAD_RDWR_VALUE 0x0bad
+ int ltrw_r_active;
+ int ltrw_w_active;
+ int ltrw_r_wait;
+ int ltrw_w_wait;
} ldap_pvt_thread_rdwr_t;
-#define LDAP_PVT_THREAD_CREATE_DETACHED 1
-#define LDAP_PVT_THREAD_CREATE_JOINABLE 0
-
LDAP_F int
ldap_pvt_thread_rdwr_init LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
LDAP_F int
LDAP_F int
ldap_pvt_thread_rdwr_rlock LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
LDAP_F int
+ldap_pvt_thread_rdwr_rtrylock LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
+LDAP_F int
ldap_pvt_thread_rdwr_runlock LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
LDAP_F int
ldap_pvt_thread_rdwr_wlock LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
LDAP_F int
+ldap_pvt_thread_rdwr_wtrylock LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
+LDAP_F int
ldap_pvt_thread_rdwr_wunlock LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
#ifdef LDAP_DEBUG
LDAP_F int
-ldap_pvt_thread_rdwr_rchk LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
+ldap_pvt_thread_rdwr_readers LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
LDAP_F int
-ldap_pvt_thread_rdwr_wchk LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
+ldap_pvt_thread_rdwr_writers LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
LDAP_F int
-ldap_pvt_thread_rdwr_rwchk LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
+ldap_pvt_thread_rdwr_active LDAP_P((ldap_pvt_thread_rdwr_t *rdwrp));
#endif /* LDAP_DEBUG */
+#define LDAP_PVT_THREAD_EINVAL EINVAL
+#define LDAP_PVT_THREAD_EBUSY EINVAL
+
LDAP_END_DECL
#endif /* _LDAP_THREAD_H */
/*
-** This basic implementation of Reader/Writer locks does not
-** protect writers from starvation. That is, if a writer is
+** This is an improved implementation of Reader/Writer locks does
+** not protect writers from starvation. That is, if a writer is
** currently waiting on a reader, any new reader will get
** the lock before the writer.
+**
+** Does not support cancellation nor does any status checking.
*/
/********************************************************
- * An example source module to accompany...
- *
- * "Using POSIX Threads: Programming with Pthreads"
- * by Brad nichols, Dick Buttlar, Jackie Farrell
- * O'Reilly & Associates, Inc.
- *
+ * Adapted from:
+ * "Programming with Posix Threads"
+ * by David R Butenhof
+ * Addison-Wesley
********************************************************
- * rdwr.c --
- *
- * Library of functions implementing reader/writer locks
*/
#include "portable.h"
#include <stdlib.h>
+#include <ac/errno.h>
#include "ldap_pvt_thread.h"
int
-ldap_pvt_thread_rdwr_init(ldap_pvt_thread_rdwr_t *rdwrp )
+ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rw )
{
- rdwrp->lt_readers_reading = 0;
- rdwrp->lt_writer_writing = 0;
- ldap_pvt_thread_mutex_init(&(rdwrp->lt_mutex) );
- ldap_pvt_thread_cond_init(&(rdwrp->lt_lock_free) );
+ memset( rw, 0, sizeof(ldap_pvt_thread_rdwr_t) );
+
+ /* we should check return results */
+ ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
+ ldap_pvt_thread_cond_init( &rw->ltrw_read );
+ ldap_pvt_thread_cond_init( &rw->ltrw_write );
+
+ rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALUE;
return 0;
}
int
-ldap_pvt_thread_rdwr_destroy(ldap_pvt_thread_rdwr_t *rdwrp )
+ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rw )
{
- ldap_pvt_thread_mutex_destroy(&(rdwrp->lt_mutex) );
- ldap_pvt_thread_cond_destroy(&(rdwrp->lt_lock_free) );
+ if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
+
+ /* active threads? */
+ if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 1) {
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+ return LDAP_PVT_THREAD_EBUSY;
+ }
+
+ /* waiting threads? */
+ if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+ return LDAP_PVT_THREAD_EBUSY;
+ }
+
+ rw->ltrw_valid = 0;
+
+ ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
+ ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
+ ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
+
return 0;
}
-int ldap_pvt_thread_rdwr_rlock(ldap_pvt_thread_rdwr_t *rdwrp){
- ldap_pvt_thread_mutex_lock(&(rdwrp->lt_mutex));
- while(rdwrp->lt_writer_writing) {
- ldap_pvt_thread_cond_wait(&(rdwrp->lt_lock_free),
- &(rdwrp->lt_mutex));
+int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rw )
+{
+ if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
+
+ if( rw->ltrw_w_active > 1 ) {
+ /* writer is active */
+
+ rw->ltrw_r_wait++;
+
+ do {
+ ldap_pvt_thread_cond_wait(
+ &rw->ltrw_read, &rw->ltrw_mutex );
+ } while( rw->ltrw_w_active > 1 );
+
+ rw->ltrw_r_wait--;
}
- rdwrp->lt_readers_reading++;
- ldap_pvt_thread_mutex_unlock(&(rdwrp->lt_mutex));
+
+ rw->ltrw_r_active++;
+
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+
return 0;
}
-int ldap_pvt_thread_rdwr_runlock(ldap_pvt_thread_rdwr_t *rdwrp)
+int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rw )
{
- ldap_pvt_thread_mutex_lock(&(rdwrp->lt_mutex));
- if (rdwrp->lt_readers_reading == 0) {
- ldap_pvt_thread_mutex_unlock(&(rdwrp->lt_mutex));
- return -1;
+ if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
+
+ if( rw->ltrw_w_active > 1) {
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+ return LDAP_PVT_THREAD_EBUSY;
}
- else {
- rdwrp->lt_readers_reading--;
- if (rdwrp->lt_readers_reading == 0) {
- ldap_pvt_thread_cond_signal(&(rdwrp->lt_lock_free));
- }
- ldap_pvt_thread_mutex_unlock(&(rdwrp->lt_mutex));
- return 0;
+
+ rw->ltrw_r_active++;
+
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+
+ return 0;
+}
+
+int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rw )
+{
+ if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
+
+ rw->ltrw_r_active--;
+
+ if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
+ ldap_pvt_thread_cond_signal( &rw->ltrw_write );
}
+
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+
+ return 0;
}
-int ldap_pvt_thread_rdwr_wlock(ldap_pvt_thread_rdwr_t *rdwrp)
+int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rw )
{
- ldap_pvt_thread_mutex_lock(&(rdwrp->lt_mutex));
- while(rdwrp->lt_writer_writing || rdwrp->lt_readers_reading) {
- ldap_pvt_thread_cond_wait(&(rdwrp->lt_lock_free),
- &(rdwrp->lt_mutex));
+ if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
+
+ if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
+ rw->ltrw_w_wait++;
+
+ do {
+ ldap_pvt_thread_cond_wait(
+ &rw->ltrw_write, &rw->ltrw_mutex );
+ } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
+
+ rw->ltrw_w_wait--;
}
- rdwrp->lt_writer_writing++;
- ldap_pvt_thread_mutex_unlock(&(rdwrp->lt_mutex));
+
+ rw->ltrw_w_active++;
+
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+
return 0;
}
-int ldap_pvt_thread_rdwr_wunlock(ldap_pvt_thread_rdwr_t *rdwrp)
+int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rw )
{
- ldap_pvt_thread_mutex_lock(&(rdwrp->lt_mutex));
- if (rdwrp->lt_writer_writing == 0) {
- ldap_pvt_thread_mutex_unlock(&(rdwrp->lt_mutex));
- return -1;
+ if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
+
+ if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+ return LDAP_PVT_THREAD_EBUSY;
}
- else {
- rdwrp->lt_writer_writing = 0;
- ldap_pvt_thread_cond_broadcast(&(rdwrp->lt_lock_free));
- ldap_pvt_thread_mutex_unlock(&(rdwrp->lt_mutex));
- return 0;
+
+ rw->ltrw_w_active++;
+
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+
+ return 0;
+}
+
+int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rw )
+{
+ if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALUE )
+ return LDAP_PVT_THREAD_EINVAL;
+
+ ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
+
+ rw->ltrw_w_active--;
+
+ if (rw->ltrw_r_wait > 0) {
+ ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
+
+ } else if (rw->ltrw_w_wait > 0) {
+ ldap_pvt_thread_cond_signal( &rw->ltrw_write );
}
+
+ ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
+
+ return 0;
}
#ifdef LDAP_DEBUG
* a lock are caught.
*/
-int ldap_pvt_thread_rdwr_rchk(ldap_pvt_thread_rdwr_t *rdwrp)
+int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rw)
{
- return(rdwrp->lt_readers_reading!=0);
+ return( rw->ltrw_r_active );
}
-int ldap_pvt_thread_rdwr_wchk(ldap_pvt_thread_rdwr_t *rdwrp)
+int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rw)
{
- return(rdwrp->lt_writer_writing!=0);
+ return( rw->ltrw_w_active );
}
-int ldap_pvt_thread_rdwr_rwchk(ldap_pvt_thread_rdwr_t *rdwrp)
+
+int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rw)
{
- return(ldap_pvt_thread_rdwr_rchk(rdwrp) ||
- ldap_pvt_thread_rdwr_wchk(rdwrp));
+ return(ldap_pvt_thread_rdwr_readers(rw) +
+ ldap_pvt_thread_rdwr_writers(rw));
}
#endif /* LDAP_DEBUG */
#include <stdio.h>
+#include <ac/errno.h>
#include <ac/string.h>
#include <ac/socket.h>
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
+#ifdef not_used
static void
cache_return_entry( struct cache *cache, Entry *e )
{
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
+#endif
static void
cache_return_entry_rw( struct cache *cache, Entry *e, int rw )
{
Debug( LDAP_DEBUG_TRACE, "====> cache_return_entry_%s\n",
rw ? "w" : "r", 0, 0);
+
+ /* set cache mutex */
+ ldap_pvt_thread_mutex_lock( &cache->c_mutex );
+
entry_rdwr_unlock(e, rw);;
- cache_return_entry(cache, e);
+
+ if ( --e->e_refcnt == 0 && e->e_state == ENTRY_STATE_DELETED ) {
+ entry_free( e );
+ }
+
+ /* free cache mutex */
+ ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
}
void
/* XXX check for writer lock - should also check no readers pending */
#ifdef LDAP_DEBUG
- assert(!ldap_pvt_thread_rdwr_rwchk(&e->e_rdwr));
+ assert(!ldap_pvt_thread_rdwr_active( &e->e_rdwr ));
#endif
/* delete from cache and lru q */
if ( (ep = (Entry *) avl_find( cache->c_dntree, (caddr_t) &e,
cache_entrydn_cmp )) != NULL )
{
+ /*
+ * ep now points to an unlocked entry
+ * we do not need to lock the entry if we only
+ * check the state, refcnt, LRU, and id.
+ */
free(e.e_ndn);
Debug(LDAP_DEBUG_TRACE, "====> cache_find_entry_dn2id: found dn: %s\n",
return( NOID );
}
- /* XXX is this safe without writer lock? */
- ep->e_refcnt++;
-
/* lru */
LRU_DELETE( cache, ep );
LRU_ADD( cache, ep );
-
- /* acquire reader lock */
- entry_rdwr_lock(ep, 0);
-
- /* re-check */
- if ( ep->e_state == ENTRY_STATE_DELETED ||
- ep->e_state == ENTRY_STATE_CREATING )
- {
- /* XXX check that is is required */
- ep->e_refcnt--;
-
- /* free reader lock */
- entry_rdwr_unlock(ep, 0);
- /* free cache mutex */
- ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
-
- return( NOID );
- }
-
+
/* save id */
id = ep->e_id;
- /* free reader lock */
- entry_rdwr_unlock(ep, 0);
-
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
- cache_return_entry( &li->li_cache, ep );
-
return( id );
}
Entry e;
Entry *ep;
+ e.e_id = id;
+
+try_again:
/* set cache mutex */
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
- e.e_id = id;
-
if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e,
cache_entryid_cmp )) != NULL )
{
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
return( NULL );
}
- /* XXX is this safe without writer lock? */
- ep->e_refcnt++;
- /* lru */
- LRU_DELETE( cache, ep );
- LRU_ADD( cache, ep );
-
/* acquire reader lock */
- entry_rdwr_lock(ep, 0);
-
- /* re-check */
- if ( ep->e_state == ENTRY_STATE_DELETED ||
- ep->e_state == ENTRY_STATE_CREATING ) {
-
- /* XXX check that is is required */
- ep->e_refcnt--;
-
- /* free reader lock */
- entry_rdwr_unlock(ep, 0);
+ if ( entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) {
+ /* could not acquire entry lock...
+ * owner cannot free as we have the cache locked.
+ * so, unlock the cache, yield, and try again.
+ */
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
- return( NULL );
+ ldap_pvt_thread_yield();
+ goto try_again;
}
- if ( rw ) {
- entry_rdwr_unlock(ep, 0);
- entry_rdwr_lock(ep, 1);
- }
+ /* lru */
+ LRU_DELETE( cache, ep );
+ LRU_ADD( cache, ep );
+
+ ep->e_refcnt++;
/* free cache mutex */
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
/* XXX check for writer lock - should also check no readers pending */
#ifdef LDAP_DEBUG
- assert(ldap_pvt_thread_rdwr_wchk(&e->e_rdwr));
+ assert(ldap_pvt_thread_rdwr_writers(&e->e_rdwr));
#endif
/* set cache mutex */