GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_process.cc Lines: 164 180 91.1 %
Date: 2019-01-07 12:15:22 Branches: 52 78 66.7 %

Line Branch Exec Source
1
#include "node.h"
2
#include "node_internals.h"
3
#include "node_errors.h"
4
#include "base_object.h"
5
#include "base_object-inl.h"
6
#include "env-inl.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 <limits.h>  // PATH_MAX
18
#include <stdio.h>
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::Object;
47
using v8::PropertyCallbackInfo;
48
using v8::String;
49
using v8::Uint32;
50
using v8::Uint32Array;
51
using v8::Value;
52
53
3597
Mutex process_mutex;
54
3597
Mutex environ_mutex;
55
56
// Microseconds in a second, as a float, used in CPUUsage() below
57
#define MICROS_PER_SEC 1e6
58
// used in Hrtime() below
59
#define NANOS_PER_SEC 1000000000
60
61
#ifdef _WIN32
62
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
63
#define CHDIR_BUFSIZE (MAX_PATH * 4)
64
#else
65
#define CHDIR_BUFSIZE (PATH_MAX)
66
#endif
67
68
static void Abort(const FunctionCallbackInfo<Value>& args) {
69
  Abort();
70
}
71
72
120
static void Chdir(const FunctionCallbackInfo<Value>& args) {
73
120
  Environment* env = Environment::GetCurrent(args);
74
120
  CHECK(env->is_main_thread());
75
76
120
  CHECK_EQ(args.Length(), 1);
77
360
  CHECK(args[0]->IsString());
78
120
  Utf8Value path(env->isolate(), args[0]);
79
120
  int err = uv_chdir(*path);
80
120
  if (err) {
81
    // Also include the original working directory, since that will usually
82
    // be helpful information when debugging a `chdir()` failure.
83
    char buf[CHDIR_BUFSIZE];
84
1
    size_t cwd_len = sizeof(buf);
85
1
    uv_cwd(buf, &cwd_len);
86
121
    return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
87
119
  }
88
}
89
90
// CPUUsage use libuv's uv_getrusage() this-process resource usage accessor,
91
// to access ru_utime (user CPU time used) and ru_stime (system CPU time used),
92
// which are uv_timeval_t structs (long tv_sec, long tv_usec).
93
// Returns those values as Float64 microseconds in the elements of the array
94
// passed to the function.
95
33
static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
96
  uv_rusage_t rusage;
97
98
  // Call libuv to get the values we'll return.
99
33
  int err = uv_getrusage(&rusage);
100
33
  if (err) {
101
    // On error, return the strerror version of the error code.
102
    Local<String> errmsg = OneByteString(args.GetIsolate(), uv_strerror(err));
103
33
    return args.GetReturnValue().Set(errmsg);
104
  }
105
106
  // Get the double array pointer from the Float64Array argument.
107
66
  CHECK(args[0]->IsFloat64Array());
108
66
  Local<Float64Array> array = args[0].As<Float64Array>();
109
33
  CHECK_EQ(array->Length(), 2);
110
33
  Local<ArrayBuffer> ab = array->Buffer();
111
33
  double* fields = static_cast<double*>(ab->GetContents().Data());
112
113
  // Set the Float64Array elements to be user / system values in microseconds.
114
33
  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
115
33
  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
