GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/api/hooks.cc Lines: 102 108 94.4 %
Date: 2021-06-01 04:11:54 Branches: 28 46 60.9 %

Line Branch Exec Source
1
#include "env-inl.h"
2
#include "node_internals.h"
3
#include "node_process-inl.h"
4
#include "async_wrap.h"
5
6
namespace node {
7
8
using v8::Context;
9
using v8::HandleScope;
10
using v8::Integer;
11
using v8::Isolate;
12
using v8::Just;
13
using v8::Local;
14
using v8::Maybe;
15
using v8::NewStringType;
16
using v8::Nothing;
17
using v8::Object;
18
using v8::String;
19
using v8::Value;
20
21
5299
void RunAtExit(Environment* env) {
22
5299
  env->RunAtExitCallbacks();
23
5300
}
24
25
10446
void AtExit(Environment* env, void (*cb)(void* arg), void* arg) {
26
10446
  CHECK_NOT_NULL(env);
27
10446
  env->AtExit(cb, arg);
28
10446
}
29
30
void EmitBeforeExit(Environment* env) {
31
  USE(EmitProcessBeforeExit(env));
32
}
33
34
4536
Maybe<bool> EmitProcessBeforeExit(Environment* env) {
35
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
36
9070
                              "BeforeExit", env);
37
4536
  if (!env->destroy_async_id_list()->empty())
38
162
    AsyncWrap::DestroyAsyncIdsCallback(env);
39
40
9070
  HandleScope handle_scope(env->isolate());
41
4536
  Context::Scope context_scope(env->context());
42
43
  Local<Value> exit_code_v;
44
18144
  if (!env->process_object()->Get(env->context(), env->exit_code_string())
45
4537
      .ToLocal(&exit_code_v)) return Nothing<bool>();
46
47
  Local<Integer> exit_code;
48
13605
  if (!exit_code_v->ToInteger(env->context()).ToLocal(&exit_code)) {
49
    return Nothing<bool>();
50
  }
51
52
13600
  return ProcessEmit(env, "beforeExit", exit_code).IsEmpty() ?
53
4532
      Nothing<bool>() : Just(true);
54
}
55
56
int EmitExit(Environment* env) {
57
  return EmitProcessExit(env).FromMaybe(1);
58
}
59
60
4509
Maybe<int> EmitProcessExit(Environment* env) {
61
  // process.emit('exit')
62
9009
  HandleScope handle_scope(env->isolate());
63
4509
  Context::Scope context_scope(env->context());
64
4509
  Local<Object> process_object = env->process_object();
65
66
  // TODO(addaleax): It might be nice to share process._exiting and
67
  // process.exitCode via getter/setter pairs that pass data directly to the
68
  // native side, so that we don't manually have to read and write JS properties
69
  // here. These getters could use e.g. a typed array for performance.
70
9018
  if (process_object
71
9018
      ->Set(env->context(),
72
            FIXED_ONE_BYTE_STRING(env->isolate(), "_exiting"),
73
22545
            True(env->isolate())).IsNothing()) return Nothing<int>();
74
75
4509
  Local<String> exit_code = env->exit_code_string();
76
  Local<Value> code_v;
77
  int code;
78

27036
  if (!process_object->Get(env->context(), exit_code).ToLocal(&code_v) ||
79
22527
      !code_v->Int32Value(env->context()).To(&code) ||
80
22516
      ProcessEmit(env, "exit", Integer::New(env->isolate(), code)).IsEmpty() ||
81
      // Reload exit code, it may be changed by `emit('exit')`
82

27009
      !process_object->Get(env->context(), exit_code).ToLocal(&code_v) ||
83
17999
      !code_v->Int32Value(env->context()).To(&code)) {
84
    return Nothing<int>();
85
  }
86
87
4500
  return Just(code);
88
}
89
90
typedef void (*CleanupHook)(void* arg);
91
typedef void (*AsyncCleanupHook)(void* arg, void(*)(void*), void*);
92
93
20
struct AsyncCleanupHookInfo final {
94
  Environment* env;
95
  AsyncCleanupHook fun;
96
  void* arg;
97
  bool started = false;
98
  // Use a self-reference to make sure the storage is kept alive while the
99
  // cleanup hook is registered but not yet finished.
100
  std::shared_ptr<AsyncCleanupHookInfo> self;
101
};
102
103
// Opaque type that is basically an alias for `shared_ptr<AsyncCleanupHookInfo>`
104
// (but not publicly so for easier ABI/API changes). In particular,
105
// std::shared_ptr does not generally maintain a consistent ABI even on a
106
// specific platform.
107
10
struct ACHHandle final {
108
  std::shared_ptr<AsyncCleanupHookInfo> info;
109
};
110
// This is implemented as an operator on a struct because otherwise you can't
111
// default-initialize AsyncCleanupHookHandle, because in C++ for a
112
// std::unique_ptr to be default-initializable the deleter type also needs
113
// to be default-initializable; in particular, function types don't satisfy
114
// this.
115
10
void DeleteACHHandle::operator ()(ACHHandle* handle) const { delete handle; }
116
117
39
void AddEnvironmentCleanupHook(Isolate* isolate,
118
                               CleanupHook fun,
119
                               void* arg) {
120
39
  Environment* env = Environment::GetCurrent(isolate);
121
39
  CHECK_NOT_NULL(env);
122
39
  env->AddCleanupHook(fun, arg);
123
39
}
124
125
25
void RemoveEnvironmentCleanupHook(Isolate* isolate,
126
                                  CleanupHook fun,
127
                                  void* arg) {
128
25
  Environment* env = Environment::GetCurrent(isolate);
129
25
  CHECK_NOT_NULL(env);
130
25
  env->RemoveCleanupHook(fun, arg);
131
25
}
132
133
6
static void FinishAsyncCleanupHook(void* arg) {
134
6
  AsyncCleanupHookInfo* info = static_cast<AsyncCleanupHookInfo*>(arg);
135
12
  std::shared_ptr<AsyncCleanupHookInfo> keep_alive = info->self;
136
137
6
  info->env->DecreaseWaitingRequestCounter();
138
6
  info->self.reset();
139
6
}
140
141
6
static void RunAsyncCleanupHook(void* arg) {
142
6
  AsyncCleanupHookInfo* info = static_cast<AsyncCleanupHookInfo*>(arg);
143
6
  info->env->IncreaseWaitingRequestCounter();
144
6
  info->started = true;
145
6
  info->fun(info->arg, FinishAsyncCleanupHook, info);
146
6
}
147
148
10
ACHHandle* AddEnvironmentCleanupHookInternal(
149
    Isolate* isolate,
150
    AsyncCleanupHook fun,
151
    void* arg) {
152
10
  Environment* env = Environment::GetCurrent(isolate);
153
10
  CHECK_NOT_NULL(env);
154
20
  auto info = std::make_shared<AsyncCleanupHookInfo>();
155
10
  info->env = env;
156
10
  info->fun = fun;
157
10
  info->arg = arg;
158
10
  info->self = info;
159
10
  env->AddCleanupHook(RunAsyncCleanupHook, info.get());
160
20
  return new ACHHandle { info };
161
}
162
163
10
void RemoveEnvironmentCleanupHookInternal(
164
    ACHHandle* handle) {
165
10
  if (handle->info->started) return;
166
4
  handle->info->self.reset();
167
4
  handle->info->env->RemoveCleanupHook(RunAsyncCleanupHook, handle->info.get());
168
}
169
170
2
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
171
2
  Environment* env = Environment::GetCurrent(isolate);
