GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_process_methods.cc Lines: 160 172 93.0 %
Date: 2019-05-05 22:32:45 Branches: 51 78 65.4 %

Line Branch Exec Source
1
#include "base_object-inl.h"
2
#include "env-inl.h"
3
#include "node.h"
4
#include "node_errors.h"
5
#include "node_internals.h"
6
#include "node_process.h"
7
#include "util-inl.h"
8
#include "uv.h"
9
#include "v8.h"
10
11
#include <vector>
12
13
#if HAVE_INSPECTOR
14
#include "inspector_io.h"
15
#endif
16
17
#include <climits>  // PATH_MAX
18
#include <cstdio>
19
20
#if defined(_MSC_VER)
21
#include <direct.h>
22
#include <io.h>
23
#define umask _umask
24
typedef int mode_t;
25
#else
26
#include <pthread.h>
27
#include <sys/resource.h>  // getrlimit, setrlimit
28
#include <termios.h>  // tcgetattr, tcsetattr
29
#endif
30
31
namespace node {
32
33
using v8::Array;
34
using v8::ArrayBuffer;
35
using v8::BigUint64Array;
36
using v8::Context;
37
using v8::Float64Array;
38
using v8::Function;
39
using v8::FunctionCallbackInfo;
40
using v8::HeapStatistics;
41
using v8::Integer;
42
using v8::Isolate;
43
using v8::Local;
44
using v8::Name;
45
using v8::NewStringType;
46
using v8::Number;
47
using v8::Object;
48
using v8::String;
49
using v8::Uint32;
50
using v8::Uint32Array;
51
using v8::Value;
52
53
namespace per_process {
54
4525
Mutex umask_mutex;
55
}   // namespace per_process
56
57
// Microseconds in a second, as a float, used in CPUUsage() below
58
#define MICROS_PER_SEC 1e6
59
// used in Hrtime() and Uptime() below
60
#define NANOS_PER_SEC 1000000000
61
62
#ifdef _WIN32
63
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
64
#define CHDIR_BUFSIZE (MAX_PATH * 4)
65
#else
66
#define CHDIR_BUFSIZE (PATH_MAX)
67
#endif
68
69
static void Abort(const FunctionCallbackInfo<Value>& args) {
70
  Abort();
71
}
72
73
126
static void Chdir(const FunctionCallbackInfo<Value>& args) {
74
126
  Environment* env = Environment::GetCurrent(args);
75
126
  CHECK(env->owns_process_state());
76
77
126
  CHECK_EQ(args.Length(), 1);
78
378
  CHECK(args[0]->IsString());
79
126
  Utf8Value path(env->isolate(), args[0]);
80
126
  int err = uv_chdir(*path);
81
126
  if (err) {
82
    // Also include the original working directory, since that will usually
83
    // be helpful information when debugging a `chdir()` failure.
84
    char buf[CHDIR_BUFSIZE];
85
1
    size_t cwd_len = sizeof(buf);
86
1
    uv_cwd(buf, &cwd_len);
87
127
    return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
88
125
  }
89
}
90
91
// CPUUsage use libuv's uv_getrusage() this-process resource usage accessor,
92
// to access ru_utime (user CPU time used) and ru_stime (system CPU time used),
93
// which are uv_timeval_t structs (long tv_sec, long tv_usec).
94
// Returns those values as Float64 microseconds in the elements of the array
95
// passed to the function.
96
35
static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
97
  uv_rusage_t rusage;
98
99
  // Call libuv to get the values we'll return.
100
35
  int err = uv_getrusage(&rusage);
101
35
  if (err) {
102
    // On error, return the strerror version of the error code.
103
    Local<String> errmsg = OneByteString(args.GetIsolate(), uv_strerror(err));
104
35
    return args.GetReturnValue().Set(errmsg);
105
  }
106
107
  // Get the double array pointer from the Float64Array argument.
108
70
  CHECK(args[0]->IsFloat64Array());
109
70
  Local<Float64Array> array = args[0].As<Float64Array>();
110
35
  CHECK_EQ(array->Length(), 2);
111
35
  Local<ArrayBuffer> ab = array->Buffer();
112
35
  double* fields = static_cast<double*>(ab->GetContents().Data());
113
114
  // Set the Float64Array elements to be user / system values in microseconds.
115
35
  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
116
35
  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
117
}
118
119
5110
static void Cwd(const FunctionCallbackInfo<Value>& args) {
120
5110
  Environment* env = Environment::GetCurrent(args);
121
5110
  CHECK(env->has_run_bootstrapping_code());
122
  char buf[CHDIR_BUFSIZE];
123
5110
  size_t cwd_len = sizeof(buf);
124
5110
  int err = uv_cwd(buf, &cwd_len);
125
5110
  if (err)
126
5124
    return env->ThrowUVException(err, "uv_cwd");
127
128
  Local<String> cwd = String::NewFromUtf8(env->isolate(),
129
                                          buf,
130
                                          NewStringType::kNormal,
131
10192
                                          cwd_len).ToLocalChecked();
132
10192
  args.GetReturnValue().Set(cwd);
133
}
134
135
136
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
137
138
// This is the legacy version of hrtime before BigInt was introduced in
139
// JavaScript.
140
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
141
// so this function instead fills in an Uint32Array with 3 entries,
142
// to avoid any integer overflow possibility.
143
// The first two entries contain the second part of the value
144
// broken into the upper/lower 32 bits to be converted back in JS,
145
// because there is no Uint64Array in JS.
146
// The third entry contains the remaining nanosecond part of the value.
147
882923
static void Hrtime(const FunctionCallbackInfo<Value>& args) {
148
882923
  uint64_t t = uv_hrtime();
149
150
2648769
  Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
151
882923
  uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
152
153
882923
  fields[0] = (t / NANOS_PER_SEC) >> 32;
154
882923
  fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
155
882923
  fields[2] = t % NANOS_PER_SEC;
156
882923
}
157
158
1036629
static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
159
3109887
  Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
