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 }