Skip to content

Commit a109388

Browse files
committed
feat: allow message port setup before starting runtime
Signed-off-by: Daeyeon Jeong <[email protected]>
1 parent 68bb4fa commit a109388

File tree

7 files changed

+129
-4
lines changed

7 files changed

+129
-4
lines changed

deps/node/src/env.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,16 @@ std::string GetExecPath(const std::vector<std::string>& argv) {
311311
return exec_path;
312312
}
313313

314+
std::unique_ptr<node::ChannelHolder> ChannelHolder::instance;
315+
316+
void ChannelHolder::Init() {
317+
channel_ = Channel::New(uv_promise_.get_future(), "embedder");
318+
}
319+
320+
std::shared_ptr<Port> ChannelHolder::GetPort() {
321+
return channel_.port1;
322+
}
323+
314324
Environment::Environment(IsolateData* isolate_data,
315325
Local<Context> context,
316326
const std::vector<std::string>& args,
@@ -359,7 +369,15 @@ Environment::Environment(IsolateData* isolate_data,
359369
}
360370

361371
#if defined(LWNODE)
362-
channel_ = Channel::New(uv_promise_.get_future(), "embedder");
372+
if (ChannelHolder::instance != nullptr) {
373+
// channel.port1 is already being used.
374+
channel_ = ChannelHolder::instance->channel_;
375+
uv_promise_ = std::move(ChannelHolder::instance->uv_promise_);
376+
ChannelHolder::instance.reset();
377+
} else {
378+
channel_ = Channel::New(uv_promise_.get_future(), "embedder");
379+
}
380+
363381
main_message_port_ =
364382
new MainMessagePort(channel_.port2, std::move(uv_promise_));
365383
loop_holder_ = new LoopHolderUV(isolate_data->event_loop());

deps/node/src/env.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,19 @@ class Environment : public MemoryRetainer {
14191419
#endif
14201420
};
14211421

1422+
class ChannelHolder {
1423+
public:
1424+
ChannelHolder() = default;
1425+
void Init();
1426+
std::shared_ptr<Port> GetPort();
1427+
thread_local static std::unique_ptr<node::ChannelHolder> instance;
1428+
1429+
private:
1430+
std::promise<uv_loop_t*> uv_promise_;
1431+
Channel channel_;
1432+
friend class Environment;
1433+
};
1434+
14221435
} // namespace node
14231436

14241437
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

deps/node/src/node_errors.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ static std::string GetErrorSource(Isolate* isolate,
105105
sourceline.c_str());
106106
CHECK_GT(buf.size(), 0);
107107

108+
// @lwnode
109+
start = std::min(start, (int)sourceline.length());
110+
end = std::min(end, (int)sourceline.length());
111+
108112
constexpr int kUnderlineBufsize = 1020;
109113
char underline_buf[kUnderlineBufsize + 4];
110114
int off = 0;

deps/node/src/node_main_lw_runner-inl.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ class LoopStrategy : public MainLoopStrategy {
103103

104104
class LWNodeMainRunner {
105105
public:
106+
LWNodeMainRunner() { ChannelHolder::instance.reset(); }
107+
106108
~LWNodeMainRunner() {
107109
LWNODE_DEV_LOG("[LWNodeMainRunner::~LWNodeMainRunner]");
108110
}
@@ -209,6 +211,9 @@ class LWNodeMainRunner {
209211

210212
v8::V8::ShutdownPlatform();
211213

214+
environment_ = nullptr;
215+
ChannelHolder::instance.reset();
216+
212217
return exit_code;
213218
}
214219

@@ -233,7 +238,17 @@ class LWNodeMainRunner {
233238
}
234239

235240
std::shared_ptr<Port> GetPort() {
236-
CHECK_NOT_NULL(environment_);
241+
if (environment_ == nullptr) {
242+
if (ChannelHolder::instance == nullptr) {
243+
ChannelHolder::instance = std::make_unique<ChannelHolder>();
244+
ChannelHolder::instance->Init();
245+
}
246+
return ChannelHolder::instance->GetPort();
247+
} else {
248+
if (ChannelHolder::instance) {
249+
ChannelHolder::instance.reset();
250+
}
251+
}
237252
return environment_->GetPort();
238253
}
239254

include/lwnode/lwnode-version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
#pragma once
1818

1919
#define LWNODE_VERSION_MAJOR 1
20-
#define LWNODE_VERSION_MINOR 0
20+
#define LWNODE_VERSION_MINOR 1
2121
#define LWNODE_VERSION_PATCH 9
22-
#define LWNODE_VERSION_TAG "v1.0.9"
22+
#define LWNODE_VERSION_TAG "v1.1.9"

test/embedding/embedtest.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,50 @@ TEST0(Embedtest, MessagePort2_Post_Many_JS_First) {
7676
EXPECT_EQ(count1, 10);
7777
}
7878

79+
TEST0(Embedtest, MessagePort2_Post_JS_First) {
80+
int count1 = 0;
81+
82+
auto runtime = std::make_shared<lwnode::Runtime>();
83+
84+
// 1. Set OnMessage before starting the runtime
85+
auto port2 = runtime->GetPort();
86+
port2->OnMessage([&](const MessageEvent* event) {
87+
count1++;
88+
if (event->data() == "ping") {
89+
auto extra = std::to_string(count1);
90+
std::cout << getTimestamp() << " NS pong " + extra << std::endl;
91+
port2->PostMessage(MessageEvent::New("pong " + extra));
92+
} else {
93+
std::cout << getTimestamp() << " NS ping" << std::endl;
94+
port2->PostMessage(MessageEvent::New("ping"));
95+
}
96+
});
97+
98+
// 2. Start the runtime
99+
std::promise<void> promise;
100+
std::future<void> init_future = promise.get_future();
101+
const char* script = "test/embedding/test-05-message-port-first.js";
102+
std::string path = (std::filesystem::current_path() / script).string();
103+
104+
const bool post_first = true;
105+
char* args[] = {const_cast<char*>(""),
106+
const_cast<char*>(path.c_str()),
107+
const_cast<char*>(std::to_string(post_first).c_str())};
108+
109+
std::thread worker = std::thread(
110+
[&](std::promise<void>&& promise) mutable {
111+
runtime->Start(COUNT_OF(args), args, std::move(promise));
112+
},
113+
std::move(promise));
114+
115+
// 3. Wait for the entry script to run
116+
init_future.wait();
117+
118+
worker.join();
119+
120+
EXPECT_EQ(count1, 1);
121+
}
122+
79123
TEST0(Embedtest, Restart) {
80124
TEST_SKIP("This is not yet production-ready.");
81125

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const lwnode = process.lwnode;
2+
const port = process.lwnode.port;
3+
const post_first = +process.argv[2];
4+
5+
lwnode.ref();
6+
7+
function getTimestamp() {
8+
const now = new Date();
9+
return now.toISOString().slice(14, 23);
10+
}
11+
12+
lwnode.postMessage(`ping`);
13+
14+
const stop_count = 1;
15+
let count = 0;
16+
17+
lwnode.onmessage = async (event) => {
18+
if (stop_count <= ++count) {
19+
console.log(`${getTimestamp()} JS stop`);
20+
lwnode.unref();
21+
return;
22+
}
23+
24+
if (event.data == "ping") {
25+
console.log(`${getTimestamp()} JS pong`);
26+
lwnode.postMessage(`pong ${count}`);
27+
} else {
28+
console.log(`${getTimestamp()} JS ping`);
29+
lwnode.postMessage(`ping`);
30+
}
31+
};

0 commit comments

Comments
 (0)