Skip to content

Instantly share code, notes, and snippets.

@ry
Created July 3, 2010 03:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ry/462282 to your computer and use it in GitHub Desktop.
Save ry/462282 to your computer and use it in GitHub Desktop.
// Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
#include <node_events.h>
#include <node.h>
namespace node {
using namespace v8;
// EventSource
EventSource* EventSource::current_source;
template <class T>
Local<FunctionTemplate> EventSource::BuildTemplate(Handle<Object> target,
const char *name) {
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(EventSource::JSNew<T>);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(String::NewSymbol(name));
NODE_SET_PROTOTYPE_METHOD(t, "start", EventSource::JSStart);
NODE_SET_PROTOTYPE_METHOD(t, "stop", EventSource::JSStop);
target->Set(String::NewSymbol(name), t->GetFunction());
return scope.Close(t);
}
Local<Value> EventSource::MakeCallback(int argc, Handle<Value> argv[]) {
HandleScope scope;
Local<Value> callback_v = handle_->Get(String::NewSymbol("callback"));
if (!callback_v->IsFunction()) return Local<Value>();
Local<Function> callback = Local<Function>::Cast(callback_v);
// TODO DTrace probe here.
TryCatch try_catch;
assert(current_source == NULL);
current_source = this;
Local<Value> ret = callback->Call(handle_, argc, argv);
current_source = NULL;
if (try_catch.HasCaught()) {
// Here we print the stack trace from try_catch
ReportException(try_catch, true);
// Then we print the stored stacktrace plus our ancestors stacks.
PrintStack();
// Stop whatever activity might have been going on.
Stop();
}
return scope.Close(ret);
}
void EventSource::PrintStack(int count) {
Local<Value> trace_v = handle_->GetHiddenValue(String::NewSymbol("stacktrace"));
assert(trace_v->IsArray());
Local<Array> trace = Local<Array>::Cast(trace_v);
// Print from for this EventSource
for (int i = 0; i < trace->Length(); i++) {
Local<Value> frame = trace->Get(i);
// how do you cast Value to StackFrame ?
// print frame somehow...
String::Utf8Value sv(frame->ToString());
fprintf(stderr, "%s\n", *sv);
}
fprintf(stderr, "\n");
// Recursively print up to kAncestorStackLimit ancestor traces...
if (parent_source_.IsEmpty() == false && count < kAncestorStackLimit) {
EventSource *parent = ObjectWrap::Unwrap<EventSource>(parent_source_);
parent->PrintStack(count + 1);
}
}
template <class T>
Handle<Value> EventSource::JSNew(const Arguments& args) {
HandleScope scope;
T *t = new T();
t->Wrap(args.This());
return args.This();
}
Handle<Value> EventSource::JSStart(const Arguments& args) {
HandleScope scope;
EventSource *s = ObjectWrap::Unwrap<EventSource>(args.Holder());
if (!s->IsActive()) {
s->Start();
s->Ref();
s->RecordStack();
// TODO DTrace probe here.
}
return Undefined();
}
Handle<Value> EventSource::JSStop(const Arguments& args) {
HandleScope scope;
EventSource *s = ObjectWrap::Unwrap<EventSource>(args.Holder());
if (s->IsActive()) {
s->DeleteParent();
s->Stop();
s->Unref();
}
return Undefined();
}
void EventSource::RecordStack() {
// Assume inside HandleScope
Local<StackTrace> trace =
StackTrace::CurrentStackTrace(kFrameLimit, StackTrace::kOverview);
// Cast to Array for storage as hidden value.
handle_->SetHiddenValue(String::NewSymbol("stacktrace"), trace->AsArray());
// Set parent.
parent_source_ = Persistent<Object>::New(current_source->handle_);
parent_source_.MakeWeak(this, WeakParent);
}
void EventSource::WeakParent(Persistent<Value> object, void* data) {
EventSource *s = static_cast<EventSource*>(data);
assert(s->parent_source_->StrictEquals(object));
s->DeleteParent();
}
void EventSource::DeleteParent() {
parent_source_.ClearWeak();
parent_source_.Dispose();
parent_source_.Clear();
}
} // namespace node
// Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
#ifndef SRC_EVENTS_H_
#define SRC_EVENTS_H_
#include <node_object_wrap.h>
#include <v8.h>
namespace node {
// "hard emitter" base class
class EventSource : public ObjectWrap {
public:
// All subclasses must call this function to initialize their JavaScript
// counterparts. Subclasses are free to decorate the template with additional
// and such.
template <class T>
static v8::Local<v8::FunctionTemplate> BuildTemplate(v8::Handle<v8::Object> target,
const char *name);
virtual void Start() = 0; // ev_io_start()
virtual void Stop() = 0; // ev_io_stop()
virtual bool IsActive() = 0; // ev_is_active()
EventSource() : ObjectWrap() {
//assert(!IsActive());
}
virtual ~EventSource() {
//Stop();
//assert(!IsActive());
}
// Subclasses call this when they get a event.
v8::Local<v8::Value> MakeCallback(int argc, v8::Handle<v8::Value> argv[]);
private:
template <class T>
static v8::Handle<v8::Value> JSNew(const v8::Arguments& args);
static v8::Handle<v8::Value> JSStart(const v8::Arguments& args);
static v8::Handle<v8::Value> JSStop(const v8::Arguments& args);
static void WeakParent(v8::Persistent<v8::Value> object, void* data);
void RecordStack();
void DeleteParent();
void PrintStack(int count = 0);
v8::Persistent<v8::Object> parent_source_;
static const int kFrameLimit = 10;
static const int kAncestorStackLimit = 10;
static EventSource* current_source;
};
} // namespace node
#endif // SRC_EVENTS_H_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment