Repository navigation
worker: refactor thread life cycle management #26099
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
The current mechanism of uses two async handles, one owned by the creator of the worker thread to terminate a running worker, and another one employed by the worker to interrupt its creator on its natural termination. The force termination piggybacks on the message- passing mechanism to inform the worker to quiesce. Also there are few flags that represent the other thread's state / request state because certain code path is shared by multiple control flows, and there are certain code path where the async handles may not have come to life. Refactor into a LoopStopper abstraction that exposes routines to install a handle as well as to save a state. Refs: #21283
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,14 +3,35 @@ | |
|
|
||
| #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | ||
|
|
||
| #include "node_messaging.h" | ||
| #include <unordered_map> | ||
| #include "node_messaging.h" | ||
| #include "uv.h" | ||
|
|
||
| namespace node { | ||
| namespace worker { | ||
|
|
||
| class WorkerThreadData; | ||
|
|
||
| class AsyncRequest : public MemoryRetainer { | ||
| public: | ||
| AsyncRequest() : stop_(true) {} | ||
| void Install(Environment* env, void* data, uv_async_cb target); | ||
| void Uninstall(); | ||
| void Stop(); | ||
| void SetStopped(bool flag); | ||
| bool IsStopped(); | ||
|
gireeshpunathil marked this conversation as resolved.
Outdated
|
||
| uv_async_t* GetHandle(); | ||
| void MemoryInfo(MemoryTracker* tracker) const override; | ||
| SET_MEMORY_INFO_NAME(AsyncRequest) | ||
| SET_SELF_SIZE(AsyncRequest) | ||
|
|
||
| private: | ||
| Environment* env_; | ||
| uv_async_t* async_ = nullptr; | ||
| mutable Mutex mutex_; | ||
| bool stop_ = true; | ||
| }; | ||
|
addaleax marked this conversation as resolved.
Outdated
|
||
|
|
||
| // A worker thread, as represented in its parent thread. | ||
| class Worker : public AsyncWrap { | ||
| public: | ||
|
|
@@ -34,14 +55,13 @@ class Worker : public AsyncWrap { | |
| tracker->TrackFieldWithSize( | ||
| "isolate_data", sizeof(IsolateData), "IsolateData"); | ||
| tracker->TrackFieldWithSize("env", sizeof(Environment), "Environment"); | ||
| tracker->TrackField("thread_exit_async", *thread_exit_async_); | ||
|
addaleax marked this conversation as resolved.
Outdated
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We’re not tracking the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you mean - the one represented by
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Neither Also, side note: I’m just noticing that we have the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, I don't understand. void AsyncRequest::MemoryInfo(MemoryTracker* tracker) const {
Mutex::ScopedLock lock(mutex_);
if (async_ != nullptr) tracker->TrackField("async_request", *async_);
}Isn't it enough? I hope we don't need multiple trackers for the same allocation? For the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gireeshpunathil The problem is that the memory tracker doesn’t know that it should call
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gireeshpunathil Should we change this PR to use
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| tracker->TrackField("parent_port", parent_port_); | ||
| } | ||
|
|
||
| SET_MEMORY_INFO_NAME(Worker) | ||
| SET_SELF_SIZE(Worker) | ||
|
|
||
| bool is_stopped() const; | ||
| bool is_stopped(); | ||
|
|
||
| static void New(const v8::FunctionCallbackInfo<v8::Value>& args); | ||
| static void StartThread(const v8::FunctionCallbackInfo<v8::Value>& args); | ||
|
|
@@ -67,16 +87,6 @@ class Worker : public AsyncWrap { | |
| // This mutex protects access to all variables listed below it. | ||
| mutable Mutex mutex_; | ||
|
|
||
| // Currently only used for telling the parent thread that the child | ||
| // thread exited. | ||
| std::unique_ptr<uv_async_t> thread_exit_async_; | ||
| bool scheduled_on_thread_stopped_ = false; | ||
|
|
||
| // This mutex only protects stopped_. If both locks are acquired, this needs | ||
| // to be the latter one. | ||
| mutable Mutex stopped_mutex_; | ||
| bool stopped_ = true; | ||
|
|
||
| bool thread_joined_ = true; | ||
| int exit_code_ = 0; | ||
| uint64_t thread_id_ = -1; | ||
|
|
@@ -96,6 +106,9 @@ class Worker : public AsyncWrap { | |
| // instance refers to it via its [kPort] property. | ||
| MessagePort* parent_port_ = nullptr; | ||
|
|
||
| AsyncRequest thread_stopper_; | ||
| AsyncRequest on_thread_finished_; | ||
|
|
||
| friend class WorkerThreadData; | ||
| }; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.