ipc/chromium/src/base/observer_list_threadsafe.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/base/observer_list_threadsafe.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,203 @@
     1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
     1.9 +#define BASE_OBSERVER_LIST_THREADSAFE_H_
    1.10 +
    1.11 +#include <vector>
    1.12 +#include <algorithm>
    1.13 +
    1.14 +#include "base/basictypes.h"
    1.15 +#include "base/logging.h"
    1.16 +#include "base/message_loop.h"
    1.17 +#include "base/observer_list.h"
    1.18 +#include "base/ref_counted.h"
    1.19 +#include "base/task.h"
    1.20 +
    1.21 +namespace base {
    1.22 +
    1.23 +///////////////////////////////////////////////////////////////////////////////
    1.24 +//
    1.25 +// OVERVIEW:
    1.26 +//
    1.27 +//   A thread-safe container for a list of observers.
    1.28 +//   This is similar to the observer_list (see observer_list.h), but it
    1.29 +//   is more robust for multi-threaded situations.
    1.30 +//
    1.31 +//   The following use cases are supported:
    1.32 +//    * Observers can register for notifications from any thread.
    1.33 +//      Callbacks to the observer will occur on the same thread where
    1.34 +//      the observer initially called AddObserver() from.
    1.35 +//    * Any thread may trigger a notification via NOTIFY_OBSERVERS.
    1.36 +//    * Observers can remove themselves from the observer list inside
    1.37 +//      of a callback.
    1.38 +//    * If one thread is notifying observers concurrently with an observer
    1.39 +//      removing itself from the observer list, the notifications will
    1.40 +//      be silently dropped.
    1.41 +//
    1.42 +//   The drawback of the threadsafe observer list is that notifications
    1.43 +//   are not as real-time as the non-threadsafe version of this class.
    1.44 +//   Notifications will always be done via PostTask() to another thread,
    1.45 +//   whereas with the non-thread-safe observer_list, notifications happen
    1.46 +//   synchronously and immediately.
    1.47 +//
    1.48 +//   IMPLEMENTATION NOTES
    1.49 +//   The ObserverListThreadSafe maintains an ObserverList for each thread
    1.50 +//   which uses the ThreadSafeObserver.  When Notifying the observers,
    1.51 +//   we simply call PostTask to each registered thread, and then each thread
    1.52 +//   will notify its regular ObserverList.
    1.53 +//
    1.54 +///////////////////////////////////////////////////////////////////////////////
    1.55 +template <class ObserverType>
    1.56 +class ObserverListThreadSafe
    1.57 +    : public base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> > {
    1.58 + public:
    1.59 +  ObserverListThreadSafe() {}
    1.60 +
    1.61 +  ~ObserverListThreadSafe() {
    1.62 +    typename ObserversListMap::const_iterator it;
    1.63 +    for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
    1.64 +      delete (*it).second;
    1.65 +    observer_lists_.clear();
    1.66 +  }
    1.67 +
    1.68 +  // Add an observer to the list.
    1.69 +  void AddObserver(ObserverType* obs) {
    1.70 +    ObserverList<ObserverType>* list = NULL;
    1.71 +    MessageLoop* loop = MessageLoop::current();
    1.72 +    // TODO(mbelshe): Get rid of this check.  Its needed right now because
    1.73 +    //                Time currently triggers usage of the ObserverList.
    1.74 +    //                And unittests use time without a MessageLoop.
    1.75 +    if (!loop)
    1.76 +      return;  // Some unittests may access this without a message loop.
    1.77 +    {
    1.78 +      AutoLock lock(list_lock_);
    1.79 +      if (observer_lists_.find(loop) == observer_lists_.end())
    1.80 +        observer_lists_[loop] = new ObserverList<ObserverType>();
    1.81 +      list = observer_lists_[loop];
    1.82 +    }
    1.83 +    list->AddObserver(obs);
    1.84 +  }
    1.85 +
    1.86 +  // Remove an observer from the list.
    1.87 +  // If there are pending notifications in-transit to the observer, they will
    1.88 +  // be aborted.
    1.89 +  // RemoveObserver MUST be called from the same thread which called
    1.90 +  // AddObserver.
    1.91 +  void RemoveObserver(ObserverType* obs) {
    1.92 +    ObserverList<ObserverType>* list = NULL;
    1.93 +    MessageLoop* loop = MessageLoop::current();
    1.94 +    if (!loop)
    1.95 +      return;  // On shutdown, it is possible that current() is already null.
    1.96 +    {
    1.97 +      AutoLock lock(list_lock_);
    1.98 +      list = observer_lists_[loop];
    1.99 +      if (!list) {
   1.100 +        NOTREACHED() << "RemoveObserver called on for unknown thread";
   1.101 +        return;
   1.102 +      }
   1.103 +
   1.104 +      // If we're about to remove the last observer from the list,
   1.105 +      // then we can remove this observer_list entirely.
   1.106 +      if (list->size() == 1)
   1.107 +        observer_lists_.erase(loop);
   1.108 +    }
   1.109 +    list->RemoveObserver(obs);
   1.110 +
   1.111 +    // If RemoveObserver is called from a notification, the size will be
   1.112 +    // nonzero.  Instead of deleting here, the NotifyWrapper will delete
   1.113 +    // when it finishes iterating.
   1.114 +    if (list->size() == 0)
   1.115 +      delete list;
   1.116 +  }
   1.117 +
   1.118 +  // Notify methods.
   1.119 +  // Make a thread-safe callback to each Observer in the list.
   1.120 +  // Note, these calls are effectively asynchronous.  You cannot assume
   1.121 +  // that at the completion of the Notify call that all Observers have
   1.122 +  // been Notified.  The notification may still be pending delivery.
   1.123 +  template <class Method>
   1.124 +  void Notify(Method m) {
   1.125 +    UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
   1.126 +    Notify<Method, Tuple0>(method);
   1.127 +  }
   1.128 +
   1.129 +  template <class Method, class A>
   1.130 +  void Notify(Method m, const A &a) {
   1.131 +    UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
   1.132 +    Notify<Method, Tuple1<A> >(method);
   1.133 +  }
   1.134 +
   1.135 +  // TODO(mbelshe):  Add more wrappers for Notify() with more arguments.
   1.136 +
   1.137 + private:
   1.138 +  template <class Method, class Params>
   1.139 +  void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
   1.140 +    AutoLock lock(list_lock_);
   1.141 +    typename ObserversListMap::iterator it;
   1.142 +    for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
   1.143 +      MessageLoop* loop = (*it).first;
   1.144 +      ObserverList<ObserverType>* list = (*it).second;
   1.145 +      loop->PostTask(FROM_HERE,
   1.146 +          NewRunnableMethod(this,
   1.147 +              &ObserverListThreadSafe<ObserverType>::
   1.148 +                 template NotifyWrapper<Method, Params>, list, method));
   1.149 +    }
   1.150 +  }
   1.151 +
   1.152 +  // Wrapper which is called to fire the notifications for each thread's
   1.153 +  // ObserverList.  This function MUST be called on the thread which owns
   1.154 +  // the unsafe ObserverList.
   1.155 +  template <class Method, class Params>
   1.156 +  void NotifyWrapper(ObserverList<ObserverType>* list,
   1.157 +      const UnboundMethod<ObserverType, Method, Params>& method) {
   1.158 +
   1.159 +    // Check that this list still needs notifications.
   1.160 +    {
   1.161 +      AutoLock lock(list_lock_);
   1.162 +      typename ObserversListMap::iterator it =
   1.163 +          observer_lists_.find(MessageLoop::current());
   1.164 +
   1.165 +      // The ObserverList could have been removed already.  In fact, it could
   1.166 +      // have been removed and then re-added!  If the master list's loop
   1.167 +      // does not match this one, then we do not need to finish this
   1.168 +      // notification.
   1.169 +      if (it == observer_lists_.end() || it->second != list)
   1.170 +        return;
   1.171 +    }
   1.172 +
   1.173 +    {
   1.174 +      typename ObserverList<ObserverType>::Iterator it(*list);
   1.175 +      ObserverType* obs;
   1.176 +      while ((obs = it.GetNext()) != NULL)
   1.177 +        method.Run(obs);
   1.178 +    }
   1.179 +
   1.180 +    // If there are no more observers on the list, we can now delete it.
   1.181 +    if (list->size() == 0) {
   1.182 +#ifndef NDEBUG
   1.183 +      {
   1.184 +        AutoLock lock(list_lock_);
   1.185 +        // Verify this list is no longer registered.
   1.186 +        typename ObserversListMap::iterator it =
   1.187 +            observer_lists_.find(MessageLoop::current());
   1.188 +        DCHECK(it == observer_lists_.end() || it->second != list);
   1.189 +      }
   1.190 +#endif
   1.191 +      delete list;
   1.192 +    }
   1.193 +  }
   1.194 +
   1.195 +  typedef std::map<MessageLoop*, ObserverList<ObserverType>*> ObserversListMap;
   1.196 +
   1.197 +  // These are marked mutable to facilitate having NotifyAll be const.
   1.198 +  Lock list_lock_;  // Protects the observer_lists_.
   1.199 +  ObserversListMap observer_lists_;
   1.200 +
   1.201 +  DISALLOW_EVIL_CONSTRUCTORS(ObserverListThreadSafe);
   1.202 +};
   1.203 +
   1.204 +} // namespace base
   1.205 +
   1.206 +#endif  // BASE_OBSERVER_LIST_THREADSAFE_H_

mercurial