srwlock.cpp

00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002    Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 // -*- mode:c++; c-basic-offset:4 -*-
00025 /*<std-header orig-src='shore'>
00026 
00027  $Id: srwlock.cpp,v 1.7 2010/12/08 17:37:50 nhall Exp $
00028 
00029 SHORE -- Scalable Heterogeneous Object REpository
00030 
00031 Copyright (c) 1994-99 Computer Sciences Department, University of
00032                       Wisconsin -- Madison
00033 All Rights Reserved.
00034 
00035 Permission to use, copy, modify and distribute this software and its
00036 documentation is hereby granted, provided that both the copyright
00037 notice and this permission notice appear in all copies of the
00038 software, derivative works or modified versions, and any portions
00039 thereof, and that both notices appear in supporting documentation.
00040 
00041 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00042 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00043 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00044 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00045 
00046 This software was developed with support by the Advanced Research
00047 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00048 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00049 Further funding for this work was provided by DARPA through
00050 Rome Research Laboratory Contract No. F30602-97-2-0247.
00051 
00052 */
00053 
00054 #include "w_defines.h"
00055 
00056 /*  -- do not edit anything above this line --   </std-header>*/
00057 
00058 #include <w.h>
00059 #include <w_debug.h>
00060 #include <sthread.h>
00061 
00062 /************************************************************************************
00063  * mcs_rwlock implementation; cheaper but problematic when we get os preemptions
00064  */
00065 
00066 // CC mangles this as __1cKmcs_rwlockOspin_on_writer6M_v_
00067 // private
00068 int mcs_rwlock::_spin_on_writer() 
00069 {
00070     int cnt=0;
00071     while(has_writer()) cnt=1;
00072     // callers do membar_enter
00073     return cnt;
00074 }
00075 // CC mangles this as __1cKmcs_rwlockPspin_on_readers6M_v_
00076 // private
00077 void mcs_rwlock::_spin_on_readers() 
00078 {
00079     while(has_reader());
00080     // callers do membar_enter
00081 }
00082 
00083 // private
00084 void mcs_rwlock::_add_when_writer_leaves(int delta) 
00085 {
00086     // we always have the parent lock to do this
00087     int cnt = _spin_on_writer();
00088     atomic_add_32(&_holders, delta);
00089     // callers do membar_enter
00090     if(cnt  && (delta == WRITER)) {
00091         INC_STH_STATS(rwlock_w_wait);
00092     }
00093 }
00094 
00095 bool mcs_rwlock::attempt_read() 
00096 {
00097     unsigned int old_value = *&_holders;
00098     if(old_value & WRITER || 
00099         old_value != atomic_cas_32(&_holders, old_value, old_value+READER))
00100         return false;
00101 
00102     membar_enter();
00103     return true;
00104 }
00105 
00106 void mcs_rwlock::acquire_read() 
00107 {
00108     /* attempt to CAS first. If no writers around, or no intervening
00109      * add'l readers, we're done
00110      */
00111     if(!attempt_read()) {
00112         INC_STH_STATS(rwlock_r_wait);
00113         /* There seem to be writers around, or other readers intervened in our
00114          * attempt_read() above.
00115          * Join the queue and wait for them to leave 
00116          */
00117         {
00118             CRITICAL_SECTION(cs, (parent_lock*) this);
00119             _add_when_writer_leaves(READER);
00120         }
00121         membar_enter();
00122     }
00123 }
00124 
00125 void mcs_rwlock::release_read() 
00126 {
00127     w_assert2(has_reader());
00128     membar_exit(); // flush protected modified data before releasing lock;
00129     // update and complete any loads by others before I do this write 
00130     atomic_add_32(&_holders, -READER);
00131 }
00132 
00133 bool mcs_rwlock::_attempt_write(unsigned int expected) 
00134 {
00135     /* succeeds iff we are the only reader (if expected==READER)
00136      * or if there are no readers or writers (if expected==0)
00137      *
00138      * How do we know if the only reader is us?
00139      * A:  we rely on these facts: 
00140      * this is called with expected==READER only from attempt_upgrade(), 
00141      *   which is called from latch only in the case
00142      *   in which we hold the latch in LATCH_SH mode and 
00143      *   are requesting it in LATCH_EX mode.
00144      *
00145      * If there is a writer waiting we have to get in line 
00146      * like everyone else.
00147      * No need for a membar because we already hold the latch
00148      */
00149 
00150 // USE_PTHREAD_MUTEX is determined by configure option and
00151 // thus defined in config/shore-config.h
00152 #if defined(USE_PTHREAD_MUTEX) && USE_PTHREAD_MUTEX==1
00153     ext_qnode me = QUEUE_EXT_QNODE_INITIALIZER;
00154 #else
00155     ext_qnode me;
00156     QUEUE_EXT_QNODE_INITIALIZE(me);
00157 #endif
00158 
00159     if(*&_holders != expected || !attempt(&me))
00160         return false;
00161     // at this point, we've called mcs_lock::attempt(&me), and
00162     // have acquired the parent/mcs lock
00163     // The following line replaces our reader bit with a writer bit.
00164     bool result = (expected == atomic_cas_32(&_holders, expected, WRITER));
00165     release(me); // parent/mcs lock
00166     membar_enter();
00167     return result;
00168 }
00169 
00170 bool mcs_rwlock::attempt_write() 
00171 {
00172     if(!_attempt_write(0))
00173         return false;
00174     
00175     // moved to end of _attempt_write() membar_enter();
00176     return true;
00177 }
00178 
00179 void mcs_rwlock::acquire_write() 
00180 {
00181     /* always join the queue first.
00182      *
00183      * 1. We don't want to race with other writers
00184      *
00185      * 2. We don't want to make readers deal with the gap between
00186      * us updating _holders and actually acquiring the MCS lock.
00187      */
00188     CRITICAL_SECTION(cs, (parent_lock*) this);
00189     _add_when_writer_leaves(WRITER);
00190     w_assert1(has_writer()); // me!
00191 
00192     // now wait for existing readers to clear out
00193     if(has_reader()) {
00194         INC_STH_STATS(rwlock_w_wait);
00195         _spin_on_readers();
00196     }
00197 
00198     // done!
00199     membar_enter();
00200 }
00201 
00202 void mcs_rwlock::release_write() {
00203     membar_exit(); // flush protected modified data before releasing lock;
00204     w_assert1(*&_holders == WRITER);
00205     *&_holders = 0;
00206 }
00207 
00208 bool mcs_rwlock::attempt_upgrade() 
00209 {
00210     w_assert1(has_reader());
00211     return _attempt_write(READER);
00212 }
00213 
00214 void mcs_rwlock::downgrade() 
00215 {
00216     membar_exit();  // this is for all intents and purposes, a release
00217     w_assert1(*&_holders == WRITER);
00218     *&_holders = READER;
00219     membar_enter(); // but it's also an acquire
00220 }

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7