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