1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22#include "async_wrap-inl.h" 23#include "env-inl.h" 24#include "handle_wrap.h" 25#include "node_external_reference.h" 26#include "node_process-inl.h" 27#include "util-inl.h" 28#include "v8.h" 29 30namespace node { 31 32using v8::Context; 33using v8::FunctionCallbackInfo; 34using v8::FunctionTemplate; 35using v8::HandleScope; 36using v8::Integer; 37using v8::Isolate; 38using v8::Local; 39using v8::Object; 40using v8::Value; 41 42void DecreaseSignalHandlerCount(int signum); 43 44namespace { 45 46static Mutex handled_signals_mutex; 47static std::map<int, int64_t> handled_signals; // Signal -> number of handlers 48 49class SignalWrap : public HandleWrap { 50 public: 51 static void Initialize(Local<Object> target, 52 Local<Value> unused, 53 Local<Context> context, 54 void* priv) { 55 Environment* env = Environment::GetCurrent(context); 56 Isolate* isolate = env->isolate(); 57 Local<FunctionTemplate> constructor = NewFunctionTemplate(isolate, New); 58 constructor->InstanceTemplate()->SetInternalFieldCount( 59 SignalWrap::kInternalFieldCount); 60 constructor->Inherit(HandleWrap::GetConstructorTemplate(env)); 61 62 SetProtoMethod(isolate, constructor, "start", Start); 63 SetProtoMethod(isolate, constructor, "stop", Stop); 64 65 SetConstructorFunction(context, target, "Signal", constructor); 66 } 67 68 static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { 69 registry->Register(New); 70 registry->Register(Start); 71 registry->Register(Stop); 72 } 73 74 SET_NO_MEMORY_INFO() 75 SET_MEMORY_INFO_NAME(SignalWrap) 76 SET_SELF_SIZE(SignalWrap) 77 78 private: 79 static void New(const FunctionCallbackInfo<Value>& args) { 80 // This constructor should not be exposed to public javascript. 81 // Therefore we assert that we are not trying to call this as a 82 // normal function. 83 CHECK(args.IsConstructCall()); 84 Environment* env = Environment::GetCurrent(args); 85 new SignalWrap(env, args.This()); 86 } 87 88 SignalWrap(Environment* env, Local<Object> object) 89 : HandleWrap(env, 90 object, 91 reinterpret_cast<uv_handle_t*>(&handle_), 92 AsyncWrap::PROVIDER_SIGNALWRAP) { 93 int r = uv_signal_init(env->event_loop(), &handle_); 94 CHECK_EQ(r, 0); 95 } 96 97 void Close(v8::Local<v8::Value> close_callback) override { 98 if (active_) { 99 DecreaseSignalHandlerCount(handle_.signum); 100 active_ = false; 101 } 102 HandleWrap::Close(close_callback); 103 } 104 105 static void Start(const FunctionCallbackInfo<Value>& args) { 106 SignalWrap* wrap; 107 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 108 Environment* env = wrap->env(); 109 int signum; 110 if (!args[0]->Int32Value(env->context()).To(&signum)) return; 111#if defined(__POSIX__) && HAVE_INSPECTOR 112 if (signum == SIGPROF) { 113 Environment* env = Environment::GetCurrent(args); 114 if (env->inspector_agent()->IsListening()) { 115 ProcessEmitWarning(env, 116 "process.on(SIGPROF) is reserved while debugging"); 117 return; 118 } 119 } 120#endif 121 int err = uv_signal_start( 122 &wrap->handle_, 123 [](uv_signal_t* handle, int signum) { 124 SignalWrap* wrap = ContainerOf(&SignalWrap::handle_, handle); 125 Environment* env = wrap->env(); 126 HandleScope handle_scope(env->isolate()); 127 Context::Scope context_scope(env->context()); 128 Local<Value> arg = Integer::New(env->isolate(), signum); 129 wrap->MakeCallback(env->onsignal_string(), 1, &arg); 130 }, 131 signum); 132 133 if (err == 0) { 134 CHECK(!wrap->active_); 135 wrap->active_ = true; 136 Mutex::ScopedLock lock(handled_signals_mutex); 137 handled_signals[signum]++; 138 } 139 140 args.GetReturnValue().Set(err); 141 } 142 143 static void Stop(const FunctionCallbackInfo<Value>& args) { 144 SignalWrap* wrap; 145 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 146 147 if (wrap->active_) { 148 wrap->active_ = false; 149 DecreaseSignalHandlerCount(wrap->handle_.signum); 150 } 151 152 int err = uv_signal_stop(&wrap->handle_); 153 args.GetReturnValue().Set(err); 154 } 155 156 uv_signal_t handle_; 157 bool active_ = false; 158}; 159 160 161} // anonymous namespace 162 163void DecreaseSignalHandlerCount(int signum) { 164 Mutex::ScopedLock lock(handled_signals_mutex); 165 int64_t new_handler_count = --handled_signals[signum]; 166 CHECK_GE(new_handler_count, 0); 167 if (new_handler_count == 0) 168 handled_signals.erase(signum); 169} 170 171bool HasSignalJSHandler(int signum) { 172 Mutex::ScopedLock lock(handled_signals_mutex); 173 return handled_signals.find(signum) != handled_signals.end(); 174} 175} // namespace node 176 177NODE_BINDING_CONTEXT_AWARE_INTERNAL(signal_wrap, node::SignalWrap::Initialize) 178NODE_BINDING_EXTERNAL_REFERENCE(signal_wrap, 179 node::SignalWrap::RegisterExternalReferences) 180