ipc/chromium/src/base/observer_list_threadsafe.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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.
     5 #ifndef BASE_OBSERVER_LIST_THREADSAFE_H_
     6 #define BASE_OBSERVER_LIST_THREADSAFE_H_
     8 #include <vector>
     9 #include <algorithm>
    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"
    18 namespace base {
    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   ObserverListThreadSafe() {}
    58   ~ObserverListThreadSafe() {
    59     typename ObserversListMap::const_iterator it;
    60     for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it)
    61       delete (*it).second;
    62     observer_lists_.clear();
    63   }
    65   // Add an observer to the list.
    66   void AddObserver(ObserverType* obs) {
    67     ObserverList<ObserverType>* list = NULL;
    68     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     if (!loop)
    73       return;  // Some unittests may access this without a message loop.
    74     {
    75       AutoLock lock(list_lock_);
    76       if (observer_lists_.find(loop) == observer_lists_.end())
    77         observer_lists_[loop] = new ObserverList<ObserverType>();
    78       list = observer_lists_[loop];
    79     }
    80     list->AddObserver(obs);
    81   }
    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   void RemoveObserver(ObserverType* obs) {
    89     ObserverList<ObserverType>* list = NULL;
    90     MessageLoop* loop = MessageLoop::current();
    91     if (!loop)
    92       return;  // On shutdown, it is possible that current() is already null.
    93     {
    94       AutoLock lock(list_lock_);
    95       list = observer_lists_[loop];
    96       if (!list) {
    97         NOTREACHED() << "RemoveObserver called on for unknown thread";
    98         return;
    99       }
   101       // If we're about to remove the last observer from the list,
   102       // then we can remove this observer_list entirely.
   103       if (list->size() == 1)
   104         observer_lists_.erase(loop);
   105     }
   106     list->RemoveObserver(obs);
   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     if (list->size() == 0)
   112       delete list;
   113   }
   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   }
   126   template <class Method, class A>
   127   void Notify(Method m, const A &a) {
   128     UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
   129     Notify<Method, Tuple1<A> >(method);
   130   }
   132   // TODO(mbelshe):  Add more wrappers for Notify() with more arguments.
   134  private:
   135   template <class Method, class Params>
   136   void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
   137     AutoLock lock(list_lock_);
   138     typename ObserversListMap::iterator it;
   139     for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
   140       MessageLoop* loop = (*it).first;
   141       ObserverList<ObserverType>* list = (*it).second;
   142       loop->PostTask(FROM_HERE,
   143           NewRunnableMethod(this,
   144               &ObserverListThreadSafe<ObserverType>::
   145                  template NotifyWrapper<Method, Params>, list, method));
   146     }
   147   }
   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   void NotifyWrapper(ObserverList<ObserverType>* list,
   154       const UnboundMethod<ObserverType, Method, Params>& method) {
   156     // Check that this list still needs notifications.
   157     {
   158       AutoLock lock(list_lock_);
   159       typename ObserversListMap::iterator it =
   160           observer_lists_.find(MessageLoop::current());
   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       if (it == observer_lists_.end() || it->second != list)
   167         return;
   168     }
   170     {
   171       typename ObserverList<ObserverType>::Iterator it(*list);
   172       ObserverType* obs;
   173       while ((obs = it.GetNext()) != NULL)
   174         method.Run(obs);
   175     }
   177     // If there are no more observers on the list, we can now delete it.
   178     if (list->size() == 0) {
   179 #ifndef NDEBUG
   180       {
   181         AutoLock lock(list_lock_);
   182         // Verify this list is no longer registered.
   183         typename ObserversListMap::iterator it =
   184             observer_lists_.find(MessageLoop::current());
   185         DCHECK(it == observer_lists_.end() || it->second != list);
   186       }
   187 #endif
   188       delete list;
   189     }
   190   }
   192   typedef std::map<MessageLoop*, ObserverList<ObserverType>*> ObserversListMap;
   194   // These are marked mutable to facilitate having NotifyAll be const.
   195   Lock list_lock_;  // Protects the observer_lists_.
   196   ObserversListMap observer_lists_;
   198   DISALLOW_EVIL_CONSTRUCTORS(ObserverListThreadSafe);
   199 };
   201 } // namespace base
   203 #endif  // BASE_OBSERVER_LIST_THREADSAFE_H_

mercurial