File: | out/../src/node_process_methods.cc |
Warning: | line 72, column 6 Dereference of null pointer (loaded from variable 'd') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | #include "async_wrap-inl.h" | |||
2 | #include "base_object-inl.h" | |||
3 | #include "debug_utils-inl.h" | |||
4 | #include "env-inl.h" | |||
5 | #include "memory_tracker-inl.h" | |||
6 | #include "node.h" | |||
7 | #include "node_errors.h" | |||
8 | #include "node_external_reference.h" | |||
9 | #include "node_internals.h" | |||
10 | #include "node_process-inl.h" | |||
11 | #include "util-inl.h" | |||
12 | #include "uv.h" | |||
13 | #include "v8-fast-api-calls.h" | |||
14 | #include "v8.h" | |||
15 | ||||
16 | #include <vector> | |||
17 | ||||
18 | #if HAVE_INSPECTOR1 | |||
19 | #include "inspector_io.h" | |||
20 | #endif | |||
21 | ||||
22 | #include <climits> // PATH_MAX | |||
23 | #include <cstdio> | |||
24 | ||||
25 | #if defined(_MSC_VER) | |||
26 | #include <direct.h> | |||
27 | #include <io.h> | |||
28 | #define umask _umask | |||
29 | typedef int mode_t; | |||
30 | #else | |||
31 | #include <pthread.h> | |||
32 | #include <sys/resource.h> // getrlimit, setrlimit | |||
33 | #include <termios.h> // tcgetattr, tcsetattr | |||
34 | #endif | |||
35 | ||||
36 | namespace node { | |||
37 | ||||
38 | using v8::Array; | |||
39 | using v8::ArrayBuffer; | |||
40 | using v8::CFunction; | |||
41 | using v8::Context; | |||
42 | using v8::Float64Array; | |||
43 | using v8::FunctionCallbackInfo; | |||
44 | using v8::HeapStatistics; | |||
45 | using v8::Integer; | |||
46 | using v8::Isolate; | |||
47 | using v8::Local; | |||
48 | using v8::NewStringType; | |||
49 | using v8::Number; | |||
50 | using v8::Object; | |||
51 | using v8::String; | |||
52 | using v8::Uint32; | |||
53 | using v8::Value; | |||
54 | ||||
55 | namespace per_process { | |||
56 | Mutex umask_mutex; | |||
57 | } // namespace per_process | |||
58 | ||||
59 | // Microseconds in a second, as a float, used in CPUUsage() below | |||
60 | #define MICROS_PER_SEC1e6 1e6 | |||
61 | // used in Hrtime() and Uptime() below | |||
62 | #define NANOS_PER_SEC1000000000 1000000000 | |||
63 | ||||
64 | static void Abort(const FunctionCallbackInfo<Value>& args) { | |||
65 | Abort(); | |||
66 | } | |||
67 | ||||
68 | // For internal testing only, not exposed to userland. | |||
69 | static void CauseSegfault(const FunctionCallbackInfo<Value>& args) { | |||
70 | // This should crash hard all platforms. | |||
71 | volatile void** d = static_cast<volatile void**>(nullptr); | |||
| ||||
72 | *d = nullptr; | |||
| ||||
73 | } | |||
74 | ||||
75 | static void Chdir(const FunctionCallbackInfo<Value>& args) { | |||
76 | Environment* env = Environment::GetCurrent(args); | |||
77 | CHECK(env->owns_process_state())do { if (__builtin_expect(!!(!(env->owns_process_state())) , 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "77", "env->owns_process_state()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
78 | ||||
79 | CHECK_EQ(args.Length(), 1)do { if (__builtin_expect(!!(!((args.Length()) == (1))), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "79", "(args.Length()) == (1)", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
80 | CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "80", "args[0]->IsString()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
81 | Utf8Value path(env->isolate(), args[0]); | |||
82 | int err = uv_chdir(*path); | |||
83 | if (err) { | |||
84 | // Also include the original working directory, since that will usually | |||
85 | // be helpful information when debugging a `chdir()` failure. | |||
86 | char buf[PATH_MAX_BYTES(4096)]; | |||
87 | size_t cwd_len = sizeof(buf); | |||
88 | uv_cwd(buf, &cwd_len); | |||
89 | return env->ThrowUVException(err, "chdir", nullptr, buf, *path); | |||
90 | } | |||
91 | } | |||
92 | ||||
93 | inline Local<ArrayBuffer> get_fields_array_buffer( | |||
94 | const FunctionCallbackInfo<Value>& args, | |||
95 | size_t index, | |||
96 | size_t array_length) { | |||
97 | CHECK(args[index]->IsFloat64Array())do { if (__builtin_expect(!!(!(args[index]->IsFloat64Array ())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "97", "args[index]->IsFloat64Array()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
98 | Local<Float64Array> arr = args[index].As<Float64Array>(); | |||
99 | CHECK_EQ(arr->Length(), array_length)do { if (__builtin_expect(!!(!((arr->Length()) == (array_length ))), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "99", "(arr->Length()) == (array_length)", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
100 | return arr->Buffer(); | |||
101 | } | |||
102 | ||||
103 | // CPUUsage use libuv's uv_getrusage() this-process resource usage accessor, | |||
104 | // to access ru_utime (user CPU time used) and ru_stime (system CPU time used), | |||
105 | // which are uv_timeval_t structs (long tv_sec, long tv_usec). | |||
106 | // Returns those values as Float64 microseconds in the elements of the array | |||
107 | // passed to the function. | |||
108 | static void CPUUsage(const FunctionCallbackInfo<Value>& args) { | |||
109 | Environment* env = Environment::GetCurrent(args); | |||
110 | uv_rusage_t rusage; | |||
111 | ||||
112 | // Call libuv to get the values we'll return. | |||
113 | int err = uv_getrusage(&rusage); | |||
114 | if (err) | |||
115 | return env->ThrowUVException(err, "uv_getrusage"); | |||
116 | ||||
117 | // Get the double array pointer from the Float64Array argument. | |||
118 | Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 2); | |||
119 | double* fields = static_cast<double*>(ab->GetBackingStore()->Data()); | |||
120 | ||||
121 | // Set the Float64Array elements to be user / system values in microseconds. | |||
122 | fields[0] = MICROS_PER_SEC1e6 * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec; | |||
123 | fields[1] = MICROS_PER_SEC1e6 * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec; | |||
124 | } | |||
125 | ||||
126 | static void Cwd(const FunctionCallbackInfo<Value>& args) { | |||
127 | Environment* env = Environment::GetCurrent(args); | |||
128 | CHECK(env->has_run_bootstrapping_code())do { if (__builtin_expect(!!(!(env->has_run_bootstrapping_code ())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "128", "env->has_run_bootstrapping_code()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
129 | char buf[PATH_MAX_BYTES(4096)]; | |||
130 | size_t cwd_len = sizeof(buf); | |||
131 | int err = uv_cwd(buf, &cwd_len); | |||
132 | if (err) | |||
133 | return env->ThrowUVException(err, "uv_cwd"); | |||
134 | ||||
135 | Local<String> cwd = String::NewFromUtf8(env->isolate(), | |||
136 | buf, | |||
137 | NewStringType::kNormal, | |||
138 | cwd_len).ToLocalChecked(); | |||
139 | args.GetReturnValue().Set(cwd); | |||
140 | } | |||
141 | ||||
142 | static void Kill(const FunctionCallbackInfo<Value>& args) { | |||
143 | Environment* env = Environment::GetCurrent(args); | |||
144 | Local<Context> context = env->context(); | |||
145 | ||||
146 | if (args.Length() < 2) { | |||
147 | THROW_ERR_MISSING_ARGS(env, "Bad argument."); | |||
148 | } | |||
149 | ||||
150 | int pid; | |||
151 | if (!args[0]->Int32Value(context).To(&pid)) return; | |||
152 | int sig; | |||
153 | if (!args[1]->Int32Value(context).To(&sig)) return; | |||
154 | ||||
155 | uv_pid_t own_pid = uv_os_getpid(); | |||
156 | if (sig > 0 && | |||
157 | (pid == 0 || pid == -1 || pid == own_pid || pid == -own_pid) && | |||
158 | !HasSignalJSHandler(sig)) { | |||
159 | // This is most likely going to terminate this process. | |||
160 | // It's not an exact method but it might be close enough. | |||
161 | RunAtExit(env); | |||
162 | } | |||
163 | ||||
164 | int err = uv_kill(pid, sig); | |||
165 | args.GetReturnValue().Set(err); | |||
166 | } | |||
167 | ||||
168 | static void Rss(const FunctionCallbackInfo<Value>& args) { | |||
169 | Environment* env = Environment::GetCurrent(args); | |||
170 | ||||
171 | size_t rss; | |||
172 | int err = uv_resident_set_memory(&rss); | |||
173 | if (err) | |||
174 | return env->ThrowUVException(err, "uv_resident_set_memory"); | |||
175 | ||||
176 | args.GetReturnValue().Set(static_cast<double>(rss)); | |||
177 | } | |||
178 | ||||
179 | static void MemoryUsage(const FunctionCallbackInfo<Value>& args) { | |||
180 | Environment* env = Environment::GetCurrent(args); | |||
181 | ||||
182 | Isolate* isolate = env->isolate(); | |||
183 | // V8 memory usage | |||
184 | HeapStatistics v8_heap_stats; | |||
185 | isolate->GetHeapStatistics(&v8_heap_stats); | |||
186 | ||||
187 | NodeArrayBufferAllocator* array_buffer_allocator = | |||
188 | env->isolate_data()->node_allocator(); | |||
189 | ||||
190 | // Get the double array pointer from the Float64Array argument. | |||
191 | Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 5); | |||
192 | double* fields = static_cast<double*>(ab->GetBackingStore()->Data()); | |||
193 | ||||
194 | size_t rss; | |||
195 | int err = uv_resident_set_memory(&rss); | |||
196 | if (err) | |||
197 | return env->ThrowUVException(err, "uv_resident_set_memory"); | |||
198 | ||||
199 | fields[0] = static_cast<double>(rss); | |||
200 | fields[1] = static_cast<double>(v8_heap_stats.total_heap_size()); | |||
201 | fields[2] = static_cast<double>(v8_heap_stats.used_heap_size()); | |||
202 | fields[3] = static_cast<double>(v8_heap_stats.external_memory()); | |||
203 | fields[4] = | |||
204 | array_buffer_allocator == nullptr | |||
205 | ? 0 | |||
206 | : static_cast<double>(array_buffer_allocator->total_mem_usage()); | |||
207 | } | |||
208 | ||||
209 | void RawDebug(const FunctionCallbackInfo<Value>& args) { | |||
210 | CHECK(args.Length() == 1 && args[0]->IsString() &&do { if (__builtin_expect(!!(!(args.Length() == 1 && args [0]->IsString() && "must be called with a single string" )), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "211", "args.Length() == 1 && args[0]->IsString() && \"must be called with a single string\"" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0) | |||
211 | "must be called with a single string")do { if (__builtin_expect(!!(!(args.Length() == 1 && args [0]->IsString() && "must be called with a single string" )), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "211", "args.Length() == 1 && args[0]->IsString() && \"must be called with a single string\"" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
212 | Utf8Value message(args.GetIsolate(), args[0]); | |||
213 | FPrintF(stderrstderr, "%s\n", message); | |||
214 | fflush(stderrstderr); | |||
215 | } | |||
216 | ||||
217 | static void Umask(const FunctionCallbackInfo<Value>& args) { | |||
218 | Environment* env = Environment::GetCurrent(args); | |||
219 | CHECK(env->has_run_bootstrapping_code())do { if (__builtin_expect(!!(!(env->has_run_bootstrapping_code ())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "219", "env->has_run_bootstrapping_code()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
220 | CHECK_EQ(args.Length(), 1)do { if (__builtin_expect(!!(!((args.Length()) == (1))), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "220", "(args.Length()) == (1)", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
221 | CHECK(args[0]->IsUndefined() || args[0]->IsUint32())do { if (__builtin_expect(!!(!(args[0]->IsUndefined() || args [0]->IsUint32())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "221", "args[0]->IsUndefined() || args[0]->IsUint32()" , __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
222 | Mutex::ScopedLock scoped_lock(per_process::umask_mutex); | |||
223 | ||||
224 | uint32_t old; | |||
225 | if (args[0]->IsUndefined()) { | |||
226 | old = umask(0); | |||
227 | umask(static_cast<mode_t>(old)); | |||
228 | } else { | |||
229 | int oct = args[0].As<Uint32>()->Value(); | |||
230 | old = umask(static_cast<mode_t>(oct)); | |||
231 | } | |||
232 | ||||
233 | args.GetReturnValue().Set(old); | |||
234 | } | |||
235 | ||||
236 | static void Uptime(const FunctionCallbackInfo<Value>& args) { | |||
237 | Environment* env = Environment::GetCurrent(args); | |||
238 | ||||
239 | uv_update_time(env->event_loop()); | |||
240 | double uptime = | |||
241 | static_cast<double>(uv_hrtime() - per_process::node_start_time); | |||
242 | Local<Number> result = Number::New(env->isolate(), uptime / NANOS_PER_SEC1000000000); | |||
243 | args.GetReturnValue().Set(result); | |||
244 | } | |||
245 | ||||
246 | static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) { | |||
247 | Environment* env = Environment::GetCurrent(args); | |||
248 | ||||
249 | std::vector<Local<Value>> request_v; | |||
250 | for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) { | |||
251 | AsyncWrap* w = req_wrap->GetAsyncWrap(); | |||
252 | if (w->persistent().IsEmpty()) | |||
253 | continue; | |||
254 | request_v.emplace_back(w->GetOwner()); | |||
255 | } | |||
256 | ||||
257 | args.GetReturnValue().Set( | |||
258 | Array::New(env->isolate(), request_v.data(), request_v.size())); | |||
259 | } | |||
260 | ||||
261 | static void GetActiveRequestsInfo(const FunctionCallbackInfo<Value>& args) { | |||
262 | Environment* env = Environment::GetCurrent(args); | |||
263 | ||||
264 | std::vector<Local<Value>> requests_info; | |||
265 | for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) { | |||
266 | AsyncWrap* w = req_wrap->GetAsyncWrap(); | |||
267 | if (w->persistent().IsEmpty()) continue; | |||
268 | requests_info.emplace_back(OneByteString(env->isolate(), | |||
269 | w->MemoryInfoName().c_str())); | |||
270 | } | |||
271 | ||||
272 | args.GetReturnValue().Set( | |||
273 | Array::New(env->isolate(), requests_info.data(), requests_info.size())); | |||
274 | } | |||
275 | ||||
276 | // Non-static, friend of HandleWrap. Could have been a HandleWrap method but | |||
277 | // implemented here for consistency with GetActiveRequests(). | |||
278 | void GetActiveHandles(const FunctionCallbackInfo<Value>& args) { | |||
279 | Environment* env = Environment::GetCurrent(args); | |||
280 | ||||
281 | std::vector<Local<Value>> handle_v; | |||
282 | for (auto w : *env->handle_wrap_queue()) { | |||
283 | if (!HandleWrap::HasRef(w)) | |||
284 | continue; | |||
285 | handle_v.emplace_back(w->GetOwner()); | |||
286 | } | |||
287 | args.GetReturnValue().Set( | |||
288 | Array::New(env->isolate(), handle_v.data(), handle_v.size())); | |||
289 | } | |||
290 | ||||
291 | void GetActiveHandlesInfo(const FunctionCallbackInfo<Value>& args) { | |||
292 | Environment* env = Environment::GetCurrent(args); | |||
293 | ||||
294 | std::vector<Local<Value>> handles_info; | |||
295 | for (HandleWrap* w : *env->handle_wrap_queue()) { | |||
296 | if (w->persistent().IsEmpty() || !HandleWrap::HasRef(w)) continue; | |||
297 | handles_info.emplace_back(OneByteString(env->isolate(), | |||
298 | w->MemoryInfoName().c_str())); | |||
299 | } | |||
300 | ||||
301 | args.GetReturnValue().Set( | |||
302 | Array::New(env->isolate(), handles_info.data(), handles_info.size())); | |||
303 | } | |||
304 | ||||
305 | static void ResourceUsage(const FunctionCallbackInfo<Value>& args) { | |||
306 | Environment* env = Environment::GetCurrent(args); | |||
307 | ||||
308 | uv_rusage_t rusage; | |||
309 | int err = uv_getrusage(&rusage); | |||
310 | if (err) | |||
311 | return env->ThrowUVException(err, "uv_getrusage"); | |||
312 | ||||
313 | Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 16); | |||
314 | double* fields = static_cast<double*>(ab->GetBackingStore()->Data()); | |||
315 | ||||
316 | fields[0] = MICROS_PER_SEC1e6 * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec; | |||
317 | fields[1] = MICROS_PER_SEC1e6 * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec; | |||
318 | fields[2] = static_cast<double>(rusage.ru_maxrss); | |||
319 | fields[3] = static_cast<double>(rusage.ru_ixrss); | |||
320 | fields[4] = static_cast<double>(rusage.ru_idrss); | |||
321 | fields[5] = static_cast<double>(rusage.ru_isrss); | |||
322 | fields[6] = static_cast<double>(rusage.ru_minflt); | |||
323 | fields[7] = static_cast<double>(rusage.ru_majflt); | |||
324 | fields[8] = static_cast<double>(rusage.ru_nswap); | |||
325 | fields[9] = static_cast<double>(rusage.ru_inblock); | |||
326 | fields[10] = static_cast<double>(rusage.ru_oublock); | |||
327 | fields[11] = static_cast<double>(rusage.ru_msgsnd); | |||
328 | fields[12] = static_cast<double>(rusage.ru_msgrcv); | |||
329 | fields[13] = static_cast<double>(rusage.ru_nsignals); | |||
330 | fields[14] = static_cast<double>(rusage.ru_nvcsw); | |||
331 | fields[15] = static_cast<double>(rusage.ru_nivcsw); | |||
332 | } | |||
333 | ||||
334 | #ifdef __POSIX__1 | |||
335 | static void DebugProcess(const FunctionCallbackInfo<Value>& args) { | |||
336 | Environment* env = Environment::GetCurrent(args); | |||
337 | ||||
338 | if (args.Length() < 1) { | |||
339 | return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments."); | |||
340 | } | |||
341 | ||||
342 | CHECK(args[0]->IsNumber())do { if (__builtin_expect(!!(!(args[0]->IsNumber())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "342", "args[0]->IsNumber()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
343 | pid_t pid = args[0].As<Integer>()->Value(); | |||
344 | int r = kill(pid, SIGUSR110); | |||
345 | ||||
346 | if (r != 0) { | |||
347 | return env->ThrowErrnoException(errno(*__errno_location ()), "kill"); | |||
348 | } | |||
349 | } | |||
350 | #endif // __POSIX__ | |||
351 | ||||
352 | #ifdef _WIN32 | |||
353 | static int GetDebugSignalHandlerMappingName(DWORD pid, | |||
354 | wchar_t* buf, | |||
355 | size_t buf_len) { | |||
356 | return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid); | |||
357 | } | |||
358 | ||||
359 | static void DebugProcess(const FunctionCallbackInfo<Value>& args) { | |||
360 | Environment* env = Environment::GetCurrent(args); | |||
361 | Isolate* isolate = args.GetIsolate(); | |||
362 | ||||
363 | if (args.Length() < 1) { | |||
364 | return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments."); | |||
365 | } | |||
366 | ||||
367 | HANDLE process = nullptr; | |||
368 | HANDLE thread = nullptr; | |||
369 | HANDLE mapping = nullptr; | |||
370 | wchar_t mapping_name[32]; | |||
371 | LPTHREAD_START_ROUTINE* handler = nullptr; | |||
372 | DWORD pid = 0; | |||
373 | ||||
374 | auto cleanup = OnScopeLeave([&]() { | |||
375 | if (process != nullptr) CloseHandle(process); | |||
376 | if (thread != nullptr) CloseHandle(thread); | |||
377 | if (handler != nullptr) UnmapViewOfFile(handler); | |||
378 | if (mapping != nullptr) CloseHandle(mapping); | |||
379 | }); | |||
380 | ||||
381 | CHECK(args[0]->IsNumber())do { if (__builtin_expect(!!(!(args[0]->IsNumber())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "381", "args[0]->IsNumber()", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
382 | pid = static_cast<DWORD>(args[0].As<Integer>()->Value()); | |||
383 | ||||
384 | process = | |||
385 | OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | | |||
386 | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, | |||
387 | FALSE, | |||
388 | pid); | |||
389 | if (process == nullptr) { | |||
390 | isolate->ThrowException( | |||
391 | WinapiErrnoException(isolate, GetLastError(), "OpenProcess")); | |||
392 | return; | |||
393 | } | |||
394 | ||||
395 | if (GetDebugSignalHandlerMappingName( | |||
396 | pid, mapping_name, arraysize(mapping_name)) < 0) { | |||
397 | env->ThrowErrnoException(errno(*__errno_location ()), "sprintf"); | |||
398 | return; | |||
399 | } | |||
400 | ||||
401 | mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name); | |||
402 | if (mapping == nullptr) { | |||
403 | isolate->ThrowException( | |||
404 | WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW")); | |||
405 | return; | |||
406 | } | |||
407 | ||||
408 | handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>( | |||
409 | MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler)); | |||
410 | if (handler == nullptr || *handler == nullptr) { | |||
411 | isolate->ThrowException( | |||
412 | WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile")); | |||
413 | return; | |||
414 | } | |||
415 | ||||
416 | thread = | |||
417 | CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr); | |||
418 | if (thread == nullptr) { | |||
419 | isolate->ThrowException( | |||
420 | WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread")); | |||
421 | return; | |||
422 | } | |||
423 | ||||
424 | // Wait for the thread to terminate | |||
425 | if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) { | |||
426 | isolate->ThrowException( | |||
427 | WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject")); | |||
428 | return; | |||
429 | } | |||
430 | } | |||
431 | #endif // _WIN32 | |||
432 | ||||
433 | static void DebugEnd(const FunctionCallbackInfo<Value>& args) { | |||
434 | #if HAVE_INSPECTOR1 | |||
435 | Environment* env = Environment::GetCurrent(args); | |||
436 | if (env->inspector_agent()->IsListening()) { | |||
437 | env->inspector_agent()->Stop(); | |||
438 | } | |||
439 | #endif | |||
440 | } | |||
441 | ||||
442 | static void ReallyExit(const FunctionCallbackInfo<Value>& args) { | |||
443 | Environment* env = Environment::GetCurrent(args); | |||
444 | RunAtExit(env); | |||
445 | int code = args[0]->Int32Value(env->context()).FromMaybe(0); | |||
446 | env->Exit(code); | |||
447 | } | |||
448 | ||||
449 | namespace process { | |||
450 | ||||
451 | BindingData::BindingData(Environment* env, v8::Local<v8::Object> object) | |||
452 | : SnapshotableObject(env, object, type_int) { | |||
453 | Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), kBufferSize); | |||
454 | array_buffer_.Reset(env->isolate(), ab); | |||
455 | object | |||
456 | ->Set(env->context(), | |||
457 | FIXED_ONE_BYTE_STRING(env->isolate(), "hrtimeBuffer"), | |||
458 | ab) | |||
459 | .ToChecked(); | |||
460 | backing_store_ = ab->GetBackingStore(); | |||
461 | } | |||
462 | ||||
463 | v8::CFunction BindingData::fast_number_(v8::CFunction::Make(FastNumber)); | |||
464 | v8::CFunction BindingData::fast_bigint_(v8::CFunction::Make(FastBigInt)); | |||
465 | ||||
466 | void BindingData::AddMethods() { | |||
467 | env()->SetFastMethod(object(), "hrtime", SlowNumber, &fast_number_); | |||
468 | env()->SetFastMethod(object(), "hrtimeBigInt", SlowBigInt, &fast_bigint_); | |||
469 | } | |||
470 | ||||
471 | void BindingData::RegisterExternalReferences( | |||
472 | ExternalReferenceRegistry* registry) { | |||
473 | registry->Register(SlowNumber); | |||
474 | registry->Register(SlowBigInt); | |||
475 | registry->Register(FastNumber); | |||
476 | registry->Register(FastBigInt); | |||
477 | registry->Register(fast_number_.GetTypeInfo()); | |||
478 | registry->Register(fast_bigint_.GetTypeInfo()); | |||
479 | } | |||
480 | ||||
481 | BindingData* BindingData::FromV8Value(Local<Value> value) { | |||
482 | Local<Object> v8_object = value.As<Object>(); | |||
483 | return static_cast<BindingData*>( | |||
484 | v8_object->GetAlignedPointerFromInternalField(BaseObject::kSlot)); | |||
485 | } | |||
486 | ||||
487 | void BindingData::MemoryInfo(MemoryTracker* tracker) const { | |||
488 | tracker->TrackField("array_buffer", array_buffer_); | |||
489 | } | |||
490 | ||||
491 | // This is the legacy version of hrtime before BigInt was introduced in | |||
492 | // JavaScript. | |||
493 | // The value returned by uv_hrtime() is a 64-bit int representing nanoseconds, | |||
494 | // so this function instead fills in an Uint32Array with 3 entries, | |||
495 | // to avoid any integer overflow possibility. | |||
496 | // The first two entries contain the second part of the value | |||
497 | // broken into the upper/lower 32 bits to be converted back in JS, | |||
498 | // because there is no Uint64Array in JS. | |||
499 | // The third entry contains the remaining nanosecond part of the value. | |||
500 | void BindingData::NumberImpl(BindingData* receiver) { | |||
501 | // Make sure we don't accidentally access buffers wiped for snapshot. | |||
502 | CHECK(!receiver->array_buffer_.IsEmpty())do { if (__builtin_expect(!!(!(!receiver->array_buffer_.IsEmpty ())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "502", "!receiver->array_buffer_.IsEmpty()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
503 | uint64_t t = uv_hrtime(); | |||
504 | uint32_t* fields = static_cast<uint32_t*>(receiver->backing_store_->Data()); | |||
505 | fields[0] = (t / NANOS_PER_SEC1000000000) >> 32; | |||
506 | fields[1] = (t / NANOS_PER_SEC1000000000) & 0xffffffff; | |||
507 | fields[2] = t % NANOS_PER_SEC1000000000; | |||
508 | } | |||
509 | ||||
510 | void BindingData::BigIntImpl(BindingData* receiver) { | |||
511 | // Make sure we don't accidentally access buffers wiped for snapshot. | |||
512 | CHECK(!receiver->array_buffer_.IsEmpty())do { if (__builtin_expect(!!(!(!receiver->array_buffer_.IsEmpty ())), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "512", "!receiver->array_buffer_.IsEmpty()", __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } } while (0); | |||
513 | uint64_t t = uv_hrtime(); | |||
514 | uint64_t* fields = static_cast<uint64_t*>(receiver->backing_store_->Data()); | |||
515 | fields[0] = t; | |||
516 | } | |||
517 | ||||
518 | void BindingData::SlowBigInt(const FunctionCallbackInfo<Value>& args) { | |||
519 | BigIntImpl(FromJSObject<BindingData>(args.Holder())); | |||
520 | } | |||
521 | ||||
522 | void BindingData::SlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args) { | |||
523 | NumberImpl(FromJSObject<BindingData>(args.Holder())); | |||
524 | } | |||
525 | ||||
526 | void BindingData::PrepareForSerialization(Local<Context> context, | |||
527 | v8::SnapshotCreator* creator) { | |||
528 | // It's not worth keeping. | |||
529 | // Release it, we will recreate it when the instance is dehydrated. | |||
530 | array_buffer_.Reset(); | |||
531 | } | |||
532 | ||||
533 | InternalFieldInfo* BindingData::Serialize(int index) { | |||
534 | DCHECK_EQ(index, BaseObject::kSlot); | |||
535 | InternalFieldInfo* info = InternalFieldInfo::New(type()); | |||
536 | return info; | |||
537 | } | |||
538 | ||||
539 | void BindingData::Deserialize(Local<Context> context, | |||
540 | Local<Object> holder, | |||
541 | int index, | |||
542 | InternalFieldInfo* info) { | |||
543 | DCHECK_EQ(index, BaseObject::kSlot); | |||
544 | v8::HandleScope scope(context->GetIsolate()); | |||
545 | Environment* env = Environment::GetCurrent(context); | |||
546 | // Recreate the buffer in the constructor. | |||
547 | BindingData* binding = env->AddBindingData<BindingData>(context, holder); | |||
548 | CHECK_NOT_NULL(binding)do { if (__builtin_expect(!!(!((binding) != nullptr)), 0)) { do { static const node::AssertionInfo args = { "../src/node_process_methods.cc" ":" "548", "(binding) != nullptr", __PRETTY_FUNCTION__ }; node ::Assert(args); } while (0); } } while (0); | |||
549 | } | |||
550 | ||||
551 | static void Initialize(Local<Object> target, | |||
552 | Local<Value> unused, | |||
553 | Local<Context> context, | |||
554 | void* priv) { | |||
555 | Environment* env = Environment::GetCurrent(context); | |||
556 | BindingData* const binding_data = | |||
557 | env->AddBindingData<BindingData>(context, target); | |||
558 | if (binding_data == nullptr) return; | |||
559 | binding_data->AddMethods(); | |||
560 | ||||
561 | // define various internal methods | |||
562 | if (env->owns_process_state()) { | |||
563 | env->SetMethod(target, "_debugProcess", DebugProcess); | |||
564 | env->SetMethod(target, "_debugEnd", DebugEnd); | |||
565 | env->SetMethod(target, "abort", Abort); | |||
566 | env->SetMethod(target, "causeSegfault", CauseSegfault); | |||
567 | env->SetMethod(target, "chdir", Chdir); | |||
568 | } | |||
569 | ||||
570 | env->SetMethod(target, "umask", Umask); | |||
571 | env->SetMethod(target, "_rawDebug", RawDebug); | |||
572 | env->SetMethod(target, "memoryUsage", MemoryUsage); | |||
573 | env->SetMethod(target, "rss", Rss); | |||
574 | env->SetMethod(target, "cpuUsage", CPUUsage); | |||
575 | env->SetMethod(target, "resourceUsage", ResourceUsage); | |||
576 | ||||
577 | env->SetMethod(target, "_getActiveRequests", GetActiveRequests); | |||
578 | env->SetMethod(target, "_getActiveRequestsInfo", GetActiveRequestsInfo); | |||
579 | env->SetMethod(target, "_getActiveHandles", GetActiveHandles); | |||
580 | env->SetMethod(target, "_getActiveHandlesInfo", GetActiveHandlesInfo); | |||
581 | env->SetMethod(target, "_kill", Kill); | |||
582 | ||||
583 | env->SetMethodNoSideEffect(target, "cwd", Cwd); | |||
584 | env->SetMethod(target, "dlopen", binding::DLOpen); | |||
585 | env->SetMethod(target, "reallyExit", ReallyExit); | |||
586 | env->SetMethodNoSideEffect(target, "uptime", Uptime); | |||
587 | env->SetMethod(target, "patchProcessObject", PatchProcessObject); | |||
588 | } | |||
589 | ||||
590 | void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | |||
591 | BindingData::RegisterExternalReferences(registry); | |||
592 | ||||
593 | registry->Register(DebugProcess); | |||
594 | registry->Register(DebugEnd); | |||
595 | registry->Register(Abort); | |||
596 | registry->Register(CauseSegfault); | |||
597 | registry->Register(Chdir); | |||
598 | ||||
599 | registry->Register(Umask); | |||
600 | registry->Register(RawDebug); | |||
601 | registry->Register(MemoryUsage); | |||
602 | registry->Register(Rss); | |||
603 | registry->Register(CPUUsage); | |||
604 | registry->Register(ResourceUsage); | |||
605 | ||||
606 | registry->Register(GetActiveRequests); | |||
607 | registry->Register(GetActiveRequestsInfo); | |||
608 | registry->Register(GetActiveHandles); | |||
609 | registry->Register(GetActiveHandlesInfo); | |||
610 | registry->Register(Kill); | |||
611 | ||||
612 | registry->Register(Cwd); | |||
613 | registry->Register(binding::DLOpen); | |||
614 | registry->Register(ReallyExit); | |||
615 | registry->Register(Uptime); | |||
616 | registry->Register(PatchProcessObject); | |||
617 | } | |||
618 | ||||
619 | } // namespace process | |||
620 | } // namespace node | |||
621 | ||||
622 | NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods, node::process::Initialize)static node::node_module _module = { 108, NM_F_INTERNAL, nullptr , "../src/node_process_methods.cc", nullptr, (node::addon_context_register_func )(node::process::Initialize), "process_methods", nullptr, nullptr }; void _register_process_methods() { node_module_register(& _module); } | |||
623 | NODE_MODULE_EXTERNAL_REFERENCE(process_methods,void _register_external_reference_process_methods( node::ExternalReferenceRegistry * registry) { node::process::RegisterExternalReferences(registry ); } | |||
624 | node::process::RegisterExternalReferences)void _register_external_reference_process_methods( node::ExternalReferenceRegistry * registry) { node::process::RegisterExternalReferences(registry ); } |