-
Notifications
You must be signed in to change notification settings - Fork 5
src: add AddCodeEventHook API for code events #327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: node-v22.x-nsolid-v5.x
Are you sure you want to change the base?
Conversation
WalkthroughThis change introduces a new infrastructure for registering and handling code event hooks in the NSolid runtime. It adds new source and header files for a code event handler, updates build configuration, extends core classes to support asynchronous code event dispatching, and provides a public API for registering hooks. Comprehensive tests and a Node.js addon are included to validate and expose the feature. Changes
Sequence Diagram(s)sequenceDiagram
participant JS as JavaScript
participant Addon as Native Addon
participant NSolid as NSolid Runtime
participant EnvList as EnvList
participant EnvInst as EnvInst
participant Handler as NSolidCodeEventHandler
JS->>Addon: registerCodeEventHook(callback)
Addon->>NSolid: AddCodeEventHook(cb, data)
NSolid->>EnvList: AddCodeEventHook(cb, data)
EnvList->>EnvInst: setup_code_event_handler()
EnvInst->>Handler: (creates NSolidCodeEventHandler)
Handler-->>Handler: (V8 triggers code event)
Handler->>EnvList: on_code_event_q_.enqueue(CodeEventInfo)
EnvList->>Addon: got_code_event(CodeEventInfo)
Addon->>JS: callback(functionName, threadId)
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new API for registering and handling code event hooks in nsolid, along with several infrastructure updates to support asynchronous code event callbacks. Key changes include:
- New TSList APIs to iterate with size parameters and return updated list sizes on erasure.
- Integration of code event hook registration/handling in both C++ (nsolid APIs, code event handler, and event dispatching) and JavaScript (addon tests).
- Updates to binding, build files, and API header modifications to support code event hooks.
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
test/cctest/test_nsolid_thread_safe.cc | Added tests for new TSList for_each and erase APIs. |
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js | Added tests for the new code event hook API in a multi-threaded context. |
test/addons/nsolid-code-event-hook/binding.gyp | Added binding definition for the new addon. |
test/addons/nsolid-code-event-hook/binding.cc | Implemented code event callback and hook registration logic in C++. |
src/nsolid/thread_safe.h | Added for_each overload and modified erase to return updated list size. |
src/nsolid/nsolid_code_event_handler.h & .cc | Introduced the NSolidCodeEventHandler for handling code events. |
src/nsolid/nsolid_api.h & .cc | Updated API to include code event handler setup and hook management. |
src/nsolid/nsolid.cc | Added CodeEventHook implementation and adjustments to hook lifecycle. |
node.gyp | Updated build configuration to include the new code event handler module. |
Comments suppressed due to low confidence (2)
src/nsolid/nsolid.cc:625
- Calling 'delete this;' in CodeEventHook::Dispose can be error-prone if not handled carefully. Consider clarifying the ownership semantics in documentation or refactoring to use a smart pointer based approach to avoid potential misuse.
delete this;
src/nsolid/nsolid_api.cc:1984
- The conditional use of 'std::move(info)' when size equals 1 versus passing by value when multiple hooks are present could lead to inconsistent data ownership. Consider using a consistent strategy when dispatching CodeEventInfo to hooks to avoid potential issues with moved-from objects.
code_event_hook_list_.for_each([&info, &envinst_sp](auto& stor, size_t size) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 file skipped due to size limits:
- src/nsolid/nsolid_api.cc
💡 To request another review, post a new comment with "/windsurf-review".
~Impl() { | ||
// Remove the hook from the TSList in EnvList | ||
EnvList::Inst()->RemoveCodeEventHook(hook_); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The destructor of CodeEventHook::Impl
unconditionally calls EnvList::Inst()->RemoveCodeEventHook(hook_)
, but there's no check if hook_
is a valid iterator. If Setup()
fails or is never called, this could lead to undefined behavior when removing an invalid iterator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cannot ever happen afaict
CodeEventHook* add_code_event_hook_(void* data, | ||
code_event_hook_proxy_sig proxy, | ||
deleter_sig deleter) { | ||
CodeEventHook* hook = new (std::nothrow) CodeEventHook(); | ||
if (hook == nullptr) { | ||
return nullptr; | ||
} | ||
hook->DoSetup(proxy, deleter, data); | ||
return hook; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The add_code_event_hook_
function allocates a CodeEventHook
with new
but doesn't check if DoSetup()
might fail. If DoSetup()
fails, the function would still return a partially initialized hook object that could cause issues when used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DoSetup cannot fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
🧹 Nitpick comments (10)
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js (1)
1-1
: Remove redundant 'use strict' directive.The static analysis tool correctly identifies that the 'use strict' directive is redundant since JavaScript modules are automatically in strict mode.
-'use strict';
🧰 Tools
🪛 Biome (1.9.4)
[error] 1-1: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.(lint/suspicious/noRedundantUseStrict)
src/nsolid.cc (2)
625-627
: Document the ownership model forDispose()
.The
Dispose()
method deletes the object itself (delete this
), which requires careful documentation about ownership transfer and usage patterns to prevent use-after-free errors.Consider adding a comment to clarify the ownership model:
void CodeEventHook::Dispose() { + // This method transfers ownership to the callee and deletes the object. + // The caller must not use this object after calling Dispose(). delete this; }
674-683
: Consider using exceptions or error codes for allocation failures.The function returns
nullptr
on allocation failure, but the caller might not check for this condition.Consider either:
- Using exceptions (if allowed in the codebase)
- Adding an error code parameter
- At minimum, documenting the nullptr return value in the header file
Current implementation is acceptable if callers are expected to check for nullptr.
src/nsolid/nsolid_api.cc (3)
891-898
: Async queue lambda capturesinfo
by forwarding-reference – use const ref
CodeEventInfo
can potentially be large. The lambda already moves it when
delivering, so capturing by forwarding ref (&&
) brings no extra value and
may lead to a double move/invalid use if extended.- +[](CodeEventInfo&& info, EnvList* envlist) { - envlist->got_code_event(std::move(info)); + +[](CodeEventInfo info, EnvList* envlist) { + envlist->got_code_event(std::move(info)); },A plain pass-by-value here is cheaper and clearer.
1033-1056
: Minor: potential redundant map copy during last-hook removalWhen the last hook is removed we copy
env_map_
even if it is already empty.
A quick guard can avoid unnecessary work in the common “no envs” case:if (size == 0) { decltype(env_map_) env_map; { ns_mutex::scoped_lock lock(map_lock_); if (env_map_.empty()) return; env_map = env_map_; } ... }
1498-1508
:DCHECK_EQ
may fire if invoked via EventLoop command
setup_code_event_handler()
is scheduled withCommandType::InterruptOnly
which is executed inside V8’s interrupt callback. At that point
Isolate::TryGetCurrent()
can legitimately return the same isolate but on a
different native thread (depending on how interrupts are delivered). Consider
removing or downgrading theDCHECK_EQ
to avoid false positives in RELEASE +
NODE_DEBUG
builds.src/nsolid.h (2)
660-672
: Consider making the struct fields const where appropriate.Since
CodeEventInfo
is likely used to pass immutable event data to callbacks, consider making appropriate fieldsconst
to prevent accidental modification:struct CodeEventInfo { - uint64_t thread_id; - uint64_t timestamp; - v8::CodeEventType type; - uintptr_t code_start; - uintptr_t new_code_start; - size_t code_len; - std::string fn_name; - std::string script_name; - int script_line; - int script_column; - std::string comment; + const uint64_t thread_id; + const uint64_t timestamp; + const v8::CodeEventType type; + const uintptr_t code_start; + const uintptr_t new_code_start; + const size_t code_len; + const std::string fn_name; + const std::string script_name; + const int script_line; + const int script_column; + const std::string comment; };
679-686
: Add documentation for theDispose()
method lifecycle.While the brief describes that
Dispose()
removes the hook and releases resources, it would be helpful to document whether:
- The method is idempotent (can be called multiple times safely)
- The method blocks until any in-progress callbacks complete
- The object becomes invalid immediately after calling
Dispose()
src/nsolid/nsolid_api.h (2)
248-250
: Consider adding documentation for the new methods.These methods are part of the public interface of
EnvInst
. Consider adding documentation to explain:
- When these methods should be called
- Thread safety guarantees
- Any preconditions or postconditions
653-653
: Consider documenting the threading model for code event dispatch.The method
got_code_event
takes an rvalue reference, suggesting it's designed for efficient event forwarding. Document:
- Which thread(s) call this method
- How it interacts with the async queue
- Performance considerations
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
node.gyp
(1 hunks)src/nsolid.cc
(2 hunks)src/nsolid.h
(7 hunks)src/nsolid/nsolid_api.cc
(8 hunks)src/nsolid/nsolid_api.h
(11 hunks)src/nsolid/nsolid_code_event_handler.cc
(1 hunks)src/nsolid/nsolid_code_event_handler.h
(1 hunks)src/nsolid/thread_safe.h
(2 hunks)test/addons/nsolid-code-event-hook/binding.cc
(1 hunks)test/addons/nsolid-code-event-hook/binding.gyp
(1 hunks)test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js
(1 hunks)test/cctest/test_nsolid_thread_safe.cc
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js (1)
test/common/index.js (1)
buildType
(155-157)
src/nsolid/nsolid_code_event_handler.cc (3)
src/nsolid/nsolid_code_event_handler.h (3)
NSolidCodeEventHandler
(14-14)NSolidCodeEventHandler
(15-15)code_event
(17-17)src/util.h (1)
Utf8Value
(548-548)src/nsolid/nsolid_api.cc (2)
Inst
(914-917)Inst
(914-914)
test/addons/nsolid-code-event-hook/binding.cc (3)
src/nsolid.cc (10)
CodeEventHook
(620-621)CodeEventHook
(623-623)cb
(610-615)cb
(610-612)GetThreadId
(56-64)GetThreadId
(56-56)GetLocalEnvInst
(43-45)GetLocalEnvInst
(43-43)GetLocalEnvInst
(47-49)GetLocalEnvInst
(47-47)src/nsolid.h (14)
CodeEventHook
(679-702)CodeEventHook
(690-690)CodeEventHook
(693-693)RunCommand
(523-526)RunCommand
(1602-1626)RunCommand
(1602-1605)cb
(658-658)thread_id
(852-852)thread_id
(852-852)GetThreadId
(404-404)GetLocalEnvInst
(385-385)GetLocalEnvInst
(391-391)AddCodeEventHook
(1842-1860)AddCodeEventHook
(1842-1842)src/nsolid/nsolid_api.cc (8)
RunCommand
(157-202)RunCommand
(157-160)GetCurrent
(433-436)GetCurrent
(433-433)GetCurrent
(439-442)GetCurrent
(439-439)AddCodeEventHook
(1007-1031)AddCodeEventHook
(1007-1010)
src/nsolid/nsolid_api.cc (3)
src/nsolid/nsolid_api.h (23)
data
(80-80)data
(81-81)data
(515-518)data
(520-523)data
(525-528)data
(529-532)data
(539-542)data
(544-546)envinst
(340-341)envinst
(342-343)envinst
(344-345)envinst
(346-347)it
(547-547)it
(620-620)envinst_sp
(195-198)envinst_sp
(334-335)envinst_sp
(662-662)envinst_sp
(670-670)envinst_sp
(671-671)envinst_sp
(672-672)envinst_sp
(674-674)envinst_sp
(678-678)envinst_sp
(679-679)src/nsolid.h (5)
AddCodeEventHook
(1842-1860)AddCodeEventHook
(1842-1842)RunCommand
(523-526)RunCommand
(1602-1626)RunCommand
(1602-1605)src/nsolid.cc (2)
deleter
(463-463)deleter
(611-611)
🪛 Biome (1.9.4)
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js
[error] 1-1: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.
(lint/suspicious/noRedundantUseStrict)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: test-linux (ubuntu-24.04-arm)
- GitHub Check: test-linux (ubuntu-24.04)
- GitHub Check: test-macOS
- GitHub Check: coverage-windows
- GitHub Check: build-docs
- GitHub Check: coverage-linux-without-intl
- GitHub Check: coverage-linux
- GitHub Check: lint-js-and-md
- GitHub Check: lint-cpp
- GitHub Check: build-tarball
🔇 Additional comments (25)
src/nsolid/thread_safe.h (4)
149-155
: LGTM! Well-designed enhancement for thread-safe iteration with size awareness.The new
for_each
overload that provides the current list size to the callback is a thoughtful addition. Capturing the size once before iteration ensures consistency throughout the callback execution, which is crucial for the code event hook infrastructure.
156-160
: Excellent improvement to return the new size after element removal.Returning the updated list size from the
erase
method provides valuable feedback for managing hook lifecycles and is more informative than the previousvoid
return type.
189-195
: Consistent implementation in the pointer specialization.The changes are properly mirrored in the pointer template specialization, maintaining API consistency across both variants of TSList.
196-200
: Good consistency in the pointer specialization's erase method.The pointer specialization correctly returns the new size after erasure, maintaining consistency with the main template implementation.
test/addons/nsolid-code-event-hook/binding.gyp (1)
1-9
: Clean and correct build configuration for the test addon.The binding.gyp file follows standard node-gyp conventions with appropriate debug symbols enabled for testing. The configuration correctly references the binding.cc source file and establishes the "binding" target.
node.gyp (1)
517-517
: Proper integration of the new code event handler into the build system.The source file is correctly added to the
nsolid_sources
list, following the established pattern for NSolid components and maintaining consistency with the directory structure.src/nsolid/nsolid_code_event_handler.h (1)
1-28
: Excellent design for the NSolid code event handler.This header file demonstrates several best practices:
- Proper header guards and conditional compilation for internal use only
- Clean inheritance from
v8::CodeEventHandler
with appropriate method override- Virtual destructor following best practices for polymorphic base classes
- Well-designed constructor taking necessary context (isolate and thread ID)
- Clear separation between public interface and private implementation details
The design properly encapsulates the functionality needed for capturing and processing V8 code events within the NSolid framework.
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js (1)
3-91
: Comprehensive and well-structured test for code event hooks.This test provides excellent coverage of the code event hook functionality:
- Thorough testing scope: Tests registration, callback invocation, selective unregistration, and complete cleanup
- Thread-aware testing: Uses worker threads to verify thread-specific hook behavior and thread ID correctness
- State management: Proper state tracking and reset mechanisms for reliable test execution
- Asynchronous handling: Appropriate use of setTimeout for asynchronous event testing
- Robust assertions: Verifies both positive cases (hooks firing) and negative cases (hooks not firing after unregistration)
The test design effectively validates the entire lifecycle of code event hooks and ensures proper isolation between different hook instances.
src/nsolid/nsolid_code_event_handler.cc (2)
1-39
: LGTM! Clean implementation of the code event handler.The implementation correctly:
- Inherits from
v8::CodeEventHandler
and overrides theHandle
method- Extracts all relevant information from the
CodeEvent
object- Creates a well-structured
CodeEventInfo
with proper move semantics- Enqueues the event for asynchronous processing
34-34
:✅ Verification successful
Verify that
GetComment()
never returns null.The code directly passes the result of
code_event->GetComment()
tostd::string
constructor. IfGetComment()
can return a null pointer, this would cause undefined behavior.
🏁 Script executed:
#!/bin/bash # Check the V8 header files or documentation for GetComment() behavior rg -A 5 "GetComment" --glob "*.h" --glob "*.cc" deps/v8Length of output: 5140
Confirmed
GetComment()
always returns a non-null C-stringV8’s own code and tests assume it never yields a null pointer:
In deps/v8/src/api/api.cc:
const char* CodeEvent::GetComment() { return reinterpret_cast<i::CodeEvent*>(this)->comment; }The internal
comment
field is always initialized to point at a valid string (empty or otherwise).In deps/v8/src/codegen/code-comments.cc:
const char* CodeCommentsIterator::GetComment() const { const char* comment_string = …; CHECK_EQ(GetCommentSize(), strlen(comment_string) + 1); return comment_string; }The
CHECK_EQ
guaranteescomment_string
is non-null and null-terminated.V8 unit tests (e.g. logging/log-unittest.cc) call
std::string(code_event->GetComment())
without guarding against null, and would crash ifGetComment()
could ever return nullptr.No defensive null check is needed before constructing
std::string
fromGetComment()
.test/cctest/test_nsolid_thread_safe.cc (2)
53-72
: Well-structured test for the enhancedfor_each
method.The test properly verifies that:
- The callback receives both the value and the current list size
- The size remains consistent (3) during iteration
- Values are visited in the expected order
74-83
: Good test coverage for theerase
method returning size.The test correctly verifies that
erase
returns the updated list size after each removal.src/nsolid.cc (1)
600-618
: Clean implementation of the CodeEventHook internal management.The
Impl
class properly encapsulates the hook lifecycle:
- Adds the hook to
EnvList
on setup- Removes it on destruction
- Follows RAII principles
src/nsolid/nsolid_api.cc (2)
1120-1123
: Dependent on previous fix – keep eye on enable logicThis check is correct only when the race in
AddCodeEventHook()
is fixed.
Otherwisesize()
could still be zero here and the handler would never be
enabled for this environment.
844-852
: 🛠️ Refactor suggestion
EnvInst::setup_code_event_handler()
leaks the old handler on re-enableIf a handler was created previously and
Disable()
was called,code_event_handler_
still holds the (disabled) instance.
Callingsetup_code_event_handler()
again will therefore not create a fresh handler nor re-enable the old one.void EnvInst::setup_code_event_handler() { - if (!code_event_handler_) { - code_event_handler_ = - std::make_unique<NSolidCodeEventHandler>(isolate_, thread_id_); - } - - code_event_handler_->Enable(); + if (!code_event_handler_) + code_event_handler_ = + std::make_unique<NSolidCodeEventHandler>(isolate_, thread_id_); + + code_event_handler_->Enable(); // idempotent – safe to call twice }Consider resetting the unique-ptr in
disable_code_event_handler()
(see next comment) so that a brand-new handler is constructed next time, avoiding surprises caused by a lingering disabled instance.Likely an incorrect or invalid review comment.
src/nsolid.h (5)
290-290
: LGTM!The function pointer signature is correctly defined to handle code events with the appropriate parameters.
320-320
: LGTM!The proxy function declaration follows the established pattern for other hook proxies in the codebase.
356-358
: LGTM!The internal function declaration correctly returns a
CodeEventHook*
and takes the necessary parameters for hook registration.
691-692
: LGTM!The friend declaration is necessary to allow the internal function to construct
CodeEventHook
objects while keeping the constructor private.
1930-1935
: LGTM!The proxy implementation correctly moves the
CodeEventInfo
to avoid unnecessary copying of the potentially large struct.src/nsolid/nsolid_api.h (5)
21-21
: LGTM!The include is necessary for the new async queue functionality used for code event dispatching.
427-427
: LGTM!The unique pointer correctly manages the lifetime of the code event handler.
504-507
: LGTM!The struct follows the established pattern for hook storage with proper callback and user data management.
757-758
: LGTM!The async queue and hook list are appropriately placed for managing code event distribution to registered hooks.
544-547
:✅ Verification successful
Verify thread safety of the hook list operations.
The methods operate on
TSList
which should be thread-safe based on the naming convention. However, ensure that the iterator returned byAddCodeEventHook
remains valid across concurrent operations.
🏁 Script executed:
#!/bin/bash # Check TSList implementation for thread safety guarantees rg -A 10 "class TSList" src/nsolid/thread_safe.hLength of output: 50
We need to locate the
TSList
definition to verify its thread-safety guarantees. Let’s search the entire repository:
🏁 Script executed:
#!/bin/bash # Search for TSList class definition and usages across the repo rg -n "class TSList" -n . rg -n "TSList<" -n .Length of output: 2633
Continuing verification: locate the full
TSList
implementation to confirm iterator safety.Adjust search if needed based on the results.
🏁 Script executed:
#!/bin/bash # Show TSList implementation around its declaration rg -n -A20 -B5 "struct TSList<DataType\*>" src/nsolid/thread_safe.hLength of output: 918
Continuing verification: extract the full
TSList<DataType*>
specialization (including anyerase
/remove
methods) to confirm that all list operations are mutex-protected.
🏁 Script executed:
#!/bin/bash # Print lines 170–350 of thread_safe.h to capture the entire TSList<DataType*> block sed -n '170,350p' src/nsolid/thread_safe.hLength of output: 1235
Thread safety and iterator validity confirmed
The
TSList<DataType*>
specialization insrc/nsolid/thread_safe.h
uses a singlensuv::ns_mutex
to guard allpush_back
,erase
,size
, andfor_each
operations.
push_back
acquires the lock, appends the element, and returns astd::list
iterator. According to C++ guarantees forstd::list
, this iterator remains valid across subsequent insertions.- Only calling
erase(iterator)
(i.e. viaRemoveCodeEventHook
) will invalidate that specific iterator—this matches the intended removal semantics.No further changes are required.
envlist->on_code_event_q_.reset(); | ||
if (envlist->continuous_profiler_) { | ||
envlist->continuous_profiler_.reset(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Queue reset before drain – possible event drop
on_code_event_q_.reset()
is called unconditionally during shutdown. If
there are still pending code events they will be destroyed silently, skipping
user hooks and making debugging harder.
Consider:
- Draining the queue synchronously (
dequeue
until empty) before reset. - Or calling
reset()
after confirmingthread_loop_
has stopped
processing callbacks.
🤖 Prompt for AI Agents
In src/nsolid/nsolid_api.cc around lines 1712 to 1716, the on_code_event_q_
queue is reset unconditionally during shutdown, which can cause pending code
events to be dropped silently. To fix this, modify the shutdown sequence to
first drain the queue synchronously by dequeuing all events until it is empty
before calling reset(), or ensure that thread_loop_ has fully stopped processing
callbacks before resetting the queue. This prevents loss of events and ensures
user hooks are executed properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is relevant once EnvList is gone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@santigimeno, understood! If EnvList is planned to be removed in future refactoring, then improving the queue draining behavior in the current implementation wouldn't provide much value. Thanks for the clarification on the architectural direction.
Adds a for_each method to TSList that passes the current list size and item to the callback. Updates erase to return the new size after removal. These changes improve thread-safe iteration and management of hooks.
62ac188
to
ba37b75
Compare
Introduces a new API to register code event hooks in nsolid. This includes new handler classes, queueing, and infrastructure to allow extensible code event observation and callbacks.
ba37b75
to
16f39c0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
test/addons/nsolid-code-event-hook/binding.cc (1)
53-58
:⚠️ Potential issueAdd error handling for V8 operations.
The code uses
ToLocalChecked()
without error handling, which will crash the process if the operations fail.- Local<Value> argv[2] = { - String::NewFromUtf8(isolate, info.fn_name.c_str()).ToLocalChecked(), - Number::New(isolate, info.thread_id), - }; - // Call the callback in the current context - cb->Call(isolate->GetCurrentContext(), - Undefined(isolate), 2, argv).ToLocalChecked(); + v8::TryCatch try_catch(isolate); + Local<String> fn_name; + if (!String::NewFromUtf8(isolate, info.fn_name.c_str()).ToLocal(&fn_name)) { + // Handle string creation failure + return; + } + Local<Value> argv[2] = { + fn_name, + Number::New(isolate, info.thread_id), + }; + // Call the callback in the current context + Local<Value> ret; + if (!cb->Call(isolate->GetCurrentContext(), + Undefined(isolate), 2, argv).ToLocal(&ret)) { + // Handle exception if needed + if (try_catch.HasCaught()) { + try_catch.ReThrow(); + } + }
🧹 Nitpick comments (3)
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js (3)
1-1
: Remove redundant 'use strict' directive.JavaScript modules are automatically in strict mode.
-'use strict'; -🧰 Tools
🪛 Biome (1.9.4)
[error] 1-1: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.(lint/suspicious/noRedundantUseStrict)
9-10
: Improve thread check readability.The condition is checking if the process is a worker thread but not launched with the correct PID argument.
-if (!isMainThread && +process.argv[2] !== process.pid) +// Skip if this is a worker thread that wasn't launched by the main test +if (!isMainThread && +process.argv[2] !== process.pid)
46-73
: Consider making the test more deterministic.The test uses multiple fixed 500ms timeouts which could lead to flaky tests on heavily loaded systems. Consider using a more deterministic approach.
Would you like me to suggest an implementation using promises or event-based synchronization instead of fixed timeouts to make the test more reliable?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
node.gyp
(1 hunks)src/nsolid.cc
(2 hunks)src/nsolid.h
(7 hunks)src/nsolid/nsolid_api.cc
(8 hunks)src/nsolid/nsolid_api.h
(11 hunks)src/nsolid/nsolid_code_event_handler.cc
(1 hunks)src/nsolid/nsolid_code_event_handler.h
(1 hunks)src/nsolid/thread_safe.h
(2 hunks)test/addons/nsolid-code-event-hook/binding.cc
(1 hunks)test/addons/nsolid-code-event-hook/binding.gyp
(1 hunks)test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js
(1 hunks)test/cctest/test_nsolid_thread_safe.cc
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
- test/addons/nsolid-code-event-hook/binding.gyp
- node.gyp
- src/nsolid/nsolid_code_event_handler.cc
- src/nsolid/nsolid_code_event_handler.h
- src/nsolid/thread_safe.h
- test/cctest/test_nsolid_thread_safe.cc
- src/nsolid.cc
- src/nsolid/nsolid_api.cc
- src/nsolid.h
- src/nsolid/nsolid_api.h
🧰 Additional context used
🧠 Learnings (1)
test/addons/nsolid-code-event-hook/binding.cc (1)
Learnt from: santigimeno
PR: nodesource/nsolid#327
File: test/addons/nsolid-code-event-hook/binding.cc:64-78
Timestamp: 2025-06-10T09:52:49.401Z
Learning: In the nsolid codebase, test files in test/addons/ consistently use assert() for input validation and runtime checks, not CHECK() macros. This is the established testing convention.
🧬 Code Graph Analysis (2)
test/addons/nsolid-code-event-hook/binding.cc (4)
src/nsolid.cc (12)
CodeEventHook
(620-621)CodeEventHook
(623-623)cb
(610-615)cb
(610-612)GetThreadId
(56-64)GetThreadId
(56-56)GetLocalEnvInst
(43-45)GetLocalEnvInst
(43-43)GetLocalEnvInst
(47-49)GetLocalEnvInst
(47-47)IsMainThread
(91-96)IsMainThread
(91-91)src/nsolid.h (15)
CodeEventHook
(679-702)CodeEventHook
(690-690)CodeEventHook
(693-693)RunCommand
(523-526)RunCommand
(1602-1626)RunCommand
(1602-1605)cb
(658-658)thread_id
(852-852)thread_id
(852-852)GetThreadId
(404-404)GetLocalEnvInst
(385-385)GetLocalEnvInst
(391-391)AddCodeEventHook
(1842-1860)AddCodeEventHook
(1842-1842)IsMainThread
(426-426)src/nsolid/nsolid_api.cc (8)
RunCommand
(157-202)RunCommand
(157-160)GetCurrent
(433-436)GetCurrent
(433-433)GetCurrent
(439-442)GetCurrent
(439-439)AddCodeEventHook
(1002-1028)AddCodeEventHook
(1002-1005)test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js (1)
assert
(4-4)
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js (1)
test/common/index.js (1)
buildType
(155-157)
🪛 Biome (1.9.4)
test/addons/nsolid-code-event-hook/nsolid-code-event-hook.js
[error] 1-1: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.
(lint/suspicious/noRedundantUseStrict)
⏰ Context from checks skipped due to timeout of 90000ms (7)
- GitHub Check: test-tarball-linux
- GitHub Check: test-linux (ubuntu-24.04)
- GitHub Check: test-linux (ubuntu-24.04-arm)
- GitHub Check: test-macOS
- GitHub Check: coverage-linux-without-intl
- GitHub Check: coverage-linux
- GitHub Check: coverage-windows
🔇 Additional comments (1)
test/addons/nsolid-code-event-hook/binding.cc (1)
38-61
:⚠️ Potential issueAdd thread safety for js_callback_per_thread access.
The
CodeEventCallback
function accessesholder->js_callback_per_thread
without holding the mutex, whileRegisterJSCodeEventCallback
modifies it under the mutex lock. This creates a potential data race.Since the map access happens in a lambda that runs on the event loop, you need to ensure thread-safe access:
void CodeEventCallback(std::shared_ptr<node::nsolid::EnvInst> envinst, const node::nsolid::CodeEventInfo& info, HookHolder* holder) { assert(0 == node::nsolid::RunCommand( envinst, node::nsolid::CommandType::EventLoop, [holder](node::nsolid::SharedEnvInst envinst, const node::nsolid::CodeEventInfo& info) { + nsuv::ns_mutex::scoped_lock lock(hooks_mutex_); // Call JS callback with function name if (!holder->js_callback_per_thread[info.thread_id].IsEmpty()) { Isolate* isolate = Isolate::GetCurrent(); v8::HandleScope scope(isolate); Local<Function> cb = holder->js_callback_per_thread[info.thread_id].Get(isolate); + lock.unlock(); // Release lock before calling JS Local<Value> argv[2] = { String::NewFromUtf8(isolate, info.fn_name.c_str()).ToLocalChecked(), Number::New(isolate, info.thread_id), }; // Call the callback in the current context cb->Call(isolate->GetCurrentContext(), Undefined(isolate), 2, argv).ToLocalChecked(); } }, info)); }Likely an incorrect or invalid review comment.
Introduces a new API to register code event hooks in nsolid. This
includes new handler classes, queueing, and infrastructure to allow
extensible code event observation and callbacks.
Also:
Fixes: https://github.com/nodesource/ebpf-roadmap/issues/7
Summary by CodeRabbit
New Features
Bug Fixes
Tests