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