/src/node/src/handle_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 "handle_wrap.h" |
23 | | #include "async_wrap-inl.h" |
24 | | #include "env-inl.h" |
25 | | #include "node_external_reference.h" |
26 | | #include "util-inl.h" |
27 | | |
28 | | namespace node { |
29 | | |
30 | | using v8::Context; |
31 | | using v8::FunctionCallbackInfo; |
32 | | using v8::FunctionTemplate; |
33 | | using v8::HandleScope; |
34 | | using v8::Isolate; |
35 | | using v8::Local; |
36 | | using v8::Object; |
37 | | using v8::Value; |
38 | | |
39 | | |
40 | 2 | void HandleWrap::Ref(const FunctionCallbackInfo<Value>& args) { |
41 | 2 | HandleWrap* wrap; |
42 | 2 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
43 | | |
44 | 2 | if (IsAlive(wrap)) |
45 | 2 | uv_ref(wrap->GetHandle()); |
46 | 2 | } |
47 | | |
48 | | |
49 | 4 | void HandleWrap::Unref(const FunctionCallbackInfo<Value>& args) { |
50 | 4 | HandleWrap* wrap; |
51 | 4 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
52 | | |
53 | 4 | if (IsAlive(wrap)) |
54 | 4 | uv_unref(wrap->GetHandle()); |
55 | 4 | } |
56 | | |
57 | | |
58 | 0 | void HandleWrap::HasRef(const FunctionCallbackInfo<Value>& args) { |
59 | 0 | HandleWrap* wrap; |
60 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
61 | 0 | args.GetReturnValue().Set(HasRef(wrap)); |
62 | 0 | } |
63 | | |
64 | | |
65 | 0 | void HandleWrap::Close(const FunctionCallbackInfo<Value>& args) { |
66 | 0 | HandleWrap* wrap; |
67 | 0 | ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
68 | | |
69 | 0 | wrap->Close(args[0]); |
70 | 0 | } |
71 | | |
72 | 91.3k | void HandleWrap::Close(Local<Value> close_callback) { |
73 | 91.3k | if (state_ != kInitialized) |
74 | 0 | return; |
75 | | |
76 | 91.3k | uv_close(handle_, OnClose); |
77 | 91.3k | state_ = kClosing; |
78 | | |
79 | 91.3k | if (!close_callback.IsEmpty() && close_callback->IsFunction() && |
80 | 91.3k | !persistent().IsEmpty()) { |
81 | 0 | object()->Set(env()->context(), |
82 | 0 | env()->handle_onclose_symbol(), |
83 | 0 | close_callback).Check(); |
84 | 0 | } |
85 | 91.3k | } |
86 | | |
87 | | |
88 | 91.3k | void HandleWrap::OnGCCollect() { |
89 | | // When all references to a HandleWrap are lost and the object is supposed to |
90 | | // be destroyed, we first call Close() to clean up the underlying libuv |
91 | | // handle. The OnClose callback then acquires and destroys another reference |
92 | | // to that object, and when that reference is lost, we perform the default |
93 | | // action (i.e. destroying `this`). |
94 | 91.3k | if (state_ != kClosed) { |
95 | 0 | Close(); |
96 | 91.3k | } else { |
97 | 91.3k | BaseObject::OnGCCollect(); |
98 | 91.3k | } |
99 | 91.3k | } |
100 | | |
101 | | |
102 | 0 | bool HandleWrap::IsNotIndicativeOfMemoryLeakAtExit() const { |
103 | 0 | return IsWeakOrDetached() || |
104 | 0 | !HandleWrap::HasRef(this) || |
105 | 0 | !uv_is_active(GetHandle()); |
106 | 0 | } |
107 | | |
108 | | |
109 | 0 | void HandleWrap::MarkAsInitialized() { |
110 | 0 | env()->handle_wrap_queue()->PushBack(this); |
111 | 0 | state_ = kInitialized; |
112 | 0 | } |
113 | | |
114 | | |
115 | 0 | void HandleWrap::MarkAsUninitialized() { |
116 | 0 | handle_wrap_queue_.Remove(); |
117 | 0 | state_ = kClosed; |
118 | 0 | } |
119 | | |
120 | | |
121 | | HandleWrap::HandleWrap(Environment* env, |
122 | | Local<Object> object, |
123 | | uv_handle_t* handle, |
124 | | AsyncWrap::ProviderType provider) |
125 | 91.3k | : AsyncWrap(env, object, provider), |
126 | 91.3k | state_(kInitialized), |
127 | 91.3k | handle_(handle) { |
128 | 91.3k | handle_->data = this; |
129 | 91.3k | HandleScope scope(env->isolate()); |
130 | 91.3k | CHECK(env->has_run_bootstrapping_code()); |
131 | 91.3k | env->handle_wrap_queue()->PushBack(this); |
132 | 91.3k | } |
133 | | |
134 | | |
135 | 91.3k | void HandleWrap::OnClose(uv_handle_t* handle) { |
136 | 91.3k | CHECK_NOT_NULL(handle->data); |
137 | 91.3k | BaseObjectPtr<HandleWrap> wrap { static_cast<HandleWrap*>(handle->data) }; |
138 | 91.3k | wrap->Detach(); |
139 | | |
140 | 91.3k | Environment* env = wrap->env(); |
141 | 91.3k | HandleScope scope(env->isolate()); |
142 | 91.3k | Context::Scope context_scope(env->context()); |
143 | | |
144 | 91.3k | CHECK_EQ(wrap->state_, kClosing); |
145 | | |
146 | 91.3k | wrap->state_ = kClosed; |
147 | | |
148 | 91.3k | wrap->OnClose(); |
149 | 91.3k | wrap->handle_wrap_queue_.Remove(); |
150 | | |
151 | 91.3k | if (!wrap->persistent().IsEmpty() && |
152 | 91.3k | wrap->object()->Has(env->context(), env->handle_onclose_symbol()) |
153 | 91.3k | .FromMaybe(false)) { |
154 | 4 | wrap->MakeCallback(env->handle_onclose_symbol(), 0, nullptr); |
155 | 4 | } |
156 | 91.3k | } |
157 | 92.1k | Local<FunctionTemplate> HandleWrap::GetConstructorTemplate(Environment* env) { |
158 | 92.1k | return GetConstructorTemplate(env->isolate_data()); |
159 | 92.1k | } |
160 | | |
161 | | Local<FunctionTemplate> HandleWrap::GetConstructorTemplate( |
162 | 361k | IsolateData* isolate_data) { |
163 | 361k | Local<FunctionTemplate> tmpl = isolate_data->handle_wrap_ctor_template(); |
164 | 361k | if (tmpl.IsEmpty()) { |
165 | 134k | Isolate* isolate = isolate_data->isolate(); |
166 | 134k | tmpl = NewFunctionTemplate(isolate, nullptr); |
167 | 134k | tmpl->SetClassName( |
168 | 134k | FIXED_ONE_BYTE_STRING(isolate_data->isolate(), "HandleWrap")); |
169 | 134k | tmpl->Inherit(AsyncWrap::GetConstructorTemplate(isolate_data)); |
170 | 134k | SetProtoMethod(isolate, tmpl, "close", HandleWrap::Close); |
171 | 134k | SetProtoMethodNoSideEffect(isolate, tmpl, "hasRef", HandleWrap::HasRef); |
172 | 134k | SetProtoMethod(isolate, tmpl, "ref", HandleWrap::Ref); |
173 | 134k | SetProtoMethod(isolate, tmpl, "unref", HandleWrap::Unref); |
174 | 134k | isolate_data->set_handle_wrap_ctor_template(tmpl); |
175 | 134k | } |
176 | 361k | return tmpl; |
177 | 361k | } |
178 | | |
179 | | void HandleWrap::RegisterExternalReferences( |
180 | 0 | ExternalReferenceRegistry* registry) { |
181 | 0 | registry->Register(HandleWrap::Close); |
182 | 0 | registry->Register(HandleWrap::HasRef); |
183 | 0 | registry->Register(HandleWrap::Ref); |
184 | 0 | registry->Register(HandleWrap::Unref); |
185 | 0 | } |
186 | | |
187 | | } // namespace node |
188 | | |
189 | | NODE_BINDING_EXTERNAL_REFERENCE(handle_wrap, |
190 | | node::HandleWrap::RegisterExternalReferences) |