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: 188 203 92.6 %
Date: 2019-09-26 22:31:05 Branches: 54 84 64.3 %

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
4954
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
static void Abort(const FunctionCallbackInfo<Value>& args) {
63
  Abort();
64
}
65
66
// For internal testing only, not exposed to userland.
67
static void CauseSegfault(const FunctionCallbackInfo<Value>& args) {
68
  // This should crash hard all platforms.
69
  volatile void** d = static_cast<volatile void**>(nullptr);
70
  *d = nullptr;
71
}
72
73
389
static void Chdir(const FunctionCallbackInfo<Value>& args) {
74
389
  Environment* env = Environment::GetCurrent(args);
75
389
  CHECK(env->owns_process_state());
76
77
389
  CHECK_EQ(args.Length(), 1);
78
1167
  CHECK(args[0]->IsString());
79
389
  Utf8Value path(env->isolate(), args[0]);
80
389
  int err = uv_chdir(*path);
81
389
  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[PATH_MAX_BYTES];
85
1
    size_t cwd_len = sizeof(buf);
86
1
    uv_cwd(buf, &cwd_len);
87
390
    return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
88
388
  }
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
5427
static void Cwd(const FunctionCallbackInfo<Value>& args) {
120
5427
  Environment* env = Environment::GetCurrent(args);
121
5428
  CHECK(env->has_run_bootstrapping_code());
122
  char buf[PATH_MAX_BYTES];
123
5428
  size_t cwd_len = sizeof(buf);
124
5428
  int err = uv_cwd(buf, &cwd_len);
125
5427
  if (err)
126
5440
    return env->ThrowUVException(err, "uv_cwd");
127
128
  Local<String> cwd = String::NewFromUtf8(env->isolate(),
129
                                          buf,
130
                                          NewStringType::kNormal,
131
10831
                                          cwd_len).ToLocalChecked();
132
10832
  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
990123
static void Hrtime(const FunctionCallbackInfo<Value>& args) {
148
990123
  uint64_t t = uv_hrtime();
149
150
2970369
  Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
151
990123
  uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
152
153
990123
  fields[0] = (t / NANOS_PER_SEC) >> 32;
154
990123
  fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
155
990123
  fields[2] = t % NANOS_PER_SEC;
156
990123
}
157
158
1722474
static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
159
5167422
  Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
160
1722474
  uint64_t* fields = static_cast<uint64_t*>(ab->GetContents().Data());
161
1722474
  fields[0] = uv_hrtime();
162
1722474
}
163
164
62
static void Kill(const FunctionCallbackInfo<Value>& args) {
165
62
  Environment* env = Environment::GetCurrent(args);
166
62
  Local<Context> context = env->context();
167
168
62
  if (args.Length() != 2)
169
    return env->ThrowError("Bad argument.");
170
171
  int pid;
172
186
  if (!args[0]->Int32Value(context).To(&pid)) return;
173
  int sig;
174
186
  if (!args[1]->Int32Value(context).To(&sig)) return;
175
    // TODO(joyeecheung): white list the signals?
176
177
#if HAVE_INSPECTOR
178
62
  profiler::EndStartedProfilers(env);
179
#endif
180
181
62
  int err = uv_kill(pid, sig);
182
124
  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
18
void RawDebug(const FunctionCallbackInfo<Value>& args) {
212


90
  CHECK(args.Length() == 1 && args[0]->IsString() &&
213
        "must be called with a single string");
214
18
  Utf8Value message(args.GetIsolate(), args[0]);
215
18
  PrintErrorString("%s\n", *message);
216
18
  fflush(stderr);
217
18
}
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
4440
static void Umask(const FunctionCallbackInfo<Value>& args) {
230
4440
  Environment* env = Environment::GetCurrent(args);
231
4440
  CHECK(env->has_run_bootstrapping_code());
232
4440
  CHECK_EQ(args.Length(), 1);
233


24488
  CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
234
4440
  Mutex::ScopedLock scoped_lock(per_process::umask_mutex);
235
236
  uint32_t old;
237
13320
  if (args[0]->IsUndefined()) {
238
1076
    old = umask(0);
239
1076
    umask(static_cast<mode_t>(old));
240
  } else {
241
10092
    int oct = args[0].As<Uint32>()->Value();
242
3364
    old = umask(static_cast<mode_t>(oct));
243
  }
244
245
8880
  args.GetReturnValue().Set(old);
246
4440
}
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
1
static void ResourceUsage(const FunctionCallbackInfo<Value>& args) {
289
1
  Environment* env = Environment::GetCurrent(args);
290
291
  uv_rusage_t rusage;
292
1
  int err = uv_getrusage(&rusage);
293
1
  if (err)
294
1
    return env->ThrowUVException(err, "uv_getrusage");
295
296
2
  CHECK(args[0]->IsFloat64Array());
297
2
  Local<Float64Array> array = args[0].As<Float64Array>();
298
1
  CHECK_EQ(array->Length(), 16);
299
1
  Local<ArrayBuffer> ab = array->Buffer();
300
1
  double* fields = static_cast<double*>(ab->GetContents().Data());
301
302
1
  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
303
1
  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
304
1
  fields[2] = rusage.ru_maxrss;
305
1
  fields[3] = rusage.ru_ixrss;
306
1
  fields[4] = rusage.ru_idrss;
307
1
  fields[5] = rusage.ru_isrss;
308
1
  fields[6] = rusage.ru_minflt;
309
1
  fields[7] = rusage.ru_majflt;
310
1
  fields[8] = rusage.ru_nswap;
311
1
  fields[9] = rusage.ru_inblock;
312
1
  fields[10] = rusage.ru_oublock;
313
1
  fields[11] = rusage.ru_msgsnd;
314
1
  fields[12] = rusage.ru_msgrcv;
315
1
  fields[13] = rusage.ru_nsignals;
316
1
  fields[14] = rusage.ru_nvcsw;
317
1
  fields[15] = rusage.ru_nivcsw;
318
}
319
320
#ifdef __POSIX__
321
3
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
322
3
  Environment* env = Environment::GetCurrent(args);
323
324
3
  if (args.Length() != 1) {
325
    return env->ThrowError("Invalid number of arguments.");
326
  }
327
328
6
  CHECK(args[0]->IsNumber());
329
9
  pid_t pid = args[0].As<Integer>()->Value();
330
3
  int r = kill(pid, SIGUSR1);
331
332
3
  if (r != 0) {
333
1
    return env->ThrowErrnoException(errno, "kill");
334
  }
335
}
336
#endif  // __POSIX__
337
338
#ifdef _WIN32
339
static int GetDebugSignalHandlerMappingName(DWORD pid,
340
                                            wchar_t* buf,
341
                                            size_t buf_len) {
342
  return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
343
}
344
345
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
346
  Environment* env = Environment::GetCurrent(args);
