diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/core/SkMessageBus.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/core/SkMessageBus.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,116 @@ +/* + * 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 +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* out); + + private: + SkTDArray 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 fInboxes; + SkMutex fInboxesMutex; +}; + +// This must go in a single .cpp file, not some .h, or we risk creating more than one global +// SkMessageBus per type when using shared libraries. +#define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \ + template <> \ + SkMessageBus* SkMessageBus::Get() { \ + static SkMessageBus* bus = NULL; \ + SK_DECLARE_STATIC_ONCE(once); \ + SkOnce(&once, &New, &bus); \ + SkASSERT(bus != NULL); \ + return bus; \ + } + +// ----------------------- Implementation of SkMessageBus::Inbox ----------------------- + +template +SkMessageBus::Inbox::Inbox() { + // Register ourselves with the corresponding message bus. + SkMessageBus* bus = SkMessageBus::Get(); + SkAutoMutexAcquire lock(bus->fInboxesMutex); + bus->fInboxes.push(this); +} + +template +SkMessageBus::Inbox::~Inbox() { + // Remove ourselves from the corresponding message bus. + SkMessageBus* bus = SkMessageBus::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 +void SkMessageBus::Inbox::receive(const Message& m) { + SkAutoMutexAcquire lock(fMessagesMutex); + fMessages.push(m); +} + +template +void SkMessageBus::Inbox::poll(SkTDArray* messages) { + SkASSERT(NULL != messages); + messages->reset(); + SkAutoMutexAcquire lock(fMessagesMutex); + messages->swap(fMessages); +} + +// ----------------------- Implementation of SkMessageBus ----------------------- + +template +SkMessageBus::SkMessageBus() {} + +template +/*static*/ void SkMessageBus::New(SkMessageBus** bus) { + *bus = new SkMessageBus(); +} + +template +/*static*/ void SkMessageBus::Post(const Message& m) { + SkMessageBus* bus = SkMessageBus::Get(); + SkAutoMutexAcquire lock(bus->fInboxesMutex); + for (int i = 0; i < bus->fInboxes.count(); i++) { + bus->fInboxes[i]->receive(m); + } +} + +#endif // SkMessageBus_DEFINED