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
1178358bf624c7e7c09ffccf638c50870808d884d6mtklein#include "SkLazyPtr.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();
4178358bf624c7e7c09ffccf638c50870808d884d6mtklein    static SkMessageBus* New();
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.
4978358bf624c7e7c09ffccf638c50870808d884d6mtklein#define DECLARE_SKMESSAGEBUS_MESSAGE(Message)                        \
5078358bf624c7e7c09ffccf638c50870808d884d6mtklein    template <>                                                      \
5178358bf624c7e7c09ffccf638c50870808d884d6mtklein    SkMessageBus<Message>* SkMessageBus<Message>::Get() {            \
5278358bf624c7e7c09ffccf638c50870808d884d6mtklein        SK_DECLARE_STATIC_LAZY_PTR(SkMessageBus<Message>, bus, New); \
5378358bf624c7e7c09ffccf638c50870808d884d6mtklein        return bus.get();                                            \
54c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org    }
55c665804300096c2e7617379835bb83d715538788commit-bot@chromium.org
5650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org//   ----------------------- Implementation of SkMessageBus::Inbox -----------------------
5750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
5850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
5950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgSkMessageBus<Message>::Inbox::Inbox() {
6050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // Register ourselves with the corresponding message bus.
6150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
6250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(bus->fInboxesMutex);
6350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    bus->fInboxes.push(this);
6450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
6550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
6650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
6750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgSkMessageBus<Message>::Inbox::~Inbox() {
6850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // Remove ourselves from the corresponding message bus.
6950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
7050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(bus->fInboxesMutex);
7150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
7250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    for (int i = 0; i < bus->fInboxes.count(); i++) {
7350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        if (this == bus->fInboxes[i]) {
7450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org            bus->fInboxes.removeShuffle(i);
7550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org            break;
7650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        }
7750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    }
7850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
7950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
8050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
8150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgvoid SkMessageBus<Message>::Inbox::receive(const Message& m) {
8250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(fMessagesMutex);
8350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    fMessages.push(m);
8450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
8550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
8650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate<typename Message>
8750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgvoid SkMessageBus<Message>::Inbox::poll(SkTDArray<Message>* messages) {
8849f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(messages);
8950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    messages->reset();
9050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(fMessagesMutex);
9150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    messages->swap(fMessages);
9250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
9350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
9450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org//   ----------------------- Implementation of SkMessageBus -----------------------
9550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
9650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate <typename Message>
9750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgSkMessageBus<Message>::SkMessageBus() {}
9850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
9950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate <typename Message>
10078358bf624c7e7c09ffccf638c50870808d884d6mtklein/*static*/ SkMessageBus<Message>* SkMessageBus<Message>::New() {
10178358bf624c7e7c09ffccf638c50870808d884d6mtklein    return SkNEW(SkMessageBus<Message>);
10250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
10350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
10450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgtemplate <typename Message>
10550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org/*static*/ void SkMessageBus<Message>::Post(const Message& m) {
10650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
10750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkAutoMutexAcquire lock(bus->fInboxesMutex);
10850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    for (int i = 0; i < bus->fInboxes.count(); i++) {
10950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        bus->fInboxes[i]->receive(m);
11050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    }
11150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
11250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
11350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#endif  // SkMessageBus_DEFINED
114