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 }