172
2
  if (env == nullptr) return -1;
173
2
  return env->execution_async_id();
174
}
175
176
2
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
177
2
  Environment* env = Environment::GetCurrent(isolate);
178
2
  if (env == nullptr) return -1;
179
2
  return env->trigger_async_id();
180
}
181
182
183
540
async_context EmitAsyncInit(Isolate* isolate,
184
                            Local<Object> resource,
185
                            const char* name,
186
                            async_id trigger_async_id) {
187
1080
  HandleScope handle_scope(isolate);
188
  Local<String> type =
189
1080
      String::NewFromUtf8(isolate, name, NewStringType::kInternalized)
190
540
          .ToLocalChecked();
191
1080
  return EmitAsyncInit(isolate, resource, type, trigger_async_id);
192
}
193
194
540
async_context EmitAsyncInit(Isolate* isolate,
195
                            Local<Object> resource,
196
                            Local<String> name,
197
                            async_id trigger_async_id) {
198
540
  DebugSealHandleScope handle_scope(isolate);
199
540
  Environment* env = Environment::GetCurrent(isolate);
200
540
  CHECK_NOT_NULL(env);
201
202
  // Initialize async context struct
203
540
  if (trigger_async_id == -1)
204
537
    trigger_async_id = env->get_default_trigger_async_id();
205
206
  async_context context = {
207
540
    env->new_async_id(),  // async_id_
208
    trigger_async_id  // trigger_async_id_
209
540
  };
210
211
  // Run init hooks
212
540
  AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id,
213
540
                           context.trigger_async_id);
214
215
540
  return context;
216
}
217
218
3
void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) {
219
3
  EmitAsyncDestroy(Environment::GetCurrent(isolate), asyncContext);
220
3
}
221
222
536
void EmitAsyncDestroy(Environment* env, async_context asyncContext) {
223
536
  AsyncWrap::EmitDestroy(env, asyncContext.async_id);
224
536
}
225
226

14520
}  // namespace node