00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef _I_Lock_h_
00025 #define _I_Lock_h_
00026
00027 #include "libts.h"
00028 #include "I_Thread.h"
00029
00030 #define MAX_LOCK_TIME HRTIME_MSECONDS(200)
00031 #define THREAD_MUTEX_THREAD_HOLDING (-1024*1024)
00032
00033 class EThread;
00034 typedef EThread *EThreadPtr;
00035 typedef volatile EThreadPtr VolatileEThreadPtr;
00036
00037 inkcoreapi extern void lock_waiting(const char *file, int line, const char *handler);
00038 inkcoreapi extern void lock_holding(const char *file, int line, const char *handler);
00039 extern void lock_taken(const char *file, int line, const char *handler);
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 class ProxyMutex: public RefCountObj
00068 {
00069 public:
00070
00071
00072
00073
00074
00075
00076
00077
00078 ink_mutex the_mutex;
00079
00080
00081
00082
00083
00084
00085
00086
00087 volatile EThreadPtr thread_holding;
00088
00089 int nthread_holding;
00090
00091 #ifdef DEBUG
00092 ink_hrtime hold_time;
00093 const char *file;
00094 int line;
00095 const char *handler;
00096
00097 # ifdef MAX_LOCK_TAKEN
00098 int taken;
00099 # endif //MAX_LOCK_TAKEN
00100
00101 # ifdef LOCK_CONTENTION_PROFILING
00102 int total_acquires, blocking_acquires,
00103 nonblocking_acquires, successful_nonblocking_acquires, unsuccessful_nonblocking_acquires;
00104 void print_lock_stats(int flag);
00105 # endif //LOCK_CONTENTION_PROFILING
00106 #endif //DEBUG
00107 void free();
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 ProxyMutex()
00120 {
00121 thread_holding = NULL;
00122 nthread_holding = 0;
00123 #ifdef DEBUG
00124 hold_time = 0;
00125 file = NULL;
00126 line = 0;
00127 handler = NULL;
00128 # ifdef MAX_LOCK_TAKEN
00129 taken = 0;
00130 # endif //MAX_LOCK_TAKEN
00131 # ifdef LOCK_CONTENTION_PROFILING
00132 total_acquires = 0;
00133 blocking_acquires = 0;
00134 nonblocking_acquires = 0;
00135 successful_nonblocking_acquires = 0;
00136 unsuccessful_nonblocking_acquires = 0;
00137 # endif //LOCK_CONTENTION_PROFILING
00138 #endif //DEBUG
00139
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 void init(const char *name = "UnnamedMutex") {
00153 ink_mutex_init(&the_mutex, name);
00154 }
00155 };
00156
00157
00158 extern inkcoreapi ClassAllocator<ProxyMutex> mutexAllocator;
00159
00160 inline bool
00161 Mutex_trylock(
00162 #ifdef DEBUG
00163 const char *afile, int aline, const char *ahandler,
00164 #endif
00165 ProxyMutex * m, EThread * t)
00166 {
00167
00168 ink_assert(t != 0);
00169 ink_assert(t == (EThread*)this_thread());
00170 if (m->thread_holding != t) {
00171 if (!ink_mutex_try_acquire(&m->the_mutex)) {
00172 #ifdef DEBUG
00173 lock_waiting(m->file, m->line, m->handler);
00174 #ifdef LOCK_CONTENTION_PROFILING
00175 m->unsuccessful_nonblocking_acquires++;
00176 m->nonblocking_acquires++;
00177 m->total_acquires++;
00178 m->print_lock_stats(0);
00179 #endif //LOCK_CONTENTION_PROFILING
00180 #endif //DEBUG
00181 return false;
00182 }
00183 ink_assert(m->thread_holding = t);
00184 #ifdef DEBUG
00185 m->file = afile;
00186 m->line = aline;
00187 m->handler = ahandler;
00188 m->hold_time = ink_get_hrtime();
00189 #ifdef MAX_LOCK_TAKEN
00190 m->taken++;
00191 #endif //MAX_LOCK_TAKEN
00192 #endif //DEBUG
00193 }
00194 #ifdef DEBUG
00195 #ifdef LOCK_CONTENTION_PROFILING
00196 m->successful_nonblocking_acquires++;
00197 m->nonblocking_acquires++;
00198 m->total_acquires++;
00199 m->print_lock_stats(0);
00200 #endif //LOCK_CONTENTION_PROFILING
00201 #endif //DEBUG
00202 m->nthread_holding++;
00203 return true;
00204 }
00205
00206 inline bool
00207 Mutex_trylock_spin(
00208 #ifdef DEBUG
00209 const char *afile, int aline, const char *ahandler,
00210 #endif
00211 ProxyMutex * m, EThread * t, int spincnt = 1)
00212 {
00213
00214 ink_assert(t != 0);
00215 if (m->thread_holding != t) {
00216 int locked;
00217 do {
00218 if ((locked = ink_mutex_try_acquire(&m->the_mutex)))
00219 break;
00220 } while (--spincnt);
00221 if (!locked) {
00222 #ifdef DEBUG
00223 lock_waiting(m->file, m->line, m->handler);
00224 #ifdef LOCK_CONTENTION_PROFILING
00225 m->unsuccessful_nonblocking_acquires++;
00226 m->nonblocking_acquires++;
00227 m->total_acquires++;
00228 m->print_lock_stats(0);
00229 #endif //LOCK_CONTENTION_PROFILING
00230 #endif //DEBUG
00231 return false;
00232 }
00233 m->thread_holding = t;
00234 ink_assert(m->thread_holding);
00235 #ifdef DEBUG
00236 m->file = afile;
00237 m->line = aline;
00238 m->handler = ahandler;
00239 m->hold_time = ink_get_hrtime();
00240 #ifdef MAX_LOCK_TAKEN
00241 m->taken++;
00242 #endif //MAX_LOCK_TAKEN
00243 #endif //DEBUG
00244 }
00245 #ifdef DEBUG
00246 #ifdef LOCK_CONTENTION_PROFILING
00247 m->successful_nonblocking_acquires++;
00248 m->nonblocking_acquires++;
00249 m->total_acquires++;
00250 m->print_lock_stats(0);
00251 #endif //LOCK_CONTENTION_PROFILING
00252 #endif //DEBUG
00253 m->nthread_holding++;
00254 return true;
00255 }
00256
00257 inline int
00258 Mutex_lock(
00259 #ifdef DEBUG
00260 const char *afile, int aline, const char *ahandler,
00261 #endif
00262 ProxyMutex * m, EThread * t)
00263 {
00264
00265 ink_assert(t != 0);
00266 if (m->thread_holding != t) {
00267 ink_mutex_acquire(&m->the_mutex);
00268 m->thread_holding = t;
00269 ink_assert(m->thread_holding);
00270 #ifdef DEBUG
00271 m->file = afile;
00272 m->line = aline;
00273 m->handler = ahandler;
00274 m->hold_time = ink_get_hrtime();
00275 #ifdef MAX_LOCK_TAKEN
00276 m->taken++;
00277 #endif //MAX_LOCK_TAKEN
00278 #endif //DEBUG
00279 }
00280 #ifdef DEBUG
00281 #ifdef LOCK_CONTENTION_PROFILING
00282 m->blocking_acquires++;
00283 m->total_acquires++;
00284 m->print_lock_stats(0);
00285 #endif // LOCK_CONTENTION_PROFILING
00286 #endif //DEBUG
00287 m->nthread_holding++;
00288 return true;
00289 }
00290
00291 inline void
00292 Mutex_unlock(ProxyMutex * m, EThread * t)
00293 {
00294 if (m->nthread_holding) {
00295 ink_assert(t == m->thread_holding);
00296 m->nthread_holding--;
00297 if (!m->nthread_holding) {
00298 #ifdef DEBUG
00299 if (ink_get_hrtime() - m->hold_time > MAX_LOCK_TIME)
00300 lock_holding(m->file, m->line, m->handler);
00301 #ifdef MAX_LOCK_TAKEN
00302 if (m->taken > MAX_LOCK_TAKEN)
00303 lock_taken(m->file, m->line, m->handler);
00304 #endif //MAX_LOCK_TAKEN
00305 m->file = NULL;
00306 m->line = 0;
00307 m->handler = NULL;
00308 #endif //DEBUG
00309 ink_assert(m->thread_holding);
00310 m->thread_holding = 0;
00311 ink_mutex_release(&m->the_mutex);
00312 }
00313 }
00314 }
00315
00316 struct MutexLock
00317 {
00318 Ptr<ProxyMutex> m;
00319
00320 MutexLock():m(NULL)
00321 {
00322 };
00323
00324 MutexLock(
00325 #ifdef DEBUG
00326 const char *afile, int aline, const char *ahandler,
00327 #endif
00328 ProxyMutex * am, EThread * t):m(am)
00329 {
00330
00331 Mutex_lock(
00332 #ifdef DEBUG
00333 afile, aline, ahandler,
00334 #endif
00335 m, t);
00336 }
00337
00338 void set_and_take(
00339 #ifdef DEBUG
00340 const char *afile, int aline, const char *ahandler,
00341 #endif
00342 ProxyMutex * am, EThread * t)
00343 {
00344
00345 m = am;
00346 Mutex_lock(
00347 #ifdef DEBUG
00348 afile, aline, ahandler,
00349 #endif
00350 m, t);
00351 }
00352
00353 void release()
00354 {
00355 if (m)
00356 Mutex_unlock(m, m->thread_holding);
00357 m.clear();
00358 }
00359
00360 ~MutexLock()
00361 {
00362 if (m)
00363 Mutex_unlock(m, m->thread_holding);
00364 }
00365
00366 int operator!() const { return false; }
00367 operator bool() { return true; }
00368 };
00369
00370 struct MutexTryLock
00371 {
00372 Ptr<ProxyMutex> m;
00373 volatile bool lock_acquired;
00374
00375 MutexTryLock(
00376 #ifdef DEBUG
00377 const char *afile, int aline, const char *ahandler,
00378 #endif
00379 ProxyMutex * am, EThread * t)
00380 {
00381 lock_acquired = Mutex_trylock(
00382 #ifdef DEBUG
00383 afile, aline, ahandler,
00384 #endif
00385 am, t);
00386 if (lock_acquired)
00387 m = am;
00388 }
00389
00390 MutexTryLock(
00391 #ifdef DEBUG
00392 const char *afile, int aline, const char *ahandler,
00393 #endif
00394 ProxyMutex * am, EThread * t, int sp)
00395 {
00396 lock_acquired = Mutex_trylock_spin(
00397 #ifdef DEBUG
00398 afile, aline, ahandler,
00399 #endif
00400 am, t, sp);
00401 if (lock_acquired)
00402 m = am;
00403 }
00404
00405 ~MutexTryLock()
00406 {
00407 if (m.m_ptr)
00408 Mutex_unlock(m.m_ptr, m.m_ptr->thread_holding);
00409 }
00410
00411 void release()
00412 {
00413 if (m.m_ptr) {
00414 Mutex_unlock(m.m_ptr, m.m_ptr->thread_holding);
00415 m.clear();
00416 }
00417 lock_acquired = false;
00418 }
00419
00420 int operator!() const { return !lock_acquired; }
00421 operator bool() const { return lock_acquired; }
00422 };
00423
00424 inline void
00425 ProxyMutex::free()
00426 {
00427 #ifdef DEBUG
00428 #ifdef LOCK_CONTENTION_PROFILING
00429 print_lock_stats(1);
00430 #endif
00431 #endif
00432 ink_mutex_destroy(&the_mutex);
00433 mutexAllocator.free(this);
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 inline ProxyMutex *
00449 new_ProxyMutex()
00450 {
00451 ProxyMutex *m = mutexAllocator.alloc();
00452 m->init();
00453 return m;
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 # ifdef DEBUG
00475 # define MUTEX_LOCK(_l,_m,_t) MutexLock _l(__FILE__,__LINE__,NULL,_m,_t)
00476 # else
00477 # define MUTEX_LOCK(_l,_m,_t) MutexLock _l(_m,_t)
00478 # endif //DEBUG
00479
00480 # ifdef DEBUG
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 # define MUTEX_TRY_LOCK(_l,_m,_t) \
00495 MutexTryLock _l(__FILE__,__LINE__,(char*)NULL,_m,_t)
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 # define MUTEX_TRY_LOCK_SPIN(_l,_m,_t,_sc) \
00512 MutexTryLock _l(__FILE__,__LINE__,(char*)NULL,_m,_t,_sc)
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 # define MUTEX_TRY_LOCK_FOR(_l,_m,_t,_c) \
00531 MutexTryLock _l(__FILE__,__LINE__,NULL,_m,_t)
00532 # else //DEBUG
00533 # define MUTEX_TRY_LOCK(_l,_m,_t) MutexTryLock _l(_m,_t)
00534 # define MUTEX_TRY_LOCK_SPIN(_l,_m,_t,_sc) MutexTryLock _l(_m,_t,_sc)
00535 # define MUTEX_TRY_LOCK_FOR(_l,_m,_t,_c) MutexTryLock _l(_m,_t)
00536 # endif //DEBUG
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 # define MUTEX_RELEASE(_l) (_l).release()
00551
00552
00553
00554 #ifdef DEBUG
00555 # define MUTEX_TAKE_TRY_LOCK(_m,_t) \
00556 Mutex_trylock(__FILE__,__LINE__,(char*)NULL,_m,_t)
00557 # define MUTEX_TAKE_TRY_LOCK_FOR(_m,_t,_c) \
00558 Mutex_trylock(__FILE__,__LINE__,(char*)NULL,_m,_t)
00559 # define MUTEX_TAKE_TRY_LOCK_FOR_SPIN(_m,_t,_c,_sc) \
00560 Mutex_trylock_spin(__FILE__,__LINE__,NULL,_m,_t,_sc)
00561 #else
00562 # define MUTEX_TAKE_TRY_LOCK(_m,_t) Mutex_trylock(_m,_t)
00563 # define MUTEX_TAKE_TRY_LOCK_FOR(_m,_t,_c) Mutex_trylock(_m,_t)
00564 # define MUTEX_TAKE_TRY_LOCK_FOR_SPIN(_m,_t,_c,_sc) \
00565 Mutex_trylock_spin(_m,_t,_sc)
00566 #endif
00567
00568 #ifdef DEBUG
00569 # define MUTEX_TAKE_LOCK(_m,_t)\
00570 Mutex_lock(__FILE__,__LINE__,(char*)NULL,_m,_t)
00571 # define MUTEX_SET_AND_TAKE_LOCK(_s,_m,_t)\
00572 _s.set_and_take(__FILE__,__LINE__,(char*)NULL,_m,_t)
00573 # define MUTEX_TAKE_LOCK_FOR(_m,_t,_c) \
00574 Mutex_lock(__FILE__,__LINE__,NULL,_m,_t)
00575 #else
00576 # define MUTEX_TAKE_LOCK(_m,_t) Mutex_lock(_m,_t)
00577 # define MUTEX_SET_AND_TAKE_LOCK(_s,_m,_t)_s.set_and_take(_m,_t)
00578 # define MUTEX_TAKE_LOCK_FOR(_m,_t,_c) Mutex_lock(_m,_t)
00579 #endif //DEBUG
00580
00581 #define MUTEX_UNTAKE_LOCK(_m,_t) Mutex_unlock(_m,_t)
00582
00583
00584
00585 #endif // _Lock_h_