160
1036629
  uint64_t* fields = static_cast<uint64_t*>(ab->GetContents().Data());
161
1036629
  fields[0] = uv_hrtime();
162
1036629
}
163
164
46
static void Kill(const FunctionCallbackInfo<Value>& args) {
165
46
  Environment* env = Environment::GetCurrent(args);
166
46
  Local<Context> context = env->context();
167
168
46
  if (args.Length() != 2)
169
    return env->ThrowError("Bad argument.");
170
171
  int pid;
172
138
  if (!args[0]->Int32Value(context).To(&pid)) return;
173
  int sig;
174
138
  if (!args[1]->Int32Value(context).To(&sig)) return;
175
    // TODO(joyeecheung): white list the signals?
176
177
#if HAVE_INSPECTOR
178
46
  profiler::EndStartedProfilers(env);
179
#endif
180
181
46
  int err = uv_kill(pid, sig);
182
92
  args.GetReturnValue().Set(err);
183
}
184
185
527
static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
186
527
  Environment* env = Environment::GetCurrent(args);
187
188
  size_t rss;
189
527
  int err = uv_resident_set_memory(&rss);
190
527
  if (err)
191
527
    return env->ThrowUVException(err, "uv_resident_set_memory");
192
193
527
  Isolate* isolate = env->isolate();
194
  // V8 memory usage
195
527
  HeapStatistics v8_heap_stats;
196
527
  isolate->GetHeapStatistics(&v8_heap_stats);
197
198
  // Get the double array pointer from the Float64Array argument.
199
1054
  CHECK(args[0]->IsFloat64Array());
200
1054
  Local<Float64Array> array = args[0].As<Float64Array>();
201
527
  CHECK_EQ(array->Length(), 4);
202
527
  Local<ArrayBuffer> ab = array->Buffer();
203
527
  double* fields = static_cast<double*>(ab->GetContents().Data());
204
205
527
  fields[0] = rss;
206
527
  fields[1] = v8_heap_stats.total_heap_size();
207
527
  fields[2] = v8_heap_stats.used_heap_size();
208
527
  fields[3] = v8_heap_stats.external_memory();
