|
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 "SkOnce.h" |
|
12 #include "SkTDArray.h" |
|
13 #include "SkThread.h" |
|
14 #include "SkTypes.h" |
|
15 |
|
16 template <typename Message> |
|
17 class SkMessageBus : SkNoncopyable { |
|
18 public: |
|
19 // Post a message to be received by all Inboxes for this Message type. Threadsafe. |
|
20 static void Post(const Message& m); |
|
21 |
|
22 class Inbox { |
|
23 public: |
|
24 Inbox(); |
|
25 ~Inbox(); |
|
26 |
|
27 // Overwrite out with all the messages we've received since the last call. Threadsafe. |
|
28 void poll(SkTDArray<Message>* out); |
|
29 |
|
30 private: |
|
31 SkTDArray<Message> fMessages; |
|
32 SkMutex fMessagesMutex; |
|
33 |
|
34 friend class SkMessageBus; |
|
35 void receive(const Message& m); // SkMessageBus is a friend only to call this. |
|
36 }; |
|
37 |
|
38 private: |
|
39 SkMessageBus(); |
|
40 static SkMessageBus* Get(); |
|
41 static void New(SkMessageBus**); |
|
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. |
|
49 #define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \ |
|
50 template <> \ |
|
51 SkMessageBus<Message>* SkMessageBus<Message>::Get() { \ |
|
52 static SkMessageBus<Message>* bus = NULL; \ |
|
53 SK_DECLARE_STATIC_ONCE(once); \ |
|
54 SkOnce(&once, &New, &bus); \ |
|
55 SkASSERT(bus != NULL); \ |
|
56 return bus; \ |
|
57 } |
|
58 |
|
59 // ----------------------- Implementation of SkMessageBus::Inbox ----------------------- |
|
60 |
|
61 template<typename Message> |
|
62 SkMessageBus<Message>::Inbox::Inbox() { |
|
63 // Register ourselves with the corresponding message bus. |
|
64 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); |
|
65 SkAutoMutexAcquire lock(bus->fInboxesMutex); |
|
66 bus->fInboxes.push(this); |
|
67 } |
|
68 |
|
69 template<typename Message> |
|
70 SkMessageBus<Message>::Inbox::~Inbox() { |
|
71 // Remove ourselves from the corresponding message bus. |
|
72 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); |
|
73 SkAutoMutexAcquire lock(bus->fInboxesMutex); |
|
74 // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter. |
|
75 for (int i = 0; i < bus->fInboxes.count(); i++) { |
|
76 if (this == bus->fInboxes[i]) { |
|
77 bus->fInboxes.removeShuffle(i); |
|
78 break; |
|
79 } |
|
80 } |
|
81 } |
|
82 |
|
83 template<typename Message> |
|
84 void SkMessageBus<Message>::Inbox::receive(const Message& m) { |
|
85 SkAutoMutexAcquire lock(fMessagesMutex); |
|
86 fMessages.push(m); |
|
87 } |
|
88 |
|
89 template<typename Message> |
|
90 void SkMessageBus<Message>::Inbox::poll(SkTDArray<Message>* messages) { |
|
91 SkASSERT(NULL != messages); |
|
92 messages->reset(); |
|
93 SkAutoMutexAcquire lock(fMessagesMutex); |
|
94 messages->swap(fMessages); |
|
95 } |
|
96 |
|
97 // ----------------------- Implementation of SkMessageBus ----------------------- |
|
98 |
|
99 template <typename Message> |
|
100 SkMessageBus<Message>::SkMessageBus() {} |
|
101 |
|
102 template <typename Message> |
|
103 /*static*/ void SkMessageBus<Message>::New(SkMessageBus<Message>** bus) { |
|
104 *bus = new SkMessageBus<Message>(); |
|
105 } |
|
106 |
|
107 template <typename Message> |
|
108 /*static*/ void SkMessageBus<Message>::Post(const Message& m) { |
|
109 SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); |
|
110 SkAutoMutexAcquire lock(bus->fInboxesMutex); |
|
111 for (int i = 0; i < bus->fInboxes.count(); i++) { |
|
112 bus->fInboxes[i]->receive(m); |
|
113 } |
|
114 } |
|
115 |
|
116 #endif // SkMessageBus_DEFINED |