116
}
117
118
20992
static void Cwd(const FunctionCallbackInfo<Value>& args) {
119
20992
  Environment* env = Environment::GetCurrent(args);
120
  char buf[CHDIR_BUFSIZE];
121
20992
  size_t cwd_len = sizeof(buf);
122
20992
  int err = uv_cwd(buf, &cwd_len);
123
20991
  if (err)
124
21004
    return env->ThrowUVException(err, "uv_cwd");
125
126
  Local<String> cwd = String::NewFromUtf8(env->isolate(),
127
                                          buf,
128
                                          NewStringType::kNormal,
129
41956
                                          cwd_len).ToLocalChecked();
130
41956
  args.GetReturnValue().Set(cwd);
131
}
132
133
134
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
135
136
// This is the legacy version of hrtime before BigInt was introduced in
137
// JavaScript.
138
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
139
// so this function instead fills in an Uint32Array with 3 entries,
140
// to avoid any integer overflow possibility.
141
// The first two entries contain the second part of the value
142
// broken into the upper/lower 32 bits to be converted back in JS,
143
// because there is no Uint64Array in JS.
144
// The third entry contains the remaining nanosecond part of the value.
145
82376
static void Hrtime(const FunctionCallbackInfo<Value>& args) {
146
82376
  uint64_t t = uv_hrtime();
147
148
247128
  Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
149
82376
  uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
150
151
82376
  fields[0] = (t / NANOS_PER_SEC) >> 32;
152
82376
  fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
153
82376
  fields[2] = t % NANOS_PER_SEC;
154
82376
}
155
156
2914717
static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
157
8744151
  Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
158
2914717
  uint64_t* fields = static_cast<uint64_t*>(ab->GetContents().Data());
159
2914717
  fields[0] = uv_hrtime();
160
2914717
}
161
162
77
static void Kill(const FunctionCallbackInfo<Value>& args) {
163
77
  Environment* env = Environment::GetCurrent(args);
164
77
  Local<Context> context = env->context();
165
166
77
  if (args.Length() != 2)
167
    return env->ThrowError("Bad argument.");
168
169
  int pid;
170
231
  if (!args[0]->Int32Value(context).To(&pid)) return;
171
  int sig;
172
231
  if (!args[1]->Int32Value(context).To(&sig)) return;
173
77
  int err = uv_kill(pid, sig);
174
154
  args.GetReturnValue().Set(err);
175
}
176
177
526
static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
178
526
  Environment* env = Environment::GetCurrent(args);
179
180
  size_t rss;
181
526
  int err = uv_resident_set_memory(&rss);
182
526
  if (err)
183
526
    return env->ThrowUVException(err, "uv_resident_set_memory");
184
185
526
  Isolate* isolate = env->isolate();
186
  // V8 memory usage
187
526
  HeapStatistics v8_heap_stats;
188
526
  isolate->GetHeapStatistics(&v8_heap_stats);
189
190
  // Get the double array pointer from the Float64Array argument.
191
1052
  CHECK(args[0]->IsFloat64Array());
192
1052
  Local<Float64Array> array = args[0].As<Float64Array>();
193
526
  CHECK_EQ(array->Length(), 4);
194
526
  Local<ArrayBuffer> ab = array->Buffer();
195
526
  double* fields = static_cast<double*>(ab->GetContents().Data());
196
197
526
  fields[0] = rss;
198
526
  fields[1] = v8_heap_stats.total_heap_size();
199
526
  fields[2] = v8_heap_stats.used_heap_size();
200
526
  fields[3] = v8_heap_stats.external_memory();
201
}
202
203
// Most of the time, it's best to use `console.error` to write
204
// to the process.stderr stream.  However, in some cases, such as
205
// when debugging the stream.Writable class or the process.nextTick
206
// function, it is useful to bypass JavaScript entirely.
207
9
void RawDebug(const FunctionCallbackInfo<Value>& args) {
208


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


1318
  CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
230
231
978
  if (args[0]->IsUndefined()) {
232
319
    old = umask(0);
233
319
    umask(static_cast<mode_t>(old));
234
  } else {
235
21
    int oct = args[0].As<Uint32>()->Value();
236
7
    old = umask(static_cast<mode_t>(oct));
237
  }
238
239
652
  args.GetReturnValue().Set(old);
240
326
}
241
242
2
static void Uptime(const FunctionCallbackInfo<Value>& args) {
243
2
  Environment* env = Environment::GetCurrent(args);
244
  double uptime;
245
246
2
  uv_update_time(env->event_loop());
247
2
  uptime = uv_now(env->event_loop()) - prog_start_time;
248
249
6
  args.GetReturnValue().Set(uptime / 1000);
250
2
}
251
252
11
void ProcessTitleGetter(Local<Name> property,
253
                        const PropertyCallbackInfo<Value>& info) {
254
  char buffer[512];
255
11
  uv_get_process_title(buffer, sizeof(buffer));
256
  info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), buffer,
