1 /* 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 11 #include "include/core/SkTypes.h" 12 #include "include/private/SkMutex.h" 13 #include "include/private/SkNoncopyable.h" 14 #include "include/private/SkOnce.h" 15 #include "include/private/SkTArray.h" 16 #include "include/private/SkTDArray.h" 17 18 /** 19 * 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. 25 */ 26 template <typename Message> 27 class SkMessageBus : SkNoncopyable { 28 public: 29 // Post a message to be received by Inboxes for this Message type. Checks 30 // SkShouldPostMessageToBus() for each inbox. Threadsafe. 31 static void Post(const Message& m); 32 33 class Inbox { 34 public: 35 Inbox(uint32_t uniqueID = SK_InvalidUniqueID); 36 ~Inbox(); 37 uniqueID()38 uint32_t uniqueID() const { return fUniqueID; } 39 40 // Overwrite out with all the messages we've received since the last call. Threadsafe. 41 void poll(SkTArray<Message>* out); 42 43 private: 44 SkTArray<Message> fMessages; 45 SkMutex fMessagesMutex; 46 uint32_t fUniqueID; 47 48 friend class SkMessageBus; 49 void receive(const Message& m); // SkMessageBus is a friend only to call this. 50 }; 51 52 private: 53 SkMessageBus(); 54 static SkMessageBus* Get(); 55 56 SkTDArray<Inbox*> fInboxes; 57 SkMutex fInboxesMutex; 58 }; 59 60 // This must go in a single .cpp file, not some .h, or we risk creating more than one global 61 // SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile. 62 #define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \ 63 template <> \ 64 SkMessageBus<Message>* SkMessageBus<Message>::Get() { \ 65 static SkOnce once; \ 66 static SkMessageBus<Message>* bus; \ 67 once([] { bus = new SkMessageBus<Message>(); }); \ 68 return bus; \ 69 } 70 71 // ----------------------- Implementation of SkMessageBus::Inbox ----------------------- 72 73 template<typename Message> Inbox(uint32_t uniqueID)74SkMessageBus<Message>::Inbox::Inbox(uint32_t uniqueID) : fUniqueID(uniqueID) { 75 // Register ourselves with the corresponding message bus. 76 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 77 SkAutoMutexExclusive lock(bus->fInboxesMutex); 78 bus->fInboxes.push_back(this); 79 } 80 81 template<typename Message> ~Inbox()82SkMessageBus<Message>::Inbox::~Inbox() { 83 // Remove ourselves from the corresponding message bus. 84 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 85 SkAutoMutexExclusive 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 95 template<typename Message> receive(const Message & m)96void SkMessageBus<Message>::Inbox::receive(const Message& m) { 97 SkAutoMutexExclusive lock(fMessagesMutex); 98 fMessages.push_back(m); 99 } 100 101 template<typename Message> poll(SkTArray<Message> * messages)102void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) { 103 SkASSERT(messages); 104 messages->reset(); 105 SkAutoMutexExclusive lock(fMessagesMutex); 106 fMessages.swap(*messages); 107 } 108 109 // ----------------------- Implementation of SkMessageBus ----------------------- 110 111 template <typename Message> SkMessageBus()112SkMessageBus<Message>::SkMessageBus() {} 113 114 template <typename Message> Post(const Message & m)115/*static*/ void SkMessageBus<Message>::Post(const Message& m) { 116 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 117 SkAutoMutexExclusive lock(bus->fInboxesMutex); 118 for (int i = 0; i < bus->fInboxes.count(); i++) { 119 if (SkShouldPostMessageToBus(m, bus->fInboxes[i]->fUniqueID)) { 120 bus->fInboxes[i]->receive(m); 121 } 122 } 123 } 124 125 #endif // SkMessageBus_DEFINED 126