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: 68 154 44.2 %
Date: 2019-02-01 22:03:38 Branches: 19 74 25.7 %

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
164
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
82
static void Chdir(const FunctionCallbackInfo<Value>& args) {
74
82
  Environment* env = Environment::GetCurrent(args);
75
82
  CHECK(env->is_main_thread());
76
77
82
  CHECK_EQ(args.Length(), 1);
78
246
  CHECK(args[0]->IsString());
79
82
  Utf8Value path(env->isolate(), args[0]);
80
82
  int err = uv_chdir(*path);
81
82
  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
    size_t cwd_len = sizeof(buf);
86
    uv_cwd(buf, &cwd_len);
87
82
    return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
88
82
  }
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
static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
97
  uv_rusage_t rusage;
98
99
  // Call libuv to get the values we'll return.
100
  int err = uv_getrusage(&rusage);
101
  if (err) {
102
    // On error, return the strerror version of the error code.
103
    Local<String> errmsg = OneByteString(args.GetIsolate(), uv_strerror(err));
104
    return args.GetReturnValue().Set(errmsg);
105
  }
106
107
  // Get the double array pointer from the Float64Array argument.
108
  CHECK(args[0]->IsFloat64Array());
109
  Local<Float64Array> array = args[0].As<Float64Array>();
110
  CHECK_EQ(array->Length(), 2);
111
  Local<ArrayBuffer> ab = array->Buffer();
112
  double* fields = static_cast<double*>(ab->GetContents().Data());
113
114
  // Set the Float64Array elements to be user / system values in microseconds.
115
  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
116
  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
117
}
118
119
775
static void Cwd(const FunctionCallbackInfo<Value>& args) {
120
775
  Environment* env = Environment::GetCurrent(args);
121
  char buf[CHDIR_BUFSIZE];
122
775
  size_t cwd_len = sizeof(buf);
123
775
  int err = uv_cwd(buf, &cwd_len);
124
775
  if (err)
125
775
    return env->ThrowUVException(err, "uv_cwd");
126
127
  Local<String> cwd = String::NewFromUtf8(env->isolate(),
128
                                          buf,
129
                                          NewStringType::kNormal,
130
1550
                                          cwd_len).ToLocalChecked();
131
1550
  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
1
static void Hrtime(const FunctionCallbackInfo<Value>& args) {
147
1
  uint64_t t = uv_hrtime();
148
149
3
  Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
150
1
  uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
151
152
1
  fields[0] = (t / NANOS_PER_SEC) >> 32;
153
1
  fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
154
1
  fields[2] = t % NANOS_PER_SEC;
155
1
}
156
157
static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
158
  Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
159
  uint64_t* fields = static_cast<uint64_t*>(ab->GetContents().Data());
160
  fields[0] = uv_hrtime();
161
}
162
163
static void Kill(const FunctionCallbackInfo<Value>& args) {
164
  Environment* env = Environment::GetCurrent(args);
165
  Local<Context> context = env->context();
166
167
  if (args.Length() != 2)
168
    return env->ThrowError("Bad argument.");
169
170
  int pid;
171
  if (!args[0]->Int32Value(context).To(&pid)) return;
172
  int sig;
173
  if (!args[1]->Int32Value(context).To(&sig)) return;
174
  int err = uv_kill(pid, sig);
175
  args.GetReturnValue().Set(err);
176
}
177
178
static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
179
  Environment* env = Environment::GetCurrent(args);
180
181
  size_t rss;
182
  int err = uv_resident_set_memory(&rss);
183
  if (err)
184
    return env->ThrowUVException(err, "uv_resident_set_memory");
185
186
  Isolate* isolate = env->isolate();
187
  // V8 memory usage
188
  HeapStatistics v8_heap_stats;
189
  isolate->GetHeapStatistics(&v8_heap_stats);
190
191
  // Get the double array pointer from the Float64Array argument.
192
  CHECK(args[0]->IsFloat64Array());
193
  Local<Float64Array> array = args[0].As<Float64Array>();
194
  CHECK_EQ(array->Length(), 4);
195
  Local<ArrayBuffer> ab = array->Buffer();
196
  double* fields = static_cast<double*>(ab->GetContents().Data());
197
198
  fields[0] = rss;
199
  fields[1] = v8_heap_stats.total_heap_size();
200
  fields[2] = v8_heap_stats.used_heap_size();
201
  fields[3] = v8_heap_stats.external_memory();
