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.45 2010/07/07 20:50:11 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 this list to make sure
00105  * we(this thread) doesn't already hold the latch and if not,
00106  * it creates a new latch_holder_t for the new latch acquisition,
00107  * and stuffs the latch_holder_t in this list.  If we do already
00108  * have hold the latch in some capacity, the holder_search returns
00109  * 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         if(!_lock.attempt_upgrade())
00442             return RC(sthread_t::stINUSE);
00443 
00444         w_assert2(me->_count > 0);
00445         w_assert2(new_mode == LATCH_EX);
00446         me->_mode = new_mode;
00447     } else {
00448         if(timeout == WAIT_IMMEDIATE) {
00449             bool success = (new_mode == LATCH_SH)? 
00450                 _lock.attempt_read() : _lock.attempt_write();
00451             if(!success)
00452                 return RC(sthread_t::stTIMEOUT);
00453         }
00454         else {
00455             // forever timeout
00456             if(new_mode == LATCH_SH) {
00457                 _lock.acquire_read();
00458             }
00459             else {
00460                 w_assert2(new_mode == LATCH_EX);
00461                 w_assert2(me->_count == 0);
00462                 _lock.acquire_write();
00463             }
00464         }
00465         w_assert2(me->_count == 0);
00466         me->_mode = new_mode;
00467     }
00468     atomic_inc_uint(&_total_count);// BUG_SEMANTICS_FIX
00469     me->_count++;// BUG_SEMANTICS_FIX
00470 
00471     
00472     DBGTHRD(<< "acquired " << *this );
00473 
00474 
00475     return RCOK;  
00476 };
00477 
00478 
00479 int 
00480 latch_t::_release(latch_holder_t* me)
00481 {
00482     FUNC(latch_t::release);
00483     DBGTHRD(<< "want to release " << *this );
00484 
00485     w_assert2(me->_latch == this);
00486     w_assert2(me->_mode != LATCH_NL);
00487     w_assert2(me->_count > 0);
00488 
00489     atomic_dec_uint(&_total_count); 
00490     if(--me->_count) {
00491         DBGTHRD(<< "was held multiple times -- still " << me->_count << " " << *this );
00492         return me->_count;
00493     }
00494     
00495     if(me->_mode == LATCH_SH) {
00496         w_assert2(_lock.has_reader());
00497         _lock.release_read();
00498     }
00499     else {
00500         w_assert2(_lock.has_writer());
00501         _lock.release_write();
00502     }
00503     me->_mode = LATCH_NL;
00504     return 0;
00505 }
00506 
00507 void latch_t::downgrade() {
00508     holder_search me(this);
00509     // we should already hold the latch!
00510     w_assert3(me.value() != NULL);
00511     _downgrade(me.value());
00512 }
00513 
00514 void 
00515 latch_t::_downgrade(latch_holder_t* me)
00516 {
00517     FUNC(latch_t::downgrade);
00518     DBGTHRD(<< "want to downgrade " << *this );
00519 
00520     w_assert3(me->_latch == this);
00521     w_assert3(me->_mode == LATCH_EX);
00522     w_assert3(me->_count > 0);
00523     
00524     _lock.downgrade();
00525     me->_mode = LATCH_SH;
00526     
00527 }
00528 
00529 void latch_holder_t::print(ostream &o) const
00530 {
00531     o << "Holder " << latch_t::latch_mode_str[int(_mode)] 
00532         << " cnt=" << _count 
00533     << " threadid/" << ::hex << w_base_t::uint8_t(_threadid) 
00534     << " latch:";
00535     if(_latch) {
00536         o  << *_latch << endl;
00537     } else { 
00538         o  << "NULL" << endl;
00539     }
00540 }
00541 
00542 // return the number of times the latch is held by this thread 
00543 // or 0 if I do not hold the latch
00544 // There should never be more than one holder structure for a single
00545 // latch.
00546 int
00547 latch_t::held_by_me() const 
00548 {
00549     holder_search me(this);
00550     return me.value()? me->_count : 0;
00551 }
00552 
00553 bool
00554 latch_t::is_mine() const {
00555     holder_search me(this);
00556     return me.value()? (me->_mode == LATCH_EX) : false;
00557 }
00558 
00559 // NOTE: this is not safe, but it can be used by unit tests
00560 // and for debugging
00561 #include <w_stream.h>
00562 ostream &latch_t::print(ostream &out) const
00563 {
00564     out <<    "latch(" << this << "): " << name();
00565     out << " held in " << latch_mode_str[int(mode())] << " mode ";
00566     out << "by " << num_holders() << " threads " ;
00567     out << "total " << latch_cnt() << " times " ;
00568     out << endl;
00569     return out;
00570 }
00571 
00572 
00573 ostream& operator<<(ostream& out, const latch_t& l)
00574 {
00575     return l.print(out);
00576 }
00577 
00578 // For use in debugger:
00579 void print_latch(const latch_t *l)
00580 {
00581     if(l != NULL) l->print(cerr);
00582 }
00583 
00584 // For use in debugger:
00585 void print_my_latches()
00586 {
00587     FUNC(print_my_latches);
00588     holders_print all(latch_holder_t::thread_local_holders);
00589 }
00590 
00591 void print_all_latches()
00592 {
00593     FUNC(print_all_latches);
00594 // Don't protect: this is for use in a debugger.
00595 // It's absolutely dangerous to use in a running
00596 // storage manager, since these lists will be
00597 // munged frequently. 
00598     int count=0;
00599     {
00600         holder_list_list_t::iterator  iter;
00601         for(iter= holder_list_list.begin(); 
00602              iter != holder_list_list.end(); 
00603              iter ++) count++;
00604     }
00605     holder_list_list_t::iterator  iter;
00606     cerr << "ALL " << count << " LATCHES {" << endl;
00607     for(iter= holder_list_list.begin(); 
00608          iter != holder_list_list.end(); iter ++)
00609     {
00610         DBG(<<"");
00611         sthread_t* who = iter->first;
00612         DBG(<<" who " << (void *)(who));
00613         latch_holder_t **whoslist = iter->second;
00614         DBG(<<" whoslist " << (void *)(whoslist));
00615         if(who) {
00616         cerr << "{ Thread id:" << ::dec << who->id 
00617          << " @ sthread/" << ::hex << w_base_t::uint8_t(who)
00618          << " @ pthread/" << ::hex << w_base_t::uint8_t(who->myself())
00619          << endl << "\t";
00620         } else {
00621         cerr << "{ empty }"
00622          << endl << "\t";
00623         }
00624         DBG(<<"");
00625         holders_print whose(*whoslist); 
00626         cerr <<  "} " << endl << flush;
00627     }
00628     cerr <<  "}" << endl << flush ;
00629 }

Generated on Wed Jul 7 17:22:31 2010 for Shore Storage Manager by  doxygen 1.4.7