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 17template <typename Message> 18class SkMessageBus : SkNoncopyable { 19public: 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 42private: 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 63template<typename Message> 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 71template<typename Message> 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 85template<typename Message> 86void SkMessageBus<Message>::Inbox::receive(const Message& m) { 87 SkAutoMutexAcquire lock(fMessagesMutex); 88 fMessages.push_back(m); 89} 90 91template<typename Message> 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 101template <typename Message> 102SkMessageBus<Message>::SkMessageBus() {} 103 104template <typename Message> 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