Home | History | Annotate | Download | only in core
      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>
     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>
     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>
     72 void SkMessageBus<Message>::Inbox::receive(const Message& m) {
     73     SkAutoMutexAcquire lock(fMessagesMutex);
     74     fMessages.push(m);
     75 }
     76 
     77 template<typename Message>
     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>
     88 SkMessageBus<Message>::SkMessageBus() {}
     89 
     90 template <typename Message>
     91 /*static*/ void SkMessageBus<Message>::New(SkMessageBus<Message>** bus) {
     92     *bus = new SkMessageBus<Message>();
     93 }
     94 
     95 template <typename Message>
     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>
    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