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