209
}
210
211
12
void RawDebug(const FunctionCallbackInfo<Value>& args) {
212


60
  CHECK(args.Length() == 1 && args[0]->IsString() &&
213
        "must be called with a single string");
214
12
  Utf8Value message(args.GetIsolate(), args[0]);
215
12
  PrintErrorString("%s\n", *message);
216
12
  fflush(stderr);
217
12
}
218
219
static void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
220
  Environment* env = Environment::GetCurrent(args);
221
  env->StartProfilerIdleNotifier();
222
}
223
224
static void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
225
  Environment* env = Environment::GetCurrent(args);
226
  env->StopProfilerIdleNotifier();
227
}
228
229
4407
static void Umask(const FunctionCallbackInfo<Value>& args) {
230
4407
  Environment* env = Environment::GetCurrent(args);
231
4407
  CHECK(env->has_run_bootstrapping_code());
232
4407
  CHECK_EQ(args.Length(), 1);
233


24036
  CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
234
4407
  Mutex::ScopedLock scoped_lock(per_process::umask_mutex);
235
236
  uint32_t old;
237
13221
  if (args[0]->IsUndefined()) {
238
1203
    old = umask(0);
239
1203
    umask(static_cast<mode_t>(old));
240
  } else {
241
9612
    int oct = args[0].As<Uint32>()->Value();
242
3204
    old = umask(static_cast<mode_t>(oct));
243
  }
244
245
8814
  args.GetReturnValue().Set(old);
246
4407
}
247
248
4
static void Uptime(const FunctionCallbackInfo<Value>& args) {
249
4
  Environment* env = Environment::GetCurrent(args);
250
251
4
  uv_update_time(env->event_loop());
252
  double uptime =
253
4
      static_cast<double>(uv_hrtime() - per_process::node_start_time);
254
4
  Local<Number> result = Number::New(env->isolate(), uptime / NANOS_PER_SEC);
255
8
  args.GetReturnValue().Set(result);
256
4
}
257
258
2
static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
259
2
  Environment* env = Environment::GetCurrent(args);
260
261
2
  std::vector<Local<Value>> request_v;
262
14
  for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
263
12
    AsyncWrap* w = req_wrap->GetAsyncWrap();
264
24
    if (w->persistent().IsEmpty())
265
      continue;
266
12
    request_v.emplace_back(w->GetOwner());
267
  }
268
269
  args.GetReturnValue().Set(
270
6
      Array::New(env->isolate(), request_v.data(), request_v.size()));
271
2
}
272
273
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
274
// implemented here for consistency with GetActiveRequests().
275
5
void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
276
5
  Environment* env = Environment::GetCurrent(args);
277
278
5
  std::vector<Local<Value>> handle_v;
279
25
  for (auto w : *env->handle_wrap_queue()) {
280
20
    if (!HandleWrap::HasRef(w))
281
1
      continue;
282
19
    handle_v.emplace_back(w->GetOwner());
283
  }
284
  args.GetReturnValue().Set(
285
15
      Array::New(env->isolate(), handle_v.data(), handle_v.size()));
286
5
}
287
288
#ifdef __POSIX__
289
3
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
290
3
  Environment* env = Environment::GetCurrent(args);
291
292
3
  if (args.Length() != 1) {
293
    return env->ThrowError("Invalid number of arguments.");
294
  }
295
296
6
  CHECK(args[0]->IsNumber());
297
9
  pid_t pid = args[0].As<Integer>()->Value();
298
3
  int r = kill(pid, SIGUSR1);
299
300
3
  if (r != 0) {
301
1
    return env->ThrowErrnoException(errno, "kill");
302
  }
303
}
304
#endif  // __POSIX__
305
306
#ifdef _WIN32
307
static int GetDebugSignalHandlerMappingName(DWORD pid,
308
                                            wchar_t* buf,
309
                                            size_t buf_len) {
310
  return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
311
}
312
313
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
314
  Environment* env = Environment::GetCurrent(args);
315
  Isolate* isolate = args.GetIsolate();
316
317
  if (args.Length() != 1) {
318
    env->ThrowError("Invalid number of arguments.");
319
    return;
320
  }
321
322
  HANDLE process = nullptr;
323
  HANDLE thread = nullptr;
324
  HANDLE mapping = nullptr;
