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 "SkOnce.h" 12 #include "SkTDArray.h" 13 #include "SkThread.h" 14 #include "SkTypes.h" 15 16 template <typename Message> 17 class SkMessageBus : SkNoncopyable { 18 public: 19 // Post a message to be received by all Inboxes for this Message type. Threadsafe. 20 static void Post(const Message& m); 21 22 class Inbox { 23 public: 24 Inbox(); 25 ~Inbox(); 26 27 // Overwrite out with all the messages we've received since the last call. Threadsafe. 28 void poll(SkTDArray<Message>* out); 29 30 private: 31 SkTDArray<Message> fMessages; 32 SkMutex fMessagesMutex; 33 34 friend class SkMessageBus; 35 void receive(const Message& m); // SkMessageBus is a friend only to call this. 36 }; 37 38 private: 39 SkMessageBus(); 40 static SkMessageBus* Get(); 41 static void New(SkMessageBus**); 42 43 SkTDArray<Inbox*> fInboxes; 44 SkMutex fInboxesMutex; 45 }; 46 47 // ----------------------- Implementation of SkMessageBus::Inbox ----------------------- 48 49 template<typename Message> 50 SkMessageBus<Message>::Inbox::Inbox() { 51 // Register ourselves with the corresponding message bus. 52 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 53 SkAutoMutexAcquire lock(bus->fInboxesMutex); 54 bus->fInboxes.push(this); 55 } 56 57 template<typename Message> 58 SkMessageBus<Message>::Inbox::~Inbox() { 59 // Remove ourselves from the corresponding message bus. 60 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 61 SkAutoMutexAcquire lock(bus->fInboxesMutex); 62 // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter. 63 for (int i = 0; i < bus->fInboxes.count(); i++) { 64 if (this == bus->fInboxes[i]) { 65 bus->fInboxes.removeShuffle(i); 66 break; 67 } 68 } 69 } 70 71 template<typename Message> 72 void SkMessageBus<Message>::Inbox::receive(const Message& m) { 73 SkAutoMutexAcquire lock(fMessagesMutex); 74 fMessages.push(m); 75 } 76 77 template<typename Message> 78 void SkMessageBus<Message>::Inbox::poll(SkTDArray<Message>* messages) { 79 SkASSERT(NULL != messages); 80 messages->reset(); 81 SkAutoMutexAcquire lock(fMessagesMutex); 82 messages->swap(fMessages); 83 } 84 85 // ----------------------- Implementation of SkMessageBus ----------------------- 86 87 template <typename Message> 88 SkMessageBus<Message>::SkMessageBus() {} 89 90 template <typename Message> 91 /*static*/ void SkMessageBus<Message>::New(SkMessageBus<Message>** bus) { 92 *bus = new SkMessageBus<Message>(); 93 } 94 95 template <typename Message> 96 /*static*/ SkMessageBus<Message>* SkMessageBus<Message>::Get() { 97 // The first time this method is called, create the singleton bus for this message type. 98 static SkMessageBus<Message>* bus = NULL; 99 SK_DECLARE_STATIC_ONCE(once); 100 SkOnce(&once, &New, &bus); 101 102 SkASSERT(bus != NULL); 103 return bus; 104 } 105 106 template <typename Message> 107 /*static*/ void SkMessageBus<Message>::Post(const Message& m) { 108 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 109 SkAutoMutexAcquire lock(bus->fInboxesMutex); 110 for (int i = 0; i < bus->fInboxes.count(); i++) { 111 bus->fInboxes[i]->receive(m); 112 } 113 } 114 115 #endif // SkMessageBus_DEFINED 116