Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V11.5.0 proposal #25102

Merged
merged 89 commits into from
Dec 18, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
022599c
tools: prepare tools/genv8constants.py for Python 3
Dec 3, 2018
a5c8af7
test: prepare test/message/testcfg.py for Python 3
Dec 3, 2018
a5c5786
test: refactor test-fs-write-file-sync.js
cjihrig Dec 4, 2018
8b109f0
process: simplify check in previousValueIsValid()
cjihrig Dec 4, 2018
5f60ed7
path: replace assertPath() with validator
cjihrig Dec 4, 2018
90d481e
src: remove unused env variables in node_util
danbev Dec 4, 2018
9b000e5
src: remove finalized_ member from Hash class
danbev Dec 4, 2018
c4f3cf9
doc: revise Waiting for Approvals documentation
Trott Dec 5, 2018
15632c3
tools: prepare tools/test.py for Python 3
Dec 3, 2018
526ff1d
test: prepare test/pseudo-tty/testcfg.py for Python 3
Dec 2, 2018
7cac76c
tools: prepare tools/specialize_node_d.py for Python 3
Dec 3, 2018
c3dda00
tools: prepare tools/js2c.py for Python 3
Dec 3, 2018
94d02ca
src: fix warning for potential snprintf truncation
sam-github Dec 3, 2018
5206f3a
src: do not alias new and old signal masks
sam-github Dec 3, 2018
c300aaa
doc: update LICENSE file
addaleax Dec 7, 2018
643ca14
doc: fix order of events when request is aborted
lpinca Dec 2, 2018
6db760c
test: improve test-net-socket-timeout
Trott Dec 5, 2018
3d87688
test: fix wrong parameter
zhmushan Dec 5, 2018
91ce957
test: make http2 timeout test robust
Trott Dec 6, 2018
592bad1
test: move http2 test to parallel
Trott Dec 6, 2018
f41443c
test: move test-cli-syntax to sequential
Trott Dec 8, 2018
81dce68
doc: update http doc for new Agent()/support options in socket.connect()
BeniCheni Dec 5, 2018
56b2a72
inspector: split the HostPort being used and the one parsed from CLI
joyeecheung Dec 1, 2018
cc8a805
build: fix compiler version detection
richardlau Dec 6, 2018
79c52a9
lib: improve error creation performance
BridgeAR Nov 18, 2018
2a11e6a
module: use validateString in modules/cjs
ZYSzys Dec 6, 2018
cda1da9
doc: update "Testing and CI" in Collaborator Guide
Trott Dec 7, 2018
ac46e27
tools: do not lint tools/inspector_protocol or tools/markupsafe
Dec 7, 2018
a6a3829
doc: simplify author ready
BridgeAR Dec 7, 2018
ad6104d
tools: update ESLint to 5.10.0
cjihrig Dec 8, 2018
e140d41
tools: capitalize sentences
BridgeAR Dec 3, 2018
1f61c89
tools: prepare tools/icu/icutrim.py for Python 3
Dec 7, 2018
25dae6c
module: use validateString in modules/esm
ZYSzys Dec 6, 2018
bf4faf3
assert,util: harden comparison
BridgeAR Dec 3, 2018
b60808a
tools: prepare tools/testp.py for Python 3
Dec 7, 2018
16a75be
tools: prepare ./tools/compress_json.py for Python 3
Dec 7, 2018
bc71e9e
test: prepare test/pseudo-tty/testcfg.py Python 3
Dec 7, 2018
56fd127
test: do not lint macros files (again)
Dec 7, 2018
22b6bef
test: mark test-cli-syntax as flaky/unreliable
Trott Dec 11, 2018
0220cd3
doc: remove bad link to irc info
richardlau Dec 11, 2018
08c6b21
src: use Local version of ToBoolean()
cjihrig Dec 9, 2018
9bfbb68
doc: add class worker documentation
yoshimoto8 Dec 5, 2018
e050a57
test: replace callback with arrows
Shubhamurkade Nov 27, 2018
d760572
src: remove use of CallOnForegroundThread()
cjihrig Dec 9, 2018
b2e6cbd
doc: update Useful CI Jobs section of Collaborator Guide
Trott Dec 9, 2018
39af61f
stream: fix end-of-stream for HTTP/2
addaleax Dec 9, 2018
016e352
test: test TLS client authentication
sam-github Oct 12, 2017
390e050
tls: support "BEGIN TRUSTED CERTIFICATE" for ca:
sam-github Nov 30, 2018
117e991
util: add inspection getter option
BridgeAR Dec 4, 2018
e61bbda
test: improve internet/test-dns
IlarionHalushka Dec 9, 2018
5a1289d
src: create env->inspector_console_api_object earlier
joyeecheung Dec 8, 2018
f854701
src: include node_internals.h in node_metadata.cc
danbev Dec 10, 2018
331f604
worker: drain messages from internal message port
yaelhe Dec 10, 2018
d366676
test: split test-cli-syntax into multiple tests
Trott Dec 9, 2018
1e09629
doc: fix author-ready conflict
BridgeAR Dec 13, 2018
649a728
test: from functools import reduce in test/testpy/__init__.py
Dec 11, 2018
f0bcacd
doc: update a link of npm repository
watilde Dec 11, 2018
877f8a0
doc: revise internal vs. public API in Collaborator Guide
Trott Dec 11, 2018
d5b0ce1
test: refactor test-enable-in-init
Dec 12, 2018
dbdea36
doc: add codebytere's info to release team
codebytere Dec 13, 2018
d0270f3
src: add GetLoadedLibraries routine
gireeshpunathil Dec 4, 2018
5f8950b
src: emit 'params' instead of 'data' for NodeTracing.dataCollected
kjin Dec 10, 2018
f43f45a
process: properly close file descriptor on exit
BridgeAR Dec 11, 2018
900a412
test: increase error information in test-cli-syntax-*
Trott Dec 13, 2018
a4ef54a
test: mark test-child-process-execsync flaky on AIX
Trott Dec 14, 2018
9bd4267
test: mark test-cli-node-options flaky on arm
Trott Dec 14, 2018
2456a54
lib: ensure readable stream flows to end
Rantanen Dec 9, 2018
e7b77ea
url: remove an eslint-disable comment
cjihrig Dec 12, 2018
2825894
test: mark test-worker-memory flaky on Windows CI
Trott Dec 14, 2018
da984be
test: remove reference to whatwg in file names under test/wpt
joyeecheung Dec 4, 2018
7e0dbc6
test: improve WPT runner name matching
joyeecheung Nov 18, 2018
1e3fb0a
test: mark test-child-process-exit-code flaky
Trott Dec 14, 2018
ac919ef
test: mark test-child-process-execfile flaky
Trott Dec 14, 2018
a1f0da1
util: remove todo
BridgeAR Dec 12, 2018
eb9e6e6
test: adding history regression test case
antsmartian Dec 13, 2018
e04e854
test: use blocks instead of async IIFE
addaleax Dec 12, 2018
d449c36
stream: re-use existing `once()` implementation
addaleax Dec 12, 2018
302081b
build: make lint-addon-docs run only if needed
danbev Dec 12, 2018
110fd39
test: remove dead code
BridgeAR Dec 13, 2018
ddff644
test: run eslint on test file and fix errors
BridgeAR Dec 13, 2018
ab1801b
test: use global.gc() instead of gc()
cjihrig Dec 13, 2018
4f0d17b
test: remove unnecessary linter comment
cjihrig Dec 13, 2018
f4d5c35
net: use strict comparisons for fd
cjihrig Dec 13, 2018
00ce972
doc: make README formatting more consistent
yewenjunfighting Dec 13, 2018
a9f239f
doc: add EventTarget link to worker_threads
Azard Dec 15, 2018
5931747
util: inspect all prototypes
BridgeAR Dec 11, 2018
bde5df2
doc: fix node.1 --http-parser sort order
cjihrig Dec 14, 2018
2e94f3b
querystring: remove eslint-disable
cjihrig Dec 12, 2018
9a5b243
2018-12-18, Version 11.5.0 (Current)
BethGriggs Dec 18, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
inspector: split the HostPort being used and the one parsed from CLI
Instead of using a shared pointer of the entire debug option set,
pass the parsed debug option to inspector classes by value because
they are set once the CLI argument parsing is done. Add another shared
pointer to HostPort being used by the inspector server, which is copied
from the one in the debug options initially. The port of the shared
HostPort is 9229 by default and can be specified as 0 initially but
will be set to the actual port of the server once it starts listening.

