Line data Source code
1 : /*
2 : * Copyright 2013 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #ifndef SkMessageBus_DEFINED
9 : #define SkMessageBus_DEFINED
10 :
11 : #include "SkMutex.h"
12 : #include "SkOnce.h"
13 : #include "SkTArray.h"
14 : #include "SkTDArray.h"
15 : #include "SkTypes.h"
16 :
17 : template <typename Message>
18 : class SkMessageBus : SkNoncopyable {
19 : public:
20 : // Post a message to be received by all Inboxes for this Message type. Threadsafe.
21 : static void Post(const Message& m);
22 :
23 : class Inbox {
24 : public:
25 : Inbox();
26 : ~Inbox();
27 :
28 : // Overwrite out with all the messages we've received since the last call. Threadsafe.
29 : void poll(SkTArray<Message>* out);
30 :
31 : private:
32 : SkTArray<Message> fMessages;
33 : SkMutex fMessagesMutex;
34 :
35 : friend class SkMessageBus;
36 : void receive(const Message& m); // SkMessageBus is a friend only to call this.
37 : };
38 :
39 : private:
40 : SkMessageBus();
41 : static SkMessageBus* Get();
42 :
43 : SkTDArray<Inbox*> fInboxes;
44 : SkMutex fInboxesMutex;
45 : };
46 :
47 : // This must go in a single .cpp file, not some .h, or we risk creating more than one global
48 : // SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile.
49 : #define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \
50 : template <> \
51 : SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
52 : static SkOnce once; \
53 : static SkMessageBus<Message>* bus; \
54 : once([] { bus = new SkMessageBus<Message>(); }); \
55 : return bus; \
56 : }
57 :
58 : // ----------------------- Implementation of SkMessageBus::Inbox -----------------------
59 :
60 : template<typename Message>
61 0 : SkMessageBus<Message>::Inbox::Inbox() {
62 : // Register ourselves with the corresponding message bus.
63 0 : SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
64 0 : SkAutoMutexAcquire lock(bus->fInboxesMutex);
65 0 : bus->fInboxes.push(this);
66 0 : }
67 :
68 : template<typename Message>
69 0 : SkMessageBus<Message>::Inbox::~Inbox() {
70 : // Remove ourselves from the corresponding message bus.
71 0 : SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
72 0 : SkAutoMutexAcquire lock(bus->fInboxesMutex);
73 : // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
74 0 : for (int i = 0; i < bus->fInboxes.count(); i++) {
75 0 : if (this == bus->fInboxes[i]) {
76 0 : bus->fInboxes.removeShuffle(i);
77 0 : break;
78 : }
79 : }
80 0 : }
81 :
82 : template<typename Message>
83 0 : void SkMessageBus<Message>::Inbox::receive(const Message& m) {
84 0 : SkAutoMutexAcquire lock(fMessagesMutex);
85 0 : fMessages.push_back(m);
86 0 : }
87 :
88 : template<typename Message>
89 0 : void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) {
90 0 : SkASSERT(messages);
91 0 : messages->reset();
92 0 : SkAutoMutexAcquire lock(fMessagesMutex);
93 0 : fMessages.swap(messages);
94 0 : }
95 :
96 : // ----------------------- Implementation of SkMessageBus -----------------------
97 :
98 : template <typename Message>
99 0 : SkMessageBus<Message>::SkMessageBus() {}
100 :
101 : template <typename Message>
102 0 : /*static*/ void SkMessageBus<Message>::Post(const Message& m) {
103 0 : SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
104 0 : SkAutoMutexAcquire lock(bus->fInboxesMutex);
105 0 : for (int i = 0; i < bus->fInboxes.count(); i++) {
106 0 : bus->fInboxes[i]->receive(m);
107 : }
108 0 : }
109 :
110 : #endif // SkMessageBus_DEFINED
|