• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //   ----------------------- Implementation of SkMessageBus::Inbox -----------------------
48 
49 template<typename Message>
Inbox()50 SkMessageBus<Message>::Inbox::Inbox() {
51     // Register ourselves with the corresponding message bus.
52     SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
53     SkAutoMutexAcquire lock(bus->fInboxesMutex);
54     bus->fInboxes.push(this);
55 }
56 
57 template<typename Message>
~Inbox()58 SkMessageBus<Message>::Inbox::~Inbox() {
59     // Remove ourselves from the corresponding message bus.
60     SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
61     SkAutoMutexAcquire lock(bus->fInboxesMutex);
62     // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
63     for (int i = 0; i < bus->fInboxes.count(); i++) {
64         if (this == bus->fInboxes[i]) {
65             bus->fInboxes.removeShuffle(i);
66             break;
67         }
68     }
69 }
70 
71 template<typename Message>
receive(const Message & m)72 void SkMessageBus<Message>::Inbox::receive(const Message& m) {
73     SkAutoMutexAcquire lock(fMessagesMutex);
74     fMessages.push(m);
75 }
76 
77 template<typename Message>
poll(SkTDArray<Message> * messages)78 void SkMessageBus<Message>::Inbox::poll(SkTDArray<Message>* messages) {
79     SkASSERT(NULL != messages);
80     messages->reset();
81     SkAutoMutexAcquire lock(fMessagesMutex);
82     messages->swap(fMessages);
83 }
84 
85 //   ----------------------- Implementation of SkMessageBus -----------------------
86 
87 template <typename Message>
SkMessageBus()88 SkMessageBus<Message>::SkMessageBus() {}
89 
90 template <typename Message>
New(SkMessageBus<Message> ** bus)91 /*static*/ void SkMessageBus<Message>::New(SkMessageBus<Message>** bus) {
92     *bus = new SkMessageBus<Message>();
93 }
94 
95 template <typename Message>
Get()96 /*static*/ SkMessageBus<Message>* SkMessageBus<Message>::Get() {
97     // The first time this method is called, create the singleton bus for this message type.
98     static SkMessageBus<Message>* bus = NULL;
99     SK_DECLARE_STATIC_ONCE(once);
100     SkOnce(&once, &New, &bus);
101 
102     SkASSERT(bus != NULL);
103     return bus;
104 }
105 
106 template <typename Message>
Post(const Message & m)107 /*static*/ void SkMessageBus<Message>::Post(const Message& m) {
108     SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
109     SkAutoMutexAcquire lock(bus->fInboxesMutex);
110     for (int i = 0; i < bus->fInboxes.count(); i++) {
111         bus->fInboxes[i]->receive(m);
112     }
113 }
114 
115 #endif  // SkMessageBus_DEFINED
116