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_