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 "SkMutex.h" 12 #include "SkOnce.h" 13 #include "SkTArray.h" 14 #include "SkTDArray.h" 15 #include "SkTypes.h" 16 17 template <typename Message> 18 class SkMessageBus : SkNoncopyable { 19 public: 20 // 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); 24 25 class Inbox { 26 public: 27 Inbox(uint32_t uniqueID = SK_InvalidUniqueID); 28 ~Inbox(); 29 30 // Overwrite out with all the messages we've received since the last call. Threadsafe. 31 void poll(SkTArray<Message>* out); 32 33 private: 34 SkTArray<Message> fMessages; 35 SkMutex fMessagesMutex; 36 uint32_t fUniqueID; 37 38 friend class SkMessageBus; 39 void receive(const Message& m); // SkMessageBus is a friend only to call this. 40 }; 41 42 private: 43 SkMessageBus(); 44 static SkMessageBus* Get(); 45 46 SkTDArray<Inbox*> fInboxes; 47 SkMutex fInboxesMutex; 48 }; 49 50 // This must go in a single .cpp file, not some .h, or we risk creating more than one global 51 // SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile. 52 #define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \ 53 template <> \ 54 SkMessageBus<Message>* SkMessageBus<Message>::Get() { \ 55 static SkOnce once; \ 56 static SkMessageBus<Message>* bus; \ 57 once([] { bus = new SkMessageBus<Message>(); }); \ 58 return bus; \ 59 } 60 61 // ----------------------- Implementation of SkMessageBus::Inbox ----------------------- 62 63 template<typename Message> Inbox(uint32_t uniqueID)64SkMessageBus<Message>::Inbox::Inbox(uint32_t uniqueID) : fUniqueID(uniqueID) { 65 // 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 71 template<typename Message> ~Inbox()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 85 template<typename Message> receive(const Message & m)86void SkMessageBus<Message>::Inbox::receive(const Message& m) { 87 SkAutoMutexAcquire lock(fMessagesMutex); 88 fMessages.push_back(m); 89 } 90 91 template<typename Message> poll(SkTArray<Message> * messages)92void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) { 93 SkASSERT(messages); 94 messages->reset(); 95 SkAutoMutexAcquire lock(fMessagesMutex); 96 fMessages.swap(messages); 97 } 98 99 // ----------------------- Implementation of SkMessageBus ----------------------- 100 101 template <typename Message> SkMessageBus()102SkMessageBus<Message>::SkMessageBus() {} 103 104 template <typename Message> Post(const Message & m,uint32_t destID)105/*static*/ void SkMessageBus<Message>::Post(const Message& m, uint32_t destID) { 106 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 107 SkAutoMutexAcquire lock(bus->fInboxesMutex); 108 for (int i = 0; i < bus->fInboxes.count(); i++) { 109 if (SK_InvalidUniqueID == destID || bus->fInboxes[i]->fUniqueID == destID) { 110 bus->fInboxes[i]->receive(m); 111 } 112 } 113 } 114 115 #endif // SkMessageBus_DEFINED 116