Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
      6 #define BASE_OBSERVER_LIST_THREADSAFE_H_
      7 #pragma once
      8 
      9 #include <algorithm>
     10 #include <map>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/callback.h"
     14 #include "base/logging.h"
     15 #include "base/memory/ref_counted.h"
     16 #include "base/message_loop.h"
     17 #include "base/observer_list.h"
     18 #include "base/task.h"
     19 
     20 ///////////////////////////////////////////////////////////////////////////////
     21 //
     22 // OVERVIEW:
     23 //
     24 //   A thread-safe container for a list of observers.
     25 //   This is similar to the observer_list (see observer_list.h), but it
     26 //   is more robust for multi-threaded situations.
     27 //
     28 //   The following use cases are supported:
     29 //    * Observers can register for notifications from any thread.
     30 //      Callbacks to the observer will occur on the same thread where
     31 //      the observer initially called AddObserver() from.
     32 //    * Any thread may trigger a notification via Notify().
     33 //    * Observers can remove themselves from the observer list inside
     34 //      of a callback.
     35 //    * If one thread is notifying observers concurrently with an observer
     36 //      removing itself from the observer list, the notifications will
     37 //      be silently dropped.
     38 //
     39 //   The drawback of the threadsafe observer list is that notifications
     40 //   are not as real-time as the non-threadsafe version of this class.
     41 //   Notifications will always be done via PostTask() to another thread,
     42 //   whereas with the non-thread-safe observer_list, notifications happen
     43 //   synchronously and immediately.
     44 //
     45 //   IMPLEMENTATION NOTES
     46 //   The ObserverListThreadSafe maintains an ObserverList for each thread
     47 //   which uses the ThreadSafeObserver.  When Notifying the observers,
     48 //   we simply call PostTask to each registered thread, and then each thread
     49 //   will notify its regular ObserverList.
     50 //
     51 ///////////////////////////////////////////////////////////////////////////////
     52 
     53 // Forward declaration for ObserverListThreadSafeTraits.
     54 template <class ObserverType>
     55 class ObserverListThreadSafe;
     56 
     57 // This class is used to work around VS2005 not accepting:
     58 //
     59 // friend class
     60 //     base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >;
     61 //
     62 // Instead of friending the class, we could friend the actual function
     63 // which calls delete.  However, this ends up being
     64 // RefCountedThreadSafe::DeleteInternal(), which is private.  So we
     65 // define our own templated traits class so we can friend it.
     66 template <class T>
     67 struct ObserverListThreadSafeTraits {
     68   static void Destruct(const ObserverListThreadSafe<T>* x) {
     69     delete x;
     70   }
     71 };
     72 
     73 template <class ObserverType>
     74 class ObserverListThreadSafe
     75     : public base::RefCountedThreadSafe<
     76         ObserverListThreadSafe<ObserverType>,
     77         ObserverListThreadSafeTraits<ObserverType> > {
     78  public:
     79   typedef typename ObserverList<ObserverType>::NotificationType
     80       NotificationType;
     81 
     82   ObserverListThreadSafe()
     83       : type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
     84   explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
     85 
     86   // Add an observer to the list.
     87   void AddObserver(ObserverType* obs) {
     88     ObserverList<ObserverType>* list = NULL;
     89     MessageLoop* loop = MessageLoop::current();
     90     // TODO(mbelshe): Get rid of this check.  Its needed right now because
     91     //                Time currently triggers usage of the ObserverList.
     92     //                And unittests use time without a MessageLoop.
     93     if (!loop)
     94       return;  // Some unittests may access this without a message loop.
     95     {
     96       base::AutoLock lock(list_lock_);
     97       if (observer_lists_.find(loop) == observer_lists_.end())
     98         observer_lists_[loop] = new ObserverList<ObserverType>(type_);
     99       list = observer_lists_[loop];
    100     }
    101     list->AddObserver(obs);
    102   }
    103 
    104   // Remove an observer from the list.
    105   // If there are pending notifications in-transit to the observer, they will
    106   // be aborted.
    107   // RemoveObserver MUST be called from the same thread which called
    108   // AddObserver.
    109   void RemoveObserver(ObserverType* obs) {
    110     ObserverList<ObserverType>* list = NULL;
    111     MessageLoop* loop = MessageLoop::current();
    112     if (!loop)
    113       return;  // On shutdown, it is possible that current() is already null.
    114     {
    115       base::AutoLock lock(list_lock_);
    116       list = observer_lists_[loop];
    117       if (!list) {
    118         NOTREACHED() << "RemoveObserver called on for unknown thread";
    119         return;
    120       }
    121 
    122       // If we're about to remove the last observer from the list,
    123       // then we can remove this observer_list entirely.
    124       if (list->size() == 1)
    125         observer_lists_.erase(loop);
    126     }
    127     list->RemoveObserver(obs);
    128 
    129     // If RemoveObserver is called from a notification, the size will be
    130     // nonzero.  Instead of deleting here, the NotifyWrapper will delete
    131     // when it finishes iterating.
    132     if (list->size() == 0)
    133       delete list;
    134   }
    135 
    136   // Notify methods.
    137   // Make a thread-safe callback to each Observer in the list.
    138   // Note, these calls are effectively asynchronous.  You cannot assume
    139   // that at the completion of the Notify call that all Observers have
    140   // been Notified.  The notification may still be pending delivery.
    141   template <class Method>
    142   void Notify(Method m) {
    143     UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
    144     Notify<Method, Tuple0>(method);
    145   }
    146 
    147   template <class Method, class A>
    148   void Notify(Method m, const A &a) {
    149     UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
    150     Notify<Method, Tuple1<A> >(method);
    151   }
    152 
    153   // TODO(mbelshe):  Add more wrappers for Notify() with more arguments.
    154 
    155  private:
    156   // See comment above ObserverListThreadSafeTraits' definition.
    157   friend struct ObserverListThreadSafeTraits<ObserverType>;
    158 
    159   ~ObserverListThreadSafe() {
    160     typename ObserversListMap::const_iterator it;
    161     for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
    162       delete (*it).second;
    163     observer_lists_.clear();
    164   }
    165 
    166   template <class Method, class Params>
    167   void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
    168     base::AutoLock lock(list_lock_);
    169     typename ObserversListMap::iterator it;
    170     for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
    171       MessageLoop* loop = (*it).first;
    172       ObserverList<ObserverType>* list = (*it).second;
    173       loop->PostTask(
    174           FROM_HERE,
    175           NewRunnableMethod(this,
    176               &ObserverListThreadSafe<ObserverType>::
    177                  template NotifyWrapper<Method, Params>, list, method));
    178     }
    179   }
    180 
    181   // Wrapper which is called to fire the notifications for each thread's
    182   // ObserverList.  This function MUST be called on the thread which owns
    183   // the unsafe ObserverList.
    184   template <class Method, class Params>
    185   void NotifyWrapper(ObserverList<ObserverType>* list,
    186       const UnboundMethod<ObserverType, Method, Params>& method) {
    187 
    188     // Check that this list still needs notifications.
    189     {
    190       base::AutoLock lock(list_lock_);
    191       typename ObserversListMap::iterator it =
    192           observer_lists_.find(MessageLoop::current());
    193 
    194       // The ObserverList could have been removed already.  In fact, it could
    195       // have been removed and then re-added!  If the master list's loop
    196       // does not match this one, then we do not need to finish this
    197       // notification.
    198       if (it == observer_lists_.end() || it->second != list)
    199         return;
    200     }
    201 
    202     {
    203       typename ObserverList<ObserverType>::Iterator it(*list);
    204       ObserverType* obs;
    205       while ((obs = it.GetNext()) != NULL)
    206         method.Run(obs);
    207     }
    208 
    209     // If there are no more observers on the list, we can now delete it.
    210     if (list->size() == 0) {
    211       {
    212         base::AutoLock lock(list_lock_);
    213         // Remove |list| if it's not already removed.
    214         // This can happen if multiple observers got removed in a notification.
    215         // See http://crbug.com/55725.
    216         typename ObserversListMap::iterator it =
    217             observer_lists_.find(MessageLoop::current());
    218         if (it != observer_lists_.end() && it->second == list)
    219           observer_lists_.erase(it);
    220       }
    221       delete list;
    222     }
    223   }
    224 
    225   typedef std::map<MessageLoop*, ObserverList<ObserverType>*> ObserversListMap;
    226 
    227   // These are marked mutable to facilitate having NotifyAll be const.
    228   base::Lock list_lock_;  // Protects the observer_lists_.
    229   ObserversListMap observer_lists_;
    230   const NotificationType type_;
    231 
    232   DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
    233 };
    234 
    235 #endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
    236