Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6543)

Unified Diff: chrome/browser/sync/util/channel.h

Issue 2075012: Replace changes_channel with an observer list. (Closed)
Patch Set: Ready for checkin Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/sync/syncable/syncable.cc ('k') | chrome/browser/sync/util/channel_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_
« no previous file with comments | « chrome/browser/sync/syncable/syncable.cc ('k') | chrome/browser/sync/util/channel_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698