Back to index

openldap  2.4.31
rdwr.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* This work was initially developed by Kurt D. Zeilenga for inclusion
00016  * in OpenLDAP Software.  Additional significant contributors include:
00017  *     Stuart Lynne
00018  */
00019 
00020 /*
00021  * This is an improved implementation of Reader/Writer locks does
00022  * not protect writers from starvation.  That is, if a writer is
00023  * currently waiting on a reader, any new reader will get
00024  * the lock before the writer.
00025  *
00026  * Does not support cancellation nor does any status checking.
00027  */
00028 /* Adapted from publically available examples for:
00029  *     "Programming with Posix Threads"
00030  *            by David R Butenhof, Addison-Wesley 
00031  *            http://cseng.aw.com/bookpage.taf?ISBN=0-201-63392-2
00032  */
00033 
00034 #include "portable.h"
00035 
00036 #include <ac/stdlib.h>
00037 
00038 #include <ac/errno.h>
00039 #include <ac/string.h>
00040 #include <ac/time.h>
00041 
00042 #include "ldap-int.h"
00043 #include "ldap_pvt_thread.h" /* Get the thread interface */
00044 #define LDAP_THREAD_RDWR_IMPLEMENTATION
00045 #include "ldap_thr_debug.h"  /* May rename the symbols defined below */
00046 
00047 /*
00048  * implementations that provide their own compatible 
00049  * reader/writer locks define LDAP_THREAD_HAVE_RDWR
00050  * in ldap_pvt_thread.h
00051  */
00052 #ifndef LDAP_THREAD_HAVE_RDWR
00053 
00054 struct ldap_int_thread_rdwr_s {
00055        ldap_pvt_thread_mutex_t ltrw_mutex;
00056        ldap_pvt_thread_cond_t ltrw_read;       /* wait for read */
00057        ldap_pvt_thread_cond_t ltrw_write;      /* wait for write */
00058        int ltrw_valid;
00059 #define LDAP_PVT_THREAD_RDWR_VALID 0x0bad
00060        int ltrw_r_active;
00061        int ltrw_w_active;
00062        int ltrw_r_wait;
00063        int ltrw_w_wait;
00064 #ifdef LDAP_RDWR_DEBUG
00065        /* keep track of who has these locks */
00066 #define       MAX_READERS   32
00067        int ltrw_more_readers; /* Set if ltrw_readers[] is incomplete */
00068        ldap_pvt_thread_t ltrw_readers[MAX_READERS];
00069        ldap_pvt_thread_t ltrw_writer;
00070 #endif
00071 };
00072 
00073 int 
00074 ldap_pvt_thread_rdwr_init( ldap_pvt_thread_rdwr_t *rwlock )
00075 {
00076        struct ldap_int_thread_rdwr_s *rw;
00077 
00078        assert( rwlock != NULL );
00079 
00080        rw = (struct ldap_int_thread_rdwr_s *) LDAP_CALLOC( 1,
00081               sizeof( struct ldap_int_thread_rdwr_s ) );
00082        if ( !rw )
00083               return LDAP_NO_MEMORY;
00084 
00085        /* we should check return results */
00086        ldap_pvt_thread_mutex_init( &rw->ltrw_mutex );
00087        ldap_pvt_thread_cond_init( &rw->ltrw_read );
00088        ldap_pvt_thread_cond_init( &rw->ltrw_write );
00089 
00090        rw->ltrw_valid = LDAP_PVT_THREAD_RDWR_VALID;
00091 
00092        *rwlock = rw;
00093        return 0;
00094 }
00095 
00096 int 
00097 ldap_pvt_thread_rdwr_destroy( ldap_pvt_thread_rdwr_t *rwlock )
00098 {
00099        struct ldap_int_thread_rdwr_s *rw;
00100 
00101        assert( rwlock != NULL );
00102        rw = *rwlock;
00103 
00104        assert( rw != NULL );
00105        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00106 
00107        if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
00108               return LDAP_PVT_THREAD_EINVAL;
00109 
00110        ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
00111 
00112        assert( rw->ltrw_w_active >= 0 ); 
00113        assert( rw->ltrw_w_wait >= 0 ); 
00114        assert( rw->ltrw_r_active >= 0 ); 
00115        assert( rw->ltrw_r_wait >= 0 ); 
00116 
00117        /* active threads? */
00118        if( rw->ltrw_r_active > 0 || rw->ltrw_w_active > 0) {
00119               ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00120               return LDAP_PVT_THREAD_EBUSY;
00121        }
00122 
00123        /* waiting threads? */
00124        if( rw->ltrw_r_wait > 0 || rw->ltrw_w_wait > 0) {
00125               ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00126               return LDAP_PVT_THREAD_EBUSY;
00127        }
00128 
00129        rw->ltrw_valid = 0;
00130 
00131        ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00132 
00133        ldap_pvt_thread_mutex_destroy( &rw->ltrw_mutex );
00134        ldap_pvt_thread_cond_destroy( &rw->ltrw_read );
00135        ldap_pvt_thread_cond_destroy( &rw->ltrw_write );
00136 
00137        LDAP_FREE(rw);
00138        *rwlock = NULL;
00139        return 0;
00140 }
00141 
00142 int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock )
00143 {
00144        struct ldap_int_thread_rdwr_s *rw;
00145 
00146        assert( rwlock != NULL );
00147        rw = *rwlock;
00148 
00149        assert( rw != NULL );
00150        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00151 
00152        if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
00153               return LDAP_PVT_THREAD_EINVAL;
00154 
00155        ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
00156 
00157        assert( rw->ltrw_w_active >= 0 ); 
00158        assert( rw->ltrw_w_wait >= 0 ); 
00159        assert( rw->ltrw_r_active >= 0 ); 
00160        assert( rw->ltrw_r_wait >= 0 ); 
00161 
00162        if( rw->ltrw_w_active > 0 ) {
00163               /* writer is active */
00164 
00165               rw->ltrw_r_wait++;
00166 
00167               do {
00168                      ldap_pvt_thread_cond_wait(
00169                             &rw->ltrw_read, &rw->ltrw_mutex );
00170               } while( rw->ltrw_w_active > 0 );
00171 
00172               rw->ltrw_r_wait--;
00173               assert( rw->ltrw_r_wait >= 0 ); 
00174        }
00175 
00176 #ifdef LDAP_RDWR_DEBUG
00177        if( rw->ltrw_r_active < MAX_READERS )
00178               rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self();
00179        else
00180               rw->ltrw_more_readers = 1;
00181 #endif
00182        rw->ltrw_r_active++;
00183 
00184 
00185        ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00186 
00187        return 0;
00188 }
00189 
00190 int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock )
00191 {
00192        struct ldap_int_thread_rdwr_s *rw;
00193 
00194        assert( rwlock != NULL );
00195        rw = *rwlock;
00196 
00197        assert( rw != NULL );
00198        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00199 
00200        if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
00201               return LDAP_PVT_THREAD_EINVAL;
00202 
00203        ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
00204 
00205        assert( rw->ltrw_w_active >= 0 ); 
00206        assert( rw->ltrw_w_wait >= 0 ); 
00207        assert( rw->ltrw_r_active >= 0 ); 
00208        assert( rw->ltrw_r_wait >= 0 ); 
00209 
00210        if( rw->ltrw_w_active > 0) {
00211               ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00212               return LDAP_PVT_THREAD_EBUSY;
00213        }
00214 
00215 #ifdef LDAP_RDWR_DEBUG
00216        if( rw->ltrw_r_active < MAX_READERS )
00217               rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self();
00218        else
00219               rw->ltrw_more_readers = 1;
00220 #endif
00221        rw->ltrw_r_active++;
00222 
00223        ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00224 
00225        return 0;
00226 }
00227 
00228 int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock )
00229 {
00230        struct ldap_int_thread_rdwr_s *rw;
00231 
00232        assert( rwlock != NULL );
00233        rw = *rwlock;
00234 
00235        assert( rw != NULL );
00236        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00237 
00238        if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
00239               return LDAP_PVT_THREAD_EINVAL;
00240 
00241        ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
00242 
00243        rw->ltrw_r_active--;
00244 #ifdef LDAP_RDWR_DEBUG
00245        /* Remove us from the list of readers */
00246        {
00247               ldap_pvt_thread_t self = ldap_pvt_thread_self();
00248               int i, j;
00249               for( i = j = rw->ltrw_r_active; i >= 0; i--) {
00250                      if (rw->ltrw_readers[i] == self) {
00251                             rw->ltrw_readers[i] = rw->ltrw_readers[j];
00252                             rw->ltrw_readers[j] = 0;
00253                             break;
00254                      }
00255               }
00256               if( !rw->ltrw_more_readers )
00257                      assert( i >= 0 );
00258               else if( j == 0 )
00259                      rw->ltrw_more_readers = 0;
00260        }
00261 #endif
00262 
00263        assert( rw->ltrw_w_active >= 0 ); 
00264        assert( rw->ltrw_w_wait >= 0 ); 
00265        assert( rw->ltrw_r_active >= 0 ); 
00266        assert( rw->ltrw_r_wait >= 0 ); 
00267 
00268        if (rw->ltrw_r_active == 0 && rw->ltrw_w_wait > 0 ) {
00269               ldap_pvt_thread_cond_signal( &rw->ltrw_write );
00270        }
00271 
00272        ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00273 
00274        return 0;
00275 }
00276 
00277 int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock )
00278 {
00279        struct ldap_int_thread_rdwr_s *rw;
00280 
00281        assert( rwlock != NULL );
00282        rw = *rwlock;
00283 
00284        assert( rw != NULL );
00285        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00286 
00287        if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
00288               return LDAP_PVT_THREAD_EINVAL;
00289 
00290        ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
00291 
00292        assert( rw->ltrw_w_active >= 0 ); 
00293        assert( rw->ltrw_w_wait >= 0 ); 
00294        assert( rw->ltrw_r_active >= 0 ); 
00295        assert( rw->ltrw_r_wait >= 0 ); 
00296 
00297        if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
00298               rw->ltrw_w_wait++;
00299 
00300               do {
00301                      ldap_pvt_thread_cond_wait(
00302                             &rw->ltrw_write, &rw->ltrw_mutex );
00303               } while ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 );
00304 
00305               rw->ltrw_w_wait--;
00306               assert( rw->ltrw_w_wait >= 0 ); 
00307        }
00308 
00309 #ifdef LDAP_RDWR_DEBUG
00310        rw->ltrw_writer = ldap_pvt_thread_self();
00311 #endif
00312        rw->ltrw_w_active++;
00313 
00314        ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00315 
00316        return 0;
00317 }
00318 
00319 int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock )
00320 {
00321        struct ldap_int_thread_rdwr_s *rw;
00322 
00323        assert( rwlock != NULL );
00324        rw = *rwlock;
00325 
00326        assert( rw != NULL );
00327        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00328 
00329        if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
00330               return LDAP_PVT_THREAD_EINVAL;
00331 
00332        ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
00333 
00334        assert( rw->ltrw_w_active >= 0 ); 
00335        assert( rw->ltrw_w_wait >= 0 ); 
00336        assert( rw->ltrw_r_active >= 0 ); 
00337        assert( rw->ltrw_r_wait >= 0 ); 
00338 
00339        if ( rw->ltrw_w_active > 0 || rw->ltrw_r_active > 0 ) {
00340               ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00341               return LDAP_PVT_THREAD_EBUSY;
00342        }
00343 
00344 #ifdef LDAP_RDWR_DEBUG
00345        rw->ltrw_writer = ldap_pvt_thread_self();
00346 #endif
00347        rw->ltrw_w_active++;
00348 
00349        ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00350 
00351        return 0;
00352 }
00353 
00354 int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock )
00355 {
00356        struct ldap_int_thread_rdwr_s *rw;
00357 
00358        assert( rwlock != NULL );
00359        rw = *rwlock;
00360 
00361        assert( rw != NULL );
00362        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00363 
00364        if( rw->ltrw_valid != LDAP_PVT_THREAD_RDWR_VALID )
00365               return LDAP_PVT_THREAD_EINVAL;
00366 
00367        ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex );
00368 
00369        rw->ltrw_w_active--;
00370 
00371        assert( rw->ltrw_w_active >= 0 ); 
00372        assert( rw->ltrw_w_wait >= 0 ); 
00373        assert( rw->ltrw_r_active >= 0 ); 
00374        assert( rw->ltrw_r_wait >= 0 ); 
00375 
00376        if (rw->ltrw_r_wait > 0) {
00377               ldap_pvt_thread_cond_broadcast( &rw->ltrw_read );
00378 
00379        } else if (rw->ltrw_w_wait > 0) {
00380               ldap_pvt_thread_cond_signal( &rw->ltrw_write );
00381        }
00382 
00383 #ifdef LDAP_RDWR_DEBUG
00384        assert( rw->ltrw_writer == ldap_pvt_thread_self() );
00385        rw->ltrw_writer = 0;
00386 #endif
00387        ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex );
00388 
00389        return 0;
00390 }
00391 
00392 #ifdef LDAP_RDWR_DEBUG
00393 
00394 /* just for testing, 
00395  * return 0 if false, suitable for assert(ldap_pvt_thread_rdwr_Xchk(rdwr))
00396  * 
00397  * Currently they don't check if the calling thread is the one 
00398  * that has the lock, just that there is a reader or writer.
00399  *
00400  * Basically sufficent for testing that places that should have
00401  * a lock are caught.
00402  */
00403 
00404 int ldap_pvt_thread_rdwr_readers(ldap_pvt_thread_rdwr_t *rwlock)
00405 {
00406        struct ldap_int_thread_rdwr_s *rw;
00407 
00408        assert( rwlock != NULL );
00409        rw = *rwlock;
00410 
00411        assert( rw != NULL );
00412        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00413        assert( rw->ltrw_w_active >= 0 ); 
00414        assert( rw->ltrw_w_wait >= 0 ); 
00415        assert( rw->ltrw_r_active >= 0 ); 
00416        assert( rw->ltrw_r_wait >= 0 ); 
00417 
00418        return( rw->ltrw_r_active );
00419 }
00420 
00421 int ldap_pvt_thread_rdwr_writers(ldap_pvt_thread_rdwr_t *rwlock)
00422 {
00423        struct ldap_int_thread_rdwr_s *rw;
00424 
00425        assert( rwlock != NULL );
00426        rw = *rwlock;
00427 
00428        assert( rw != NULL );
00429        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00430        assert( rw->ltrw_w_active >= 0 ); 
00431        assert( rw->ltrw_w_wait >= 0 ); 
00432        assert( rw->ltrw_r_active >= 0 ); 
00433        assert( rw->ltrw_r_wait >= 0 ); 
00434 
00435        return( rw->ltrw_w_active );
00436 }
00437 
00438 int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock)
00439 {
00440        struct ldap_int_thread_rdwr_s *rw;
00441 
00442        assert( rwlock != NULL );
00443        rw = *rwlock;
00444 
00445        assert( rw != NULL );
00446        assert( rw->ltrw_valid == LDAP_PVT_THREAD_RDWR_VALID );
00447        assert( rw->ltrw_w_active >= 0 ); 
00448        assert( rw->ltrw_w_wait >= 0 ); 
00449        assert( rw->ltrw_r_active >= 0 ); 
00450        assert( rw->ltrw_r_wait >= 0 ); 
00451 
00452        return(ldap_pvt_thread_rdwr_readers(rwlock) +
00453               ldap_pvt_thread_rdwr_writers(rwlock));
00454 }
00455 
00456 #endif /* LDAP_RDWR_DEBUG */
00457 
00458 #endif /* LDAP_THREAD_HAVE_RDWR */