00001
00002 #ifndef __MUTEX_LOCK_ET__
00003 #define __MUTEX_LOCK_ET__
00004
00005 #include "debuget.h"
00006 #include <iostream>
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 template<unsigned int num_doors>
00036 class MutexLock {
00037 public:
00038 static const unsigned int NO_OWNER=-1U;
00039
00040
00041 MutexLock() : doors_used(0), owner_index(NO_OWNER), lockcount(0) { init(); }
00042
00043
00044
00045
00046
00047
00048
00049
00050 void lock(int id);
00051
00052
00053
00054
00055
00056
00057
00058 bool try_lock(int id);
00059
00060
00061 void release();
00062
00063
00064 inline void unlock() { lockcount=1; release(); }
00065
00066
00067 unsigned int get_lock_level() const { return lockcount; }
00068
00069
00070 inline int owner() { return owner_index==NO_OWNER ? NO_OWNER : doors[owner_index].id; }
00071
00072
00073 void forget(int id);
00074
00075 #ifdef MUTEX_LOCK_ET_USE_SPINCOUNT
00076 inline unsigned int getSpincount() { return spincount; }
00077 inline unsigned int resetSpincount() { spincount=0; }
00078 #endif
00079
00080 protected:
00081
00082
00083
00084 bool do_try_lock(unsigned int index, bool block);
00085
00086
00087 unsigned int lookup(int id);
00088
00089 #ifdef MUTEX_LOCK_ET_USE_SPINCOUNT
00090 volatile unsigned int spincount;
00091 void init() { spincount=0; }
00092 inline void spin() { spincount++; }
00093 #else
00094 void init() { }
00095
00096 inline void spin() {}
00097 #endif
00098
00099
00100 struct door_t {
00101 door_t() : id(NO_OWNER), FCFS_in_use(false), BL_ready(false), BL_in_use(false), turn('\0'), next_turn_bit('\0') {}
00102
00103 int id;
00104 volatile bool FCFS_in_use;
00105 volatile bool BL_ready;
00106 volatile bool BL_in_use;
00107 volatile unsigned char turn;
00108 unsigned char next_turn_bit;
00109 };
00110
00111 door_t doors[num_doors];
00112 unsigned int doors_used;
00113 unsigned int owner_index;
00114 unsigned int lockcount;
00115 };
00116
00117
00118 template<unsigned int num_doors>
00119 void
00120 MutexLock<num_doors>::lock(int id) {
00121 if(owner()!=id)
00122 while(!do_try_lock(lookup(id),true))
00123 spin();
00124 lockcount++;
00125 }
00126
00127
00128 template<unsigned int num_doors>
00129 bool
00130 MutexLock<num_doors>::try_lock(int id) {
00131 if(owner()==id) {
00132 lockcount++;
00133 return true;
00134 } else {
00135 if(do_try_lock(lookup(id),false)) {
00136 lockcount++;
00137 return true;
00138 } else
00139 return false;
00140 }
00141 }
00142
00143
00144 template<unsigned int num_doors>
00145 void
00146 MutexLock<num_doors>::release() {
00147 if(lockcount>0)
00148 if(--lockcount==0)
00149 if(owner_index!=NO_OWNER) {
00150 unsigned int tmp = owner_index;
00151 owner_index=NO_OWNER;
00152 doors[tmp].BL_in_use=false;
00153 doors[tmp].BL_ready=false;
00154
00155 }
00156 }
00157
00158
00159
00160 #define mutexdebugout(i,c) {}
00161
00162
00163
00164 template<unsigned int num_doors>
00165 bool
00166 MutexLock<num_doors>::do_try_lock(unsigned int i, bool block) {
00167 if(i==NO_OWNER) {
00168 std::cerr << "WARNING: new process attempted to lock beyond num_doors ("<<num_doors<<")" << std::endl;
00169 return false;
00170 }
00171 unsigned char S[num_doors];
00172
00173
00174 mutexdebugout(i,'A');
00175 doors[i].FCFS_in_use=true;
00176 for(unsigned int j=0; j<num_doors; j++)
00177 S[j]=doors[j].turn;
00178 doors[i].next_turn_bit=1-doors[i].next_turn_bit;
00179 doors[i].turn^=(1<<doors[i].next_turn_bit);
00180 doors[i].BL_ready=true;
00181 doors[i].FCFS_in_use=false;
00182
00183 mutexdebugout(i,'B');
00184 for(unsigned int j=0; j<num_doors; j++) {
00185 mutexdebugout(i,'C');
00186 while(doors[j].FCFS_in_use || (doors[j].BL_ready && S[j]==doors[j].turn))
00187 if(block)
00188 spin();
00189 else {
00190 doors[i].BL_ready=false;
00191 return false;
00192 }
00193 mutexdebugout(i,'D');
00194 }
00195
00196 mutexdebugout(i,'E');
00197 do {
00198 doors[i].BL_in_use=true;
00199 for(unsigned int t=0; t<i; t++)
00200 if(doors[t].BL_in_use) {
00201 doors[i].BL_in_use=false;
00202 if(!block) {
00203 doors[i].BL_ready=false;
00204 return false;
00205 }
00206 mutexdebugout(i,'F');
00207 while(doors[t].BL_in_use)
00208 spin();
00209 mutexdebugout(i,'G');
00210 break;
00211 }
00212 } while(!doors[i].BL_in_use);
00213 for(unsigned int t=i+1; t<num_doors; t++)
00214 while(doors[t].BL_in_use)
00215 spin();
00216
00217
00218 mutexdebugout(i,'H');
00219 owner_index=i;
00220 return true;
00221 }
00222
00223
00224 template<unsigned int num_doors>
00225 unsigned int
00226 MutexLock<num_doors>::lookup(int id) {
00227
00228
00229
00230
00231 unsigned int i;
00232 for(i=0; i<doors_used; i++)
00233 if(doors[i].id==id)
00234 return i;
00235 if(i==num_doors)
00236 return NO_OWNER;
00237 doors[i].id=id;
00238 doors_used++;
00239 return i;
00240 }
00241
00242
00243 template<unsigned int num_doors>
00244 void
00245 MutexLock<num_doors>::forget(int id) {
00246 unsigned int i = lookup(id);
00247 do_try_lock(i,true);
00248 doors[i].id=doors[--doors_used].id;
00249 doors[doors_used].id=NO_OWNER;
00250 release();
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 #endif