diff --git a/src/common/Timer.cc b/src/common/Timer.cc index 38688778368..ac0550c768f 100644 --- a/src/common/Timer.cc +++ b/src/common/Timer.cc @@ -45,10 +45,11 @@ public: typedef std::multimap < utime_t, Context *> scheduled_map_t; typedef std::map < Context*, scheduled_map_t::iterator > event_lookup_map_t; -SafeTimer::SafeTimer(CephContext *cct_, Mutex &l) +SafeTimer::SafeTimer(CephContext *cct_, Mutex &l, bool safe_callbacks) : cct(cct_), lock(l), + safe_callbacks(safe_callbacks), thread(NULL), - stopping(false) + stopping(false) { } @@ -99,8 +100,12 @@ void SafeTimer::timer_thread() schedule.erase(p); ldout(cct,10) << "timer_thread executing " << callback << dendl; + if (!safe_callbacks) + lock.Unlock(); callback->finish(0); delete callback; + if (!safe_callbacks) + lock.Lock(); } ldout(cct,20) << "timer_thread going to sleep" << dendl; diff --git a/src/common/Timer.h b/src/common/Timer.h index 17626a5d376..40d5015e18b 100644 --- a/src/common/Timer.h +++ b/src/common/Timer.h @@ -33,6 +33,7 @@ class SafeTimer CephContext *cct; Mutex& lock; Cond cond; + bool safe_callbacks; friend class SafeTimerThread; SafeTimerThread *thread; @@ -47,7 +48,17 @@ class SafeTimer void dump(const char *caller = 0) const; public: - SafeTimer(CephContext *cct, Mutex &l); + /* Safe callbacks determines whether callbacks are called with the lock + * held. + * + * safe_callbacks = true (default option) guarantees that a cancelled + * event's callback will never be called. + * + * Under some circumstances, holding the lock can cause lock cycles. + * If you are able to relax requirements on cancelled callbacks, then + * setting safe_callbacks = false eliminates the lock cycle issue. + * */ + SafeTimer(CephContext *cct, Mutex &l, bool safe_callbacks=true); ~SafeTimer(); /* Call with the event_lock UNLOCKED.