Index: chrome/browser/sync/util/channel.h |
diff --git a/chrome/browser/sync/util/channel.h b/chrome/browser/sync/util/channel.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ba516b6e789e18877068f03b59a2a74314580b78 |
--- /dev/null |
+++ b/chrome/browser/sync/util/channel.h |
@@ -0,0 +1,140 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef CHROME_BROWSER_SYNC_UTIL_CHANNEL_H_ |
+#define CHROME_BROWSER_SYNC_UTIL_CHANNEL_H_ |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+// |
+// OVERVIEW: |
+// |
+// A threadsafe container for a list of observers. Observers are able to |
+// remove themselves during iteration, and can be added on any thread. This |
+// allows observers to safely remove themselves during notifications. It |
+// also provides a handler when an observer is added that will remove the |
+// observer on destruction. |
+// |
+// It is expected that all observers are removed before destruction. |
+// The channel owner should notify all observers to disconnect on shutdown if |
+// needed to ensure this. |
+// |
+// TYPICAL USAGE: |
+// |
+// class MyWidget { |
+// public: |
+// ... |
+// |
+// class Observer : public ChannelEventHandler<FooEvent> { |
+// public: |
+// virtual void HandleChannelEvent(const FooEvent& w) = 0; |
+// }; |
+// |
+// ChannelHookup<MyEvent>* AddObserver(Observer* obs) { |
+// return channel_.AddObserver(obs); |
+// } |
+// |
+// void RemoveObserver(Observer* obs) { |
+// channel_.RemoveObserver(obs); |
+// } |
+// |
+// void NotifyFoo(FooEvent& event) { |
+// channel_.Notify(event); |
+// } |
+// |
+// private: |
+// Channel<FooEvent> channel_; |
+// }; |
+// |
+// |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+#include "base/lock.h" |
+#include "base/observer_list.h" |
+ |
+namespace browser_sync { |
+ |
+template <typename EventType> |
+class Channel; |
+ |
+class EventHandler { |
+}; |
+ |
+template <typename EventType> |
+class ChannelEventHandler : public EventHandler { |
+ public: |
+ virtual void HandleChannelEvent(const EventType& event) = 0; |
+}; |
+ |
+// This class manages a connection to a channel. When it is destroyed, it |
+// will remove the listener from the channel observer list. |
+template <typename EventType> |
+class ChannelHookup { |
+ public: |
+ ChannelHookup(Channel<EventType>* channel, |
+ browser_sync::ChannelEventHandler<EventType>* handler) |
+ : channel_(channel), |
+ handler_(handler) {} |
+ ~ChannelHookup() { |
+ channel_->RemoveObserver(handler_); |
+ } |
+ |
+ private: |
+ Channel<EventType>* channel_; |
+ browser_sync::ChannelEventHandler<EventType>* handler_; |
+}; |
+ |
+template <typename EventType> |
+class Channel { |
+ public: |
+ typedef ObserverListBase<EventHandler> ChannelObserverList; |
+ |
+ Channel() : locking_thread_(0) {} |
+ |
+ ChannelHookup<EventType>* AddObserver( |
+ ChannelEventHandler<EventType>* observer) { |
+ AutoLock scoped_lock(event_handlers_mutex_); |
+ event_handlers_.AddObserver(observer); |
+ return new ChannelHookup<EventType>(this, observer); |
+ } |
+ |
+ void RemoveObserver(ChannelEventHandler<EventType>* observer) { |
+ // This can be called in response to a notification, so we may already have |
+ // locked this channel on this thread. |
+ bool need_lock = (locking_thread_ != PlatformThread::CurrentId()); |
+ if (need_lock) |
+ event_handlers_mutex_.Acquire(); |
+ |
+ event_handlers_mutex_.AssertAcquired(); |
+ event_handlers_.RemoveObserver(observer); |
+ if (need_lock) |
+ event_handlers_mutex_.Release(); |
+ } |
+ |
+ void Notify(const EventType& event) { |
+ AutoLock scoped_lock(event_handlers_mutex_); |
+ |
+ // This may result in an observer trying to remove itself, so keep track |
+ // of the thread we're locked on. |
+ locking_thread_ = PlatformThread::CurrentId(); |
+ |
+ ChannelObserverList::Iterator it(event_handlers_); |
+ EventHandler* obs; |
+ while ((obs = it.GetNext()) != NULL) { |
+ static_cast<ChannelEventHandler<EventType>* >(obs)-> |
+ HandleChannelEvent(event); |
+ } |
+ |
+ // Set back to an invalid thread id. |
+ locking_thread_ = 0; |
+ } |
+ |
+ private: |
+ Lock event_handlers_mutex_; |
+ PlatformThreadId locking_thread_; |
+ ObserverList<EventHandler> event_handlers_; |
+}; |
+ |
+} // namespace browser_sync |
+ |
+#endif // CHROME_BROWSER_SYNC_UTIL_CHANNEL_H_ |