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 all Inboxes for this Message type. Threadsafe. 21 static void Post(const Message& m); 22 23 class Inbox { 24 public: 25 Inbox(); 26 ~Inbox(); 27 28 // Overwrite out with all the messages we've received since the last call. Threadsafe. 29 void poll(SkTArray<Message>* out); 30 31 private: 32 SkTArray<Message> fMessages; 33 SkMutex fMessagesMutex; 34 35 friend class SkMessageBus; 36 void receive(const Message& m); // SkMessageBus is a friend only to call this. 37 }; 38 39 private: 40 SkMessageBus(); 41 static SkMessageBus* Get(); 42 43 SkTDArray<Inbox*> fInboxes; 44 SkMutex fInboxesMutex; 45 }; 46 47 // This must go in a single .cpp file, not some .h, or we risk creating more than one global 48 // SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile. 49 #define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \ 50 template <> \ 51 SkMessageBus<Message>* SkMessageBus<Message>::Get() { \ 52 static SkOnce once; \ 53 static SkMessageBus<Message>* bus; \ 54 once([] { bus = new SkMessageBus<Message>(); }); \ 55 return bus; \ 56 } 57 58 // ----------------------- Implementation of SkMessageBus::Inbox ----------------------- 59 60 template<typename Message> Inbox()61SkMessageBus<Message>::Inbox::Inbox() { 62 // Register ourselves with the corresponding message bus. 63 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 64 SkAutoMutexAcquire lock(bus->fInboxesMutex); 65 bus->fInboxes.push(this); 66 } 67 68 template<typename Message> ~Inbox()69SkMessageBus<Message>::Inbox::~Inbox() { 70 // Remove ourselves from the corresponding message bus. 71 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 72 SkAutoMutexAcquire lock(bus->fInboxesMutex); 73 // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter. 74 for (int i = 0; i < bus->fInboxes.count(); i++) { 75 if (this == bus->fInboxes[i]) { 76 bus->fInboxes.removeShuffle(i); 77 break; 78 } 79 } 80 } 81 82 template<typename Message> receive(const Message & m)83void SkMessageBus<Message>::Inbox::receive(const Message& m) { 84 SkAutoMutexAcquire lock(fMessagesMutex); 85 fMessages.push_back(m); 86 } 87 88 template<typename Message> poll(SkTArray<Message> * messages)89void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) { 90 SkASSERT(messages); 91 messages->reset(); 92 SkAutoMutexAcquire lock(fMessagesMutex); 93 fMessages.swap(messages); 94 } 95 96 // ----------------------- Implementation of SkMessageBus ----------------------- 97 98 template <typename Message> SkMessageBus()99SkMessageBus<Message>::SkMessageBus() {} 100 101 template <typename Message> Post(const Message & m)102/*static*/ void SkMessageBus<Message>::Post(const Message& m) { 103 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 104 SkAutoMutexAcquire lock(bus->fInboxesMutex); 105 for (int i = 0; i < bus->fInboxes.count(); i++) { 106 bus->fInboxes[i]->receive(m); 107 } 108 } 109 110 #endif // SkMessageBus_DEFINED 111