summaryrefslogtreecommitdiffstats
path: root/content/common/notification_service.cc
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-07 03:53:00 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-07 03:53:00 +0000
commit652e16d050c69adcf9a8e97912d8e554d49902bc (patch)
treed8702ed6cf5ec554872019563f1efdddc5fcc42e /content/common/notification_service.cc
parent5b3e09dcf48a717eccca25d4a99036dcefb31001 (diff)
downloadchromium_src-652e16d050c69adcf9a8e97912d8e554d49902bc.zip
chromium_src-652e16d050c69adcf9a8e97912d8e554d49902bc.tar.gz
chromium_src-652e16d050c69adcf9a8e97912d8e554d49902bc.tar.bz2
Move notification service code to content. We'll need to figure out how to split the type enum so that chrome specific parts aren't in content later.
TBR=avi Review URL: http://codereview.chromium.org/6627043 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77102 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/common/notification_service.cc')
-rw-r--r--content/common/notification_service.cc151
1 files changed, 151 insertions, 0 deletions
diff --git a/content/common/notification_service.cc b/content/common/notification_service.cc
new file mode 100644
index 0000000..59d26d6
--- /dev/null
+++ b/content/common/notification_service.cc
@@ -0,0 +1,151 @@
+// 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.
+
+#include "content/common/notification_service.h"
+
+#include "base/lazy_instance.h"
+#include "base/threading/thread_local.h"
+#include "content/common/notification_observer.h"
+
+static base::LazyInstance<base::ThreadLocalPointer<NotificationService> >
+ lazy_tls_ptr(base::LINKER_INITIALIZED);
+
+// static
+NotificationService* NotificationService::current() {
+ return lazy_tls_ptr.Pointer()->Get();
+}
+
+// static
+bool NotificationService::HasKey(const NotificationSourceMap& map,
+ const NotificationSource& source) {
+ return map.find(source.map_key()) != map.end();
+}
+
+NotificationService::NotificationService() {
+ DCHECK(current() == NULL);
+#ifndef NDEBUG
+ memset(observer_counts_, 0, sizeof(observer_counts_));
+#endif
+
+ lazy_tls_ptr.Pointer()->Set(this);
+}
+
+void NotificationService::AddObserver(NotificationObserver* observer,
+ NotificationType type,
+ const NotificationSource& source) {
+ DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
+
+ // We have gotten some crashes where the observer pointer is NULL. The problem
+ // is that this happens when we actually execute a notification, so have no
+ // way of knowing who the bad observer was. We want to know when this happens
+ // in release mode so we know what code to blame the crash on (since this is
+ // guaranteed to crash later).
+ CHECK(observer);
+
+ NotificationObserverList* observer_list;
+ if (HasKey(observers_[type.value], source)) {
+ observer_list = observers_[type.value][source.map_key()];
+ } else {
+ observer_list = new NotificationObserverList;
+ observers_[type.value][source.map_key()] = observer_list;
+ }
+
+ observer_list->AddObserver(observer);
+#ifndef NDEBUG
+ ++observer_counts_[type.value];
+#endif
+}
+
+void NotificationService::RemoveObserver(NotificationObserver* observer,
+ NotificationType type,
+ const NotificationSource& source) {
+ DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
+
+ // This is a very serious bug. An object is most likely being deleted on
+ // the wrong thread, and as a result another thread's NotificationService
+ // has its deleted pointer in its map. A garbge object will be called in the
+ // future.
+ // NOTE: when this check shows crashes, use BrowserThread::DeleteOnIOThread or
+ // other variants as the trait on the object.
+ CHECK(HasKey(observers_[type.value], source));
+
+ NotificationObserverList* observer_list =
+ observers_[type.value][source.map_key()];
+ if (observer_list) {
+ observer_list->RemoveObserver(observer);
+#ifndef NDEBUG
+ --observer_counts_[type.value];
+#endif
+ }
+
+ // TODO(jhughes): Remove observer list from map if empty?
+}
+
+void NotificationService::Notify(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(type.value > NotificationType::ALL) <<
+ "Allowed for observing, but not posting.";
+ DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
+
+ // There's no particular reason for the order in which the different
+ // classes of observers get notified here.
+
+ // Notify observers of all types and all sources
+ if (HasKey(observers_[NotificationType::ALL], AllSources()) &&
+ source != AllSources()) {
+ FOR_EACH_OBSERVER(NotificationObserver,
+ *observers_[NotificationType::ALL][AllSources().map_key()],
+ Observe(type, source, details));
+ }
+
+ // Notify observers of all types and the given source
+ if (HasKey(observers_[NotificationType::ALL], source)) {
+ FOR_EACH_OBSERVER(NotificationObserver,
+ *observers_[NotificationType::ALL][source.map_key()],
+ Observe(type, source, details));
+ }
+
+ // Notify observers of the given type and all sources
+ if (HasKey(observers_[type.value], AllSources()) &&
+ source != AllSources()) {
+ FOR_EACH_OBSERVER(NotificationObserver,
+ *observers_[type.value][AllSources().map_key()],
+ Observe(type, source, details));
+ }
+
+ // Notify observers of the given type and the given source
+ if (HasKey(observers_[type.value], source)) {
+ FOR_EACH_OBSERVER(NotificationObserver,
+ *observers_[type.value][source.map_key()],
+ Observe(type, source, details));
+ }
+}
+
+
+NotificationService::~NotificationService() {
+ lazy_tls_ptr.Pointer()->Set(NULL);
+
+#ifndef NDEBUG
+ for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
+ if (observer_counts_[i] > 0) {
+ // This may not be completely fixable -- see
+ // http://code.google.com/p/chromium/issues/detail?id=11010 .
+ VLOG(1) << observer_counts_[i] << " notification observer(s) leaked "
+ "of notification type " << i;
+ }
+ }
+#endif
+
+ for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
+ NotificationSourceMap omap = observers_[i];
+ for (NotificationSourceMap::iterator it = omap.begin();
+ it != omap.end(); ++it)
+ delete it->second;
+ }
+}
+
+NotificationObserver::NotificationObserver() {}
+
+NotificationObserver::~NotificationObserver() {}