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: 155 167 92.8 %
Date: 2019-02-26 22:23:30 Branches: 49 74 66.2 %

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


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


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

17128
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
435
                                   node::InitializeProcessMethods)