202
}
203
204
void RawDebug(const FunctionCallbackInfo<Value>& args) {
205
  CHECK(args.Length() == 1 && args[0]->IsString() &&
206
        "must be called with a single string");
207
  Utf8Value message(args.GetIsolate(), args[0]);
208
  PrintErrorString("%s\n", *message);
209
  fflush(stderr);
210
}
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
360
static void Umask(const FunctionCallbackInfo<Value>& args) {
223
  uint32_t old;
224
225
360
  CHECK_EQ(args.Length(), 1);
226


1556
  CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
227
360
  Mutex::ScopedLock scoped_lock(per_process::umask_mutex);
228
229
1080
  if (args[0]->IsUndefined()) {
230
302
    old = umask(0);
231
302
    umask(static_cast<mode_t>(old));
232
  } else {
233
174
    int oct = args[0].As<Uint32>()->Value();
234
58
    old = umask(static_cast<mode_t>(oct));
235
  }
236
237
720
  args.GetReturnValue().Set(old);
238
360
}
239
240
1
static void Uptime(const FunctionCallbackInfo<Value>& args) {
241
1
  Environment* env = Environment::GetCurrent(args);
242
  double uptime;
243
244
1
  uv_update_time(env->event_loop());
245
1
  uptime = uv_now(env->event_loop()) - per_process::prog_start_time;
246
247
3
  args.GetReturnValue().Set(uptime / 1000);
248
1
}
249
250
static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
251
  Environment* env = Environment::GetCurrent(args);
252
253
  std::vector<Local<Value>> request_v;
254
  for (auto w : *env->req_wrap_queue()) {
255
    if (w->persistent().IsEmpty())
256
      continue;
257
    request_v.push_back(w->GetOwner());
258
  }
259
260
  args.GetReturnValue().Set(
261
      Array::New(env->isolate(), request_v.data(), request_v.size()));
262
}
263
264
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
265
// implemented here for consistency with GetActiveRequests().
266
void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
267
  Environment* env = Environment::GetCurrent(args);
268
269
  std::vector<Local<Value>> handle_v;
270
  for (auto w : *env->handle_wrap_queue()) {
271
    if (!HandleWrap::HasRef(w))
272
      continue;
273
    handle_v.push_back(w->GetOwner());
274
  }
275
  args.GetReturnValue().Set(
276
      Array::New(env->isolate(), handle_v.data(), handle_v.size()));
277
}
278
279
#ifdef __POSIX__
280
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
281
  Environment* env = Environment::GetCurrent(args);
282
283
  if (args.Length() != 1) {
284
    return env->ThrowError("Invalid number of arguments.");
285
  }
286
287
  CHECK(args[0]->IsNumber());
288
  pid_t pid = args[0].As<Integer>()->Value();
289
  int r = kill(pid, SIGUSR1);
290
291
  if (r != 0) {
292
    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
static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
380
#if HAVE_INSPECTOR
381
  Environment* env = Environment::GetCurrent(args);
382
  if (env->inspector_agent()->IsListening()) {
383
    env->inspector_agent()->Stop();
384
  }
385
#endif
386
}
387
388
164
static void InitializeProcessMethods(Local<Object> target,
389
                                     Local<Value> unused,
390
                                     Local<Context> context,
391
                                     void* priv) {
392
164
  Environment* env = Environment::GetCurrent(context);
393
394
  // define various internal methods
395
164
  if (env->is_main_thread()) {
396
164
    env->SetMethod(target, "_debugProcess", DebugProcess);
397
164
    env->SetMethod(target, "_debugEnd", DebugEnd);
398
    env->SetMethod(
399
164
        target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
400
    env->SetMethod(
401
164
        target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
402
164
    env->SetMethod(target, "abort", Abort);
403
164
    env->SetMethod(target, "chdir", Chdir);
404
  }
405
406
164
  env->SetMethod(target, "umask", Umask);
407
164
  env->SetMethod(target, "_rawDebug", RawDebug);
408
164
  env->SetMethod(target, "memoryUsage", MemoryUsage);
409
164
  env->SetMethod(target, "cpuUsage", CPUUsage);
410
164
  env->SetMethod(target, "hrtime", Hrtime);
411
164
  env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
412
413
164
  env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
414
164
  env->SetMethod(target, "_getActiveHandles", GetActiveHandles);
415
164
  env->SetMethod(target, "_kill", Kill);
416
417
164
  env->SetMethodNoSideEffect(target, "cwd", Cwd);
418
164
  env->SetMethod(target, "dlopen", binding::DLOpen);
419
164
  env->SetMethod(target, "reallyExit", Exit);
420
164
  env->SetMethodNoSideEffect(target, "uptime", Uptime);
421
164
}
422
423
}  // namespace node
424
425

656
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
426
                                   node::InitializeProcessMethods)