Created
July 3, 2010 03:41
-
-
Save ry/462282 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2009 Ryan Dahl <[email protected]> | |
#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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2009 Ryan Dahl <[email protected]> | |
#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