257
33
      NewStringType::kNormal).ToLocalChecked());
258
11
}
259
260
84
void ProcessTitleSetter(Local<Name> property,
261
                        Local<Value> value,
262
                        const PropertyCallbackInfo<void>& info) {
263
84
  node::Utf8Value title(info.GetIsolate(), value);
264

85
  TRACE_EVENT_METADATA1("__metadata", "process_name", "name",
265
                        TRACE_STR_COPY(*title));
266
84
  uv_set_process_title(*title);
267
84
}
268
269
6
void GetParentProcessId(Local<Name> property,
270
                        const PropertyCallbackInfo<Value>& info) {
271
18
  info.GetReturnValue().Set(uv_os_getppid());
272
6
}
273
274
1
static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
275
1
  Environment* env = Environment::GetCurrent(args);
276
277
1
  std::vector<Local<Value>> request_v;
278
13
  for (auto w : *env->req_wrap_queue()) {
279
24
    if (w->persistent().IsEmpty())
280
      continue;
281
24
    request_v.push_back(w->GetOwner());
282
  }
283
284
  args.GetReturnValue().Set(
285
3
      Array::New(env->isolate(), request_v.data(), request_v.size()));
286
1
}
287
288
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
289
// implemented here for consistency with GetActiveRequests().
290
4
void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
291
4
  Environment* env = Environment::GetCurrent(args);
292
293
4
  std::vector<Local<Value>> handle_v;
294
24
  for (auto w : *env->handle_wrap_queue()) {
295
20
    if (!HandleWrap::HasRef(w))
296
1
      continue;
297
38
    handle_v.push_back(w->GetOwner());
298
  }
299
  args.GetReturnValue().Set(
300
12
      Array::New(env->isolate(), handle_v.data(), handle_v.size()));
301
4
}
302
303
84
void DebugPortGetter(Local<Name> property,
304
                     const PropertyCallbackInfo<Value>& info) {
305
84
  Environment* env = Environment::GetCurrent(info);
306
84
  int port = env->inspector_host_port()->port();
307
168
  info.GetReturnValue().Set(port);
308
84
}
309
310
311
void DebugPortSetter(Local<Name> property,
312
                     Local<Value> value,
313
                     const PropertyCallbackInfo<void>& info) {
314
  Environment* env = Environment::GetCurrent(info);
315
  int32_t port = value->Int32Value(env->context()).FromMaybe(0);
316
  env->inspector_host_port()->set_port(static_cast<int>(port));
317
}
318
319
#ifdef __POSIX__
320
3
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
321
3
  Environment* env = Environment::GetCurrent(args);
322
323
3
  if (args.Length() != 1) {
324
    return env->ThrowError("Invalid number of arguments.");
325
  }
326
327
6
  CHECK(args[0]->IsNumber());
328
9
  pid_t pid = args[0].As<Integer>()->Value();
329
3
  int r = kill(pid, SIGUSR1);
330
331
3
  if (r != 0) {
332
1
    return env->ThrowErrnoException(errno, "kill");
333
  }
334
}
335
#endif  // __POSIX__
336
337
#ifdef _WIN32
338
static int GetDebugSignalHandlerMappingName(DWORD pid,
339
                                            wchar_t* buf,
340
                                            size_t buf_len) {
341
  return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
342
}
343
344
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
345
  Environment* env = Environment::GetCurrent(args);
346
  Isolate* isolate = args.GetIsolate();
347
348
  if (args.Length() != 1) {
349
    env->ThrowError("Invalid number of arguments.");
350
    return;
351
  }