325
  wchar_t mapping_name[32];
326
  LPTHREAD_START_ROUTINE* handler = nullptr;
327
  DWORD pid = 0;
328
329
  OnScopeLeave cleanup([&]() {
330
    if (process != nullptr) CloseHandle(process);
331
    if (thread != nullptr) CloseHandle(thread);
332
    if (handler != nullptr) UnmapViewOfFile(handler);
333
    if (mapping != nullptr) CloseHandle(mapping);
334
  });
335
336
  CHECK(args[0]->IsNumber());
337
  pid = args[0].As<Integer>()->Value();
338
339
  process =
340
      OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
341
                      PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
342
                  FALSE,
343
                  pid);
344
  if (process == nullptr) {
345
    isolate->ThrowException(
346
        WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
347
    return;
348
  }
349
350
  if (GetDebugSignalHandlerMappingName(
351
          pid, mapping_name, arraysize(mapping_name)) < 0) {
352
    env->ThrowErrnoException(errno, "sprintf");
353
    return;
354
  }
355
356
  mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
357
  if (mapping == nullptr) {
358
    isolate->ThrowException(
359
        WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW"));
360
    return;
361
  }
362
363
  handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
364
      MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler));
365
  if (handler == nullptr || *handler == nullptr) {
366
    isolate->ThrowException(
367
        WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
368
    return;
369
  }
370
371
  thread =
372
      CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr);
373
  if (thread == nullptr) {
374
    isolate->ThrowException(
375
        WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread"));
376
    return;
377
  }
378
379
  // Wait for the thread to terminate
380
  if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
381
    isolate->ThrowException(
382
        WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject"));
383
    return;
384
  }
385
}
386
#endif  // _WIN32
387
388
6
static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
389
#if HAVE_INSPECTOR
390
6
  Environment* env = Environment::GetCurrent(args);
391
6
  if (env->inspector_agent()->IsListening()) {
392
4
    env->inspector_agent()->Stop();
393
  }
394
#endif
395
6
}
396
397
241
static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
398
241
  Environment* env = Environment::GetCurrent(args);
399
241
  WaitForInspectorDisconnect(env);
400
964
  int code = args[0]->Int32Value(env->context()).FromMaybe(0);
401
241
  env->Exit(code);
402
23
}
403
404
4646
static void InitializeProcessMethods(Local<Object> target,
405
                                     Local<Value> unused,
406
                                     Local<Context> context,
407
                                     void* priv) {
408
4646
  Environment* env = Environment::GetCurrent(context);
409
410
  // define various internal methods
411
4646
  if (env->owns_process_state()) {
412
4469
    env->SetMethod(target, "_debugProcess", DebugProcess);
413
4469
    env->SetMethod(target, "_debugEnd", DebugEnd);
414
4469
    env->SetMethod(target, "abort", Abort);
415
4469
    env->SetMethod(target, "chdir", Chdir);
416
  }
417
418
  env->SetMethod(
419
4646
      target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
420
4646
  env->SetMethod(target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
421
422
4646
  env->SetMethod(target, "umask", Umask);
423
4646
  env->SetMethod(target, "_rawDebug", RawDebug);
424
4646
  env->SetMethod(target, "memoryUsage", MemoryUsage);
425
4646
  env->SetMethod(target, "cpuUsage", CPUUsage);
426
4646
  env->SetMethod(target, "hrtime", Hrtime);
427
4646
  env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
428
429
4646
  env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
430
4646
  env->SetMethod(target, "_getActiveHandles", GetActiveHandles);
431
4646
  env->SetMethod(target, "_kill", Kill);
432
433
4646
  env->SetMethodNoSideEffect(target, "cwd", Cwd);
434
4646
  env->SetMethod(target, "dlopen", binding::DLOpen);
435
4646
  env->SetMethod(target, "reallyExit", ReallyExit);
436
4646
  env->SetMethodNoSideEffect(target, "uptime", Uptime);
437
4646
  env->SetMethod(target, "patchProcessObject", PatchProcessObject);
438
4646
}
439
440
}  // namespace node
441
442

18099
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
443
                                   node::InitializeProcessMethods)