00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 #include "w_defines.h"
00055 
00056 
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     
00086     if(t) {
00087         fprintf(stderr, "t=%d\n", t);
00088     }
00089     w_assert2(t == 0);
00090 
00091     w_assert2(mode() == LATCH_NL);
00092     w_assert2(num_holders() == 0);
00093 #endif
00094 }
00095 
00096 
00097 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 
00114 
00115 
00116 __thread latch_holder_t* latch_holder_t::thread_local_holders(NULL);
00117 
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 
00128 
00129 
00130 __thread latch_holder_t* latch_holder_t::thread_local_freelist(NULL);
00131 
00132 
00133 
00134 
00135 
00136 
00137 
00138 
00139 
00140 
00141 class holder_list 
00142 {
00143     latch_holder_t* &_first;
00144 public:
00145     holder_list(latch_holder_t* &first) : _first(first) { }
00146 
00147 
00148     struct iterator {
00149         latch_holder_t* _cur;
00150         public:
00151 
00152 
00153         explicit iterator(latch_holder_t* cur) : _cur(cur) { }
00154 
00155 
00156         operator latch_holder_t*() const { return _cur; }
00157 
00158 
00159         latch_holder_t* operator->() const { return *this; }
00160 
00161 
00162         iterator &operator++() { _cur = _cur->_next; return *this; }
00163 
00164 
00165         iterator operator++(int) { return ++iterator(*this); }
00166     };
00167 
00168 
00169     iterator begin() { return iterator(_first); }
00170 
00171 
00172     iterator end() { return iterator(NULL); }
00173 
00174 
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 
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         
00193         return it;
00194     }
00195 };
00196 
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206 
00207 
00208 
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 
00231 
00232 
00233 
00234 
00235 
00236 
00237 
00238 
00239 class holder_search 
00240 {
00241 public:
00242 
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 
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 
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         
00274         
00275         
00276         
00277         if(_it == _end) {
00278             latch_holder_t* h = _freelist;
00279             if(h) _freelist = h->_next;
00280             
00281             if(h)
00282                 
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         
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 }; 
00308 
00309 
00310 
00311 
00312 
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 
00318 
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 
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     
00362     w_assert3(me.value() != NULL);
00363     
00364     
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         
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         
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     
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         
00411         w_assert2(me->_mode != LATCH_NL);
00412         w_assert2(mode() == me->_mode); 
00413         
00414         if(mode() == LATCH_EX) {
00415             w_assert2(num_holders() == 1);
00416             
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);
00424             me->_count++; 
00425             
00426             
00427 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00428             
00429             
00430             
00431             
00432             
00433             
00434             
00435             
00436             INC_STH_STATS(latch_uncondl_nowait);
00437 #endif
00438             return RCOK;
00439         } else if(new_mode == LATCH_EX && me->_mode == LATCH_SH) {
00440             is_upgrade = true;
00441         }
00442     } else {
00443         
00444         me->_latch = this;
00445         me->_mode = LATCH_NL;
00446         me->_count = 0;
00447     }
00448 
00449     
00450     
00451     if(is_upgrade) {
00452         
00453         
00454         if(!_lock.attempt_upgrade())
00455             return RC(sthread_t::stINUSE);
00456 
00457         w_assert2(me->_count > 0);
00458         w_assert2(new_mode == LATCH_EX);
00459         me->_mode = new_mode;
00460 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00461         
00462         
00463         
00464         
00465         
00466         
00467         
00468         
00469         INC_STH_STATS(latch_uncondl_nowait);
00470 #endif
00471     } else {
00472         if(timeout == WAIT_IMMEDIATE) {
00473             INC_STH_STATS(needs_latch_condl);
00474             bool success = (new_mode == LATCH_SH)? 
00475                 _lock.attempt_read() : _lock.attempt_write();
00476             if(!success)
00477                 return RC(sthread_t::stTIMEOUT);
00478             INC_STH_STATS(latch_condl_nowait);
00479         }
00480         else {
00481             
00482             INC_STH_STATS(needs_latch_uncondl);
00483             if(new_mode == LATCH_SH) {
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00492                 if(_lock.attempt_read()) {
00493                     INC_STH_STATS(latch_uncondl_nowait);
00494                 } else
00495 #endif
00496                 _lock.acquire_read();
00497             }
00498             else {
00499                 w_assert2(new_mode == LATCH_EX);
00500                 w_assert2(me->_count == 0);
00501 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00502                 if(_lock.attempt_write()) {
00503                     INC_STH_STATS(latch_uncondl_nowait);
00504                 } else 
00505 #endif
00506                 _lock.acquire_write();
00507             }
00508         }
00509         w_assert2(me->_count == 0);
00510         me->_mode = new_mode;
00511     }
00512     atomic_inc_uint(&_total_count);
00513     me->_count++;
00514     DBGTHRD(<< "acquired " << *this );
00515     return RCOK;  
00516 }
00517 
00518 
00519 int 
00520 latch_t::_release(latch_holder_t* me)
00521 {
00522     FUNC(latch_t::release);
00523     DBGTHRD(<< "want to release " << *this );
00524 
00525     w_assert2(me->_latch == this);
00526     w_assert2(me->_mode != LATCH_NL);
00527     w_assert2(me->_count > 0);
00528 
00529     atomic_dec_uint(&_total_count); 
00530     if(--me->_count) {
00531         DBGTHRD(<< "was held multiple times -- still " << me->_count << " " << *this );
00532         return me->_count;
00533     }
00534     
00535     if(me->_mode == LATCH_SH) {
00536         w_assert2(_lock.has_reader());
00537         _lock.release_read();
00538     }
00539     else {
00540         w_assert2(_lock.has_writer());
00541         _lock.release_write();
00542     }
00543     me->_mode = LATCH_NL;
00544     return 0;
00545 }
00546 
00547 void latch_t::downgrade() {
00548     holder_search me(this);
00549     
00550     w_assert3(me.value() != NULL);
00551     _downgrade(me.value());
00552 }
00553 
00554 void 
00555 latch_t::_downgrade(latch_holder_t* me)
00556 {
00557     FUNC(latch_t::downgrade);
00558     DBGTHRD(<< "want to downgrade " << *this );
00559 
00560     w_assert3(me->_latch == this);
00561     w_assert3(me->_mode == LATCH_EX);
00562     w_assert3(me->_count > 0);
00563     
00564     _lock.downgrade();
00565     me->_mode = LATCH_SH;
00566     
00567 }
00568 
00569 void latch_holder_t::print(ostream &o) const
00570 {
00571     o << "Holder " << latch_t::latch_mode_str[int(_mode)] 
00572         << " cnt=" << _count 
00573     << " threadid/" << ::hex << w_base_t::uint8_t(_threadid) 
00574     << " latch:";
00575     if(_latch) {
00576         o  << *_latch << endl;
00577     } else { 
00578         o  << "NULL" << endl;
00579     }
00580 }
00581 
00582 
00583 
00584 
00585 
00586 int
00587 latch_t::held_by_me() const 
00588 {
00589     holder_search me(this);
00590     return me.value()? me->_count : 0;
00591 }
00592 
00593 bool
00594 latch_t::is_mine() const {
00595     holder_search me(this);
00596     return me.value()? (me->_mode == LATCH_EX) : false;
00597 }
00598 
00599 
00600 
00601 #include <w_stream.h>
00602 ostream &latch_t::print(ostream &out) const
00603 {
00604     out <<    "latch(" << this << "): " << name();
00605     out << " held in " << latch_mode_str[int(mode())] << " mode ";
00606     out << "by " << num_holders() << " threads " ;
00607     out << "total " << latch_cnt() << " times " ;
00608     out << endl;
00609     return out;
00610 }
00611 
00612 
00613 ostream& operator<<(ostream& out, const latch_t& l)
00614 {
00615     return l.print(out);
00616 }
00617 
00618 
00619 void print_latch(const latch_t *l)
00620 {
00621     if(l != NULL) l->print(cerr);
00622 }
00623 
00624 
00625 void print_my_latches()
00626 {
00627     FUNC(print_my_latches);
00628     holders_print all(latch_holder_t::thread_local_holders);
00629 }
00630 
00631 void print_all_latches()
00632 {
00633     FUNC(print_all_latches);
00634 
00635 
00636 
00637 
00638     int count=0;
00639     {
00640         holder_list_list_t::iterator  iter;
00641         for(iter= holder_list_list.begin(); 
00642              iter != holder_list_list.end(); 
00643              iter ++) count++;
00644     }
00645     holder_list_list_t::iterator  iter;
00646     cerr << "ALL " << count << " LATCHES {" << endl;
00647     for(iter= holder_list_list.begin(); 
00648          iter != holder_list_list.end(); iter ++)
00649     {
00650         DBG(<<"");
00651         sthread_t* who = iter->first;
00652         DBG(<<" who " << (void *)(who));
00653         latch_holder_t **whoslist = iter->second;
00654         DBG(<<" whoslist " << (void *)(whoslist));
00655         if(who) {
00656         cerr << "{ Thread id:" << ::dec << who->id 
00657          << " @ sthread/" << ::hex << w_base_t::uint8_t(who)
00658          << " @ pthread/" << ::hex << w_base_t::uint8_t(who->myself())
00659          << endl << "\t";
00660         } else {
00661         cerr << "{ empty }"
00662          << endl << "\t";
00663         }
00664         DBG(<<"");
00665         holders_print whose(*whoslist); 
00666         cerr <<  "} " << endl << flush;
00667     }
00668     cerr <<  "}" << endl << flush ;
00669 }