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