15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_OBSERVER_LIST_THREADSAFE_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/observer_list.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OVERVIEW:
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   A thread-safe container for a list of observers.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   This is similar to the observer_list (see observer_list.h), but it
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   is more robust for multi-threaded situations.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   The following use cases are supported:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    * Observers can register for notifications from any thread.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      Callbacks to the observer will occur on the same thread where
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      the observer initially called AddObserver() from.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    * Any thread may trigger a notification via Notify().
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    * Observers can remove themselves from the observer list inside
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      of a callback.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    * If one thread is notifying observers concurrently with an observer
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      removing itself from the observer list, the notifications will
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      be silently dropped.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   The drawback of the threadsafe observer list is that notifications
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   are not as real-time as the non-threadsafe version of this class.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Notifications will always be done via PostTask() to another thread,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   whereas with the non-thread-safe observer_list, notifications happen
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   synchronously and immediately.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   IMPLEMENTATION NOTES
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   The ObserverListThreadSafe maintains an ObserverList for each thread
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   which uses the ThreadSafeObserver.  When Notifying the observers,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   we simply call PostTask to each registered thread, and then each thread
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   will notify its regular ObserverList.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Forward declaration for ObserverListThreadSafeTraits.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ObserverType>
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ObserverListThreadSafe;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An UnboundMethod is a wrapper for a method where the actual object is
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// provided at Run dispatch time.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class T, class Method, class Params>
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UnboundMethod {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    COMPILE_ASSERT(
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        badunboundmethodparams);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Run(T* obj) const {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DispatchToMethod(obj, m_, p_);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Method m_;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Params p_;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is used to work around VS2005 not accepting:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// friend class
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Instead of friending the class, we could friend the actual function
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which calls delete.  However, this ends up being
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RefCountedThreadSafe::DeleteInternal(), which is private.  So we
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// define our own templated traits class so we can friend it.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class T>
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ObserverListThreadSafeTraits {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void Destruct(const ObserverListThreadSafe<T>* x) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete x;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ObserverType>
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ObserverListThreadSafe
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ObserverListThreadSafe<ObserverType>,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ObserverListThreadSafeTraits<ObserverType> > {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef typename ObserverList<ObserverType>::NotificationType
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotificationType;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ObserverListThreadSafe()
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add an observer to the list.  An observer should not be added to
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the same list more than once.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddObserver(ObserverType* obs) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there is not a current MessageLoop, it is impossible to notify on it,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // so do not add the observer.
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!base::MessageLoop::current())
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ObserverList<ObserverType>* list = NULL;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock lock(list_lock_);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (observer_lists_.find(thread_id) == observer_lists_.end())
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        observer_lists_[thread_id] = new ObserverListContext(type_);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      list = &(observer_lists_[thread_id]->list);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    list->AddObserver(obs);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove an observer from the list if it is in the list.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there are pending notifications in-transit to the observer, they will
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be aborted.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the observer to be removed is in the list, RemoveObserver MUST
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be called from the same thread which called AddObserver.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RemoveObserver(ObserverType* obs) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ObserverListContext* context = NULL;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ObserverList<ObserverType>* list = NULL;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock lock(list_lock_);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      typename ObserversListMap::iterator it = observer_lists_.find(thread_id);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (it == observer_lists_.end()) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // This will happen if we try to remove an observer on a thread
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // we never added an observer for.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context = it->second;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      list = &context->list;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we're about to remove the last observer from the list,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // then we can remove this observer_list entirely.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (list->HasObserver(obs) && list->size() == 1)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        observer_lists_.erase(it);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    list->RemoveObserver(obs);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If RemoveObserver is called from a notification, the size will be
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // nonzero.  Instead of deleting here, the NotifyWrapper will delete
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // when it finishes iterating.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (list->size() == 0)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete context;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verifies that the list is currently empty (i.e. there are no observers).
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AssertEmpty() const {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(list_lock_);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(observer_lists_.empty());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify methods.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make a thread-safe callback to each Observer in the list.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note, these calls are effectively asynchronous.  You cannot assume
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that at the completion of the Notify call that all Observers have
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // been Notified.  The notification may still be pending delivery.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class Method>
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Notify(Method m) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Notify<Method, Tuple0>(method);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class Method, class A>
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Notify(Method m, const A& a) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Notify<Method, Tuple1<A> >(method);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class Method, class A, class B>
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Notify(Method m, const A& a, const B& b) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnboundMethod<ObserverType, Method, Tuple2<A, B> > method(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        m, MakeTuple(a, b));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Notify<Method, Tuple2<A, B> >(method);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class Method, class A, class B, class C>
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Notify(Method m, const A& a, const B& b, const C& c) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnboundMethod<ObserverType, Method, Tuple3<A, B, C> > method(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        m, MakeTuple(a, b, c));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Notify<Method, Tuple3<A, B, C> >(method);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class Method, class A, class B, class C, class D>
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Notify(Method m, const A& a, const B& b, const C& c, const D& d) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnboundMethod<ObserverType, Method, Tuple4<A, B, C, D> > method(
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        m, MakeTuple(a, b, c, d));
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Notify<Method, Tuple4<A, B, C, D> >(method);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mbelshe):  Add more wrappers for Notify() with more arguments.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See comment above ObserverListThreadSafeTraits' definition.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct ObserverListThreadSafeTraits<ObserverType>;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct ObserverListContext {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    explicit ObserverListContext(NotificationType type)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : loop(base::MessageLoopProxy::current()),
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          list(type) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> loop;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ObserverList<ObserverType> list;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ObserverListThreadSafe() {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STLDeleteValues(&observer_lists_);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class Method, class Params>
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock lock(list_lock_);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    typename ObserversListMap::iterator it;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ObserverListContext* context = (*it).second;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context->loop->PostTask(
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&ObserverListThreadSafe<ObserverType>::
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              template NotifyWrapper<Method, Params>, this, context, method));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wrapper which is called to fire the notifications for each thread's
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ObserverList.  This function MUST be called on the thread which owns
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the unsafe ObserverList.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  template <class Method, class Params>
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyWrapper(ObserverListContext* context,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const UnboundMethod<ObserverType, Method, Params>& method) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that this list still needs notifications.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock lock(list_lock_);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      typename ObserversListMap::iterator it =
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          observer_lists_.find(base::PlatformThread::CurrentId());
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The ObserverList could have been removed already.  In fact, it could
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // have been removed and then re-added!  If the master list's loop
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // does not match this one, then we do not need to finish this
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // notification.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (it == observer_lists_.end() || it->second != context)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      typename ObserverList<ObserverType>::Iterator it(context->list);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ObserverType* obs;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while ((obs = it.GetNext()) != NULL)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        method.Run(obs);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there are no more observers on the list, we can now delete it.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (context->list.size() == 0) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::AutoLock lock(list_lock_);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Remove |list| if it's not already removed.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // This can happen if multiple observers got removed in a notification.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // See http://crbug.com/55725.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        typename ObserversListMap::iterator it =
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            observer_lists_.find(base::PlatformThread::CurrentId());
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (it != observer_lists_.end() && it->second == context)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          observer_lists_.erase(it);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete context;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Key by PlatformThreadId because in tests, clients can attempt to remove
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // observers without a MessageLoop. If this were keyed by MessageLoop, that
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // operation would be silently ignored, leaving garbage in the ObserverList.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<base::PlatformThreadId, ObserverListContext*>
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ObserversListMap;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable base::Lock list_lock_;  // Protects the observer_lists_.
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ObserversListMap observer_lists_;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const NotificationType type_;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
296