#include "dtrace_provider.h" #include #include namespace node { using namespace v8; DTraceProvider::DTraceProvider() : Nan::ObjectWrap() { provider = NULL; } DTraceProvider::~DTraceProvider() { usdt_provider_disable(provider); usdt_provider_free(provider); } Nan::Persistent DTraceProvider::constructor_template; void DTraceProvider::Initialize(v8::Local target) { Nan::HandleScope scope; Local t = Nan::New(DTraceProvider::New); t->InstanceTemplate()->SetInternalFieldCount(1); t->SetClassName(Nan::New("DTraceProvider").ToLocalChecked()); constructor_template.Reset(t); Nan::SetPrototypeMethod(t, "addProbe", DTraceProvider::AddProbe); Nan::SetPrototypeMethod(t, "removeProbe", DTraceProvider::RemoveProbe); Nan::SetPrototypeMethod(t, "enable", DTraceProvider::Enable); Nan::SetPrototypeMethod(t, "disable", DTraceProvider::Disable); Nan::SetPrototypeMethod(t, "fire", DTraceProvider::Fire); target->Set(Nan::New("DTraceProvider").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked()); DTraceProbe::Initialize(target); } NAN_METHOD(DTraceProvider::New) { Nan::HandleScope scope; DTraceProvider *p = new DTraceProvider(); char module[128]; p->Wrap(info.This()); if (info.Length() < 1 || !info[0]->IsString()) { Nan::ThrowTypeError("Must give provider name as argument"); return; } Nan::Utf8String name(info[0]); if (info.Length() == 2) { if (!info[1]->IsString()) { Nan::ThrowTypeError("Must give module name as argument"); return; } Nan::Utf8String mod(info[1]); (void) snprintf(module, sizeof (module), "%s", *mod); } else if (info.Length() == 1) { // If no module name is provided, develop a synthetic module name based // on our address (void) snprintf(module, sizeof (module), "mod-%p", p); } else { Nan::ThrowError("Expected only provider name and module as arguments"); return; } if ((p->provider = usdt_create_provider(*name, module)) == NULL) { Nan::ThrowError("usdt_create_provider failed"); return; } info.GetReturnValue().Set(info.This()); } NAN_METHOD(DTraceProvider::AddProbe) { Nan::HandleScope scope; const char *types[USDT_ARG_MAX]; v8::Local obj = info.Holder(); DTraceProvider *provider = Nan::ObjectWrap::Unwrap(obj); // create a DTraceProbe object v8::Local tmpl = Nan::New(DTraceProbe::constructor_template); v8::Local klass = Nan::GetFunction(tmpl).ToLocalChecked(); v8::Local pd = Nan::NewInstance(klass).ToLocalChecked(); // store in provider object DTraceProbe *probe = Nan::ObjectWrap::Unwrap(Nan::To(pd).ToLocalChecked()); obj->Set(Nan::To(info[0]).ToLocalChecked(), pd); // reference the provider to avoid GC'ing it when only probes remain in scope. Nan::DefineOwnProperty(pd, Nan::New("__prov__").ToLocalChecked(), obj, static_cast(DontEnum | ReadOnly | DontDelete)); // add probe to provider for (int i = 0; i < USDT_ARG_MAX; i++) { if (i < info.Length() - 1) { Nan::Utf8String type(info[i + 1]); if (strncmp("json", *type, 4) == 0) probe->arguments[i] = new DTraceJsonArgument(); else if (strncmp("char *", *type, 6) == 0) probe->arguments[i] = new DTraceStringArgument(); else if (strncmp("int", *type, 3) == 0) probe->arguments[i] = new DTraceIntegerArgument(); else probe->arguments[i] = new DTraceStringArgument(); types[i] = strdup(probe->arguments[i]->Type()); probe->argc++; } } Nan::Utf8String name(info[0]); probe->probedef = usdt_create_probe(*name, *name, probe->argc, types); Nan::SetInternalFieldPointer(pd, 1, provider); usdt_provider_add_probe(provider->provider, probe->probedef); for (size_t i = 0; i < probe->argc; i++) { free((char *)types[i]); } info.GetReturnValue().Set(pd); } NAN_METHOD(DTraceProvider::RemoveProbe) { Nan::HandleScope scope; v8::Local provider_obj = info.Holder(); DTraceProvider *provider = Nan::ObjectWrap::Unwrap(provider_obj); v8::Local probe_obj = Local::Cast(info[0]); DTraceProbe *probe = Nan::ObjectWrap::Unwrap(probe_obj); v8::Local name = Nan::New(probe->probedef->name).ToLocalChecked(); Nan::Delete(provider_obj, name); if (usdt_provider_remove_probe(provider->provider, probe->probedef) != 0) { Nan::ThrowError(usdt_errstr(provider->provider)); return; } info.GetReturnValue().Set(Nan::True()); } NAN_METHOD(DTraceProvider::Enable) { Nan::HandleScope scope; DTraceProvider *provider = Nan::ObjectWrap::Unwrap(info.Holder()); if (usdt_provider_enable(provider->provider) != 0) { Nan::ThrowError(usdt_errstr(provider->provider)); return; } return; } NAN_METHOD(DTraceProvider::Disable) { Nan::HandleScope scope; DTraceProvider *provider = Nan::ObjectWrap::Unwrap(info.Holder()); if (usdt_provider_disable(provider->provider) != 0) { Nan::ThrowError(usdt_errstr(provider->provider)); return; } return; } NAN_METHOD(DTraceProvider::Fire) { Nan::HandleScope scope; if (!info[0]->IsString()) { Nan::ThrowTypeError("Must give probe name as first argument"); return; } if (!info[1]->IsFunction()) { Nan::ThrowTypeError("Must give probe value callback as second argument"); return; } v8::Local holder = info.Holder(); DTraceProvider *provider = Nan::ObjectWrap::Unwrap(holder); Nan::MaybeLocal maybe = Nan::Get(holder, info[0]); if (maybe.IsEmpty()) { return; } v8::Local value = maybe.ToLocalChecked(); if (!value->IsObject()) { return; } v8::Local probe = Local::Cast(value); if (probe->InternalFieldCount() != 2) { return; } if (Nan::GetInternalFieldPointer(probe, 1) != provider) { return; } DTraceProbe *p = Nan::ObjectWrap::Unwrap(probe); if (p == NULL) { return; } p->_fire(info, 1); info.GetReturnValue().Set(Nan::True()); } extern "C" void init(v8::Local target) { DTraceProvider::Initialize(target); } NODE_MODULE(DTraceProviderBindings, init) } // namespace node