latch.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: latch.cpp,v 1.48 2010/11/08 15:06: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 #ifdef __GNUC__
00059 #pragma implementation
00060 #endif
00061 
00062 #include "w.h"
00063 #include "sthread.h"
00064 #include "latch.h"
00065 #include "w_debug.h"
00066 
00067 #include <cstring>
00068 #include <sthread_stats.h>
00069 #include <list>
00070 #include <algorithm>
00071 
00072 const char* const  latch_t::latch_mode_str[3] = { "NL", "SH", "EX" };
00073 
00074 
00075 latch_t::latch_t(const char* const desc) :
00076     _total_count(0) 
00077 {
00078     setname(desc);
00079 }
00080 
00081 latch_t::~latch_t()
00082 {
00083 #if W_DEBUG_LEVEL > 1
00084     int t = _total_count;
00085     // do this just to get the symbol to remain 
00086     if(t) {
00087         fprintf(stderr, "t=%d\n", t);
00088     }
00089     w_assert2(t == 0);// BUG_SEMANTICS_FIX
00090 
00091     w_assert2(mode() == LATCH_NL);
00092     w_assert2(num_holders() == 0);
00093 #endif
00094 }
00095 
00096 
00097 /**\var static __thread latch_holder_t* latch_holder_t::thread_local_holders;
00098  * \brief Linked list of all latches held by this thread.
00099  * \ingroup TLS
00100  *
00101  * \details
00102  * Every time we want to grab a latch,
00103  * we have to create a latch_holder_t; we do that with the
00104  * holder_search class, which searches the per-thread list below
00105  * to make sure we `(this thread) don't already hold the latch and 
00106  * if not, it creates a new latch_holder_t for the new latch acquisition,
00107  * and stuffs the latch_holder_t in this list.  
00108  * If we do already have hold the latch in some capacity, the 
00109  * holder_search returns that existing latch_holder_t.
00110  * So we can tell if this thread holds a given latch, and we can
00111  * find all latches held by this thread, but we can't find
00112  * all the holders of a given latch.
00113  *
00114  * \sa latch_holder_t
00115  */
00116 __thread latch_holder_t* latch_holder_t::thread_local_holders(NULL);
00117 
00118 /**\var static __thread latch_holder_t* latch_holder_t::thread_local_freelist;
00119  * \brief Pool of unused latch_holder_t instances.
00120  * \ingroup TLS
00121  *
00122  * \details
00123  * Ready for recycling.  These structures are first taken from the global heap
00124  * but put on this list for reuse rather than ::free-ed.
00125  * When the thread is destroyed, the items on this list are returned
00126  * to the global heap.
00127  *
00128  * \sa latch_holder_t
00129  */
00130 __thread latch_holder_t* latch_holder_t::thread_local_freelist(NULL);
00131 
00132 /**\brief The list-handling class for latch_holder_t instances.
00133  *
00134  * \details
00135  * Really, all this does is provide an iterator and a means to
00136  * insert (push_front)  and remove (unlink) these things.
00137  *
00138  * The list contents are always instances of latch_holder_t, which 
00139  * have an internal link for creating the list.
00140  */
00141 class holder_list 
00142 {
00143     latch_holder_t* &_first;
00144 public:
00145     holder_list(latch_holder_t* &first) : _first(first) { }
00146 
00147     /**\brief Iterator over a list of latch_holder_t structures */
00148     struct iterator {
00149         latch_holder_t* _cur;
00150         public:
00151 
00152         /// Construct an iterator starting with the given latch_holder_t.
00153         explicit iterator(latch_holder_t* cur) : _cur(cur) { }
00154 
00155         /// Get current.
00156         operator latch_holder_t*() const { return _cur; }
00157 
00158         /// Get current.
00159         latch_holder_t* operator->() const { return *this; }
00160 
00161         ///  Make iterator point to next.
00162         iterator &operator++() { _cur = _cur->_next; return *this; }
00163 
00164         ///  Make iterator point to next.
00165         iterator operator++(int) { return ++iterator(*this); }
00166     };
00167 
00168     /// Dereferencing this iterator brings us to the first item in the list.
00169     iterator begin() { return iterator(_first); }
00170 
00171     /// Dereferencing this iterator brings us past the last item in any list.
00172     iterator end() { return iterator(NULL); }
00173 
00174     /// Insert h at the front of this list.
00175     void push_front(latch_holder_t* h) {
00176         h->_next = _first;
00177         if(_first) _first->_prev = h;
00178         h->_prev = NULL;
00179         _first = h;
00180     }
00181 
00182     /// Remove whatever is the current item for the given iterator.
00183     latch_holder_t* unlink(iterator const &it) {
00184         if(it->_next)
00185             it->_next->_prev = it->_prev;
00186         
00187         if(it->_prev) 
00188             it->_prev->_next = it->_next;
00189         else 
00190             _first = it->_next;
00191 
00192         // now it's orphaned...
00193         return it;
00194     }
00195 };
00196 
00197 /**\class holders_print
00198  * \brief For debugging only.
00199  *
00200  * \details
00201  *
00202  * Constructor looks through all the holders in the 
00203  * implied list starting with the latch_holder_t passed in as the sole
00204  * constructor argument.  
00205  *
00206  * It prints info about each latch_holder_t in the list.
00207  *
00208  * \sa latch_holder_t.
00209  */
00210 class  holders_print 
00211 {
00212 private:
00213     holder_list _holders;
00214     void print(holder_list holders)
00215     {
00216         holder_list::iterator it=holders.begin();
00217         for(; it!=holders.end() && it->_latch;  ++it) 
00218         {
00219             it->print(cerr);
00220         }
00221     }
00222 public:
00223     holders_print(latch_holder_t *list) 
00224     : _holders(list)
00225     {
00226         print(_holders);
00227     }
00228 };
00229 
00230 /**\class holder_search
00231  * \brief Finds all latches held by this thread.
00232  *
00233  * \details
00234  * Searches a thread-local list for a latch_holder_t that is a
00235  * reference to the given latch_t.
00236  *
00237  * \sa latch_holder_t.
00238  */
00239 class holder_search 
00240 {
00241 public:
00242     /// find holder of given latch in given list
00243     static holder_list::iterator find(holder_list holders, latch_t const* l) 
00244     {
00245         holder_list::iterator it=holders.begin();
00246         for(; it!=holders.end() && it->_latch != l; ++it) ;
00247         return it;
00248     }
00249 
00250     /// count # times we find a given latch in the list. For debugging, asserts.
00251     static int count(holder_list holders, latch_t const* l) 
00252     {
00253         holder_list::iterator it=holders.begin();
00254         int c=0;
00255         for(; it!=holders.end(); ++it) if(it->_latch == l) c++;
00256         return c;
00257     }
00258 
00259 private:
00260     holder_list _holders;
00261     latch_holder_t* &_freelist;
00262     holder_list::iterator _end;
00263     holder_list::iterator _it;
00264 
00265 public:
00266     /// Insert latch_holder_t for given latch if not already there.
00267     holder_search(latch_t const* l)
00268         : _holders(latch_holder_t::thread_local_holders),
00269           _freelist(latch_holder_t::thread_local_freelist),
00270           _end(_holders.end()),
00271           _it(find(_holders, l))
00272     {
00273         // if we didn't find the latch in the list,
00274         // create a new latch_holder_t (with mode LATCH_NL)
00275         // to return, just so that the value() method always
00276         // returns a non-null ptr.  It might be used, might not.
00277         if(_it == _end) {
00278             latch_holder_t* h = _freelist;
00279             if(h) _freelist = h->_next;
00280             // need to clear out the latch either way
00281             if(h)
00282                 // h->latch_holder_t(); // reinit
00283                 h = new(h) latch_holder_t();
00284             else
00285                 h = new latch_holder_t;
00286             _holders.push_front(h);
00287             _it = _holders.begin();
00288         }
00289         w_assert2(count(_holders, l) <= 1);
00290     }
00291 
00292     ~holder_search() 
00293     {
00294         if(_it == _end || _it->_mode != LATCH_NL)
00295             return;
00296         
00297         // don't hang onto it in the holders list  if it's not latched.
00298         latch_holder_t* h = _holders.unlink(_it);
00299         h->_next = _freelist;
00300         _freelist = h;
00301     }
00302 
00303     latch_holder_t* operator->() { return this->value(); }
00304 
00305     latch_holder_t* value() { return (_it == _end)? 
00306         (latch_holder_t *)(NULL) : &(*_it); }
00307 }; // holder_search
00308 
00309 /**\cond skip */
00310 // For debugging purposes, let's string together all the thread_local
00311 // lists so that we can print all the latches and their
00312 // holders.   smthread_t calls on_thread_init and on_thread_destroy.
00313 #include <map>
00314 typedef std::map<sthread_t*, latch_holder_t**> holder_list_list_t;
00315 static holder_list_list_t holder_list_list;
00316 
00317 // It's not that this needs to be queue-based, but we want to avoid
00318 // pthreads API use directly as much as possible.
00319 static queue_based_block_lock_t    holder_list_list_lock;
00320 
00321 void latch_t::on_thread_init(sthread_t *who) 
00322 {
00323     CRITICAL_SECTION(cs, holder_list_list_lock);
00324     holder_list_list.insert(std::make_pair(who, 
00325                 &latch_holder_t::thread_local_holders));
00326 }
00327 
00328 void latch_t::on_thread_destroy(sthread_t *who) 
00329 {
00330     {
00331        CRITICAL_SECTION(cs, holder_list_list_lock);
00332        holder_list_list.erase(who);
00333     }
00334 
00335     w_assert3(!latch_holder_t::thread_local_holders);
00336     latch_holder_t* freelist = latch_holder_t::thread_local_freelist;
00337     while(freelist) {
00338         latch_holder_t* node = freelist;
00339         freelist = node->_next;
00340         delete node;
00341     }
00342     latch_holder_t::thread_local_freelist = NULL;
00343 }
00344 /**\endcond skip */
00345 
00346 
00347 w_rc_t 
00348 latch_t::latch_acquire(latch_mode_t mode, sthread_t::timeout_in_ms timeout) 
00349 {
00350     w_assert1(mode != LATCH_NL); 
00351     holder_search me(this);
00352     return _acquire(mode, timeout, me.value());
00353 }
00354 
00355 w_rc_t
00356 latch_t::upgrade_if_not_block(bool& would_block)
00357 {
00358     DBGTHRD(<< " want to upgrade " << *this );
00359     holder_search me(this);
00360     
00361     // should already hold the latch
00362     w_assert3(me.value() != NULL);
00363     
00364     // already hold EX? DON'T INCREMENT THE COUNT!
00365     if(me->_mode == LATCH_EX) {
00366         would_block = false;
00367         return RCOK;
00368     }
00369     
00370     w_rc_t rc = _acquire(LATCH_EX, WAIT_IMMEDIATE, me.value());
00371     if(rc.is_error()) {
00372         // it never should have tried to block
00373         w_assert3(rc.err_num() != sthread_t::stTIMEOUT);
00374         if(rc.err_num() != sthread_t::stINUSE) 
00375             return RC_AUGMENT(rc);
00376     
00377         would_block = true;
00378     }
00379     else {
00380         // upgrade should not increase the lock count
00381         atomic_dec_uint(&_total_count); 
00382         me->_count--;
00383         would_block = false;
00384     }
00385     return RCOK;
00386 }
00387 
00388 int latch_t::latch_release() 
00389 {
00390     holder_search me(this);
00391     // we should already hold the latch!
00392     w_assert2(me.value() != NULL);
00393     return _release(me.value());
00394 }
00395 
00396 w_rc_t latch_t::_acquire(latch_mode_t new_mode, 
00397     sthread_t::timeout_in_ms timeout, 
00398     latch_holder_t* me) 
00399 {
00400     FUNC(latch_t::_acquire);
00401     DBGTHRD( << "want to acquire in mode " 
00402             << W_ENUM(new_mode) << " " << *this
00403             );
00404     w_assert2(new_mode != LATCH_NL);
00405     w_assert2(me);
00406 
00407     bool is_upgrade = false;
00408     if(me->_latch == this) 
00409     {
00410         // we already hold the latch
00411         w_assert2(me->_mode != LATCH_NL);
00412         w_assert2(mode() == me->_mode); 
00413         // note: _mode can't change while we hold the latch!
00414         if(mode() == LATCH_EX) {
00415             w_assert2(num_holders() == 1);
00416             // once we hold it in EX all later acquires default to EX as well
00417             new_mode = LATCH_EX; 
00418         } else {
00419             w_assert2(num_holders() >= 1);
00420         }
00421         if(me->_mode == new_mode) {
00422             DBGTHRD(<< "we already held latch in desired mode " << *this);
00423             atomic_inc_uint(&_total_count);// BUG_SEMANTICS_FIX
00424             me->_count++; // thread-local
00425             // fprintf(stderr, "acquire latch %p %dx in mode %s\n", 
00426             //        this, me->_count, latch_mode_str[new_mode]);
00427             return RCOK;
00428         } else if(new_mode == LATCH_EX && me->_mode == LATCH_SH) {
00429             is_upgrade = true;
00430         }
00431     } else {
00432         // init 'me' (latch holder) for the critical section
00433         me->_latch = this;
00434         me->_mode = LATCH_NL;
00435         me->_count = 0;
00436     }
00437 
00438     // have to acquire for real
00439     
00440     if(is_upgrade) {
00441   // to avoid deadlock,
00442   // never block on upgrade 
00443         if(!_lock.attempt_upgrade())
00444             return RC(sthread_t::stINUSE);
00445 
00446         w_assert2(me->_count > 0);
00447         w_assert2(new_mode == LATCH_EX);
00448         me->_mode = new_mode;
00449   // We don't count upgrades 
00450   // These are counted in bf statistics.
00451     } else {
00452         if(timeout == WAIT_IMMEDIATE) {
00453    INC_STH_STATS(needs_latch_condl);
00454             bool success = (new_mode == LATCH_SH)? 
00455                 _lock.attempt_read() : _lock.attempt_write();
00456             if(!success)
00457                 return RC(sthread_t::stTIMEOUT);
00458    INC_STH_STATS(latch_condl_nowait);
00459         }
00460         else {
00461             // forever timeout
00462    INC_STH_STATS(needs_latch_uncondl);
00463             if(new_mode == LATCH_SH) {
00464 #define EXPENSIVE_LATCH_COUNTS 1
00465 #if EXPENSIVE_LATCH_COUNTS
00466     if(_lock.attempt_read()) {
00467      INC_STH_STATS(latch_uncondl_nowait);
00468     } else
00469 #endif
00470                 _lock.acquire_read();
00471             }
00472             else {
00473                 w_assert2(new_mode == LATCH_EX);
00474                 w_assert2(me->_count == 0);
00475 #if EXPENSIVE_LATCH_COUNTS
00476     if(_lock.attempt_write()) {
00477      INC_STH_STATS(latch_uncondl_nowait);
00478     } else 
00479 #endif
00480                 _lock.acquire_write();
00481             }
00482         }
00483         w_assert2(me->_count == 0);
00484         me->_mode = new_mode;
00485     }
00486     atomic_inc_uint(&_total_count);// BUG_SEMANTICS_FIX
00487     me->_count++;// BUG_SEMANTICS_FIX
00488     DBGTHRD(<< "acquired " << *this );
00489     return RCOK;  
00490 }
00491 
00492 
00493 int 
00494 latch_t::_release(latch_holder_t* me)
00495 {
00496     FUNC(latch_t::release);
00497     DBGTHRD(<< "want to release " << *this );
00498 
00499     w_assert2(me->_latch == this);
00500     w_assert2(me->_mode != LATCH_NL);
00501     w_assert2(me->_count > 0);
00502 
00503     atomic_dec_uint(&_total_count); 
00504     if(--me->_count) {
00505         DBGTHRD(<< "was held multiple times -- still " << me->_count << " " << *this );
00506         return me->_count;
00507     }
00508     
00509     if(me->_mode == LATCH_SH) {
00510         w_assert2(_lock.has_reader());
00511         _lock.release_read();
00512     }
00513     else {
00514         w_assert2(_lock.has_writer());
00515         _lock.release_write();
00516     }
00517     me->_mode = LATCH_NL;
00518     return 0;
00519 }
00520 
00521 void latch_t::downgrade() {
00522     holder_search me(this);
00523     // we should already hold the latch!
00524     w_assert3(me.value() != NULL);
00525     _downgrade(me.value());
00526 }
00527 
00528 void 
00529 latch_t::_downgrade(latch_holder_t* me)
00530 {
00531     FUNC(latch_t::downgrade);
00532     DBGTHRD(<< "want to downgrade " << *this );
00533 
00534     w_assert3(me->_latch == this);
00535     w_assert3(me->_mode == LATCH_EX);
00536     w_assert3(me->_count > 0);
00537     
00538     _lock.downgrade();
00539     me->_mode = LATCH_SH;
00540     
00541 }
00542 
00543 void latch_holder_t::print(ostream &o) const
00544 {
00545     o << "Holder " << latch_t::latch_mode_str[int(_mode)] 
00546         << " cnt=" << _count 
00547     << " threadid/" << ::hex << w_base_t::uint8_t(_threadid) 
00548     << " latch:";
00549     if(_latch) {
00550         o  << *_latch << endl;
00551     } else { 
00552         o  << "NULL" << endl;
00553     }
00554 }
00555 
00556 // return the number of times the latch is held by this thread 
00557 // or 0 if I do not hold the latch
00558 // There should never be more than one holder structure for a single
00559 // latch.
00560 int
00561 latch_t::held_by_me() const 
00562 {
00563     holder_search me(this);
00564     return me.value()? me->_count : 0;
00565 }
00566 
00567 bool
00568 latch_t::is_mine() const {
00569     holder_search me(this);
00570     return me.value()? (me->_mode == LATCH_EX) : false;
00571 }
00572 
00573 // NOTE: this is not safe, but it can be used by unit tests
00574 // and for debugging
00575 #include <w_stream.h>
00576 ostream &latch_t::print(ostream &out) const
00577 {
00578     out <<    "latch(" << this << "): " << name();
00579     out << " held in " << latch_mode_str[int(mode())] << " mode ";
00580     out << "by " << num_holders() << " threads " ;
00581     out << "total " << latch_cnt() << " times " ;
00582     out << endl;
00583     return out;
00584 }
00585 
00586 
00587 ostream& operator<<(ostream& out, const latch_t& l)
00588 {
00589     return l.print(out);
00590 }
00591 
00592 // For use in debugger:
00593 void print_latch(const latch_t *l)
00594 {
00595     if(l != NULL) l->print(cerr);
00596 }
00597 
00598 // For use in debugger:
00599 void print_my_latches()
00600 {
00601     FUNC(print_my_latches);
00602     holders_print all(latch_holder_t::thread_local_holders);
00603 }
00604 
00605 void print_all_latches()
00606 {
00607     FUNC(print_all_latches);
00608 // Don't protect: this is for use in a debugger.
00609 // It's absolutely dangerous to use in a running
00610 // storage manager, since these lists will be
00611 // munged frequently. 
00612     int count=0;
00613     {
00614         holder_list_list_t::iterator  iter;
00615         for(iter= holder_list_list.begin(); 
00616              iter != holder_list_list.end(); 
00617              iter ++) count++;
00618     }
00619     holder_list_list_t::iterator  iter;
00620     cerr << "ALL " << count << " LATCHES {" << endl;
00621     for(iter= holder_list_list.begin(); 
00622          iter != holder_list_list.end(); iter ++)
00623     {
00624         DBG(<<"");
00625         sthread_t* who = iter->first;
00626         DBG(<<" who " << (void *)(who));
00627         latch_holder_t **whoslist = iter->second;
00628         DBG(<<" whoslist " << (void *)(whoslist));
00629         if(who) {
00630         cerr << "{ Thread id:" << ::dec << who->id 
00631          << " @ sthread/" << ::hex << w_base_t::uint8_t(who)
00632          << " @ pthread/" << ::hex << w_base_t::uint8_t(who->myself())
00633          << endl << "\t";
00634         } else {
00635         cerr << "{ empty }"
00636          << endl << "\t";
00637         }
00638         DBG(<<"");
00639         holders_print whose(*whoslist); 
00640         cerr <<  "} " << endl << flush;
00641     }
00642     cerr <<  "}" << endl << flush ;
00643 }

Generated on Mon Nov 8 11:12:36 2010 for Shore Storage Manager by  doxygen 1.4.7