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
00442
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
00450
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
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);
00487 me->_count++;
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
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
00557
00558
00559
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
00574
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
00593 void print_latch(const latch_t *l)
00594 {
00595 if(l != NULL) l->print(cerr);
00596 }
00597
00598
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
00609
00610
00611
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 }