LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - observer_list_threadsafe.h (source / functions) Found Hit Coverage
Test: app.info Lines: 55 0 0.0 %
Date: 2012-06-02 Functions: 7 0 0.0 %

       1                 : // Copyright (c) 2006-2008 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                 : 
       8                 : #include <vector>
       9                 : #include <algorithm>
      10                 : 
      11                 : #include "base/basictypes.h"
      12                 : #include "base/logging.h"
      13                 : #include "base/message_loop.h"
      14                 : #include "base/observer_list.h"
      15                 : #include "base/ref_counted.h"
      16                 : #include "base/task.h"
      17                 : 
      18                 : namespace base {
      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_OBSERVERS.
      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                 : template <class ObserverType>
      53                 : class ObserverListThreadSafe
      54                 :     : public base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> > {
      55                 :  public:
      56               0 :   ObserverListThreadSafe() {}
      57                 : 
      58               0 :   ~ObserverListThreadSafe() {
      59               0 :     typename ObserversListMap::const_iterator it;
      60               0 :     for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
      61               0 :       delete (*it).second;
      62               0 :     observer_lists_.clear();
      63               0 :   }
      64                 : 
      65                 :   // Add an observer to the list.
      66               0 :   void AddObserver(ObserverType* obs) {
      67               0 :     ObserverList<ObserverType>* list = NULL;
      68               0 :     MessageLoop* loop = MessageLoop::current();
      69                 :     // TODO(mbelshe): Get rid of this check.  Its needed right now because
      70                 :     //                Time currently triggers usage of the ObserverList.
      71                 :     //                And unittests use time without a MessageLoop.
      72               0 :     if (!loop)
      73               0 :       return;  // Some unittests may access this without a message loop.
      74                 :     {
      75               0 :       AutoLock lock(list_lock_);
      76               0 :       if (observer_lists_.find(loop) == observer_lists_.end())
      77               0 :         observer_lists_[loop] = new ObserverList<ObserverType>();
      78               0 :       list = observer_lists_[loop];
      79                 :     }
      80               0 :     list->AddObserver(obs);
      81                 :   }
      82                 : 
      83                 :   // Remove an observer from the list.
      84                 :   // If there are pending notifications in-transit to the observer, they will
      85                 :   // be aborted.
      86                 :   // RemoveObserver MUST be called from the same thread which called
      87                 :   // AddObserver.
      88               0 :   void RemoveObserver(ObserverType* obs) {
      89               0 :     ObserverList<ObserverType>* list = NULL;
      90               0 :     MessageLoop* loop = MessageLoop::current();
      91               0 :     if (!loop)
      92               0 :       return;  // On shutdown, it is possible that current() is already null.
      93                 :     {
      94               0 :       AutoLock lock(list_lock_);
      95               0 :       list = observer_lists_[loop];
      96               0 :       if (!list) {
      97               0 :         NOTREACHED() << "RemoveObserver called on for unknown thread";
      98                 :         return;
      99                 :       }
     100                 : 
     101                 :       // If we're about to remove the last observer from the list,
     102                 :       // then we can remove this observer_list entirely.
     103               0 :       if (list->size() == 1)
     104               0 :         observer_lists_.erase(loop);
     105                 :     }
     106               0 :     list->RemoveObserver(obs);
     107                 : 
     108                 :     // If RemoveObserver is called from a notification, the size will be
     109                 :     // nonzero.  Instead of deleting here, the NotifyWrapper will delete
     110                 :     // when it finishes iterating.
     111               0 :     if (list->size() == 0)
     112               0 :       delete list;
     113                 :   }
     114                 : 
     115                 :   // Notify methods.
     116                 :   // Make a thread-safe callback to each Observer in the list.
     117                 :   // Note, these calls are effectively asynchronous.  You cannot assume
     118                 :   // that at the completion of the Notify call that all Observers have
     119                 :   // been Notified.  The notification may still be pending delivery.
     120                 :   template <class Method>
     121                 :   void Notify(Method m) {
     122                 :     UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
     123                 :     Notify<Method, Tuple0>(method);
     124                 :   }
     125                 : 
     126                 :   template <class Method, class A>
     127               0 :   void Notify(Method m, const A &a) {
     128               0 :     UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
     129               0 :     Notify<Method, Tuple1<A> >(method);
     130               0 :   }
     131                 : 
     132                 :   // TODO(mbelshe):  Add more wrappers for Notify() with more arguments.
     133                 : 
     134                 :  private:
     135                 :   template <class Method, class Params>
     136               0 :   void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
     137               0 :     AutoLock lock(list_lock_);
     138               0 :     typename ObserversListMap::iterator it;
     139               0 :     for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
     140               0 :       MessageLoop* loop = (*it).first;
     141               0 :       ObserverList<ObserverType>* list = (*it).second;
     142               0 :       loop->PostTask(FROM_HERE,
     143                 :           NewRunnableMethod(this,
     144                 :               &ObserverListThreadSafe<ObserverType>::
     145                 :                  template NotifyWrapper<Method, Params>, list, method));
     146                 :     }
     147               0 :   }
     148                 : 
     149                 :   // Wrapper which is called to fire the notifications for each thread's
     150                 :   // ObserverList.  This function MUST be called on the thread which owns
     151                 :   // the unsafe ObserverList.
     152                 :   template <class Method, class Params>
     153               0 :   void NotifyWrapper(ObserverList<ObserverType>* list,
     154                 :       const UnboundMethod<ObserverType, Method, Params>& method) {
     155                 : 
     156                 :     // Check that this list still needs notifications.
     157                 :     {
     158               0 :       AutoLock lock(list_lock_);
     159                 :       typename ObserversListMap::iterator it =
     160               0 :           observer_lists_.find(MessageLoop::current());
     161                 : 
     162                 :       // The ObserverList could have been removed already.  In fact, it could
     163                 :       // have been removed and then re-added!  If the master list's loop
     164                 :       // does not match this one, then we do not need to finish this
     165                 :       // notification.
     166               0 :       if (it == observer_lists_.end() || it->second != list)
     167                 :         return;
     168                 :     }
     169                 : 
     170                 :     {
     171               0 :       typename ObserverList<ObserverType>::Iterator it(*list);
     172                 :       ObserverType* obs;
     173               0 :       while ((obs = it.GetNext()) != NULL)
     174               0 :         method.Run(obs);
     175                 :     }
     176                 : 
     177                 :     // If there are no more observers on the list, we can now delete it.
     178               0 :     if (list->size() == 0) {
     179                 : #ifndef NDEBUG
     180                 :       {
     181               0 :         AutoLock lock(list_lock_);
     182                 :         // Verify this list is no longer registered.
     183                 :         typename ObserversListMap::iterator it =
     184               0 :             observer_lists_.find(MessageLoop::current());
     185               0 :         DCHECK(it == observer_lists_.end() || it->second != list);
     186                 :       }
     187                 : #endif
     188               0 :       delete list;
     189                 :     }
     190                 :   }
     191                 : 
     192                 :   typedef std::map<MessageLoop*, ObserverList<ObserverType>*> ObserversListMap;
     193                 : 
     194                 :   // These are marked mutable to facilitate having NotifyAll be const.
     195                 :   Lock list_lock_;  // Protects the observer_lists_.
     196                 :   ObserversListMap observer_lists_;
     197                 : 
     198                 :   DISALLOW_EVIL_CONSTRUCTORS(ObserverListThreadSafe);
     199                 : };
     200                 : 
     201                 : } // namespace base
     202                 : 
     203                 : #endif  // BASE_OBSERVER_LIST_THREADSAFE_H_

Generated by: LCOV version 1.7