Index: src/core/SkMessageBus.h |
diff --git a/src/core/SkMessageBus.h b/src/core/SkMessageBus.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1cb0ccf108c5172c85cede705f4ba3b9f73ba8f4 |
--- /dev/null |
+++ b/src/core/SkMessageBus.h |
@@ -0,0 +1,117 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#ifndef SkMessageBus_DEFINED |
+#define SkMessageBus_DEFINED |
+ |
+#include "SkOnce.h" |
+#include "SkTDArray.h" |
+#include "SkThread.h" |
+#include "SkTypes.h" |
+ |
+template <typename Message> |
+class SkMessageBus : SkNoncopyable { |
+public: |
+ // Post a message to be received by all Inboxes for this Message type. Threadsafe. |
+ static void post(const Message& m); |
+ |
+ class Inbox { |
+ public: |
+ Inbox(); |
+ ~Inbox(); |
scroggo
2013/10/22 21:04:02
Should this be virtual?
mtklein
2013/10/23 15:28:10
Nope. No virtual methods on Inbox (or SkMessageBu
|
+ |
+ // Make messages contain all the messages we've received since the last call. Threadsafe. |
scroggo
2013/10/22 21:04:02
I find this comment hard to read - it would help t
bsalomon
2013/10/23 13:52:57
"The array messages"?
mtklein
2013/10/23 15:28:10
Better?
bsalomon
2013/10/23 15:32:27
ok by me
scroggo
2013/10/23 15:39:19
Yes.
|
+ void poll(SkTDArray<Message>* messages); |
+ |
+ private: |
+ SkTDArray<Message> fMessages; |
+ SkMutex fMessagesMutex; |
+ |
+ friend class SkMessageBus; |
+ void receive(const Message& m); // SkMessageBus is a friend only to call this. |
+ }; |
+ |
+private: |
+ SkMessageBus(); |
+ static SkMessageBus* Get(); |
+ static void New(SkMessageBus**); |
+ |
+ SkTDArray<Inbox*> fInboxes; |
+ SkMutex fInboxesMutex; |
+}; |
+ |
+// ----------------------- Implementation of SkMessageBus::Inbox ----------------------- |
+ |
+template<typename Message> |
+SkMessageBus<Message>::Inbox::Inbox() { |
+ // Register ourselves with the corresponding message bus. |
+ SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); |
+ SkAutoMutexAcquire lock(bus->fInboxesMutex); |
+ bus->fInboxes.push(this); |
+} |
+ |
+template<typename Message> |
+SkMessageBus<Message>::Inbox::~Inbox() { |
+ // Remove ourselves from the corresponding message bus. |
+ SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); |
+ SkAutoMutexAcquire lock(bus->fInboxesMutex); |
+ // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter. |
scroggo
2013/10/22 21:04:02
Clever. Should this be an option on SkTDArray?
bsalomon
2013/10/23 13:52:57
It already is: removeShuffle
mtklein
2013/10/23 15:28:10
Ah! Missed that. Updated.
|
+ for (int i = 0; i < bus->fInboxes.count(); i++) { |
+ if (this == bus->fInboxes[i]) { |
+ bus->fInboxes[i] = bus->fInboxes.top(); |
+ bus->fInboxes.pop(); |
+ break; |
+ } |
+ } |
+} |
+ |
+template<typename Message> |
+void SkMessageBus<Message>::Inbox::receive(const Message& m) { |
+ SkAutoMutexAcquire lock(fMessagesMutex); |
+ fMessages.push(m); |
+} |
+ |
+template<typename Message> |
+void SkMessageBus<Message>::Inbox::poll(SkTDArray<Message>* messages) { |
+ messages->reset(); |
scroggo
2013/10/22 21:04:02
Should we check for NULL or assert non NULL?
mtklein
2013/10/23 15:28:10
Yes. Added an assert.
|
+ SkAutoMutexAcquire lock(fMessagesMutex); |
+ messages->swap(fMessages); |
+} |
+ |
+// ----------------------- Implementation of SkMessageBus ----------------------- |
+ |
+template <typename Message> |
+SkMessageBus<Message>::SkMessageBus() {} |
+ |
+template <typename Message> |
+/*static*/ void SkMessageBus<Message>::New(SkMessageBus<Message>** bus) { |
+ *bus = new SkMessageBus<Message>(); |
+} |
+ |
+template <typename Message> |
+/*static*/ SkMessageBus<Message>* SkMessageBus<Message>::Get() { |
+ // The first time this method is called, create the singleton bus for this message type. |
+ static SkMessageBus<Message>* bus = NULL; |
+ static bool initialized = false; |
+ SK_DECLARE_STATIC_MUTEX(mutex); |
+ |
+ sk_once(&initialized, &mutex, &New, &bus); |
+ |
+ SkASSERT(bus != NULL); |
+ return bus; |
+} |
+ |
+template <typename Message> |
+/*static*/ void SkMessageBus<Message>::post(const Message& m) { |
bsalomon
2013/10/23 13:52:57
Is the Get()/post() pattern useful? Could we just
mtklein
2013/10/23 15:28:10
Ah, this may just be an issue with my tenuous gras
bsalomon
2013/10/23 15:32:27
Ha... I should have realized that from the impl.
|
+ SkMessageBus<Message>* bus = SkMessageBus<Message>::Get(); |
+ SkAutoMutexAcquire lock(bus->fInboxesMutex); |
+ for (int i = 0; i < bus->fInboxes.count(); i++) { |
+ bus->fInboxes[i]->receive(m); |
+ } |
+} |
+ |
+#endif // SkMessageBus_DEFINED |