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 DBGTHRD(<< "acquired " << *this );
00471 return RCOK;
00472 }
00473
00474
00475 int
00476 latch_t::_release(latch_holder_t* me)
00477 {
00478 FUNC(latch_t::release);
00479 DBGTHRD(<< "want to release " << *this );
00480
00481 w_assert2(me->_latch == this);
00482 w_assert2(me->_mode != LATCH_NL);
00483 w_assert2(me->_count > 0);
00484
00485 atomic_dec_uint(&_total_count);
00486 if(--me->_count) {
00487 DBGTHRD(<< "was held multiple times -- still " << me->_count << " " << *this );
00488 return me->_count;
00489 }
00490
00491 if(me->_mode == LATCH_SH) {
00492 w_assert2(_lock.has_reader());
00493 _lock.release_read();
00494 }
00495 else {
00496 w_assert2(_lock.has_writer());
00497 _lock.release_write();
00498 }
00499 me->_mode = LATCH_NL;
00500 return 0;
00501 }
00502
00503 void latch_t::downgrade() {
00504 holder_search me(this);
00505
00506 w_assert3(me.value() != NULL);
00507 _downgrade(me.value());
00508 }
00509
00510 void
00511 latch_t::_downgrade(latch_holder_t* me)
00512 {
00513 FUNC(latch_t::downgrade);
00514 DBGTHRD(<< "want to downgrade " << *this );
00515
00516 w_assert3(me->_latch == this);
00517 w_assert3(me->_mode == LATCH_EX);
00518 w_assert3(me->_count > 0);
00519
00520 _lock.downgrade();
00521 me->_mode = LATCH_SH;
00522
00523 }
00524
00525 void latch_holder_t::print(ostream &o) const
00526 {
00527 o << "Holder " << latch_t::latch_mode_str[int(_mode)]
00528 << " cnt=" << _count
00529 << " threadid/" << ::hex << w_base_t::uint8_t(_threadid)
00530 << " latch:";
00531 if(_latch) {
00532 o << *_latch << endl;
00533 } else {
00534 o << "NULL" << endl;
00535 }
00536 }
00537
00538
00539
00540
00541
00542 int
00543 latch_t::held_by_me() const
00544 {
00545 holder_search me(this);
00546 return me.value()? me->_count : 0;
00547 }
00548
00549 bool
00550 latch_t::is_mine() const {
00551 holder_search me(this);
00552 return me.value()? (me->_mode == LATCH_EX) : false;
00553 }
00554
00555
00556
00557 #include <w_stream.h>
00558 ostream &latch_t::print(ostream &out) const
00559 {
00560 out << "latch(" << this << "): " << name();
00561 out << " held in " << latch_mode_str[int(mode())] << " mode ";
00562 out << "by " << num_holders() << " threads " ;
00563 out << "total " << latch_cnt() << " times " ;
00564 out << endl;
00565 return out;
00566 }
00567
00568
00569 ostream& operator<<(ostream& out, const latch_t& l)
00570 {
00571 return l.print(out);
00572 }
00573
00574
00575 void print_latch(const latch_t *l)
00576 {
00577 if(l != NULL) l->print(cerr);
00578 }
00579
00580
00581 void print_my_latches()
00582 {
00583 FUNC(print_my_latches);
00584 holders_print all(latch_holder_t::thread_local_holders);
00585 }
00586
00587 void print_all_latches()
00588 {
00589 FUNC(print_all_latches);
00590
00591
00592
00593
00594 int count=0;
00595 {
00596 holder_list_list_t::iterator iter;
00597 for(iter= holder_list_list.begin();
00598 iter != holder_list_list.end();
00599 iter ++) count++;
00600 }
00601 holder_list_list_t::iterator iter;
00602 cerr << "ALL " << count << " LATCHES {" << endl;
00603 for(iter= holder_list_list.begin();
00604 iter != holder_list_list.end(); iter ++)
00605 {
00606 DBG(<<"");
00607 sthread_t* who = iter->first;
00608 DBG(<<" who " << (void *)(who));
00609 latch_holder_t **whoslist = iter->second;
00610 DBG(<<" whoslist " << (void *)(whoslist));
00611 if(who) {
00612 cerr << "{ Thread id:" << ::dec << who->id
00613 << " @ sthread/" << ::hex << w_base_t::uint8_t(who)
00614 << " @ pthread/" << ::hex << w_base_t::uint8_t(who->myself())
00615 << endl << "\t";
00616 } else {
00617 cerr << "{ empty }"
00618 << endl << "\t";
00619 }
00620 DBG(<<"");
00621 holders_print whose(*whoslist);
00622 cerr << "} " << endl << flush;
00623 }
00624 cerr << "}" << endl << flush ;
00625 }