Skip to content

Commit a1bfb28

Browse files
davidaureliofacebook-github-bot
authored andcommitted
Use atomic list for event subscribers
Summary: Replace the *copy on write* vector with an atomic pointer to a linked list. This allows to publish without locking a mutex, at the cost of the slower traversal of a linked list (a vector has better locality). At the moment, the typical use case is to have one subscriber, meaning that the afforementioned slower traversal is not a problem. Adding subscribers is implemented as atomic *compare and swap.* Reviewed By: SidharthGuglani Differential Revision: D15546964 fbshipit-source-id: 41bfa41f1ac6be5c9b6bf4288ea3271ee995877e
1 parent 5b7edb5 commit a1bfb28

File tree

1 file changed

+31
-25
lines changed

1 file changed

+31
-25
lines changed

ReactCommon/yoga/yoga/event/event.cpp

+31-25
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,57 @@
55
* file in the root directory of this source tree.
66
*/
77
#include "event.h"
8+
#include <atomic>
89
#include <memory>
910
#include <stdexcept>
10-
#include <mutex>
11-
12-
#include <iostream>
1311

1412
namespace facebook {
1513
namespace yoga {
1614

1715
namespace {
1816

19-
std::mutex& eventSubscribersMutex() {
20-
static std::mutex subscribersMutex;
21-
return subscribersMutex;
22-
}
17+
struct Node {
18+
std::function<Event::Subscriber> subscriber = nullptr;
19+
Node* next = nullptr;
20+
21+
Node(std::function<Event::Subscriber>&& subscriber)
22+
: subscriber{std::move(subscriber)} {}
23+
};
2324

24-
std::shared_ptr<Event::Subscribers>& eventSubscribers() {
25-
static auto subscribers = std::make_shared<Event::Subscribers>();
26-
return subscribers;
25+
std::atomic<Node*> subscribers{nullptr};
26+
27+
Node* push(Node* newHead) {
28+
Node* oldHead;
29+
do {
30+
oldHead = subscribers.load(std::memory_order_relaxed);
31+
if (newHead != nullptr) {
32+
newHead->next = oldHead;
33+
}
34+
} while (!subscribers.compare_exchange_weak(
35+
oldHead, newHead, std::memory_order_release, std::memory_order_relaxed));
36+
return oldHead;
2737
}
2838

2939
} // namespace
3040

3141
void Event::reset() {
32-
eventSubscribers() = std::make_shared<Event::Subscribers>();
42+
auto head = push(nullptr);
43+
while (head != nullptr) {
44+
auto current = head;
45+
head = head->next;
46+
delete current;
47+
}
3348
}
3449

3550
void Event::subscribe(std::function<Subscriber>&& subscriber) {
36-
std::lock_guard<std::mutex> guard(eventSubscribersMutex());
37-
eventSubscribers() =
38-
std::make_shared<Event::Subscribers>(*eventSubscribers());
39-
eventSubscribers()->push_back(subscriber);
51+
push(new Node{std::move(subscriber)});
4052
}
4153

4254
void Event::publish(const YGNode& node, Type eventType, const Data& eventData) {
43-
std::shared_ptr<Event::Subscribers> subscribers;
44-
{
45-
std::lock_guard<std::mutex> guard(eventSubscribersMutex());
46-
subscribers = eventSubscribers();
47-
}
48-
49-
for (auto& subscriber : *subscribers) {
50-
if (subscriber) {
51-
subscriber(node, eventType, eventData);
52-
}
55+
for (auto subscriber = subscribers.load(std::memory_order_relaxed);
56+
subscriber != nullptr;
57+
subscriber = subscriber->next) {
58+
subscriber->subscriber(node, eventType, eventData);
5359
}
5460
}
5561

0 commit comments

Comments
 (0)