blob: 6ddf82c446568f0bb946a611c15089e0583517b7 [file] [log] [blame]
commit-bot@chromium.org50a30432013-10-24 17:44:27 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkMessageBus_DEFINED
9#define SkMessageBus_DEFINED
10
mtklein1b249332015-07-07 12:21:21 -070011#include "SkMutex.h"
mtkleinffa4a922016-05-05 16:05:56 -070012#include "SkOnce.h"
bsalomon23e619c2015-02-06 11:54:28 -080013#include "SkTArray.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000014#include "SkTDArray.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000015#include "SkTypes.h"
16
17template <typename Message>
18class SkMessageBus : SkNoncopyable {
19public:
Jim Van Verth474d6872017-12-14 13:00:05 -050020 // Post a message to be received by Inboxes for this Message type. Threadsafe.
21 // If id is SK_InvalidUniqueID then it will be sent to all inboxes.
22 // Otherwise it will be sent to the inbox with that id.
23 static void Post(const Message& m, uint32_t destID = SK_InvalidUniqueID);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000024
25 class Inbox {
26 public:
Jim Van Verth474d6872017-12-14 13:00:05 -050027 Inbox(uint32_t uniqueID = SK_InvalidUniqueID);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000028 ~Inbox();
29
30 // Overwrite out with all the messages we've received since the last call. Threadsafe.
bsalomon23e619c2015-02-06 11:54:28 -080031 void poll(SkTArray<Message>* out);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000032
33 private:
bsalomon23e619c2015-02-06 11:54:28 -080034 SkTArray<Message> fMessages;
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000035 SkMutex fMessagesMutex;
Jim Van Verth474d6872017-12-14 13:00:05 -050036 uint32_t fUniqueID;
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000037
38 friend class SkMessageBus;
39 void receive(const Message& m); // SkMessageBus is a friend only to call this.
40 };
41
42private:
43 SkMessageBus();
44 static SkMessageBus* Get();
mtklein148ec592014-10-13 13:17:56 -070045
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000046 SkTDArray<Inbox*> fInboxes;
47 SkMutex fInboxesMutex;
48};
49
commit-bot@chromium.orgc6658042014-01-15 23:09:01 +000050// This must go in a single .cpp file, not some .h, or we risk creating more than one global
mtklein148ec592014-10-13 13:17:56 -070051// SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile.
mtklein6c59d802015-09-09 09:09:53 -070052#define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \
mtklein6c59d802015-09-09 09:09:53 -070053 template <> \
54 SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
mtkleinffa4a922016-05-05 16:05:56 -070055 static SkOnce once; \
56 static SkMessageBus<Message>* bus; \
57 once([] { bus = new SkMessageBus<Message>(); }); \
58 return bus; \
commit-bot@chromium.orgc6658042014-01-15 23:09:01 +000059 }
60
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000061// ----------------------- Implementation of SkMessageBus::Inbox -----------------------
62
63template<typename Message>
Jim Van Verth474d6872017-12-14 13:00:05 -050064SkMessageBus<Message>::Inbox::Inbox(uint32_t uniqueID) : fUniqueID(uniqueID) {
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000065 // Register ourselves with the corresponding message bus.
66 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
67 SkAutoMutexAcquire lock(bus->fInboxesMutex);
68 bus->fInboxes.push(this);
69}
70
71template<typename Message>
72SkMessageBus<Message>::Inbox::~Inbox() {
73 // Remove ourselves from the corresponding message bus.
74 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
75 SkAutoMutexAcquire lock(bus->fInboxesMutex);
76 // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
77 for (int i = 0; i < bus->fInboxes.count(); i++) {
78 if (this == bus->fInboxes[i]) {
79 bus->fInboxes.removeShuffle(i);
80 break;
81 }
82 }
83}
84
85template<typename Message>
86void SkMessageBus<Message>::Inbox::receive(const Message& m) {
87 SkAutoMutexAcquire lock(fMessagesMutex);
bsalomon23e619c2015-02-06 11:54:28 -080088 fMessages.push_back(m);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000089}
90
91template<typename Message>
bsalomon23e619c2015-02-06 11:54:28 -080092void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) {
bsalomon49f085d2014-09-05 13:34:00 -070093 SkASSERT(messages);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000094 messages->reset();
95 SkAutoMutexAcquire lock(fMessagesMutex);
bsalomon23e619c2015-02-06 11:54:28 -080096 fMessages.swap(messages);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000097}
98
99// ----------------------- Implementation of SkMessageBus -----------------------
100
101template <typename Message>
102SkMessageBus<Message>::SkMessageBus() {}
103
104template <typename Message>
Jim Van Verth474d6872017-12-14 13:00:05 -0500105/*static*/ void SkMessageBus<Message>::Post(const Message& m, uint32_t destID) {
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000106 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
107 SkAutoMutexAcquire lock(bus->fInboxesMutex);
108 for (int i = 0; i < bus->fInboxes.count(); i++) {
Jim Van Verth474d6872017-12-14 13:00:05 -0500109 if (SK_InvalidUniqueID == destID || bus->fInboxes[i]->fUniqueID == destID) {
110 bus->fInboxes[i]->receive(m);
111 }
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000112 }
113}
114
115#endif // SkMessageBus_DEFINED