Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions bindings/otel-thread-ctx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,12 @@ thread_local CtxWrap* g_live_ctx_wraps = nullptr;
// fires exactly once, at teardown, while the Environment is still alive.
void DrainLiveCtxWraps(void* arg) {
auto* isolate = static_cast<Isolate*>(arg);
// We must allocate our own HandleScope here as node::FreeEnvironment wraps
// RunCleanup in a SealHandleScope, so handle_.Get() below has to allocate
// inside a scope of our own or V8 aborts with "Cannot create a handle without
// a HandleScope".
v8::HandleScope scope(isolate);

CtxWrap* p = g_live_ctx_wraps;
while (p != nullptr) {
CtxWrap* next = p->next_;
Expand Down
12 changes: 8 additions & 4 deletions bindings/profilers/wall.cc
Original file line number Diff line number Diff line change
Expand Up @@ -700,15 +700,19 @@ WallProfiler::~WallProfiler() {
// unlink. (~PCP still resets its weak handle during delete, so the dangling
// internal-field pointer in the wrap object stays inert even if V8 later
// GCs the wrap.)
//
// While it'd be tempting to do the same "zero out internal field logic" here
// as in otel-thread-ctx.cc's DrainLiveCtxWraps, we shouldn't. That one only
// ever runs as an environment cleanup hook, while this can also get here from
// Nan::ObjectWrap's weak callback, and V8 forbids the API in a first-pass
// weak callback. The holders' internal fields therefore keep pointing at the
// PCPs we free, but since they are only ever read back through our own
// cpedKey_ that dies with us it is not an issue.
auto* p = liveContextPtrHead_;
auto isolate = Isolate::GetCurrent();
while (p != nullptr) {
auto* next = p->next_;
p->pprev_ = nullptr;
p->next_ = nullptr;
if (isolate != nullptr && !p->handle_.IsEmpty()) {
SetAlignedPointerInInternalField(p->handle_.Get(isolate), 0, nullptr);
}
delete p;
p = next;
}
Expand Down
22 changes: 18 additions & 4 deletions ts/test/worker2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,22 @@ time.start({
useCPED: useCPED,
});

parentPort?.on('message', () => {
void delay(50).then(() => {
parentPort?.postMessage('hello');
function listen() {
parentPort?.on('message', () => {
void delay(50).then(() => {
parentPort?.postMessage('hello');
});
});
});
}

// Establish a sample context, and do it around the listener registration so
// the async context frame holding it stays reachable until we are terminated.
// That leaves a live PersistentContextPtr for ~WallProfiler to walk when it
// runs from the environment cleanup hook; with an empty list the walk is a
// no-op and the teardown path goes untested.
if (useCPED) {
time.runWithContext({worker: 'worker2'}, listen);
} else {
time.setContext({worker: 'worker2'});
listen();
}
Loading