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: 107 107 100.0 %
Date: 2020-08-22 22:13:06 Branches: 23 34 67.6 %

Line Branch Exec Source
1
#include "env-inl.h"
2
#include "node_internals.h"
3
#include "node_process.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::Local;
13
using v8::NewStringType;
14
using v8::Object;
15
using v8::String;
16
using v8::Value;
17
18
4914
void RunAtExit(Environment* env) {
19
4914
  env->RunAtExitCallbacks();
20
4915
}
21
22
1
void AtExit(void (*cb)(void* arg), void* arg) {
23
1
  auto env = Environment::GetThreadLocalEnv();
24
1
  AtExit(env, cb, arg);
25
1
}
26
27
9697
void AtExit(Environment* env, void (*cb)(void* arg), void* arg) {
28
9697
  CHECK_NOT_NULL(env);
29
9697
  env->AtExit(cb, arg);
30
9697
}
31
32
4284
void EmitBeforeExit(Environment* env) {
33
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
34
8565
                              "BeforeExit", env);
35
4283
  if (!env->destroy_async_id_list()->empty())
36
155
    AsyncWrap::DestroyAsyncIdsCallback(env);
37
38
8568
  HandleScope handle_scope(env->isolate());
39
8568
  Context::Scope context_scope(env->context());
40
41
  Local<Value> exit_code_v;
42
17142
  if (!env->process_object()->Get(env->context(), env->exit_code_string())
43
4290
      .ToLocal(&exit_code_v)) return;
44
45
  Local<Integer> exit_code;
46
12851
  if (!exit_code_v->ToInteger(env->context()).ToLocal(&exit_code)) return;
47
48
8564
  ProcessEmit(env, "beforeExit", exit_code).ToLocalChecked();
49
}
50
51
4267
int EmitExit(Environment* env) {
52
  // process.emit('exit')
53
8526
  HandleScope handle_scope(env->isolate());
54
4266
  Context::Scope context_scope(env->context());
55
4268
  Local<Object> process_object = env->process_object();
56
  process_object
57
8538
      ->Set(env->context(),
58
            FIXED_ONE_BYTE_STRING(env->isolate(), "_exiting"),
59
21342
            True(env->isolate()))
60
      .Check();
61
62
4269
  Local<String> exit_code = env->exit_code_string();
63
12803
  int code = process_object->Get(env->context(), exit_code)
64
8534
                 .ToLocalChecked()
65
12803
                 ->Int32Value(env->context())
66
4266
                 .ToChecked();
67
8534
  ProcessEmit(env, "exit", Integer::New(env->isolate(), code));
68
69
  // Reload exit code, it may be changed by `emit('exit')`
70
12776
  return process_object->Get(env->context(), exit_code)
71
8517
      .ToLocalChecked()
72
12776
      ->Int32Value(env->context())
73
8518
      .ToChecked();
74
}
75
76
typedef void (*CleanupHook)(void* arg);
77
typedef void (*AsyncCleanupHook)(void* arg, void(*)(void*), void*);
78
79
20
struct AsyncCleanupHookInfo final {
80
  Environment* env;
81
  AsyncCleanupHook fun;
82
  void* arg;
83
  bool started = false;
84
  // Use a self-reference to make sure the storage is kept alive while the
85
  // cleanup hook is registered but not yet finished.
86
  std::shared_ptr<AsyncCleanupHookInfo> self;
87
};
88
89
// Opaque type that is basically an alias for `shared_ptr<AsyncCleanupHookInfo>`
90
// (but not publicly so for easier ABI/API changes). In particular,
91
// std::shared_ptr does not generally maintain a consistent ABI even on a
92
// specific platform.
93
10
struct ACHHandle final {
94
  std::shared_ptr<AsyncCleanupHookInfo> info;
95
};
96
// This is implemented as an operator on a struct because otherwise you can't
97
// default-initialize AsyncCleanupHookHandle, because in C++ for a
98
// std::unique_ptr to be default-initializable the deleter type also needs
99
// to be default-initializable; in particular, function types don't satisfy
100
// this.
101
10
void DeleteACHHandle::operator ()(ACHHandle* handle) const { delete handle; }
102
103
38
void AddEnvironmentCleanupHook(Isolate* isolate,
104
                               CleanupHook fun,
105
                               void* arg) {
106
38
  Environment* env = Environment::GetCurrent(isolate);
107
38
  CHECK_NOT_NULL(env);
108
38
  env->AddCleanupHook(fun, arg);
109
38
}
110
111
24
void RemoveEnvironmentCleanupHook(Isolate* isolate,
112
                                  CleanupHook fun,
113
                                  void* arg) {
114
24
  Environment* env = Environment::GetCurrent(isolate);
115
24
  CHECK_NOT_NULL(env);
116
24
  env->RemoveCleanupHook(fun, arg);
117
24
}
118
119
6
static void FinishAsyncCleanupHook(void* arg) {
120
6
  AsyncCleanupHookInfo* info = static_cast<AsyncCleanupHookInfo*>(arg);
121
12
  std::shared_ptr<AsyncCleanupHookInfo> keep_alive = info->self;
122
123
6
  info->env->DecreaseWaitingRequestCounter();
124
6
  info->self.reset();
125
6
}
126
127
6
static void RunAsyncCleanupHook(void* arg) {
128
6
  AsyncCleanupHookInfo* info = static_cast<AsyncCleanupHookInfo*>(arg);
129
6
  info->env->IncreaseWaitingRequestCounter();
130
6
  info->started = true;
131
6
  info->fun(info->arg, FinishAsyncCleanupHook, info);
132
6
}
133
134
10
AsyncCleanupHookHandle AddEnvironmentCleanupHook(
135
    Isolate* isolate,
136
    AsyncCleanupHook fun,
137
    void* arg) {
138
10
  Environment* env = Environment::GetCurrent(isolate);
139
10
  CHECK_NOT_NULL(env);
140
20
  auto info = std::make_shared<AsyncCleanupHookInfo>();
141
10
  info->env = env;
142
10
  info->fun = fun;
143
10
  info->arg = arg;
144
10
  info->self = info;
145
10
  env->AddCleanupHook(RunAsyncCleanupHook, info.get());
146
20
  return AsyncCleanupHookHandle(new ACHHandle { info });
147
}
148
149
8
void RemoveEnvironmentCleanupHook(
150
    AsyncCleanupHookHandle handle) {
151
8
  if (handle->info->started) return;
152
4
  handle->info->self.reset();
153
4
  handle->info->env->RemoveCleanupHook(RunAsyncCleanupHook, handle->info.get());
154
}
155
156
2
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
157
2
  Environment* env = Environment::GetCurrent(isolate);
