From 5d57fa5060ff9d6a5c708ad4159fe582d146f700 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 21 Apr 2009 16:22:14 +0200 Subject: [PATCH] clean up timers a bit --- src/timers.cc | 188 +++++++++++++++------------------------- test/test-setTimeout.js | 5 ++ 2 files changed, 75 insertions(+), 118 deletions(-) diff --git a/src/timers.cc b/src/timers.cc index 88154ed81d..967cfb27e1 100644 --- a/src/timers.cc +++ b/src/timers.cc @@ -4,102 +4,82 @@ using namespace v8; +static Persistent timer_template; + class Timer { public: - Timer(Handle callback, int argc, Handle argv[], ev_tstamp after, ev_tstamp repeat); + Timer(Handle callback, ev_tstamp after, ev_tstamp repeat); ~Timer(); - Local CreateTimeoutID (); - void CallCallback (); - private: - ev_timer watcher; - Persistent timeoutID; - Persistent callback; - int argc; - Persistent argv[]; -}; -static void -onTimeout (struct ev_loop *loop, ev_timer *watcher, int revents) -{ - Timer *timer = static_cast(watcher->data); + static Handle setTimeout (const Arguments& args); + static Handle setInterval (const Arguments& args); + static Handle clearTimeout (const Arguments& args); - timer->CallCallback(); + Persistent handle_; - // use ev_is_active instead? - if(watcher->repeat == 0.) - delete timer; -} + private: + static Timer* Unwrap (Handle handle); + static void OnTimeout (EV_P_ ev_timer *watcher, int revents); + ev_timer watcher_; +}; -Timer::Timer (Handle _callback, int _argc, Handle _argv[], ev_tstamp after, ev_tstamp repeat) +Timer* +Timer::Unwrap (Handle handle) { HandleScope scope; - callback = Persistent::New(_callback); - argc = _argc; - - ev_timer_init (&watcher, onTimeout, after, repeat); - watcher.data = this; - ev_timer_start (node_loop(), &watcher); -} - -Timer::~Timer () -{ - ev_timer_stop (node_loop(), &watcher); - - callback.Dispose(); - - timeoutID.Dispose(); - timeoutID.Clear(); + Handle field = Handle::Cast(handle->GetInternalField(0)); + Timer* timer = static_cast(field->Value()); + return timer; } void -Timer::CallCallback () +Timer::OnTimeout (EV_P_ ev_timer *watcher, int revents) { + Timer *timer = static_cast(watcher->data); + HandleScope scope; - TryCatch try_catch; + Local callback_value = timer->handle_->Get(String::NewSymbol("callback")); + if (!callback_value->IsFunction()) + return; - callback->Call (Context::GetCurrent()->Global(), argc, argv); + Local callback = Local::Cast(callback_value); + TryCatch try_catch; + callback->Call (Context::GetCurrent()->Global(), 0, NULL); if(try_catch.HasCaught()) node_fatal_exception(try_catch); + + // use ev_is_active instead? + if(watcher->repeat == 0.) + delete timer; } -Local -Timer::CreateTimeoutID () +Timer::Timer (Handle callback, ev_tstamp after, ev_tstamp repeat) { HandleScope scope; - Local timeoutID_local = External::New(this); + handle_ = Persistent::New(timer_template->NewInstance()); + handle_->Set(String::NewSymbol("callback"), callback); - timeoutID = Persistent::New(timeoutID_local); + Local external = External::New(this); + handle_->SetInternalField(0, external); - return scope.Close(timeoutID_local); + ev_timer_init(&watcher_, Timer::OnTimeout, after, repeat); + watcher_.data = this; + + ev_timer_start(node_loop(), &watcher_); } -static Timer * -UnwrapTimeoutID (Handle timeoutID) +Timer::~Timer () { - HandleScope scope; - - Timer *timer = static_cast(timeoutID->Value()); - - return timer; + ev_timer_stop (node_loop(), &watcher_); + handle_->SetInternalField(0, Undefined()); + handle_.Dispose(); } -// timeoutID = setTimeout(func, delay, [param1, param2, ...]); -// timeoutID = setTimeout(code, delay); -// -// * timeoutID is the ID of the timeout, which can be used with -// clearTimeout. -// -// * func is the function you want to execute after delay milliseconds. -// -// * code in the alternate syntax, is a string of code you want to execute -// after delay milliseconds. (not recommended) -// -// * delay is the number of milliseconds (thousandths of a second) that the -// function call should be delayed by. -NODE_METHOD(setTimeout) +Handle +Timer::setTimeout (const Arguments& args) { if (args.Length() < 2) return Undefined(); @@ -113,52 +93,14 @@ NODE_METHOD(setTimeout) if (args.Length() > 2) assert(0 && "extra params to setTimeout not yet implemented."); - int argc = 0; - Handle argv[] = {}; - /* - int argc = args.Length() - 2; - Handle argv[] = new Handle[argc]; - // the rest of the arguments, if any arg parameters for the callback - for(int i = 2; i < args.Length(); i++) - argv[i - 2] = args[i]; - */ - - Timer *timer = new Timer(callback, argc, argv, after, 0.0); - Local timeoutID = timer->CreateTimeoutID(); + Timer *timer = new Timer(callback, after, 0.0); - return scope.Close(timeoutID); + return scope.Close(timer->handle_); } -// clearTimeout(timeoutID) -NODE_METHOD(clearTimeout) -{ - if (args.Length() < 1) - return Undefined(); - - Handle timeoutID = Handle::Cast(args[0]); - Timer *timer = UnwrapTimeoutID(timeoutID); - - delete timer; - - return Undefined(); -} - -// intervalID = setInterval(func, delay[, param1, param2, ...]); -// intervalID = setInterval(code, delay); -// -// where -// -// * intervalID is a unique interval ID you can pass to clearInterval(). -// -// * func is the function you want to be called repeatedly. -// -// * code in the alternate syntax, is a string of code you want to be executed -// repeatedly. -// -// * delay is the number of milliseconds (thousandths of a second) that the -// setInterval() function should wait before each call to func. -NODE_METHOD(setInterval) +Handle +Timer::setInterval (const Arguments& args) { if (args.Length() < 2) return Undefined(); @@ -170,16 +112,23 @@ NODE_METHOD(setInterval) ev_tstamp after = (double)delay / 1000.0; - if (args.Length() > 2) - assert(0 && "extra params to setInterval not yet implemented."); - int argc = 0; - Handle argv[] = {}; + Timer *timer = new Timer(callback, after, after); - Timer *timer = new Timer(callback, argc, argv, after, after); + return scope.Close(timer->handle_); +} - Local timeoutID = timer->CreateTimeoutID(); +Handle +Timer::clearTimeout (const Arguments& args) +{ + if (args.Length() < 1) + return Undefined(); + + HandleScope scope; + Local handle = Local::Cast(args[0]); + Timer *timer = Timer::Unwrap(handle); + delete timer; - return scope.Close(timeoutID); + return Undefined(); } void @@ -187,8 +136,11 @@ NodeInit_timers (Handle target) { HandleScope scope; - NODE_SET_METHOD(target, "setTimeout", setTimeout); - NODE_SET_METHOD(target, "clearTimeout", clearTimeout); - NODE_SET_METHOD(target, "setInterval", setInterval); - NODE_SET_METHOD(target, "clearInterval", clearTimeout); + timer_template = Persistent::New(ObjectTemplate::New()); + timer_template->SetInternalFieldCount(1); + + NODE_SET_METHOD(target, "setTimeout", Timer::setTimeout); + NODE_SET_METHOD(target, "setInterval", Timer::setInterval); + NODE_SET_METHOD(target, "clearTimeout", Timer::clearTimeout); + NODE_SET_METHOD(target, "clearInterval", Timer::clearTimeout); } diff --git a/test/test-setTimeout.js b/test/test-setTimeout.js index 4a05be25b4..ef29fe2296 100644 --- a/test/test-setTimeout.js +++ b/test/test-setTimeout.js @@ -3,10 +3,15 @@ include("mjsunit"); function on_load () { assertInstanceof(setTimeout, Function); var starttime = new Date; + setTimeout(function () { var endtime = new Date; var diff = endtime - starttime; if (diff < 0) diff = -diff; assertTrue(900 < diff || diff < 1100); }, 1000); + + // this timer shouldn't execute + var id = setTimeout(function () { assertTrue(false); }, 500); + clearTimeout(id); }