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: 153 165 92.7 %
Date: 2019-02-13 22:28:58 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::Object;
48
using v8::String;
49
using v8::Uint32;
50
using v8::Uint32Array;
51
using v8::Value;
52
53
namespace per_process {
54
4314
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() 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
129
static void Chdir(const FunctionCallbackInfo<Value>& args) {
74
129
  Environment* env = Environment::GetCurrent(args);
75
129
  CHECK(env->owns_process_state());
76
77
129
  CHECK_EQ(args.Length(), 1);
78
387
  CHECK(args[0]->IsString());
79
129
  Utf8Value path(env->isolate(), args[0]);
80
129
  int err = uv_chdir(*path);
81
129
  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
130
    return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
88
128
  }
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
23009
static void Cwd(const FunctionCallbackInfo<Value>& args) {
120
23009
  Environment* env = Environment::GetCurrent(args);
121
  char buf[CHDIR_BUFSIZE];
122
23009
  size_t cwd_len = sizeof(buf);
123
23009
  int err = uv_cwd(buf, &cwd_len);
124
23009
  if (err)
125
23022
    return env->ThrowUVException(err, "uv_cwd");
126
127
  Local<String> cwd = String::NewFromUtf8(env->isolate(),
128
                                          buf,
129
                                          NewStringType::kNormal,
130
45992
                                          cwd_len).ToLocalChecked();
131
45992
  args.GetReturnValue().Set(cwd);
132
}
133
134
135
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
136
137
// This is the legacy version of hrtime before BigInt was introduced in
138
// JavaScript.
139
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
140
// so this function instead fills in an Uint32Array with 3 entries,
141
// to avoid any integer overflow possibility.
142
// The first two entries contain the second part of the value
143
// broken into the upper/lower 32 bits to be converted back in JS,
144
// because there is no Uint64Array in JS.
145
// The third entry contains the remaining nanosecond part of the value.
146
882853
static void Hrtime(const FunctionCallbackInfo<Value>& args) {
147
882853
  uint64_t t = uv_hrtime();
148
149
2648559
  Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
150
882853
  uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
151
152
882853
  fields[0] = (t / NANOS_PER_SEC) >> 32;
153
882853
  fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
154
882853
  fields[2] = t % NANOS_PER_SEC;
155
882853
}
156
157
1038849
static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
158
3116547
  Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
159
1038849
  uint64_t* fields = static_cast<uint64_t*>(ab->GetContents().Data());
160
1038849
  fields[0] = uv_hrtime();
161
1038849
}
162
163
41
static void Kill(const FunctionCallbackInfo<Value>& args) {
164
41
  Environment* env = Environment::GetCurrent(args);
165
41
  Local<Context> context = env->context();
166
167
41
  if (args.Length() != 2)
168
    return env->ThrowError("Bad argument.");
169
170
  int pid;
171
123
  if (!args[0]->Int32Value(context).To(&pid)) return;
172
  int sig;
173
123
  if (!args[1]->Int32Value(context).To(&sig)) return;
174
41
  int err = uv_kill(pid, sig);
175
82
  args.GetReturnValue().Set(err);
176
}
177
178
3627
static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
179
3627
  Environment* env = Environment::GetCurrent(args);
180
181
  size_t rss;
182
3627
  int err = uv_resident_set_memory(&rss);
183
3627
  if (err)
184
3627
    return env->ThrowUVException(err, "uv_resident_set_memory");
185
186
3627
  Isolate* isolate = env->isolate();
187
  // V8 memory usage
188
3627
  HeapStatistics v8_heap_stats;
189
3627
  isolate->GetHeapStatistics(&v8_heap_stats);
190
191
  // Get the double array pointer from the Float64Array argument.
192
7254
  CHECK(args[0]->IsFloat64Array());
193
7254
  Local<Float64Array> array = args[0].As<Float64Array>();
194
3627
  CHECK_EQ(array->Length(), 4);
195
3627
  Local<ArrayBuffer> ab = array->Buffer();
196
3627
  double* fields = static_cast<double*>(ab->GetContents().Data());
197
198
3627
  fields[0] = rss;
199
3627
  fields[1] = v8_heap_stats.total_heap_size();
200
3627
  fields[2] = v8_heap_stats.used_heap_size();
201
3627
  fields[3] = v8_heap_stats.external_memory();
202
}
203
204
237
void RawDebug(const FunctionCallbackInfo<Value>& args) {
205


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


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

17256
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
433
                                   node::InitializeProcessMethods)