This makes the shared state clearer and makes it possible to use
`require('internal/options')` in JS land to query the CLI options
instead of using `process._breakFirstLine` and other underscored
properties of `process` since we are now certain that these
values should not be altered once the parsing is done and can be
passed around in copies without locks.

PR-URL: #24772
Reviewed-By: Anna Henningsen <[email protected]>
  • Loading branch information
joyeecheung authored and BethGriggs committed Dec 17, 2018
commit 56b2a7274c84e37c757134d0158a8e03ec842db8
4 changes: 4 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,10 @@ inline std::shared_ptr<EnvironmentOptions> Environment::options() {
return options_;
}

inline std::shared_ptr<HostPort> Environment::inspector_host_port() {
return inspector_host_port_;
}

inline std::shared_ptr<PerIsolateOptions> IsolateData::options() {
return options_;
}
Expand Down
3 changes: 2 additions & 1 deletion src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "node_file.h"
#include "node_internals.h"
#include "node_native_module.h"
#include "node_options-inl.h"
#include "node_platform.h"
#include "node_worker.h"
#include "tracing/agent.h"
Expand Down Expand Up @@ -192,7 +193,7 @@ Environment::Environment(IsolateData* isolate_data,
// part of the per-Isolate option set, for which in turn the defaults are
// part of the per-process option set.
options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
options_->debug_options.reset(new DebugOptions(*options_->debug_options));
inspector_host_port_.reset(new HostPort(options_->debug_options().host_port));

#if HAVE_INSPECTOR
// We can only create the inspector agent after having cloned the options.
Expand Down
9 changes: 9 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ class Environment {
void* data);

inline std::shared_ptr<EnvironmentOptions> options();
inline std::shared_ptr<HostPort> inspector_host_port();

private:
inline void CreateImmediate(native_immediate_callback cb,
Expand Down Expand Up @@ -942,6 +943,14 @@ class Environment {
std::vector<double> destroy_async_id_list_;

std::shared_ptr<EnvironmentOptions> options_;
// options_ contains debug options parsed from CLI arguments,
// while inspector_host_port_ stores the actual inspector host
// and port being used. For example the port is -1 by default
// and can be specified as 0 (meaning any port allocated when the
// server starts listening), but when the inspector server starts
// the inspector_host_port_->port() will be the actual port being
// used.
std::shared_ptr<HostPort> inspector_host_port_;

uint32_t module_id_counter_ = 0;
uint32_t script_id_counter_ = 0;
Expand Down
29 changes: 17 additions & 12 deletions src/inspector_agent.cc
Original file line number Diff line number Diff line change
Expand Up @@ -669,8 +669,9 @@ class NodeInspectorClient : public V8InspectorClient {
};

Agent::Agent(Environment* env)
: parent_env_(env),
debug_options_(env->options()->debug_options) {}
: parent_env_(env),
debug_options_(env->options()->debug_options()),
host_port_(env->inspector_host_port()) {}

Agent::~Agent() {
if (start_io_thread_async.data == this) {
Expand All @@ -681,13 +682,14 @@ Agent::~Agent() {
}

bool Agent::Start(const std::string& path,
std::shared_ptr<DebugOptions> options,
const DebugOptions& options,
std::shared_ptr<HostPort> host_port,
bool is_main) {
if (options == nullptr) {
options = std::make_shared<DebugOptions>();
}
path_ = path;
debug_options_ = options;
CHECK_NE(host_port, nullptr);
host_port_ = host_port;

client_ = std::make_shared<NodeInspectorClient>(parent_env_, is_main);
if (parent_env_->is_main_thread()) {
CHECK_EQ(0, uv_async_init(parent_env_->event_loop(),
Expand All @@ -699,13 +701,18 @@ bool Agent::Start(const std::string& path,
StartDebugSignalHandler();
}

bool wait_for_connect = options->wait_for_connect();
bool wait_for_connect = options.wait_for_connect();
if (parent_handle_) {
wait_for_connect = parent_handle_->WaitForConnect();
parent_handle_->WorkerStarted(client_->getThreadHandle(), wait_for_connect);
} else if (!options->inspector_enabled || !StartIoThread()) {
} else if (!options.inspector_enabled || !StartIoThread()) {
return false;
}

// TODO(joyeecheung): we should not be using process as a global object
// to transport --inspect-brk. Instead, the JS land can get this through
// require('internal/options') since it should be set once CLI parsing
// is done.
if (wait_for_connect) {
HandleScope scope(parent_env_->isolate());
parent_env_->process_object()->DefineOwnProperty(
Expand All @@ -725,8 +732,7 @@ bool Agent::StartIoThread() {

CHECK_NOT_NULL(client_);

io_ = InspectorIo::Start(
client_->getThreadHandle(), path_, debug_options_);
io_ = InspectorIo::Start(client_->getThreadHandle(), path_, host_port_);
if (io_ == nullptr) {
return false;
}
Expand Down Expand Up @@ -867,8 +873,7 @@ void Agent::ContextCreated(Local<Context> context, const ContextInfo& info) {
}

bool Agent::WillWaitForConnect() {
if (debug_options_->wait_for_connect())
return true;
if (debug_options_.wait_for_connect()) return true;
if (parent_handle_)
return parent_handle_->WaitForConnect();
return false;
Expand Down
18 changes: 13 additions & 5 deletions src/inspector_agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#error("This header can only be used when inspector is enabled")
#endif

#include "node_options.h"
#include "node_options-inl.h"
#include "node_persistent.h"
#include "v8.h"

Expand Down Expand Up @@ -50,8 +50,9 @@ class Agent {

// Create client_, may create io_ if option enabled
bool Start(const std::string& path,
std::shared_ptr<DebugOptions> options,
bool is_worker);
const DebugOptions& options,
std::shared_ptr<HostPort> host_port,
bool is_main);
// Stop and destroy io_
void Stop();

Expand Down Expand Up @@ -104,7 +105,8 @@ class Agent {
// Calls StartIoThread() from off the main thread.
void RequestIoThreadStart();

std::shared_ptr<DebugOptions> options() { return debug_options_; }
const DebugOptions& options() { return debug_options_; }
std::shared_ptr<HostPort> host_port() { return host_port_; }
void ContextCreated(v8::Local<v8::Context> context, const ContextInfo& info);

// Interface for interacting with inspectors in worker threads
Expand All @@ -121,7 +123,13 @@ class Agent {
std::unique_ptr<InspectorIo> io_;
std::unique_ptr<ParentInspectorHandle> parent_handle_;
std::string path_;
std::shared_ptr<DebugOptions> debug_options_;

// This is a copy of the debug options parsed from CLI in the Environment.
// Do not use the host_port in that, instead manipulate the shared host_port_
// pointer which is meant to store the actual host and port of the inspector
// server.
DebugOptions debug_options_;
std::shared_ptr<HostPort> host_port_;

bool pending_enable_async_hook_ = false;
bool pending_disable_async_hook_ = false;
Expand Down
22 changes: 13 additions & 9 deletions src/inspector_io.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,9 @@ class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
std::unique_ptr<InspectorIo> InspectorIo::Start(
std::shared_ptr<MainThreadHandle> main_thread,
const std::string& path,
std::shared_ptr<DebugOptions> options) {
std::shared_ptr<HostPort> host_port) {
auto io = std::unique_ptr<InspectorIo>(
new InspectorIo(main_thread, path, options));
new InspectorIo(main_thread, path, host_port));
if (io->request_queue_->Expired()) { // Thread is not running
return nullptr;
}
Expand All @@ -253,9 +253,12 @@ std::unique_ptr<InspectorIo> InspectorIo::Start(

InspectorIo::InspectorIo(std::shared_ptr<MainThreadHandle> main_thread,
const std::string& path,
std::shared_ptr<DebugOptions> options)
: main_thread_(main_thread), options_(options),
thread_(), script_name_(path), id_(GenerateID()) {
std::shared_ptr<HostPort> host_port)
: main_thread_(main_thread),
host_port_(host_port),
thread_(),
script_name_(path),
id_(GenerateID()) {
Mutex::ScopedLock scoped_lock(thread_start_lock_);
CHECK_EQ(uv_thread_create(&thread_, InspectorIo::ThreadMain, this), 0);
thread_start_condition_.Wait(scoped_lock);
Expand Down Expand Up @@ -287,16 +290,17 @@ void InspectorIo::ThreadMain() {
std::unique_ptr<InspectorIoDelegate> delegate(
new InspectorIoDelegate(queue, main_thread_, id_,
script_path, script_name_));
InspectorSocketServer server(std::move(delegate), &loop,
options_->host().c_str(),
options_->port());
InspectorSocketServer server(std::move(delegate),
&loop,
host_port_->host().c_str(),
host_port_->port());
request_queue_ = queue->handle();
// Its lifetime is now that of the server delegate
queue.reset();
{
Mutex::ScopedLock scoped_lock(thread_start_lock_);
if (server.Start()) {
port_ = server.Port();
host_port_->set_port(server.Port());
}
thread_start_condition_.Broadcast(scoped_lock);
}
Expand Down
14 changes: 7 additions & 7 deletions src/inspector_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,22 @@ class InspectorIo {
// bool Start();
// Returns empty pointer if thread was not started
static std::unique_ptr<InspectorIo> Start(
std::shared_ptr<MainThreadHandle> main_thread, const std::string& path,
std::shared_ptr<DebugOptions> options);
std::shared_ptr<MainThreadHandle> main_thread,
const std::string& path,
std::shared_ptr<HostPort> host_port);

// Will block till the transport thread shuts down
~InspectorIo();

void StopAcceptingNewConnections();
const std::string& host() const { return options_->host(); }
int port() const { return port_; }
const std::string& host() const { return host_port_->host(); }
int port() const { return host_port_->port(); }
std::vector<std::string> GetTargetIds() const;

private:
InspectorIo(std::shared_ptr<MainThreadHandle> handle,
const std::string& path,
std::shared_ptr<DebugOptions> options);
std::shared_ptr<HostPort> host_port);

// Wrapper for agent->ThreadMain()
static void ThreadMain(void* agent);
Expand All @@ -74,7 +75,7 @@ class InspectorIo {
// Used to post on a frontend interface thread, lives while the server is
// running
std::shared_ptr<RequestQueue> request_queue_;
std::shared_ptr<DebugOptions> options_;
std::shared_ptr<HostPort> host_port_;

// The IO thread runs its own uv_loop to implement the TCP server off
// the main thread.
Expand All @@ -84,7 +85,6 @@ class InspectorIo {
Mutex thread_start_lock_;
ConditionVariable thread_start_condition_;
std::string script_name_;
int port_ = -1;
// May be accessed from any thread
const std::string id_;
};
Expand Down
4 changes: 2 additions & 2 deletions src/inspector_js_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,12 @@ void Open(const FunctionCallbackInfo<Value>& args) {

if (args.Length() > 0 && args[0]->IsUint32()) {
uint32_t port = args[0].As<Uint32>()->Value();
agent->options()->host_port.port = port;
agent->host_port()->set_port(static_cast<int>(port));
}

if (args.Length() > 1 && args[1]->IsString()) {
Utf8Value host(env->isolate(), args[1].As<String>());
agent->options()->host_port.host_name = *host;
agent->host_port()->set_host(*host);
}

if (args.Length() > 2 && args[2]->IsBoolean()) {
Expand Down
32 changes: 16 additions & 16 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "node_internals.h"
#include "node_metadata.h"
#include "node_native_module.h"
#include "node_options-inl.h"
#include "node_perf.h"
#include "node_platform.h"
#include "node_revert.h"
Expand Down Expand Up @@ -259,13 +260,15 @@ static struct {
}

#if HAVE_INSPECTOR
bool StartInspector(Environment* env, const char* script_path,
std::shared_ptr<DebugOptions> options) {
bool StartInspector(Environment* env, const char* script_path) {
// Inspector agent can't fail to start, but if it was configured to listen
// right away on the websocket port and fails to bind/etc, this will return
// false.
return env->inspector_agent()->Start(
script_path == nullptr ? "" : script_path, options, true);
script_path == nullptr ? "" : script_path,
env->options()->debug_options(),
env->inspector_host_port(),
true);
}

bool InspectorStarted(Environment* env) {
Expand Down Expand Up @@ -306,8 +309,7 @@ static struct {
void Dispose() {}
void DrainVMTasks(Isolate* isolate) {}
void CancelVMTasks(Isolate* isolate) {}
bool StartInspector(Environment* env, const char* script_path,
const DebugOptions& options) {
bool StartInspector(Environment* env, const char* script_path) {
env->ThrowError("Node compiled with NODE_USE_V8_PLATFORM=0");
return true;
}
Expand Down Expand Up @@ -1127,24 +1129,24 @@ void SetupProcessObject(Environment* env,

// TODO(refack): move the following 4 to `node_config`
// --inspect-brk
if (env->options()->debug_options->wait_for_connect()) {
if (env->options()->debug_options().wait_for_connect()) {
READONLY_DONT_ENUM_PROPERTY(process,
"_breakFirstLine", True(env->isolate()));
}

if (env->options()->debug_options->break_node_first_line) {
if (env->options()->debug_options().break_node_first_line) {
READONLY_DONT_ENUM_PROPERTY(process,
"_breakNodeFirstLine", True(env->isolate()));
}

// --inspect --debug-brk
if (env->options()->debug_options->deprecated_invocation()) {
if (env->options()->debug_options().deprecated_invocation()) {
READONLY_DONT_ENUM_PROPERTY(process,
"_deprecatedDebugBrk", True(env->isolate()));
}

// --debug or, --debug-brk without --inspect
if (env->options()->debug_options->invalid_invocation()) {
if (env->options()->debug_options().invalid_invocation()) {
READONLY_DONT_ENUM_PROPERTY(process,
"_invalidDebug", True(env->isolate()));
}
Expand Down Expand Up @@ -1356,7 +1358,7 @@ void LoadEnvironment(Environment* env) {
get_linked_binding_fn,
get_internal_binding_fn,
Boolean::New(env->isolate(),
env->options()->debug_options->break_node_first_line)
env->options()->debug_options().break_node_first_line)
};

// Bootstrap internal loaders
Expand Down Expand Up @@ -1390,12 +1392,10 @@ void LoadEnvironment(Environment* env) {
}
}


static void StartInspector(Environment* env, const char* path,
std::shared_ptr<DebugOptions> debug_options) {
static void StartInspector(Environment* env, const char* path) {
#if HAVE_INSPECTOR
CHECK(!env->inspector_agent()->IsListening());
v8_platform.StartInspector(env, path, debug_options);
v8_platform.StartInspector(env, path);
#endif // HAVE_INSPECTOR
}

Expand Down Expand Up @@ -2038,9 +2038,9 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
env.Start(args, exec_args, v8_is_profiling);

const char* path = args.size() > 1 ? args[1].c_str() : nullptr;
StartInspector(&env, path, env.options()->debug_options);
StartInspector(&env, path);

if (env.options()->debug_options->inspector_enabled &&
if (env.options()->debug_options().inspector_enabled &&
!v8_platform.InspectorStarted(&env)) {
return 12; // Signal internal error.
}
Expand Down
Loading