summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-11-05 22:50:24 +0100
committerRich Trott <rtrott@gmail.com>2019-11-07 19:51:11 -0800
commite460e14d57869c37b181f1e4839c70d8fa89ffb3 (patch)
tree9c481c15fbce5e5a5e8413518faf099badb5ae0b
parent96db5a271c859eabbf81565e4ce82a93fd037fb9 (diff)
downloadandroid-node-v8-e460e14d57869c37b181f1e4839c70d8fa89ffb3.tar.gz
android-node-v8-e460e14d57869c37b181f1e4839c70d8fa89ffb3.tar.bz2
android-node-v8-e460e14d57869c37b181f1e4839c70d8fa89ffb3.zip
src: allow adding linked bindings to Environment
This allows manually adding linked bindings to an `Environment` instance, without having to register modules at program load in a global namespace. PR-URL: https://github.com/nodejs/node/pull/30274 Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
-rw-r--r--src/api/environment.cc28
-rw-r--r--src/env-inl.h13
-rw-r--r--src/env.cc7
-rw-r--r--src/env.h7
-rw-r--r--src/node.h11
-rw-r--r--src/node_binding.cc24
-rw-r--r--test/cctest/test_linked_binding.cc42
7 files changed, 120 insertions, 12 deletions
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 846e4a873d..4cb2da4b86 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -498,4 +498,32 @@ uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
return env->event_loop();
}
+void AddLinkedBinding(Environment* env, const node_module& mod) {
+ CHECK_NOT_NULL(env);
+ Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
+
+ node_module* prev_head = env->extra_linked_bindings_head();
+ env->extra_linked_bindings()->push_back(mod);
+ if (prev_head != nullptr)
+ prev_head->nm_link = &env->extra_linked_bindings()->back();
+}
+
+void AddLinkedBinding(Environment* env,
+ const char* name,
+ addon_context_register_func fn,
+ void* priv) {
+ node_module mod = {
+ NODE_MODULE_VERSION,
+ NM_F_LINKED,
+ nullptr, // nm_dso_handle
+ nullptr, // nm_filename
+ nullptr, // nm_register_func
+ fn,
+ name,
+ priv,
+ nullptr // nm_link
+ };
+ AddLinkedBinding(env, mod);
+}
+
} // namespace node
diff --git a/src/env-inl.h b/src/env-inl.h
index 79708080d1..ee170b0715 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -868,6 +868,19 @@ inline bool Environment::is_stopping() const {
return thread_stopper_.is_stopped();
}
+inline std::list<node_module>* Environment::extra_linked_bindings() {
+ return &extra_linked_bindings_;
+}
+
+inline node_module* Environment::extra_linked_bindings_head() {
+ return extra_linked_bindings_.size() > 0 ?
+ &extra_linked_bindings_.front() : nullptr;
+}
+
+inline const Mutex& Environment::extra_linked_bindings_mutex() const {
+ return extra_linked_bindings_mutex_;
+}
+
inline performance::performance_state* Environment::performance_state() {
return performance_state_.get();
}
diff --git a/src/env.cc b/src/env.cc
index dd326adf2a..acbbb92b67 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -935,9 +935,10 @@ void Environment::stop_sub_worker_contexts() {
}
}
-#if HAVE_INSPECTOR
-
-#endif // HAVE_INSPECTOR
+Environment* Environment::worker_parent_env() const {
+ if (worker_context_ == nullptr) return nullptr;
+ return worker_context_->env();
+}
void MemoryTracker::TrackField(const char* edge_name,
const CleanupHookCallback& value,
diff --git a/src/env.h b/src/env.h
index e5490c0a5b..3e3aacc8f7 100644
--- a/src/env.h
+++ b/src/env.h
@@ -1069,11 +1069,15 @@ class Environment : public MemoryRetainer {
inline bool owns_inspector() const;
inline uint64_t thread_id() const;
inline worker::Worker* worker_context() const;
+ Environment* worker_parent_env() const;
inline void set_worker_context(worker::Worker* context);
inline void add_sub_worker_context(worker::Worker* context);
inline void remove_sub_worker_context(worker::Worker* context);
void stop_sub_worker_contexts();
inline bool is_stopping() const;
+ inline std::list<node_module>* extra_linked_bindings();
+ inline node_module* extra_linked_bindings_head();
+ inline const Mutex& extra_linked_bindings_mutex() const;
inline void ThrowError(const char* errmsg);
inline void ThrowTypeError(const char* errmsg);
@@ -1369,6 +1373,9 @@ class Environment : public MemoryRetainer {
worker::Worker* worker_context_ = nullptr;
+ std::list<node_module> extra_linked_bindings_;
+ Mutex extra_linked_bindings_mutex_;
+
static void RunTimers(uv_timer_t* handle);
struct ExitCallback {
diff --git a/src/node.h b/src/node.h
index 8215552227..7602d14ed7 100644
--- a/src/node.h
+++ b/src/node.h
@@ -668,6 +668,17 @@ extern "C" NODE_EXTERN void node_module_register(void* mod);
v8::Local<v8::Value> module, \
v8::Local<v8::Context> context)
+// Allows embedders to add a binding to the current Environment* that can be
+// accessed through process._linkedBinding() in the target Environment and all
+// Worker threads that it creates.
+// In each variant, the registration function needs to be usable at least for
+// the time during which the Environment exists.
+NODE_EXTERN void AddLinkedBinding(Environment* env, const node_module& mod);
+NODE_EXTERN void AddLinkedBinding(Environment* env,
+ const char* name,
+ addon_context_register_func fn,
+ void* priv);
+
/* Called after the event loop exits but before the VM is disposed.
* Callbacks are run in reverse order of registration, i.e. newest first.
*
diff --git a/src/node_binding.cc b/src/node_binding.cc
index 3ae361634d..d083c64d10 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -552,13 +552,6 @@ inline struct node_module* FindModule(struct node_module* list,
return mp;
}
-node_module* get_internal_module(const char* name) {
- return FindModule(modlist_internal, name, NM_F_INTERNAL);
-}
-node_module* get_linked_module(const char* name) {
- return FindModule(modlist_linked, name, NM_F_LINKED);
-}
-
static Local<Object> InitModule(Environment* env,
node_module* mod,
Local<String> module) {
@@ -586,7 +579,7 @@ void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
node::Utf8Value module_v(env->isolate(), module);
Local<Object> exports;
- node_module* mod = get_internal_module(*module_v);
+ node_module* mod = FindModule(modlist_internal, *module_v, NM_F_INTERNAL);
if (mod != nullptr) {
exports = InitModule(env, mod, module);
} else if (!strcmp(*module_v, "constants")) {
@@ -619,7 +612,20 @@ void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
Local<String> module_name = args[0].As<String>();
node::Utf8Value module_name_v(env->isolate(), module_name);
- node_module* mod = get_linked_module(*module_name_v);
+ const char* name = *module_name_v;
+ node_module* mod = nullptr;
+
+ // Iterate from here to the nearest non-Worker Environment to see if there's
+ // a linked binding defined locally rather than through the global list.
+ Environment* cur_env = env;
+ while (mod == nullptr && cur_env != nullptr) {
+ Mutex::ScopedLock lock(cur_env->extra_linked_bindings_mutex());
+ mod = FindModule(cur_env->extra_linked_bindings_head(), name, NM_F_LINKED);
+ cur_env = cur_env->worker_parent_env();
+ }
+
+ if (mod == nullptr)
+ mod = FindModule(modlist_linked, name, NM_F_LINKED);
if (mod == nullptr) {
char errmsg[1024];
diff --git a/test/cctest/test_linked_binding.cc b/test/cctest/test_linked_binding.cc
index 9068865552..6724402c55 100644
--- a/test/cctest/test_linked_binding.cc
+++ b/test/cctest/test_linked_binding.cc
@@ -41,3 +41,45 @@ TEST_F(LinkedBindingTest, SimpleTest) {
CHECK_NOT_NULL(*utf8val);
CHECK_EQ(strcmp(*utf8val, "value"), 0);
}
+
+void InitializeLocalBinding(v8::Local<v8::Object> exports,
+ v8::Local<v8::Value> module,
+ v8::Local<v8::Context> context,
+ void* priv) {
+ ++*static_cast<int*>(priv);
+ v8::Isolate* isolate = context->GetIsolate();
+ exports->Set(
+ context,
+ v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>("key"),
+ v8::NewStringType::kNormal).ToLocalChecked(),
+ v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>("value"),
+ v8::NewStringType::kNormal).ToLocalChecked())
+ .FromJust();
+}
+
+TEST_F(LinkedBindingTest, LocallyDefinedLinkedBindingTest) {
+ const v8::HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env test_env {handle_scope, argv};
+
+ int calls = 0;
+ AddLinkedBinding(*test_env, "local_linked", InitializeLocalBinding, &calls);
+
+ v8::Local<v8::Context> context = isolate_->GetCurrentContext();
+
+ const char* run_script =
+ "process._linkedBinding('local_linked').key";
+ v8::Local<v8::Script> script = v8::Script::Compile(
+ context,
+ v8::String::NewFromOneByte(isolate_,
+ reinterpret_cast<const uint8_t*>(run_script),
+ v8::NewStringType::kNormal).ToLocalChecked())
+ .ToLocalChecked();
+ v8::Local<v8::Value> completion_value = script->Run(context).ToLocalChecked();
+ v8::String::Utf8Value utf8val(isolate_, completion_value);
+ CHECK_NOT_NULL(*utf8val);
+ CHECK_EQ(strcmp(*utf8val, "value"), 0);
+ CHECK_EQ(calls, 1);
+}