[Make Scheme hooks and timers threadsafe clinton@unknownlamer.org**20081113222011 * Timers are now maintained as a sorted list * Timer callbacks and other threads can call bot:[add|del]timer * Running hooks presently *cannot* call bot:addhook. ] { hunk ./source/BotInterp.C 24 +#include + hunk ./source/BotInterp.C 39 - : bot(b), counter(0) + : bot(b), counter(0), timer_mutex (true) hunk ./source/BotInterp.C 75 - String name) { + String name) +{ hunk ./source/BotInterp.C 86 + + BotLock hook_lock (hook_mutex); + hunk ./source/BotInterp.C 114 + BotLock hook_lock (hook_mutex); + hunk ./source/BotInterp.C 117 + hunk ./source/BotInterp.C 122 + hunk ./source/BotInterp.C 125 + hunk ./source/BotInterp.C 140 + hunk ./source/BotInterp.C 147 + BotLock timer_lock (timer_mutex); hunk ./source/BotInterp.C 149 - int c = ++counter; + hunk ./source/BotInterp.C 151 - Timer *t = new Timer(c, when, function); - timersList.push_back(t); - return scm_from_int (c); + + Timer *timer = new Timer (++counter, when, function); + TimerList::iterator it = std::find_if (timers.begin (), timers.end (), + std::bind1st (timer_sort_p, timer)); + + if (it != timers.end ()) + timers.insert (it, timer); + else + timers.push_back (timer); + + return scm_from_int (counter); + hunk ./source/BotInterp.C 168 + BotLock timer_lock (timer_mutex); + hunk ./source/BotInterp.C 171 - std::list::iterator it = timersList.begin(); - std::list::iterator it2 = timersList.end(); + TimerList::iterator it = timers.begin(); + TimerList::iterator end = timers.end(); hunk ./source/BotInterp.C 174 - for ( ; it != it2; ++it) { - if ((*it)->count == count) { - scm_gc_unprotect_object((*it)->function); - delete (*it); - timersList.erase(it); - return true; + for ( ; it != end; ++it) + { + if ((*it)->count == count) + { + scm_gc_unprotect_object((*it)->function); + delete (*it); + timers.erase(it); + + return true; + } hunk ./source/BotInterp.C 185 - } + hunk ./source/BotInterp.C 192 - std::list::iterator it = timersList.begin(); - std::list::iterator it2 = timersList.end(); - std::list::iterator it3; - + BotLock timer_lock (timer_mutex); hunk ./source/BotInterp.C 196 - while (it != it2) { - if ((*it)->when <= now) { - wd.func = (*it)->function; - scm_internal_catch(SCM_BOOL_T, - (scm_t_catch_body) Interp::LazyApplyWrapper, (void *)&wd, - (scm_t_catch_handler) Interp::EmptyHandler, 0); - scm_gc_unprotect_object(wd.func); - it3 = it; - ++it3; - delete (*it); - timersList.erase(it); - it = it3; - } else { - ++it; + while (!timers.empty ()) + { + // Keep a stack allocated copy of the front of the timer queue + // just in case the timer is deleted while being executed (which + // is very unlikely as the only place this could occur is if the + // timer deleted itself) + Timer current_timer = *timers.front () ; + + if (current_timer.when <= now) + { + wd.func = current_timer.function; + + scm_internal_catch (SCM_BOOL_T, + (scm_t_catch_body) Interp::LazyApplyWrapper, + (void *)&wd, + (scm_t_catch_handler) Interp::EmptyHandler, + 0); + + // The timer list may have been modified by the timer + // callback; if it has in such a way that the first queue + // item has changed (adding a timer in the past) then we + // switch the slow path for deleting a timer + if (current_timer.count == timers.front()->count) + { + scm_gc_unprotect_object (current_timer.function); + delete timers.front (); + timers.pop_front (); + } + else + { + DelTimer (scm_from_int (current_timer.count)); + } + } + else + { + break; + } hunk ./source/BotInterp.C 234 - } + hunk ./source/BotInterp.H 3 -// Copyright (C) 2002,2005 Clinton Ebadi +// Copyright (C) 2002,2005,2008 Clinton Ebadi hunk ./source/BotInterp.H 30 +#include +#include +#include + hunk ./source/BotInterp.H 35 + +#include "BotThreading.H" hunk ./source/BotInterp.H 38 +#include "Utils.H" hunk ./source/BotInterp.H 105 + + bool operator< (const Timer & other) const + { return when < other.when; } hunk ./source/BotInterp.H 111 + typedef std::list TimerList; + hunk ./source/BotInterp.H 116 - std::list timersList; + TimerList timers; + Utils::IndirectPred > timer_sort_p; hunk ./source/BotInterp.H 119 + BotMutex hook_mutex; + BotMutex timer_mutex; // NOTE: recursive lock }