/src/node/src/signal_wrap.cc
Line | Count | Source (jump to first uncovered line) |
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 | | |
30 | | namespace node { |
31 | | |
32 | | using v8::Context; |
33 | | using v8::FunctionCallbackInfo; |
34 | | using v8::FunctionTemplate; |
35 | | using v8::HandleScope; |
36 | | using v8::Integer; |
37 | | using v8::Isolate; |
38 | | using v8::Local; |
39 | | using v8::Object; |
40 | | using v8::Value; |
41 | | |
42 | | void DecreaseSignalHandlerCount(int signum); |
43 | | |
44 | | namespace { |
45 | | |
46 | | static Mutex handled_signals_mutex; |
47 | | static std::map<int, int64_t> handled_signals; // Signal -> number of handlers |
48 | | |
49 | | class SignalWrap : public HandleWrap { |
50 | | public: |
51 | | static void Initialize(Local<Object> target, |
52 | | Local<Value> unused, |
53 | | Local<Context> context, |
54 | 0 | void* priv) { |
55 | 0 | Environment* env = Environment::GetCurrent(context); |
56 | 0 | Isolate* isolate = env->isolate(); |
57 | 0 | Local<FunctionTemplate> constructor = NewFunctionTemplate(isolate, New); |
58 | 0 | constructor->InstanceTemplate()->SetInternalFieldCount( |
59 | 0 | SignalWrap::kInternalFieldCount); |
60 | 0 | constructor->Inherit(HandleWrap::GetConstructorTemplate(env)); |
61 | |
|
62 | 0 | SetProtoMethod(isolate, constructor, "start", Start); |
63 | 0 | SetProtoMethod(isolate, constructor, "stop", Stop); |
64 | |
|
65 | 0 | SetConstructorFunction(context, target, "Signal", constructor); |
66 | 0 | } |
67 | | |
68 | 0 | static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
69 | 0 | registry->Register(New); |
70 | 0 | registry->Register(Start); |
71 | 0 | registry->Register(Stop); |
72 | 0 | } |
73 | | |
74 | | SET_NO_MEMORY_INFO() |
75 | | SET_MEMORY_INFO_NAME(SignalWrap) |
76 | | SET_SELF_SIZE(SignalWrap) |
77 | | |
78 | | private: |
79 | 0 | 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 | 0 | CHECK(args.IsConstructCall()); |
84 | 0 | Environment* env = Environment::GetCurrent(args); |
85 | 0 | new SignalWrap(env, args.This()); |
86 | 0 | } |
87 | | |
88 | | SignalWrap(Environment* env, Local<Object> object) |
89 | 0 | : HandleWrap(env, |
90 | 0 | object, |
91 | 0 | reinterpret_cast<uv_handle_t*>(&handle_), |
92 | 0 | AsyncWrap::PROVIDER_SIGNALWRAP) { |
93 | 0 | int r = uv_signal_init(env->event_loop(), &handle_); |
94 | 0 | CHECK_EQ(r, 0); |
95 | 0 | } |
96 | | |
97 | 0 | void Close(v8::Local<v8::Value> close_callback) override { |
98 | 0 | if (active_) { |
99 | 0 | DecreaseSignalHandlerCount(handle_.signum); |
100 | 0 | active_ = false; |
101 | 0 | } |
102 | 0 | HandleWrap::Close(close_callback); |
103 | 0 | } |
104 | | |
105 | 0 | static void Start(const FunctionCallbackInfo<Value>& args) { |
106 | 0 | SignalWrap* wrap; |
107 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
108 | 0 | Environment* env = wrap->env(); |
109 | 0 | int signum; |
110 | 0 | if (!args[0]->Int32Value(env->context()).To(&signum)) return; |
111 | 0 | #if defined(__POSIX__) && HAVE_INSPECTOR |
112 | 0 | if (signum == SIGPROF) { |
113 | 0 | Environment* env = Environment::GetCurrent(args); |
114 | 0 | if (env->inspector_agent()->IsListening()) { |
115 | 0 | ProcessEmitWarning(env, |
116 | 0 | "process.on(SIGPROF) is reserved while debugging"); |
117 | 0 | return; |
118 | 0 | } |
119 | 0 | } |
120 | 0 | #endif |
121 | 0 | int err = uv_signal_start( |
122 | 0 | &wrap->handle_, |
123 | 0 | [](uv_signal_t* handle, int signum) { |
124 | 0 | SignalWrap* wrap = ContainerOf(&SignalWrap::handle_, handle); |
125 | 0 | Environment* env = wrap->env(); |
126 | 0 | HandleScope handle_scope(env->isolate()); |
127 | 0 | Context::Scope context_scope(env->context()); |
128 | 0 | Local<Value> arg = Integer::New(env->isolate(), signum); |
129 | 0 | wrap->MakeCallback(env->onsignal_string(), 1, &arg); |
130 | 0 | }, |
131 | 0 | signum); |
132 | |
|
133 | 0 | if (err == 0) { |
134 | 0 | CHECK(!wrap->active_); |
135 | 0 | wrap->active_ = true; |
136 | 0 | Mutex::ScopedLock lock(handled_signals_mutex); |
137 | 0 | handled_signals[signum]++; |
138 | 0 | } |
139 | | |
140 | 0 | args.GetReturnValue().Set(err); |
141 | 0 | } |
142 | | |
143 | 0 | static void Stop(const FunctionCallbackInfo<Value>& args) { |
144 | 0 | SignalWrap* wrap; |
145 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
146 | | |
147 | 0 | if (wrap->active_) { |
148 | 0 | wrap->active_ = false; |
149 | 0 | DecreaseSignalHandlerCount(wrap->handle_.signum); |
150 | 0 | } |
151 | |
|
152 | 0 | int err = uv_signal_stop(&wrap->handle_); |
153 | 0 | args.GetReturnValue().Set(err); |
154 | 0 | } |
155 | | |
156 | | uv_signal_t handle_; |
157 | | bool active_ = false; |
158 | | }; |
159 | | |
160 | | |
161 | | } // anonymous namespace |
162 | | |
163 | 0 | void DecreaseSignalHandlerCount(int signum) { |
164 | 0 | Mutex::ScopedLock lock(handled_signals_mutex); |
165 | 0 | int64_t new_handler_count = --handled_signals[signum]; |
166 | 0 | CHECK_GE(new_handler_count, 0); |
167 | 0 | if (new_handler_count == 0) |
168 | 0 | handled_signals.erase(signum); |
169 | 0 | } |
170 | | |
171 | 0 | bool HasSignalJSHandler(int signum) { |
172 | 0 | Mutex::ScopedLock lock(handled_signals_mutex); |
173 | 0 | return handled_signals.find(signum) != handled_signals.end(); |
174 | 0 | } |
175 | | } // namespace node |
176 | | |
177 | | NODE_BINDING_CONTEXT_AWARE_INTERNAL(signal_wrap, node::SignalWrap::Initialize) |
178 | | NODE_BINDING_EXTERNAL_REFERENCE(signal_wrap, |
179 | | node::SignalWrap::RegisterExternalReferences) |