347
  Isolate* isolate = args.GetIsolate();
348
349
  if (args.Length() != 1) {
350
    env->ThrowError("Invalid number of arguments.");
351
    return;
352
  }
353
354
  HANDLE process = nullptr;
355
  HANDLE thread = nullptr;
356
  HANDLE mapping = nullptr;
357
  wchar_t mapping_name[32];
358
  LPTHREAD_START_ROUTINE* handler = nullptr;
359
  DWORD pid = 0;
360
361
  OnScopeLeave cleanup([&]() {
362
    if (process != nullptr) CloseHandle(process);
363
    if (thread != nullptr) CloseHandle(thread);
364
    if (handler != nullptr) UnmapViewOfFile(handler);
365
    if (mapping != nullptr) CloseHandle(mapping);
366
  });
367
368
  CHECK(args[0]->IsNumber());
369
  pid = args[0].As<Integer>()->Value();
370
371
  process =
372
      OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
373
                      PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
374
                  FALSE,
375
                  pid);
376
  if (process == nullptr) {
377
    isolate->ThrowException(
378
        WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
379
    return;
380
  }
381
382
  if (GetDebugSignalHandlerMappingName(
383
          pid, mapping_name, arraysize(mapping_name)) < 0) {
384
    env->ThrowErrnoException(errno, "sprintf");
385
    return;
386
  }
387
388
  mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
389
  if (mapping == nullptr) {
390
    isolate->ThrowException(
391
        WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW"));
392
    return;
393
  }
394
395
  handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
396
      MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler));
397
  if (handler == nullptr || *handler == nullptr) {
398
    isolate->ThrowException(
399
        WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
400
    return;
401
  }
402
403
  thread =
404
      CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr);
405
  if (thread == nullptr) {
406
    isolate->ThrowException(
407
        WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread"));
408
    return;
409
  }
410
411
  // Wait for the thread to terminate
412
  if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
413
    isolate->ThrowException(
414
        WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject"));
415
    return;
416
  }
417
}
418
#endif  // _WIN32
419
420
6
static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
421
#if HAVE_INSPECTOR
422
6
  Environment* env = Environment::GetCurrent(args);
423
6
  if (env->inspector_agent()->IsListening()) {
424
4
    env->inspector_agent()->Stop();
425
  }
426
#endif
427
6
}
428
429
248
static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
430
248
  Environment* env = Environment::GetCurrent(args);
431
248
  WaitForInspectorDisconnect(env);
432
992
  int code = args[0]->Int32Value(env->context()).FromMaybe(0);
433
248
  env->Exit(code);
434
26
}
435
436
5099
static void InitializeProcessMethods(Local<Object> target,
437
                                     Local<Value> unused,
438
                                     Local<Context> context,
439
                                     void* priv) {
440
5099
  Environment* env = Environment::GetCurrent(context);
441
442
  // define various internal methods
443
5099
  if (env->owns_process_state()) {
444
4893
    env->SetMethod(target, "_debugProcess", DebugProcess);
445
4893
    env->SetMethod(target, "_debugEnd", DebugEnd);
446
4893
    env->SetMethod(target, "abort", Abort);
447
4893
    env->SetMethod(target, "causeSegfault", CauseSegfault);
448
4893
    env->SetMethod(target, "chdir", Chdir);
449
  }
450
451
  env->SetMethod(
452
5099
      target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
453
5099
  env->SetMethod(target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
454
455
5099
  env->SetMethod(target, "umask", Umask);
456
5099
  env->SetMethod(target, "_rawDebug", RawDebug);
457
5099
  env->SetMethod(target, "memoryUsage", MemoryUsage);
458
5099
  env->SetMethod(target, "cpuUsage", CPUUsage);
459
5099
  env->SetMethod(target, "hrtime", Hrtime);
460
5099
  env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
461
5099
  env->SetMethod(target, "resourceUsage", ResourceUsage);
462
463
5099
  env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
464
5099
  env->SetMethod(target, "_getActiveHandles", GetActiveHandles);
465
5099
  env->SetMethod(target, "_kill", Kill);
466
467
5099
  env->SetMethodNoSideEffect(target, "cwd", Cwd);
468
5099
  env->SetMethod(target, "dlopen", binding::DLOpen);
469
5099
  env->SetMethod(target, "reallyExit", ReallyExit);
470
5099
  env->SetMethodNoSideEffect(target, "uptime", Uptime);
471
5099
  env->SetMethod(target, "patchProcessObject", PatchProcessObject);
472
5099
}
473
474
}  // namespace node
475
476

19815
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
477
                                   node::InitializeProcessMethods)