Skip to content

Commit 2285512

Browse files
rshestmeta-codesync[bot]
authored andcommitted
Explicit shutdown of TimerManager to ensure this is done on the main thread (#54625)
Summary: Pull Request resolved: #54625 # Changelog [Internal] - It makes sense to explicitly shut down TimerManager instance to make sure that this is done from the place and thread it's intended to - otherwise, since lifetime of TimerManager instance is managed by a shared pointer, this can lead to situations, whereas some other thread retains the shared pointer and calls the shut down at some later stage, which can lead to all kinds of unintended consequences. Reviewed By: Nurtau Differential Revision: D87631467 fbshipit-source-id: 206198ffd019b1d3edb4db557e67b22ca107757e
1 parent 33f783a commit 2285512

File tree

7 files changed

+33
-9
lines changed

7 files changed

+33
-9
lines changed

packages/react-native/ReactCommon/react/runtime/PlatformTimerRegistry.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class PlatformTimerRegistry {
2525
virtual void createRecurringTimer(uint32_t timerID, double delayMS) = 0;
2626

2727
virtual ~PlatformTimerRegistry() noexcept = default;
28+
29+
virtual void quit() {}
2830
};
2931

3032
using TimerManagerDelegate = PlatformTimerRegistry;

packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ ReactInstance::ReactInstance(
162162
runtimeScheduler->scheduleWork(std::move(callback));
163163
});
164164
}
165+
ReactInstance::~ReactInstance() noexcept {
166+
if (timerManager_ != nullptr) {
167+
timerManager_->quit();
168+
}
169+
}
165170

166171
void ReactInstance::unregisterFromInspector() {
167172
if (inspectorTarget_ != nullptr) {
@@ -184,8 +189,8 @@ RuntimeExecutor ReactInstance::getUnbufferedRuntimeExecutor() noexcept {
184189

185190
// This BufferedRuntimeExecutor ensures that the main JS bundle finished
186191
// execution before any JS queued into it from C++ are executed. Use
187-
// getUnbufferedRuntimeExecutor() instead if you do not need the main JS bundle
188-
// to have finished. e.g. setting global variables into JS runtime.
192+
// getUnbufferedRuntimeExecutor() instead if you do not need the main JS
193+
// bundle to have finished. e.g. setting global variables into JS runtime.
189194
RuntimeExecutor ReactInstance::getBufferedRuntimeExecutor() noexcept {
190195
return [weakBufferedRuntimeExecutor_ =
191196
std::weak_ptr<BufferedRuntimeExecutor>(bufferedRuntimeExecutor_)](
@@ -219,8 +224,8 @@ std::string simpleBasename(const std::string& path) {
219224
* Load the JS bundle and flush buffered JS calls, future JS calls won't be
220225
* buffered after calling this.
221226
* Note that this method is asynchronous. However, a completion callback
222-
* isn't needed because all calls into JS should be dispatched to the JSThread,
223-
* preferably via the runtimeExecutor_.
227+
* isn't needed because all calls into JS should be dispatched to the
228+
* JSThread, preferably via the runtimeExecutor_.
224229
*/
225230
void ReactInstance::loadScript(
226231
std::unique_ptr<const JSBigString> script,

packages/react-native/ReactCommon/react/runtime/ReactInstance.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate {
3131
JsErrorHandler::OnJsError onJsError,
3232
jsinspector_modern::HostTarget *parentInspectorTarget = nullptr);
3333

34+
~ReactInstance() noexcept;
35+
3436
RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept;
3537

3638
RuntimeExecutor getBufferedRuntimeExecutor() noexcept;

packages/react-native/ReactCommon/react/runtime/TimerManager.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ TimerManager::TimerManager(
5656
std::unique_ptr<PlatformTimerRegistry> platformTimerRegistry) noexcept
5757
: platformTimerRegistry_(std::move(platformTimerRegistry)) {}
5858

59+
TimerManager::~TimerManager() noexcept {
60+
quit();
61+
}
62+
63+
void TimerManager::quit() {
64+
if (platformTimerRegistry_ == nullptr) {
65+
return;
66+
}
67+
platformTimerRegistry_->quit();
68+
platformTimerRegistry_ = nullptr;
69+
}
70+
5971
void TimerManager::setRuntimeExecutor(
6072
RuntimeExecutor runtimeExecutor) noexcept {
6173
runtimeExecutor_ = std::move(runtimeExecutor);

packages/react-native/ReactCommon/react/runtime/TimerManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,16 @@ struct TimerCallback {
4646
class TimerManager {
4747
public:
4848
explicit TimerManager(std::unique_ptr<PlatformTimerRegistry> platformTimerRegistry) noexcept;
49+
~TimerManager() noexcept;
4950

5051
void setRuntimeExecutor(RuntimeExecutor runtimeExecutor) noexcept;
5152

5253
void callTimer(TimerHandle handle);
5354

5455
void attachGlobals(jsi::Runtime &runtime);
5556

57+
void quit();
58+
5659
private:
5760
TimerHandle createTimer(
5861
jsi::Function &&callback,

packages/react-native/ReactCxxPlatform/react/runtime/platform/cxx/react/runtime/PlatformTimerRegistryImpl.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
1212

1313
namespace facebook::react {
1414

15-
PlatformTimerRegistryImpl::~PlatformTimerRegistryImpl() noexcept {
16-
LOG(INFO)
17-
<< "PlatformTimerRegistryImpl::~PlatformTimerRegistryImpl() was called (address: "
18-
<< this << ").";
15+
void PlatformTimerRegistryImpl::quit() {
16+
LOG(INFO) << "Shutting down PlatformTimerRegistryImpl...";
1917
taskDispatchThread_.quit();
2018
std::lock_guard<std::mutex> guard(timersMutex_);
2119
timers_.clear();

packages/react-native/ReactCxxPlatform/react/runtime/platform/cxx/react/runtime/PlatformTimerRegistryImpl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class PlatformTimerRegistryImpl : public PlatformTimerRegistry {
2323
PlatformTimerRegistryImpl &operator=(const PlatformTimerRegistryImpl &) = delete;
2424
PlatformTimerRegistryImpl(PlatformTimerRegistryImpl &&) noexcept = delete;
2525
PlatformTimerRegistryImpl &operator=(PlatformTimerRegistryImpl &&) noexcept = delete;
26-
~PlatformTimerRegistryImpl() noexcept override;
26+
~PlatformTimerRegistryImpl() noexcept = default;
2727

2828
void createTimer(uint32_t timerId, double delayMs) override;
2929

@@ -33,6 +33,8 @@ class PlatformTimerRegistryImpl : public PlatformTimerRegistry {
3333

3434
void setTimerManager(std::weak_ptr<TimerManager> timerManager);
3535

36+
void quit() override;
37+
3638
private:
3739
struct Timer {
3840
uint32_t timerId{0};

0 commit comments

Comments
 (0)