SkMessageBus.h revision c665804300096c2e7617379835bb83d715538788
150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org/*
250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org * Copyright 2013 Google Inc.
350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org *
450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org * found in the LICENSE file.
650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org */
750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#ifndef SkMessageBus_DEFINED
950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#define SkMessageBus_DEFINED
1050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
1150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#include "SkOnce.h"
1250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#include "SkTDArray.h"
1350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#include "SkThread.h"
1450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#include "SkTypes.h"
1550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
1650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate <typename Message>
1750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgclass SkMessageBus : SkNoncopyable {
1850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgpublic:
1950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // Post a message to be received by all Inboxes for this Message type.  Threadsafe.
2050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    static void Post(const Message& m);
2150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
2250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    class Inbox {
2350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    public:
2450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        Inbox();
2550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        ~Inbox();
2650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
2750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        // Overwrite out with all the messages we've received since the last call.  Threadsafe.
2850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        void poll(SkTDArray<Message>* out);
2950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
3050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    private:
3150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        SkTDArray<Message> fMessages;
3250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        SkMutex            fMessagesMutex;
3350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
3450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        friend class SkMessageBus;
3550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        void receive(const Message& m);  // SkMessageBus is a friend only to call this.
3650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    };
3750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
3850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgprivate:
3950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus();
4050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    static SkMessageBus* Get();
4150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    static void New(SkMessageBus**);
4250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
4350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkTDArray<Inbox*> fInboxes;
4450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMutex           fInboxesMutex;
4550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org};
4650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
47c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org// This must go in a single .cpp file, not some .h, or we risk creating more than one global
48c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org// SkMessageBus per type when using shared libraries.
49c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org#define DECLARE_SKMESSAGEBUS_MESSAGE(Message)             \
50c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org    template <>                                           \
51c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org    SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
52c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org        static SkMessageBus<Message>* bus = NULL;         \
53c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org        SK_DECLARE_STATIC_ONCE(once);                     \
54c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org        SkOnce(&once, &New, &bus);                        \
55c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org        SkASSERT(bus != NULL);                            \
56c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org        return bus;                                       \
57c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org    }
58c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org
5950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org//   ----------------------- Implementation of SkMessageBus::Inbox -----------------------
6050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
6150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
6250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgSkMessageBus<Message>::Inbox::Inbox() {
6350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // Register ourselves with the corresponding message bus.
6450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
6550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(bus->fInboxesMutex);
6650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    bus->fInboxes.push(this);
6750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
6850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
6950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
7050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgSkMessageBus<Message>::Inbox::~Inbox() {
7150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // Remove ourselves from the corresponding message bus.
7250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
7350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(bus->fInboxesMutex);
7450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
7550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    for (int i = 0; i < bus->fInboxes.count(); i++) {
7650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        if (this == bus->fInboxes[i]) {
7750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org            bus->fInboxes.removeShuffle(i);
7850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org            break;
7950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        }
8050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    }
8150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
8250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
8350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
8450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgvoid SkMessageBus<Message>::Inbox::receive(const Message& m) {
8550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(fMessagesMutex);
8650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    fMessages.push(m);
8750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
8850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
8950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
9050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgvoid SkMessageBus<Message>::Inbox::poll(SkTDArray<Message>* messages) {
9150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkASSERT(NULL != messages);
9250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    messages->reset();
9350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(fMessagesMutex);
9450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    messages->swap(fMessages);
9550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
9650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
9750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org//   ----------------------- Implementation of SkMessageBus -----------------------
9850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
9950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate <typename Message>
10050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgSkMessageBus<Message>::SkMessageBus() {}
10150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
10250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate <typename Message>
10350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org/*static*/ void SkMessageBus<Message>::New(SkMessageBus<Message>** bus) {
10450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    *bus = new SkMessageBus<Message>();
10550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
10650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
10750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate <typename Message>
10850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org/*static*/ void SkMessageBus<Message>::Post(const Message& m) {
10950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
11050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(bus->fInboxesMutex);
11150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    for (int i = 0; i < bus->fInboxes.count(); i++) {
11250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        bus->fInboxes[i]->receive(m);
11350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    }
11450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
11550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
11650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#endif  // SkMessageBus_DEFINED
117