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             return RCOK;
00428         } else if(new_mode == LATCH_EX && me->_mode == LATCH_SH) {
00429             is_upgrade = true;
00430         }
00431     } else {
00432         
00433         me->_latch = this;
00434         me->_mode = LATCH_NL;
00435         me->_count = 0;
00436     }
00437 
00438     
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             
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);
00469     me->_count++;
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     
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 
00543 
00544 
00545 
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 
00560 
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 
00579 void print_latch(const latch_t *l)
00580 {
00581     if(l != NULL) l->print(cerr);
00582 }
00583 
00584 
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 
00595 
00596 
00597 
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 }