352
353
  HANDLE process = nullptr;
354
  HANDLE thread = nullptr;
355
  HANDLE mapping = nullptr;
356
  wchar_t mapping_name[32];
357
  LPTHREAD_START_ROUTINE* handler = nullptr;
358
  DWORD pid = 0;
359
360
  OnScopeLeave cleanup([&]() {
361
    if (process != nullptr) CloseHandle(process);
362
    if (thread != nullptr) CloseHandle(thread);
363
    if (handler != nullptr) UnmapViewOfFile(handler);
364
    if (mapping != nullptr) CloseHandle(mapping);
365
  });
366
367
  CHECK(args[0]->IsNumber());
368
  pid = args[0].As<Integer>()->Value();
369
370
  process =
371
      OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
372
                      PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
373
                  FALSE,
374
                  pid);
375
  if (process == nullptr) {
376
    isolate->ThrowException(
377
        WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
378
    return;
379
  }
380
381
  if (GetDebugSignalHandlerMappingName(
382
          pid, mapping_name, arraysize(mapping_name)) < 0) {
383
    env->ThrowErrnoException(errno, "sprintf");
384
    return;
385
  }
386
387
  mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
388
  if (mapping == nullptr) {
389
    isolate->ThrowException(
390
        WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW"));
391
    return;
392
  }
393
394
  handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
395
      MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler));
396
  if (handler == nullptr || *handler == nullptr) {
397
    isolate->ThrowException(
398
        WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
399
    return;
400
  }
401
402
  thread =
403
      CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr);
404
  if (thread == nullptr) {
405
    isolate->ThrowException(
406
        WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread"));
407
    return;
408
  }
409
410
  // Wait for the thread to terminate
411
  if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
412
    isolate->ThrowException(
413
        WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject"));
414
    return;
415
  }
416
}
417
#endif  // _WIN32
418
419
6
static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
420
#if HAVE_INSPECTOR
421
6
  Environment* env = Environment::GetCurrent(args);
422
6
  if (env->inspector_agent()->IsListening()) {
423
4
    env->inspector_agent()->Stop();
424
  }
425
#endif
426
6
}
427
428
3661
static void InitializeProcessMethods(Local<Object> target,
429
                                     Local<Value> unused,
430
                                     Local<Context> context,
431
                                     void* priv) {
432
3661
  Environment* env = Environment::GetCurrent(context);
433
434
  // define various internal methods
435
3661
  if (env->is_main_thread()) {
436
3553
    env->SetMethod(target, "_debugProcess", DebugProcess);
437
3553
    env->SetMethod(target, "_debugEnd", DebugEnd);
438
    env->SetMethod(
439
3553
        target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
440
    env->SetMethod(
441
3553
        target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
442
3553
    env->SetMethod(target, "abort", Abort);
443
3553
    env->SetMethod(target, "chdir", Chdir);
444
3553
    env->SetMethod(target, "umask", Umask);
445
  }
446
447
3661
  env->SetMethod(target, "_rawDebug", RawDebug);
448
3661
  env->SetMethod(target, "memoryUsage", MemoryUsage);
449
3661
  env->SetMethod(target, "cpuUsage", CPUUsage);
450
3661
  env->SetMethod(target, "hrtime", Hrtime);
451
3661
  env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
452
453
3661
  env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
454
3661
  env->SetMethod(target, "_getActiveHandles", GetActiveHandles);
455
3661
  env->SetMethod(target, "_kill", Kill);
456
457
3661
  env->SetMethodNoSideEffect(target, "cwd", Cwd);
458
3661
  env->SetMethod(target, "dlopen", binding::DLOpen);
459
3661
  env->SetMethod(target, "reallyExit", Exit);
460
3661
  env->SetMethodNoSideEffect(target, "uptime", Uptime);
461
3661
}
462
463
}  // namespace node
464
465

14387
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
466
                                   node::InitializeProcessMethods)