// BotInterp.C -*- C++ -*-
// Copyright (c) 1998 Etienne BERNARD
-// Copyright (C) 2002 Clinton Ebadi
+// Copyright (C) 2002,2005,2008 Clinton Ebadi
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#include <algorithm>
+
#include "Utils.H"
#include "Bot.H"
#include "BotInterp.H"
}
BotInterp::BotInterp(Bot *b, String fn)
- : bot(b), counter(0)
+ : bot(b), counter(0), timer_mutex (true)
{
- logPort = scm_open_file(Utils::str2scm (fn),
- Utils::str2scm ("a"));
+ logPort = scm_open_file (Utils::str2scm (fn),
+ Utils::str2scm ("a"));
+
scm_gc_protect_object(logPort);
}
Interp::LoadScript(bot, filename);
}
-void
-BotInterp::ScriptLog(SCM throw_args)
+SCM
+BotInterp::ScriptLog()
{
- scm_display_error_message(SCM_CADR (throw_args),
- SCM_CADDR (throw_args),
- logPort);
- scm_flush(logPort);
+ return logPort;
}
namespace
bool
BotInterp::AddHook(int hooktype, SCM regex, SCM function, int pri, bool fall,
- String name) {
+ String name)
+{
if (scm_string_p(regex) == SCM_BOOL_F)
return false;
String rx = Utils::to_upper (Utils::scm2str (regex));
- SCM r = scm_make_regexp(regex,
- scm_listify (gh_lookup("regexp/icase"),
- SCM_UNDEFINED));
+ // fixme: really ought to use scm_c_module_lookup with bot module
+ SCM r = scm_make_regexp (regex,
+ scm_list_n (scm_variable_ref (scm_c_lookup ("regexp/icase")),
+ SCM_UNDEFINED));
scm_gc_protect_object(r);
scm_gc_protect_object(function);
+
+ BotLock hook_lock (hook_mutex);
+
// First, we check if an hook doesn't exist yet
std::list<Hook *>::iterator it = hooksMap[hooktype].begin();
std::list<Hook *>::iterator it2 = hooksMap[hooktype].end();
bool
BotInterp::RunHooks(int hooktype, String match, SCM args)
{
+ BotLock hook_lock (hook_mutex);
+
SCM result;
+
// We want to execute higher priority hooks first, so we start at
// the end of the list instead of the beggining
std::list<Hook *>::reverse_iterator it = hooksMap[hooktype].rbegin();
std::list<Hook *>::reverse_iterator it2 = hooksMap[hooktype].rend();
+
wrapper_data wd;
wd.args = args;
+
for ( ; it != it2; ++it) {
if (scm_regexp_exec((*it)->regex, Utils::str2scm (match),
SCM_UNDEFINED, SCM_UNDEFINED) != SCM_BOOL_F)
{
wd.func = (*it)->function;
- result = gh_catch(SCM_BOOL_T,
- (scm_t_catch_body) scm_apply_wrapper,
- static_cast<void *> (&wd),
- (scm_t_catch_handler) Interp::ErrorHandler, 0);
+ result = scm_internal_catch(SCM_BOOL_T,
+ (scm_t_catch_body)
+ Interp::LazyApplyWrapper,
+ static_cast<void *> (&wd),
+ (scm_t_catch_handler) Interp::EmptyHandler, 0);
if (! (*it)->fallthru)
break;
}
}
+
return true;
}
SCM
BotInterp::AddTimer(int delay, SCM function)
{
+ BotLock timer_lock (timer_mutex);
int when = time(NULL) + delay;
- int c = ++counter;
+
scm_gc_protect_object(function);
- Timer *t = new Timer(c, when, function);
- timersList.push_back(t);
- return scm_long2num (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);
+
}
bool
BotInterp::DelTimer(SCM timer)
{
- int count = scm_num2long(timer, SCM_ARG1, "BotInterp::DelTimer");
- std::list<Timer *>::iterator it = timersList.begin();
- std::list<Timer *>::iterator it2 = timersList.end();
-
- for ( ; it != it2; ++it) {
- if ((*it)->count == count) {
- scm_gc_unprotect_object((*it)->function);
- delete (*it);
- timersList.erase(it);
- return true;
+ BotLock timer_lock (timer_mutex);
+
+ int count = scm_to_int (timer);
+ TimerList::iterator it = timers.begin();
+ TimerList::iterator end = timers.end();
+
+ for ( ; it != end; ++it)
+ {
+ if ((*it)->count == count)
+ {
+ scm_gc_unprotect_object((*it)->function);
+ delete (*it);
+ timers.erase(it);
+
+ return true;
+ }
}
- }
+
return false;
}
bool
BotInterp::RunTimers(int now)
{
- std::list<Timer *>::iterator it = timersList.begin();
- std::list<Timer *>::iterator it2 = timersList.end();
- std::list<Timer *>::iterator it3;
-
+ BotLock timer_lock (timer_mutex);
struct wrapper_data wd;
- wd.args = scm_listify (SCM_UNDEFINED);
-
- while (it != it2) {
- if ((*it)->when <= now) {
- wd.func = (*it)->function;
- gh_catch(SCM_BOOL_T, (scm_t_catch_body) scm_apply_wrapper,
- (void *)&wd, (scm_t_catch_handler) Interp::ErrorHandler, 0);
- scm_gc_unprotect_object(wd.func);
- it3 = it;
- ++it3;
- delete (*it);
- timersList.erase(it);
- it = it3;
- } else {
- ++it;
+ wd.args = scm_list_n (SCM_UNDEFINED);
+
+ 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;
+ }
}
- }
+
return true;
}