00001
00002 #ifndef __MUTEX_LOCK_ET__
00003 #define __MUTEX_LOCK_ET__
00004
00005 #include "Shared/Resource.h"
00006 #include "ProcessID.h"
00007 #include <iostream>
00008 #include <exception>
00009 #include <typeinfo>
00010
00011 #ifndef PLATFORM_APERIOS
00012 # include "SemaphoreManager.h"
00013 # if !defined(MUTEX_LOCK_ET_USE_SOFTWARE_ONLY) && TEKKOTSU_SHM_STYLE==NO_SHM
00014 # include "Thread.h"
00015 # endif
00016 # include "RCRegion.h"
00017 # include <unistd.h>
00018 # include <pthread.h>
00019 #endif
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 class MutexLockBase : public Resource {
00037 public:
00038 virtual ~MutexLockBase() {}
00039
00040 static const unsigned int NO_OWNER=-1U;
00041 static unsigned int usleep_granularity;
00042
00043
00044 #if !defined(PLATFORM_APERIOS) && TEKKOTSU_SHM_STYLE!=NO_SHM
00045
00046 class no_more_semaphores : public std::exception {
00047 public:
00048
00049 no_more_semaphores() throw() : std::exception() {}
00050
00051 virtual const char* what() const throw() { return "SemaphoreManager::getSemaphore() returned invalid()"; }
00052 };
00053
00054
00055
00056 static void setSemaphoreManager(SemaphoreManager* mgr) {
00057 if(mgr==NULL) {
00058 preallocated=*semgr;
00059 semgr=&preallocated;
00060 } else {
00061 *mgr=*semgr;
00062 semgr=mgr;
00063 }
00064 }
00065
00066 static SemaphoreManager* getSemaphoreManager() {
00067 return semgr;
00068 }
00069
00070 static void aboutToFork() {
00071 preallocated.aboutToFork();
00072 }
00073
00074 protected:
00075
00076 static SemaphoreManager* semgr;
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 static SemaphoreManager preallocated;
00091
00092 #elif TEKKOTSU_SHM_STYLE==NO_SHM
00093 public:
00094 static void aboutToFork() {}
00095 #endif
00096 };
00097
00098
00099
00100 #if !defined(PLATFORM_APERIOS) && !defined(MUTEX_LOCK_ET_USE_SOFTWARE_ONLY)
00101 #if TEKKOTSU_SHM_STYLE==NO_SHM
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 template<unsigned int num_doors>
00121 class MutexLock : public MutexLockBase {
00122 public:
00123
00124 MutexLock() : owner_index(NO_OWNER), thdLock() {}
00125
00126
00127 ~MutexLock() {
00128 if(owner_index!=NO_OWNER) {
00129 owner_index=NO_OWNER;
00130 while(thdLock.getLockLevel()>0)
00131 thdLock.unlock();
00132 }
00133 }
00134
00135
00136
00137
00138 void lock(int id) {
00139 thdLock.lock();
00140 if(owner_index!=static_cast<unsigned>(id))
00141 owner_index=id;
00142 }
00143
00144
00145
00146
00147 bool try_lock(int id) {
00148 if(!thdLock.trylock())
00149 return false;
00150 owner_index=id;
00151 return true;
00152 }
00153
00154
00155 inline void unlock() {
00156 if(thdLock.getLockLevel()<=0)
00157 std::cerr << "Warning: MutexLock::unlock caused underflow" << std::endl;
00158 if(thdLock.getLockLevel()<=1)
00159 owner_index=NO_OWNER;
00160 thdLock.unlock();
00161 }
00162
00163
00164 void releaseAll() {
00165 owner_index=NO_OWNER;
00166 while(thdLock.getLockLevel()>0)
00167 thdLock.unlock();
00168 }
00169
00170
00171 unsigned int get_lock_level() const { return thdLock.getLockLevel(); }
00172
00173
00174 inline int owner() const { return owner_index; }
00175
00176 protected:
00177 friend class MarkScope;
00178 virtual void useResource(Resource::Data&) { lock(ProcessID::getID()); }
00179 virtual void releaseResource(Resource::Data&) { unlock(); }
00180
00181 unsigned int owner_index;
00182 ThreadNS::Lock thdLock;
00183 };
00184
00185 #else
00186 # include "SemaphoreManager.h"
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 template<unsigned int num_doors>
00214 class MutexLock : public MutexLockBase {
00215 public:
00216
00217 MutexLock() : MutexLockBase(),
00218 sem(semgr->getSemaphore()), owner_index(NO_OWNER), owner_thread()
00219 {
00220 if(sem==semgr->invalid())
00221 throw no_more_semaphores();
00222 semgr->setValue(sem,0);
00223 }
00224
00225
00226 MutexLock(SemaphoreManager::semid_t semid) : MutexLockBase(),
00227 sem(semid), owner_index(NO_OWNER), owner_thread()
00228 {
00229 if(sem==semgr->invalid())
00230 throw no_more_semaphores();
00231 semgr->setValue(sem,0);
00232 }
00233
00234
00235 ~MutexLock() {
00236 owner_index=NO_OWNER;
00237 if(semgr!=NULL && !semgr->hadFault())
00238 semgr->releaseSemaphore(sem);
00239 else
00240 std::cerr << "Warning: MutexLock leaked semaphore " << sem << " because SemaphoreManager is NULL" << std::endl;
00241 }
00242
00243
00244
00245
00246 void lock(int id) {
00247 if(owner_index!=static_cast<unsigned>(id) || !isOwnerThread()) {
00248
00249 if(semgr!=NULL && !semgr->hadFault()) {
00250 semgr->testZero_add(sem,1);
00251 } else
00252 std::cerr << "Warning: MutexLock assuming lock of " << sem << " because SemaphoreManager is NULL" << std::endl;
00253 owner_index=id;
00254 owner_thread=pthread_self();
00255 } else {
00256
00257 if(semgr!=NULL && !semgr->hadFault())
00258 semgr->raise(sem,1);
00259 else
00260 std::cerr << "Warning: MutexLock assuming lock of " << sem << " because SemaphoreManager is NULL" << std::endl;
00261 }
00262 }
00263
00264
00265
00266
00267 bool try_lock(int id) {
00268 if(semgr==NULL || semgr->hadFault()) {
00269 std::cerr << "Warning: MutexLock assuming try_lock success of " << sem << " because SemaphoreManager is NULL" << std::endl;
00270 owner_index=id;
00271 return true;
00272 }
00273 if(owner()==id && isOwnerThread()) {
00274
00275 semgr->raise(sem,1);
00276 return true;
00277 } else {
00278 if(semgr->testZero_add(sem,1,false)) {
00279 owner_index=id;
00280 owner_thread=pthread_self();
00281 return true;
00282 } else {
00283 return false;
00284 }
00285 }
00286 }
00287
00288
00289 inline void unlock() {
00290 if(semgr==NULL || semgr->hadFault()) {
00291 std::cerr << "Warning: MutexLock assuming unlock of " << sem << " from " << owner_index << " because SemaphoreManager is NULL" << std::endl;
00292 owner_index=NO_OWNER;
00293 return;
00294 }
00295 if(semgr->getValue(sem)<=0) {
00296 std::cerr << "Warning: MutexLock::unlock caused underflow" << std::endl;
00297 owner_index=NO_OWNER;
00298 return;
00299 }
00300 if(semgr->getValue(sem)==1)
00301 owner_index=NO_OWNER;
00302 if(!semgr->lower(sem,1,false))
00303 std::cerr << "Warning: MutexLock::unlock caused strange underflow" << std::endl;
00304 }
00305
00306
00307 void releaseAll() {
00308 owner_index=NO_OWNER;
00309 if(semgr==NULL || semgr->hadFault()) {
00310 std::cerr << "Warning: MutexLock assuming releaseAll of " << sem << " because SemaphoreManager is NULL" << std::endl;
00311 return;
00312 }
00313 semgr->setValue(sem,0);
00314 }
00315
00316
00317 unsigned int get_lock_level() const {
00318 if(semgr==NULL || semgr->hadFault())
00319 return (owner_index==NO_OWNER) ? 0 : 1;
00320 else
00321 return semgr->getValue(sem);
00322 }
00323
00324
00325 inline int owner() const { return owner_index; }
00326
00327 protected:
00328
00329 bool isOwnerThread() {
00330 pthread_t cur=pthread_self();
00331 return pthread_equal(cur,owner_thread);
00332 }
00333 friend class MarkScope;
00334 virtual void useResource(Resource::Data&) {
00335 lock(ProcessID::getID());
00336 }
00337 virtual void releaseResource(Resource::Data&) {
00338 unlock();
00339 }
00340
00341 SemaphoreManager::semid_t sem;
00342 unsigned int owner_index;
00343 pthread_t owner_thread;
00344
00345 private:
00346 MutexLock(const MutexLock& ml);
00347 MutexLock& operator=(const MutexLock& ml);
00348 };
00349
00350
00351
00352
00353 #endif
00354 #else //SOFTWARE ONLY mutual exclusion, used on Aperios, or if MUTEX_LOCK_ET_USE_SOFTWARE_ONLY is defined
00355
00356
00357
00358
00359
00360
00361
00362
00363 #ifdef DEBUG_MUTEX_LOCK
00364 # include "Shared/WorldState.h"
00365 #endif
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 template<unsigned int num_doors>
00397 class MutexLock : public MutexLockBase {
00398 public:
00399
00400 MutexLock() : doors_used(0), owner_index(NO_OWNER), lockcount(0) { init(); }
00401
00402 #ifndef PLATFORM_APERIOS
00403
00404 ~MutexLock() {
00405 if(owner_index!=NO_OWNER) {
00406 owner_index=NO_OWNER;
00407 thdLock[sem].unlock();
00408 }
00409 }
00410 #endif
00411
00412
00413
00414
00415
00416 void lock(int id);
00417
00418
00419
00420
00421 bool try_lock(int id);
00422
00423
00424 inline void unlock();
00425
00426
00427 void releaseAll() { lockcount=1; unlock(); }
00428
00429
00430 unsigned int get_lock_level() const { return lockcount; }
00431
00432
00433 inline int owner() const { return owner_index==NO_OWNER ? NO_OWNER : doors[owner_index].id; }
00434
00435
00436 void forget(int id);
00437
00438 #ifdef MUTEX_LOCK_ET_USE_SPINCOUNT
00439 inline unsigned int getSpincount() { return spincount; }
00440 inline unsigned int resetSpincount() { spincount=0; }
00441 #endif
00442
00443 protected:
00444 friend class MarkScope;
00445 virtual void useResource(Resource::Data&) {
00446 lock(ProcessID::getID());
00447 }
00448 virtual void releaseResource(Resource::Data&) {
00449 unlock();
00450 }
00451
00452
00453
00454
00455 bool do_try_lock(unsigned int index, bool block);
00456
00457
00458 unsigned int lookup(int id);
00459
00460 #ifdef MUTEX_LOCK_ET_USE_SPINCOUNT
00461 volatile unsigned int spincount;
00462 void init() { spincount=0; }
00463 inline void spin() {
00464 spincount++;
00465 #ifndef PLATFORM_APERIOS
00466 usleep(usleep_granularity*10);
00467 #endif
00468 }
00469 #else
00470 void init() { }
00471
00472 inline void spin() {
00473 #ifndef PLATFORM_APERIOS
00474 usleep(usleep_granularity*10);
00475 #endif
00476 }
00477 #endif
00478
00479
00480 struct door_t {
00481 door_t() : id(NO_OWNER), FCFS_in_use(false), BL_ready(false), BL_in_use(false), turn('\0'), next_turn_bit('\0') {}
00482
00483 int id;
00484 volatile bool FCFS_in_use;
00485 volatile bool BL_ready;
00486 volatile bool BL_in_use;
00487 volatile unsigned char turn;
00488 unsigned char next_turn_bit;
00489 };
00490
00491 door_t doors[num_doors];
00492 unsigned int doors_used;
00493 unsigned int owner_index;
00494 unsigned int lockcount;
00495 };
00496
00497
00498 template<unsigned int num_doors>
00499 void
00500 MutexLock<num_doors>::lock(int id) {
00501 #ifndef PLATFORM_APERIOS
00502 thdLock[sem].lock();
00503 #endif
00504 if(owner()!=id) {
00505 if(!do_try_lock(lookup(id),true)) {
00506
00507 std::cout << "Warning: lock() failed to achieve lock" << std::endl;
00508 }
00509 } else {
00510 #ifdef DEBUG_MUTEX_LOCK
00511 if(state==NULL || state->buttons[LFrPawOffset])
00512 std::cerr << id << " re-locked " << this << " level " << lockcount+1 << std::endl;
00513 #endif
00514 }
00515 lockcount++;
00516 }
00517
00518
00519 template<unsigned int num_doors>
00520 bool
00521 MutexLock<num_doors>::try_lock(int id) {
00522 #ifndef PLATFORM_APERIOS
00523 if(!thdLock[sem].trylock())
00524 return false;
00525 #endif
00526 if(owner()==id) {
00527 #ifdef DEBUG_MUTEX_LOCK
00528 if(state==NULL || state->buttons[LFrPawOffset])
00529 std::cerr << id << " re-locked " << this << " level " << lockcount+1 << std::endl;
00530 #endif
00531 lockcount++;
00532 return true;
00533 } else {
00534 if(do_try_lock(lookup(id),false)) {
00535 lockcount++;
00536 return true;
00537 } else {
00538 #ifndef PLATFORM_APERIOS
00539 thdLock[sem].unlock())
00540 #endif
00541 return false;
00542 }
00543 }
00544 }
00545
00546
00547 template<unsigned int num_doors>
00548 void
00549 MutexLock<num_doors>::unlock() {
00550 if(lockcount==0) {
00551 std::cerr << "Warning: MutexLock::unlock caused underflow" << std::endl;
00552 return;
00553 }
00554 #ifdef DEBUG_MUTEX_LOCK
00555 if(state==NULL || state->buttons[LFrPawOffset])
00556 std::cerr << doors[owner_index].id << " unlock " << this << " level "<< lockcount << std::endl;
00557 #endif
00558 if(--lockcount==0) {
00559 if(owner_index!=NO_OWNER) {
00560 unsigned int tmp = owner_index;
00561 owner_index=NO_OWNER;
00562 doors[tmp].BL_in_use=false;
00563 doors[tmp].BL_ready=false;
00564
00565 #ifndef PLATFORM_APERIOS
00566 if(owner_index==id) {
00567 thdLock[sem].unlock();
00568 }
00569 #endif
00570 }
00571 }
00572 }
00573
00574
00575
00576
00577
00578
00579 template<unsigned int num_doors>
00580 bool
00581 MutexLock<num_doors>::do_try_lock(unsigned int i, bool block) {
00582 if(i==NO_OWNER) {
00583 std::cerr << "WARNING: new process attempted to lock beyond num_doors ("<<num_doors<<")" << std::endl;
00584 return false;
00585 }
00586 #ifdef DEBUG_MUTEX_LOCK
00587 if(state==NULL || state->buttons[LFrPawOffset])
00588 std::cerr << doors[i].id << " attempting lock " << this << " held by " << owner_index << " at " << get_time() << std::endl;
00589 #endif
00590 unsigned char S[num_doors];
00591
00592 doors[i].FCFS_in_use=true;
00593 for(unsigned int j=0; j<num_doors; j++)
00594 S[j]=doors[j].turn;
00595 doors[i].next_turn_bit=1-doors[i].next_turn_bit;
00596 doors[i].turn^=(1<<doors[i].next_turn_bit);
00597 doors[i].BL_ready=true;
00598 doors[i].FCFS_in_use=false;
00599
00600 for(unsigned int j=0; j<num_doors; j++) {
00601 while(doors[j].FCFS_in_use || (doors[j].BL_ready && S[j]==doors[j].turn))
00602 if(block)
00603 spin();
00604 else {
00605 doors[i].BL_ready=false;
00606 #ifdef DEBUG_MUTEX_LOCK
00607 if(state==NULL || state->buttons[LFrPawOffset])
00608 std::cerr << doors[i].id << " giving up on lock " << this << " held by " << owner_index << " at " << get_time() << std::endl;
00609 #endif
00610 return false;
00611 }
00612 }
00613
00614 do {
00615 doors[i].BL_in_use=true;
00616 for(unsigned int t=0; t<i; t++)
00617 if(doors[t].BL_in_use) {
00618 doors[i].BL_in_use=false;
00619 if(!block) {
00620 doors[i].BL_ready=false;
00621 #ifdef DEBUG_MUTEX_LOCK
00622 if(state==NULL || state->buttons[LFrPawOffset])
00623 std::cerr << doors[i].id << " giving up on lock " << this << " held by " << owner_index << " at " << get_time() << std::endl;
00624 #endif
00625 return false;
00626 }
00627 while(doors[t].BL_in_use)
00628 spin();
00629 break;
00630 }
00631 } while(!doors[i].BL_in_use);
00632 for(unsigned int t=i+1; t<num_doors; t++)
00633 while(doors[t].BL_in_use)
00634 spin();
00635
00636
00637 owner_index=i;
00638 #ifdef DEBUG_MUTEX_LOCK
00639 if(state==NULL || state->buttons[LFrPawOffset])
00640 std::cerr << doors[i].id << " received lock " << this << " at " << get_time() << std::endl;
00641 #endif
00642 return true;
00643 }
00644
00645
00646 template<unsigned int num_doors>
00647 unsigned int
00648 MutexLock<num_doors>::lookup(int id) {
00649
00650
00651
00652
00653 unsigned int i;
00654 for(i=0; i<doors_used; i++)
00655 if(doors[i].id==id)
00656 return i;
00657 if(i==num_doors)
00658 return NO_OWNER;
00659 doors[i].id=id;
00660 doors_used++;
00661 return i;
00662 }
00663
00664
00665 template<unsigned int num_doors>
00666 void
00667 MutexLock<num_doors>::forget(int id) {
00668 unsigned int i = lookup(id);
00669 do_try_lock(i,true);
00670 doors[i].id=doors[--doors_used].id;
00671 doors[doors_used].id=NO_OWNER;
00672 releaseAll();
00673 }
00674
00675 #endif //MUTEX_LOCK_ET_USE_SOFTWARE_ONLY
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688 #endif