blob: 649edf605d55359157b5b9d4497a814503d47e69 [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
Ben Wagnerd5148e32018-07-16 17:44:06 -040011#include "../private/SkNoncopyable.h"
mtklein1b249332015-07-07 12:21:21 -070012#include "SkMutex.h"
mtkleinffa4a922016-05-05 16:05:56 -070013#include "SkOnce.h"
bsalomon23e619c2015-02-06 11:54:28 -080014#include "SkTArray.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000015#include "SkTDArray.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000016#include "SkTypes.h"
17
Brian Salomon238069b2018-07-11 15:58:57 -040018/**
Chris Dalton9a986cf2018-10-18 15:27:59 -060019 * The following method must have a specialization for type 'Message':
20 *
21 * bool SkShouldPostMessageToBus(const Message&, uint32_t msgBusUniqueID)
22 *
23 * We may want to consider providing a default template implementation, to avoid this requirement by
24 * sending to all inboxes when the specialization for type 'Message' is not present.
Brian Salomon238069b2018-07-11 15:58:57 -040025 */
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000026template <typename Message>
27class SkMessageBus : SkNoncopyable {
28public:
Brian Salomon238069b2018-07-11 15:58:57 -040029 // Post a message to be received by Inboxes for this Message type. Checks
Chris Dalton9a986cf2018-10-18 15:27:59 -060030 // SkShouldPostMessageToBus() for each inbox. Threadsafe.
Brian Salomon238069b2018-07-11 15:58:57 -040031 static void Post(const Message& m);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000032
33 class Inbox {
34 public:
Jim Van Verth474d6872017-12-14 13:00:05 -050035 Inbox(uint32_t uniqueID = SK_InvalidUniqueID);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000036 ~Inbox();
37
Chris Dalton9a986cf2018-10-18 15:27:59 -060038 uint32_t uniqueID() const { return fUniqueID; }
39
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000040 // Overwrite out with all the messages we've received since the last call. Threadsafe.
bsalomon23e619c2015-02-06 11:54:28 -080041 void poll(SkTArray<Message>* out);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000042
43 private:
bsalomon23e619c2015-02-06 11:54:28 -080044 SkTArray<Message> fMessages;
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000045 SkMutex fMessagesMutex;
Jim Van Verth474d6872017-12-14 13:00:05 -050046 uint32_t fUniqueID;
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000047
48 friend class SkMessageBus;
49 void receive(const Message& m); // SkMessageBus is a friend only to call this.
50 };
51
52private:
53 SkMessageBus();
54 static SkMessageBus* Get();
mtklein148ec592014-10-13 13:17:56 -070055
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000056 SkTDArray<Inbox*> fInboxes;
57 SkMutex fInboxesMutex;
58};
59
commit-bot@chromium.orgc6658042014-01-15 23:09:01 +000060// 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 -070061// SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile.
mtklein6c59d802015-09-09 09:09:53 -070062#define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \
mtklein6c59d802015-09-09 09:09:53 -070063 template <> \
64 SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
mtkleinffa4a922016-05-05 16:05:56 -070065 static SkOnce once; \
66 static SkMessageBus<Message>* bus; \
67 once([] { bus = new SkMessageBus<Message>(); }); \
68 return bus; \
commit-bot@chromium.orgc6658042014-01-15 23:09:01 +000069 }
70
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000071// ----------------------- Implementation of SkMessageBus::Inbox -----------------------
72
73template<typename Message>
Jim Van Verth474d6872017-12-14 13:00:05 -050074SkMessageBus<Message>::Inbox::Inbox(uint32_t uniqueID) : fUniqueID(uniqueID) {
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000075 // Register ourselves with the corresponding message bus.
76 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
77 SkAutoMutexAcquire lock(bus->fInboxesMutex);
Mike Reed5edcd312018-08-08 11:23:41 -040078 bus->fInboxes.push_back(this);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000079}
80
81template<typename Message>
82SkMessageBus<Message>::Inbox::~Inbox() {
83 // Remove ourselves from the corresponding message bus.
84 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
85 SkAutoMutexAcquire lock(bus->fInboxesMutex);
86 // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
87 for (int i = 0; i < bus->fInboxes.count(); i++) {
88 if (this == bus->fInboxes[i]) {
89 bus->fInboxes.removeShuffle(i);
90 break;
91 }
92 }
93}
94
95template<typename Message>
96void SkMessageBus<Message>::Inbox::receive(const Message& m) {
97 SkAutoMutexAcquire lock(fMessagesMutex);
bsalomon23e619c2015-02-06 11:54:28 -080098 fMessages.push_back(m);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000099}
100
101template<typename Message>
bsalomon23e619c2015-02-06 11:54:28 -0800102void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) {
bsalomon49f085d2014-09-05 13:34:00 -0700103 SkASSERT(messages);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000104 messages->reset();
105 SkAutoMutexAcquire lock(fMessagesMutex);
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400106 fMessages.swap(*messages);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000107}
108
109// ----------------------- Implementation of SkMessageBus -----------------------
110
111template <typename Message>
112SkMessageBus<Message>::SkMessageBus() {}
113
114template <typename Message>
Brian Salomon238069b2018-07-11 15:58:57 -0400115/*static*/ void SkMessageBus<Message>::Post(const Message& m) {
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000116 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
117 SkAutoMutexAcquire lock(bus->fInboxesMutex);
118 for (int i = 0; i < bus->fInboxes.count(); i++) {
Chris Dalton9a986cf2018-10-18 15:27:59 -0600119 if (SkShouldPostMessageToBus(m, bus->fInboxes[i]->fUniqueID)) {
Jim Van Verth474d6872017-12-14 13:00:05 -0500120 bus->fInboxes[i]->receive(m);
121 }
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000122 }
123}
124
125#endif // SkMessageBus_DEFINED