Skip to content

Commit 6f3e0f9

Browse files
authored
fix(💣): fix race condition in RuntimeAwareCache (#3478)
1 parent 7f69729 commit 6f3e0f9

File tree

1 file changed

+27
-12
lines changed

1 file changed

+27
-12
lines changed

‎packages/skia/cpp/jsi/RuntimeLifecycleMonitor.cpp‎

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "RuntimeLifecycleMonitor.h"
22

3+
#include <mutex>
34
#include <unordered_map>
45
#include <unordered_set>
56
#include <utility>
@@ -9,25 +10,43 @@ namespace RNJsi {
910
static std::unordered_map<jsi::Runtime *,
1011
std::unordered_set<RuntimeLifecycleListener *>>
1112
listeners;
13+
static std::mutex listenersMutex;
1214

1315
struct RuntimeLifecycleMonitorObject : public jsi::HostObject {
1416
jsi::Runtime *_rt;
1517
explicit RuntimeLifecycleMonitorObject(jsi::Runtime *rt) : _rt(rt) {}
1618
~RuntimeLifecycleMonitorObject() {
17-
auto listenersSet = listeners.find(_rt);
18-
if (listenersSet != listeners.end()) {
19-
for (auto listener : listenersSet->second) {
20-
listener->onRuntimeDestroyed(_rt);
19+
std::unordered_set<RuntimeLifecycleListener *> listenersCopy;
20+
{
21+
std::lock_guard<std::mutex> lock(listenersMutex);
22+
auto listenersSet = listeners.find(_rt);
23+
if (listenersSet != listeners.end()) {
24+
listenersCopy = listenersSet->second;
25+
listeners.erase(listenersSet);
2126
}
22-
listeners.erase(listenersSet);
27+
}
28+
for (auto listener : listenersCopy) {
29+
listener->onRuntimeDestroyed(_rt);
2330
}
2431
}
2532
};
2633

2734
void RuntimeLifecycleMonitor::addListener(jsi::Runtime &rt,
2835
RuntimeLifecycleListener *listener) {
29-
auto listenersSet = listeners.find(&rt);
30-
if (listenersSet == listeners.end()) {
36+
bool shouldInstallMonitor = false;
37+
{
38+
std::lock_guard<std::mutex> lock(listenersMutex);
39+
auto listenersSet = listeners.find(&rt);
40+
if (listenersSet == listeners.end()) {
41+
std::unordered_set<RuntimeLifecycleListener *> newSet;
42+
newSet.insert(listener);
43+
listeners.emplace(&rt, std::move(newSet));
44+
shouldInstallMonitor = true;
45+
} else {
46+
listenersSet->second.insert(listener);
47+
}
48+
}
49+
if (shouldInstallMonitor) {
3150
// We install a global host object in the provided runtime, this way we can
3251
// use that host object destructor to get notified when the runtime is being
3352
// terminated. We use a unique name for the object as it gets saved with the
@@ -36,16 +55,12 @@ void RuntimeLifecycleMonitor::addListener(jsi::Runtime &rt,
3655
rt, "__rnskia_rt_lifecycle_monitor",
3756
jsi::Object::createFromHostObject(
3857
rt, std::make_shared<RuntimeLifecycleMonitorObject>(&rt)));
39-
std::unordered_set<RuntimeLifecycleListener *> newSet;
40-
newSet.insert(listener);
41-
listeners.emplace(&rt, std::move(newSet));
42-
} else {
43-
listenersSet->second.insert(listener);
4458
}
4559
}
4660

4761
void RuntimeLifecycleMonitor::removeListener(
4862
jsi::Runtime &rt, RuntimeLifecycleListener *listener) {
63+
std::lock_guard<std::mutex> lock(listenersMutex);
4964
auto listenersSet = listeners.find(&rt);
5065
if (listenersSet == listeners.end()) {
5166
// nothing to do here

0 commit comments

Comments
 (0)