Browse Source

clean up timers a bit

v0.7.4-release
Ryan 16 years ago
parent
commit
5d57fa5060
  1. 188
      src/timers.cc
  2. 5
      test/test-setTimeout.js

188
src/timers.cc

@ -4,102 +4,82 @@
using namespace v8; using namespace v8;
static Persistent<ObjectTemplate> timer_template;
class Timer { class Timer {
public: public:
Timer(Handle<Function> callback, int argc, Handle<Value> argv[], ev_tstamp after, ev_tstamp repeat); Timer(Handle<Function> callback, ev_tstamp after, ev_tstamp repeat);
~Timer(); ~Timer();
Local<External> CreateTimeoutID ();
void CallCallback ();
private:
ev_timer watcher;
Persistent<External> timeoutID;
Persistent<Function> callback;
int argc;
Persistent<Value> argv[];
};
static void static Handle<Value> setTimeout (const Arguments& args);
onTimeout (struct ev_loop *loop, ev_timer *watcher, int revents) static Handle<Value> setInterval (const Arguments& args);
{ static Handle<Value> clearTimeout (const Arguments& args);
Timer *timer = static_cast<Timer*>(watcher->data);
timer->CallCallback(); Persistent<Object> handle_;
// use ev_is_active instead? private:
if(watcher->repeat == 0.) static Timer* Unwrap (Handle<Object> handle);
delete timer; static void OnTimeout (EV_P_ ev_timer *watcher, int revents);
} ev_timer watcher_;
};
Timer::Timer (Handle<Function> _callback, int _argc, Handle<Value> _argv[], ev_tstamp after, ev_tstamp repeat) Timer*
Timer::Unwrap (Handle<Object> handle)
{ {
HandleScope scope; HandleScope scope;
callback = Persistent<Function>::New(_callback); Handle<External> field = Handle<External>::Cast(handle->GetInternalField(0));
argc = _argc; Timer* timer = static_cast<Timer*>(field->Value());
return timer;
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();
} }
void void
Timer::CallCallback () Timer::OnTimeout (EV_P_ ev_timer *watcher, int revents)
{ {
Timer *timer = static_cast<Timer*>(watcher->data);
HandleScope scope; HandleScope scope;
TryCatch try_catch; Local<Value> callback_value = timer->handle_->Get(String::NewSymbol("callback"));
if (!callback_value->IsFunction())
return;
callback->Call (Context::GetCurrent()->Global(), argc, argv); Local<Function> callback = Local<Function>::Cast(callback_value);
TryCatch try_catch;
callback->Call (Context::GetCurrent()->Global(), 0, NULL);
if(try_catch.HasCaught()) if(try_catch.HasCaught())
node_fatal_exception(try_catch); node_fatal_exception(try_catch);
// use ev_is_active instead?
if(watcher->repeat == 0.)
delete timer;
} }
Local<External> Timer::Timer (Handle<Function> callback, ev_tstamp after, ev_tstamp repeat)
Timer::CreateTimeoutID ()
{ {
HandleScope scope; HandleScope scope;
Local<External> timeoutID_local = External::New(this); handle_ = Persistent<Object>::New(timer_template->NewInstance());
handle_->Set(String::NewSymbol("callback"), callback);
timeoutID = Persistent<External>::New(timeoutID_local); Local<External> 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 * Timer::~Timer ()
UnwrapTimeoutID (Handle<External> timeoutID)
{ {
HandleScope scope; ev_timer_stop (node_loop(), &watcher_);
handle_->SetInternalField(0, Undefined());
Timer *timer = static_cast<Timer*>(timeoutID->Value()); handle_.Dispose();
return timer;
} }
// timeoutID = setTimeout(func, delay, [param1, param2, ...]); Handle<Value>
// timeoutID = setTimeout(code, delay); Timer::setTimeout (const Arguments& args)
//
// * 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)
{ {
if (args.Length() < 2) if (args.Length() < 2)
return Undefined(); return Undefined();
@ -113,52 +93,14 @@ NODE_METHOD(setTimeout)
if (args.Length() > 2) if (args.Length() > 2)
assert(0 && "extra params to setTimeout not yet implemented."); assert(0 && "extra params to setTimeout not yet implemented.");
int argc = 0;
Handle<Value> argv[] = {};
/*
int argc = args.Length() - 2;
Handle<Value> argv[] = new Handle<Value>[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<External> timeoutID = timer->CreateTimeoutID(); Timer *timer = new Timer(callback, after, 0.0);
return scope.Close(timeoutID); return scope.Close(timer->handle_);
} }
// clearTimeout(timeoutID) Handle<Value>
NODE_METHOD(clearTimeout) Timer::setInterval (const Arguments& args)
{
if (args.Length() < 1)
return Undefined();
Handle<External> timeoutID = Handle<External>::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)
{ {
if (args.Length() < 2) if (args.Length() < 2)
return Undefined(); return Undefined();
@ -170,16 +112,23 @@ NODE_METHOD(setInterval)
ev_tstamp after = (double)delay / 1000.0; ev_tstamp after = (double)delay / 1000.0;
if (args.Length() > 2) Timer *timer = new Timer(callback, after, after);
assert(0 && "extra params to setInterval not yet implemented.");
int argc = 0;
Handle<Value> argv[] = {};
Timer *timer = new Timer(callback, argc, argv, after, after); return scope.Close(timer->handle_);
}
Local<External> timeoutID = timer->CreateTimeoutID(); Handle<Value>
Timer::clearTimeout (const Arguments& args)
{
if (args.Length() < 1)
return Undefined();
HandleScope scope;
Local<Object> handle = Local<Object>::Cast(args[0]);
Timer *timer = Timer::Unwrap(handle);
delete timer;
return scope.Close(timeoutID); return Undefined();
} }
void void
@ -187,8 +136,11 @@ NodeInit_timers (Handle<Object> target)
{ {
HandleScope scope; HandleScope scope;
NODE_SET_METHOD(target, "setTimeout", setTimeout); timer_template = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
NODE_SET_METHOD(target, "clearTimeout", clearTimeout); timer_template->SetInternalFieldCount(1);
NODE_SET_METHOD(target, "setInterval", setInterval);
NODE_SET_METHOD(target, "clearInterval", clearTimeout); 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);
} }

5
test/test-setTimeout.js

@ -3,10 +3,15 @@ include("mjsunit");
function on_load () { function on_load () {
assertInstanceof(setTimeout, Function); assertInstanceof(setTimeout, Function);
var starttime = new Date; var starttime = new Date;
setTimeout(function () { setTimeout(function () {
var endtime = new Date; var endtime = new Date;
var diff = endtime - starttime; var diff = endtime - starttime;
if (diff < 0) diff = -diff; if (diff < 0) diff = -diff;
assertTrue(900 < diff || diff < 1100); assertTrue(900 < diff || diff < 1100);
}, 1000); }, 1000);
// this timer shouldn't execute
var id = setTimeout(function () { assertTrue(false); }, 500);
clearTimeout(id);
} }

Loading…
Cancel
Save