SkMessageBus.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. #ifndef SkMessageBus_DEFINED
  8. #define SkMessageBus_DEFINED
  9. #include "include/core/SkTypes.h"
  10. #include "include/private/SkMutex.h"
  11. #include "include/private/SkNoncopyable.h"
  12. #include "include/private/SkOnce.h"
  13. #include "include/private/SkTArray.h"
  14. #include "include/private/SkTDArray.h"
  15. /**
  16. * The following method must have a specialization for type 'Message':
  17. *
  18. * bool SkShouldPostMessageToBus(const Message&, uint32_t msgBusUniqueID)
  19. *
  20. * We may want to consider providing a default template implementation, to avoid this requirement by
  21. * sending to all inboxes when the specialization for type 'Message' is not present.
  22. */
  23. template <typename Message>
  24. class SkMessageBus : SkNoncopyable {
  25. public:
  26. // Post a message to be received by Inboxes for this Message type. Checks
  27. // SkShouldPostMessageToBus() for each inbox. Threadsafe.
  28. static void Post(const Message& m);
  29. class Inbox {
  30. public:
  31. Inbox(uint32_t uniqueID = SK_InvalidUniqueID);
  32. ~Inbox();
  33. uint32_t uniqueID() const { return fUniqueID; }
  34. // Overwrite out with all the messages we've received since the last call. Threadsafe.
  35. void poll(SkTArray<Message>* out);
  36. private:
  37. SkTArray<Message> fMessages;
  38. SkMutex fMessagesMutex;
  39. uint32_t fUniqueID;
  40. friend class SkMessageBus;
  41. void receive(const Message& m); // SkMessageBus is a friend only to call this.
  42. };
  43. private:
  44. SkMessageBus();
  45. static SkMessageBus* Get();
  46. SkTDArray<Inbox*> fInboxes;
  47. SkMutex fInboxesMutex;
  48. };
  49. // This must go in a single .cpp file, not some .h, or we risk creating more than one global
  50. // SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile.
  51. #define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \
  52. template <> \
  53. SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
  54. static SkOnce once; \
  55. static SkMessageBus<Message>* bus; \
  56. once([] { bus = new SkMessageBus<Message>(); }); \
  57. return bus; \
  58. }
  59. // ----------------------- Implementation of SkMessageBus::Inbox -----------------------
  60. template<typename Message>
  61. SkMessageBus<Message>::Inbox::Inbox(uint32_t uniqueID) : fUniqueID(uniqueID) {
  62. // Register ourselves with the corresponding message bus.
  63. SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
  64. SkAutoMutexExclusive lock(bus->fInboxesMutex);
  65. bus->fInboxes.push_back(this);
  66. }
  67. template<typename Message>
  68. SkMessageBus<Message>::Inbox::~Inbox() {
  69. // Remove ourselves from the corresponding message bus.
  70. SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
  71. SkAutoMutexExclusive lock(bus->fInboxesMutex);
  72. // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
  73. for (int i = 0; i < bus->fInboxes.count(); i++) {
  74. if (this == bus->fInboxes[i]) {
  75. bus->fInboxes.removeShuffle(i);
  76. break;
  77. }
  78. }
  79. }
  80. template<typename Message>
  81. void SkMessageBus<Message>::Inbox::receive(const Message& m) {
  82. SkAutoMutexExclusive lock(fMessagesMutex);
  83. fMessages.push_back(m);
  84. }
  85. template<typename Message>
  86. void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) {
  87. SkASSERT(messages);
  88. messages->reset();
  89. SkAutoMutexExclusive lock(fMessagesMutex);
  90. fMessages.swap(*messages);
  91. }
  92. // ----------------------- Implementation of SkMessageBus -----------------------
  93. template <typename Message>
  94. SkMessageBus<Message>::SkMessageBus() {}
  95. template <typename Message>
  96. /*static*/ void SkMessageBus<Message>::Post(const Message& m) {
  97. SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
  98. SkAutoMutexExclusive lock(bus->fInboxesMutex);
  99. for (int i = 0; i < bus->fInboxes.count(); i++) {
  100. if (SkShouldPostMessageToBus(m, bus->fInboxes[i]->fUniqueID)) {
  101. bus->fInboxes[i]->receive(m);
  102. }
  103. }
  104. }
  105. #endif // SkMessageBus_DEFINED