| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 7031eae commit f421422
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -181,18 +181,19 @@ int RunNodeInstance(MultiIsolatePlatform* platform, | |||
| 181 | 181 | more = uv_loop_alive(&loop); | |
| 182 | 182 | if (more) continue; | |
| 183 | 183 | ||
| 184 | - // node::EmitBeforeExit() is used to emit the 'beforeExit' event on | ||
| 185 | - // the `process` object. | ||
| 186 | - node::EmitBeforeExit(env.get()); | ||
| 184 | + // node::EmitProcessBeforeExit() is used to emit the 'beforeExit' event | ||
| 185 | + // on the `process` object. | ||
| 186 | + if (node::EmitProcessBeforeExit(env.get()).IsNothing()) | ||
| 187 | + break; | ||
| 187 | 188 | ||
| 188 | 189 | // 'beforeExit' can also schedule new work that keeps the event loop | |
| 189 | 190 | // running. | |
| 190 | 191 | more = uv_loop_alive(&loop); | |
| 191 | 192 | } while (more == true); | |
| 192 | 193 | } | |
| 193 | 194 | ||
| 194 | - // node::EmitExit() returns the current exit code. | ||
| 195 | - exit_code = node::EmitExit(env.get()); | ||
| 195 | + // node::EmitProcessExit() returns the current exit code. | ||
| 196 | + exit_code = node::EmitProcessExit(env.get()).FromMaybe(1); | ||
| 196 | 197 | ||
| 197 | 198 | // node::Stop() can be used to explicitly stop the event loop and keep | |
| 198 | 199 | // further JavaScript from running. It can be called from any thread, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,8 +9,11 @@ using v8::Context; | |||
| 9 | 9 | using v8::HandleScope; | |
| 10 | 10 | using v8::Integer; | |
| 11 | 11 | using v8::Isolate; | |
| 12 | + using v8::Just; | ||
| 12 | 13 | using v8::Local; | |
| 14 | + using v8::Maybe; | ||
| 13 | 15 | using v8::NewStringType; | |
| 16 | + using v8::Nothing; | ||
| 14 | 17 | using v8::Object; | |
| 15 | 18 | using v8::String; | |
| 16 | 19 | using v8::Value; | |
@@ -30,6 +33,10 @@ void AtExit(Environment* env, void (*cb)(void* arg), void* arg) { | |||
| 30 | 33 | } | |
| 31 | 34 | ||
| 32 | 35 | void EmitBeforeExit(Environment* env) { | |
| 36 | + USE(EmitProcessBeforeExit(env)); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + Maybe<bool> EmitProcessBeforeExit(Environment* env) { | ||
| 33 | 40 | TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment), | |
| 34 | 41 | "BeforeExit", env); | |
| 35 | 42 | if (!env->destroy_async_id_list()->empty()) | |
@@ -40,39 +47,49 @@ void EmitBeforeExit(Environment* env) { | |||
| 40 | 47 | ||
| 41 | 48 | Local<Value> exit_code_v; | |
| 42 | 49 | if (!env->process_object()->Get(env->context(), env->exit_code_string()) | |
| 43 | - .ToLocal(&exit_code_v)) return; | ||
| 50 | + .ToLocal(&exit_code_v)) return Nothing<bool>(); | ||
| 44 | 51 | ||
| 45 | 52 | Local<Integer> exit_code; | |
| 46 | - if (!exit_code_v->ToInteger(env->context()).ToLocal(&exit_code)) return; | ||
| 53 | + if (!exit_code_v->ToInteger(env->context()).ToLocal(&exit_code)) { | ||
| 54 | + return Nothing<bool>(); | ||
| 55 | + } | ||
| 47 | 56 | ||
| 48 | - // TODO(addaleax): Provide variants of EmitExit() and EmitBeforeExit() that | ||
| 49 | - // actually forward empty MaybeLocal<>s (and check env->can_call_into_js()). | ||
| 50 | - USE(ProcessEmit(env, "beforeExit", exit_code)); | ||
| 57 | + return ProcessEmit(env, "beforeExit", exit_code).IsEmpty() ? | ||
| 58 | + Nothing<bool>() : Just(true); | ||
| 51 | 59 | } | |
| 52 | 60 | ||
| 53 | 61 | int EmitExit(Environment* env) { | |
| 62 | + return EmitProcessExit(env).FromMaybe(1); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + Maybe<int> EmitProcessExit(Environment* env) { | ||
| 54 | 66 | // process.emit('exit') | |
| 55 | 67 | HandleScope handle_scope(env->isolate()); | |
| 56 | 68 | Context::Scope context_scope(env->context()); | |
| 57 | 69 | Local<Object> process_object = env->process_object(); | |
| 58 | - process_object | ||
| 70 | + | ||
| 71 | + // TODO(addaleax): It might be nice to share process._exiting and | ||
| 72 | + // process.exitCode via getter/setter pairs that pass data directly to the | ||
| 73 | + // native side, so that we don't manually have to read and write JS properties | ||
| 74 | + // here. These getters could use e.g. a typed array for performance. | ||
| 75 | + if (process_object | ||
| 59 | 76 | ->Set(env->context(), | |
| 60 | 77 | FIXED_ONE_BYTE_STRING(env->isolate(), "_exiting"), | |
| 61 | - True(env->isolate())) | ||
| 62 | - .Check(); | ||
| 78 | + True(env->isolate())).IsNothing()) return Nothing<int>(); | ||
| 63 | 79 | ||
| 64 | 80 | Local<String> exit_code = env->exit_code_string(); | |
| 65 | - int code = process_object->Get(env->context(), exit_code) | ||
| 66 | - .ToLocalChecked() | ||
| 67 | - ->Int32Value(env->context()) | ||
| 68 | - .ToChecked(); | ||
| 69 | - ProcessEmit(env, "exit", Integer::New(env->isolate(), code)); | ||
| 70 | - | ||
| 71 | - // Reload exit code, it may be changed by `emit('exit')` | ||
| 72 | - return process_object->Get(env->context(), exit_code) | ||
| 73 | - .ToLocalChecked() | ||
| 74 | - ->Int32Value(env->context()) | ||
| 75 | - .ToChecked(); | ||
| 81 | + Local<Value> code_v; | ||
| 82 | + int code; | ||
| 83 | + if (!process_object->Get(env->context(), exit_code).ToLocal(&code_v) || | ||
| 84 | + !code_v->Int32Value(env->context()).To(&code) || | ||
| 85 | + ProcessEmit(env, "exit", Integer::New(env->isolate(), code)).IsEmpty() || | ||
| 86 | + // Reload exit code, it may be changed by `emit('exit')` | ||
| 87 | + !process_object->Get(env->context(), exit_code).ToLocal(&code_v) || | ||
| 88 | + !code_v->Int32Value(env->context()).To(&code)) { | ||
| 89 | + return Nothing<int>(); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + return Just(code); | ||
| 76 | 93 | } | |
| 77 | 94 | ||
| 78 | 95 | typedef void (*CleanupHook)(void* arg); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -539,8 +539,19 @@ NODE_EXTERN void FreePlatform(MultiIsolatePlatform* platform); | |||
| 539 | 539 | NODE_EXTERN v8::TracingController* GetTracingController(); | |
| 540 | 540 | NODE_EXTERN void SetTracingController(v8::TracingController* controller); | |
| 541 | 541 | ||
| 542 | - NODE_EXTERN void EmitBeforeExit(Environment* env); | ||
| 543 | - NODE_EXTERN int EmitExit(Environment* env); | ||
| 542 | + // Run `process.emit('beforeExit')` as it would usually happen when Node.js is | ||
| 543 | + // run in standalone mode. | ||
| 544 | + NODE_EXTERN v8::Maybe<bool> EmitProcessBeforeExit(Environment* env); | ||
| 545 | + NODE_DEPRECATED("Use Maybe version (EmitProcessBeforeExit) instead", | ||
| 546 | + NODE_EXTERN void EmitBeforeExit(Environment* env)); | ||
| 547 | + // Run `process.emit('exit')` as it would usually happen when Node.js is run | ||
| 548 | + // in standalone mode. The return value corresponds to the exit code. | ||
| 549 | + NODE_EXTERN v8::Maybe<int> EmitProcessExit(Environment* env); | ||
| 550 | + NODE_DEPRECATED("Use Maybe version (EmitProcessExit) instead", | ||
| 551 | + NODE_EXTERN int EmitExit(Environment* env)); | ||
| 552 | + | ||
| 553 | + // Runs hooks added through `AtExit()`. This is part of `FreeEnvironment()`, | ||
| 554 | + // so calling it manually is typically not necessary. | ||
| 544 | 555 | NODE_EXTERN void RunAtExit(Environment* env); | |
| 545 | 556 | ||
| 546 | 557 | // This may return nullptr if the current v8::Context is not associated | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -135,7 +135,8 @@ int NodeMainInstance::Run() { | |||
| 135 | 135 | if (more && !env->is_stopping()) continue; | |
| 136 | 136 | ||
| 137 | 137 | if (!uv_loop_alive(env->event_loop())) { | |
| 138 | - EmitBeforeExit(env.get()); | ||
| 138 | + if (EmitProcessBeforeExit(env.get()).IsNothing()) | ||
| 139 | + break; | ||
| 139 | 140 | } | |
| 140 | 141 | ||
| 141 | 142 | // Emit `beforeExit` if the loop became alive either after emitting | |
@@ -148,7 +149,7 @@ int NodeMainInstance::Run() { | |||
| 148 | 149 | ||
| 149 | 150 | env->set_trace_sync_io(false); | |
| 150 | 151 | if (!env->is_stopping()) env->VerifyNoStrongBaseObjects(); | |
| 151 | - exit_code = EmitExit(env.get()); | ||
| 152 | + exit_code = EmitProcessExit(env.get()).FromMaybe(1); | ||
| 152 | 153 | } | |
| 153 | 154 | ||
| 154 | 155 | ResetStdio(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -352,7 +352,8 @@ void Worker::Run() { | |||
| 352 | 352 | more = uv_loop_alive(&data.loop_); | |
| 353 | 353 | if (more && !is_stopped()) continue; | |
| 354 | 354 | ||
| 355 | - EmitBeforeExit(env_.get()); | ||
| 355 | + if (EmitProcessBeforeExit(env_.get()).IsNothing()) | ||
| 356 | + break; | ||
| 356 | 357 | ||
| 357 | 358 | // Emit `beforeExit` if the loop became alive either after emitting | |
| 358 | 359 | // event, or after running some callbacks. | |
@@ -368,7 +369,7 @@ void Worker::Run() { | |||
| 368 | 369 | bool stopped = is_stopped(); | |
| 369 | 370 | if (!stopped) { | |
| 370 | 371 | env_->VerifyNoStrongBaseObjects(); | |
| 371 | - exit_code = EmitExit(env_.get()); | ||
| 372 | + exit_code = EmitProcessExit(env_.get()).FromMaybe(1); | ||
| 372 | 373 | } | |
| 373 | 374 | Mutex::ScopedLock lock(mutex_); | |
| 374 | 375 | if (exit_code_ == 0 && !stopped) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -110,12 +110,14 @@ int RunNodeInstance(MultiIsolatePlatform* platform, | |||
| 110 | 110 | more = uv_loop_alive(&loop); | |
| 111 | 111 | if (more) continue; | |
| 112 | 112 | ||
| 113 | - node::EmitBeforeExit(env.get()); | ||
| 113 | + if (node::EmitProcessBeforeExit(env.get()).IsNothing()) | ||
| 114 | + break; | ||
| 115 | + | ||
| 114 | 116 | more = uv_loop_alive(&loop); | |
| 115 | 117 | } while (more == true); | |
| 116 | 118 | } | |
| 117 | 119 | ||
| 118 | - exit_code = node::EmitExit(env.get()); | ||
| 120 | + exit_code = node::EmitProcessExit(env.get()).FromMaybe(1); | ||
| 119 | 121 | ||
| 120 | 122 | node::Stop(env.get()); | |
| 121 | 123 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,12 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + common.skipIfWorker(); | ||
| 4 | + | ||
| 5 | + // Test that 'exit' is emitted if 'beforeExit' throws. | ||
| 6 | + | ||
| 7 | + process.on('exit', common.mustCall(() => { | ||
| 8 | + process.exitCode = 0; | ||
| 9 | + })); | ||
| 10 | + process.on('beforeExit', common.mustCall(() => { | ||
| 11 | + throw new Error(); | ||
| 12 | + })); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,28 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const assert = require('assert'); | ||
| 4 | + const { Worker } = require('worker_threads'); | ||
| 5 | + | ||
| 6 | + // Test that 'exit' is emitted if 'beforeExit' throws, both inside the Worker. | ||
| 7 | + | ||
| 8 | + const workerData = new Uint8Array(new SharedArrayBuffer(2)); | ||
| 9 | + const w = new Worker(` | ||
| 10 | + const { workerData } = require('worker_threads'); | ||
| 11 | + process.on('exit', () => { | ||
| 12 | + workerData[0] = 100; | ||
| 13 | + }); | ||
| 14 | + process.on('beforeExit', () => { | ||
| 15 | + workerData[1] = 200; | ||
| 16 | + throw new Error('banana'); | ||
| 17 | + }); | ||
| 18 | + `, { eval: true, workerData }); | ||
| 19 | + | ||
| 20 | + w.on('error', common.mustCall((err) => { | ||
| 21 | + assert.strictEqual(err.message, 'banana'); | ||
| 22 | + })); | ||
| 23 | + | ||
| 24 | + w.on('exit', common.mustCall((code) => { | ||
| 25 | + assert.strictEqual(code, 1); | ||
| 26 | + assert.strictEqual(workerData[0], 100); | ||
| 27 | + assert.strictEqual(workerData[1], 200); | ||
| 28 | + })); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments