/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkMessageBus_DEFINED #define SkMessageBus_DEFINED #include "SkOnce.h" #include "SkTDArray.h" #include "SkThread.h" #include "SkTypes.h" template <typename Message> class SkMessageBus : SkNoncopyable { public: // Post a message to be received by all Inboxes for this Message type. Threadsafe. static void Post(const Message& m); class Inbox { public: Inbox(); ~Inbox(); // Overwrite out with all the messages we've received since the last call. Threadsafe. void poll(SkTDArray<Message>* out); private: SkTDArray<Message> fMessages; SkMutex fMessagesMutex; friend class SkMessageBus; void receive(const Message& m); // SkMessageBus is a friend only to call this. }; private: SkMessageBus(); static SkMessageBus* Get(); static void New(SkMessageBus**); SkTDArray<Inbox*> fInboxes; SkMutex fInboxesMutex; }; // ----------------------- Implementation of SkMessageBus::Inbox ----------------------- template<typename Message> SkMessageBus<Message>::Inbox::Inbox() { // Register ourselves with the corresponding message bus. SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); SkAutoMutexAcquire lock(bus->fInboxesMutex); bus->fInboxes.push(this); } template<typename Message> SkMessageBus<Message>::Inbox::~Inbox() { // Remove ourselves from the corresponding message bus. SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); SkAutoMutexAcquire lock(bus->fInboxesMutex); // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter. for (int i = 0; i < bus->fInboxes.count(); i++) { if (this == bus->fInboxes[i]) { bus->fInboxes.removeShuffle(i); break; } } } template<typename Message> void SkMessageBus<Message>::Inbox::receive(const Message& m) { SkAutoMutexAcquire lock(fMessagesMutex); fMessages.push(m); } template<typename Message> void SkMessageBus<Message>::Inbox::poll(SkTDArray<Message>* messages) { SkASSERT(NULL != messages); messages->reset(); SkAutoMutexAcquire lock(fMessagesMutex); messages->swap(fMessages); } // ----------------------- Implementation of SkMessageBus ----------------------- template <typename Message> SkMessageBus<Message>::SkMessageBus() {} template <typename Message> /*static*/ void SkMessageBus<Message>::New(SkMessageBus<Message>** bus) { *bus = new SkMessageBus<Message>(); } template <typename Message> /*static*/ SkMessageBus<Message>* SkMessageBus<Message>::Get() { // The first time this method is called, create the singleton bus for this message type. static SkMessageBus<Message>* bus = NULL; SK_DECLARE_STATIC_ONCE(once); SkOnce(&once, &New, &bus); SkASSERT(bus != NULL); return bus; } template <typename Message> /*static*/ void SkMessageBus<Message>::Post(const Message& m) { SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); SkAutoMutexAcquire lock(bus->fInboxesMutex); for (int i = 0; i < bus->fInboxes.count(); i++) { bus->fInboxes[i]->receive(m); } } #endif // SkMessageBus_DEFINED