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 "SkLazyPtr.h" 12#include "SkTArray.h" 13#include "SkTDArray.h" 14#include "SkThread.h" 15#include "SkTypes.h" 16 17template <typename Message> 18class SkMessageBus : SkNoncopyable { 19public: 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 39private: 40 SkMessageBus(); 41 static SkMessageBus* Get(); 42 43 // Allow SkLazyPtr to call SkMessageBus::SkMessageBus(). 44 template <typename T> friend T* Private::sk_new(); 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 SK_DECLARE_STATIC_LAZY_PTR(SkMessageBus<Message>, bus); \ 54 template <> \ 55 SkMessageBus<Message>* SkMessageBus<Message>::Get() { \ 56 return bus.get(); \ 57 } 58 59// ----------------------- Implementation of SkMessageBus::Inbox ----------------------- 60 61template<typename Message> 62SkMessageBus<Message>::Inbox::Inbox() { 63 // Register ourselves with the corresponding message bus. 64 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 65 SkAutoMutexAcquire lock(bus->fInboxesMutex); 66 bus->fInboxes.push(this); 67} 68 69template<typename Message> 70SkMessageBus<Message>::Inbox::~Inbox() { 71 // Remove ourselves from the corresponding message bus. 72 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 73 SkAutoMutexAcquire lock(bus->fInboxesMutex); 74 // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter. 75 for (int i = 0; i < bus->fInboxes.count(); i++) { 76 if (this == bus->fInboxes[i]) { 77 bus->fInboxes.removeShuffle(i); 78 break; 79 } 80 } 81} 82 83template<typename Message> 84void SkMessageBus<Message>::Inbox::receive(const Message& m) { 85 SkAutoMutexAcquire lock(fMessagesMutex); 86 fMessages.push_back(m); 87} 88 89template<typename Message> 90void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) { 91 SkASSERT(messages); 92 messages->reset(); 93 SkAutoMutexAcquire lock(fMessagesMutex); 94 fMessages.swap(messages); 95} 96 97// ----------------------- Implementation of SkMessageBus ----------------------- 98 99template <typename Message> 100SkMessageBus<Message>::SkMessageBus() {} 101 102template <typename Message> 103/*static*/ void SkMessageBus<Message>::Post(const Message& m) { 104 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); 105 SkAutoMutexAcquire lock(bus->fInboxesMutex); 106 for (int i = 0; i < bus->fInboxes.count(); i++) { 107 bus->fInboxes[i]->receive(m); 108 } 109} 110 111#endif // SkMessageBus_DEFINED 112