@@ -159,6 +159,7 @@ class CtxWrap : public ObjectWrap {
159159 static void New (const FunctionCallbackInfo<Value>& args);
160160 static void DebugBytes (const FunctionCallbackInfo<Value>& args);
161161 static void AppendAttributes (const FunctionCallbackInfo<Value>& args);
162+ static void Invalidate (const FunctionCallbackInfo<Value>& args);
162163 static void IsTruncated (const FunctionCallbackInfo<Value>& args);
163164
164165 // Encode the JS array at `attrs_val` into `out` as packed (key, len, value)
@@ -516,6 +517,25 @@ void CtxWrap::AppendAttributes(const FunctionCallbackInfo<Value>& args) {
516517 free (old_rec);
517518}
518519
520+ // Mark this record's `valid` byte as 0 in place. Every async-context
521+ // frame that holds this ThreadContext reference — including those that
522+ // merely inherited it verbatim from a parent frame — will subsequently
523+ // present the same shared record to a reader, so this one write drops
524+ // the record out of scope for every such frame at once. Intended for
525+ // span-finish, where clearing the current frame's context via
526+ // `clearContext()` alone leaves sibling / detached-continuation frames
527+ // still exposing the finished span. Idempotent; safe to call multiple
528+ // times.
529+ void CtxWrap::Invalidate (const FunctionCallbackInfo<Value>& args) {
530+ CtxWrap* self = ObjectWrap::Unwrap<CtxWrap>(args.This ());
531+ if (!self) {
532+ args.GetIsolate ()->ThrowError (" not a ThreadContext" );
533+ return ;
534+ }
535+ std::atomic_signal_fence (std::memory_order_release);
536+ *reinterpret_cast <volatile uint8_t *>(&self->record_ ->valid ) = 0 ;
537+ }
538+
519539// Returns true if any attribute was ever dropped from this wrapper's
520540// record because it would have pushed attrs_data past the cap — set during
521541// CtxWrap::New() if the initial set didn't fit, or by any subsequent
@@ -560,6 +580,9 @@ void CtxWrap::Init(Local<Object> exports) {
560580 tpl->PrototypeTemplate ()->Set (
561581 String::NewFromUtf8Literal (isolate, " appendAttributes" ),
562582 FunctionTemplate::New (isolate, AppendAttributes));
583+ tpl->PrototypeTemplate ()->Set (
584+ String::NewFromUtf8Literal (isolate, " invalidate" ),
585+ FunctionTemplate::New (isolate, Invalidate));
563586 tpl->PrototypeTemplate ()->Set (
564587 String::NewFromUtf8Literal (isolate, " isTruncated" ),
565588 FunctionTemplate::New (isolate, IsTruncated));
0 commit comments