158
2
  if (env == nullptr) return -1;
159
2
  return env->execution_async_id();
160
}
161
162
2
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
163
2
  Environment* env = Environment::GetCurrent(isolate);
164
2
  if (env == nullptr) return -1;
165
2
  return env->trigger_async_id();
166
}
167
168
169
539
async_context EmitAsyncInit(Isolate* isolate,
170
                            Local<Object> resource,
171
                            const char* name,
172
                            async_id trigger_async_id) {
173
1078
  HandleScope handle_scope(isolate);
174
  Local<String> type =
175
1078
      String::NewFromUtf8(isolate, name, NewStringType::kInternalized)
176
539
          .ToLocalChecked();
177
1078
  return EmitAsyncInit(isolate, resource, type, trigger_async_id);
178
}
179
180
550
async_context EmitAsyncInit(Isolate* isolate,
181
                            Local<Object> resource,
182
                            Local<String> name,
183
                            async_id trigger_async_id) {
184
550
  DebugSealHandleScope handle_scope(isolate);
185
550
  Environment* env = Environment::GetCurrent(isolate);
186
550
  CHECK_NOT_NULL(env);
187
188
  // Initialize async context struct
189
550
  if (trigger_async_id == -1)
190
547
    trigger_async_id = env->get_default_trigger_async_id();
191
192
  async_context context = {
193
550
    env->new_async_id(),  // async_id_
194
    trigger_async_id  // trigger_async_id_
195
550
  };
196
197
  // Run init hooks
198
550
  AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id,
199
550
                           context.trigger_async_id);
200
201
550
  return context;
202
}
203
204
3
void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) {
205
3
  EmitAsyncDestroy(Environment::GetCurrent(isolate), asyncContext);
206
3
}
207
208
546
void EmitAsyncDestroy(Environment* env, async_context asyncContext) {
209
546
  AsyncWrap::EmitDestroy(env, asyncContext.async_id);
210
546
}
211
212

13395
}  // namespace node