Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
src: add C++ support for diagnostics channels
Add a C++ API for diagnostics channels that allows native code to check
for subscribers and publish messages without unnecessary JS boundary
crossings. Uses a shared AliasedUint32Array buffer between C++ and JS
to track subscriber counts per channel, enabling a fast inline check
(HasSubscribers) that reads the buffer directly.
  • Loading branch information
RafaelGSS committed Feb 24, 2026
commit f1d50056561bfcbbc0a3b21acc3f0cacb6ecbda4
16 changes: 15 additions & 1 deletion lib/diagnostics_channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const {

const { triggerUncaughtException } = internalBinding('errors');

const dc_binding = internalBinding('diagnostics_channel');
const { subscribers: subscriberCounts } = dc_binding;

const { WeakReference } = require('internal/util');

// Can't delete when weakref count reaches 0 as it could increment again.
Expand Down Expand Up @@ -108,6 +111,7 @@ class ActiveChannel {
this._subscribers = ArrayPrototypeSlice(this._subscribers);
ArrayPrototypePush(this._subscribers, subscription);
channels.incRef(this.name);
if (this._index !== undefined) subscriberCounts[this._index]++;
}

unsubscribe(subscription) {
Expand All @@ -120,14 +124,18 @@ class ActiveChannel {
ArrayPrototypePushApply(this._subscribers, after);

channels.decRef(this.name);
if (this._index !== undefined) subscriberCounts[this._index]--;
maybeMarkInactive(this);

return true;
}

bindStore(store, transform) {
const replacing = this._stores.has(store);
if (!replacing) channels.incRef(this.name);
if (!replacing) {
channels.incRef(this.name);
if (this._index !== undefined) subscriberCounts[this._index]++;
}
this._stores.set(store, transform);
}

Expand All @@ -139,6 +147,7 @@ class ActiveChannel {
this._stores.delete(store);

channels.decRef(this.name);
if (this._index !== undefined) subscriberCounts[this._index]--;
maybeMarkInactive(this);

return true;
Expand Down Expand Up @@ -183,6 +192,9 @@ class Channel {
this._subscribers = undefined;
this._stores = undefined;
this.name = name;
if (typeof name === 'string') {
this._index = dc_binding.getOrCreateChannelIndex(name);
}

channels.set(name, this);
}
Expand Down Expand Up @@ -434,6 +446,8 @@ function tracingChannel(nameOrChannels) {
return new TracingChannel(nameOrChannels);
}

dc_binding.linkNativeChannel((name) => channel(name));

module.exports = {
channel,
hasSubscribers,
Expand Down
10 changes: 10 additions & 0 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ function prepareExecution(options) {
// Process initial diagnostic reporting configuration, if present.
initializeReport();

setupDiagnosticsChannel();

// Load permission system API
initializePermission();

Expand Down Expand Up @@ -619,6 +621,14 @@ function initializeClusterIPC() {
}
}

function setupDiagnosticsChannel() {
// Re-link native channels after snapshot deserialization since
// JS references are cleared during serialization.
const dc = require('diagnostics_channel');
const dc_binding = internalBinding('diagnostics_channel');
dc_binding.linkNativeChannel((name) => dc.channel(name));
}

function initializePermission() {
const permission = getOptionValue('--permission');
if (permission) {
Expand Down
2 changes: 2 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
'src/node_main_instance.cc',
'src/node_messaging.cc',
'src/node_metadata.cc',
'src/node_diagnostics_channel.cc',
'src/node_modules.cc',
'src/node_options.cc',
'src/node_os.cc',
Expand Down Expand Up @@ -270,6 +271,7 @@
'src/node_messaging.h',
'src/node_metadata.h',
'src/node_mutex.h',
'src/node_diagnostics_channel.h',
'src/node_modules.h',
'src/node_object_wrap.h',
'src/node_options.h',
Expand Down
1 change: 1 addition & 0 deletions src/base_object_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace node {
// what the class passes to SET_BINDING_ID(), the second argument should match
// the C++ class name.
#define SERIALIZABLE_BINDING_TYPES(V) \
V(diagnostics_channel_binding_data, diagnostics_channel::BindingData) \
V(encoding_binding_data, encoding_binding::BindingData) \
V(fs_binding_data, fs::BindingData) \
V(mksnapshot_binding_data, mksnapshot::BindingData) \
Expand Down
1 change: 1 addition & 0 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
V(constants) \
V(contextify) \
V(credentials) \
V(diagnostics_channel) \
V(encoding_binding) \
V(errors) \
V(fs) \
Expand Down
1 change: 1 addition & 0 deletions src/node_binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
V(blob) \
V(builtins) \
V(contextify) \
V(diagnostics_channel) \
V(encoding_binding) \
V(fs) \
V(fs_dir) \
Expand Down
Loading