| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/common/notification_service.h" | 5 #include "content/common/notification_service.h" |
| 6 | 6 |
| 7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
| 8 #include "base/threading/thread_local.h" | 8 #include "base/threading/thread_local.h" |
| 9 #include "content/common/notification_observer.h" | 9 #include "content/common/notification_observer.h" |
| 10 | 10 |
| 11 static base::LazyInstance<base::ThreadLocalPointer<NotificationService> > | 11 static base::LazyInstance<base::ThreadLocalPointer<NotificationService> > |
| 12 lazy_tls_ptr(base::LINKER_INITIALIZED); | 12 lazy_tls_ptr(base::LINKER_INITIALIZED); |
| 13 | 13 |
| 14 // static | 14 // static |
| 15 NotificationService* NotificationService::current() { | 15 NotificationService* NotificationService::current() { |
| 16 return lazy_tls_ptr.Pointer()->Get(); | 16 return lazy_tls_ptr.Pointer()->Get(); |
| 17 } | 17 } |
| 18 | 18 |
| 19 // static | 19 // static |
| 20 bool NotificationService::HasKey(const NotificationSourceMap& map, | 20 bool NotificationService::HasKey(const NotificationSourceMap& map, |
| 21 const NotificationSource& source) { | 21 const NotificationSource& source) { |
| 22 return map.find(source.map_key()) != map.end(); | 22 return map.find(source.map_key()) != map.end(); |
| 23 } | 23 } |
| 24 | 24 |
| 25 NotificationService::NotificationService() { | 25 NotificationService::NotificationService() { |
| 26 DCHECK(current() == NULL); | 26 DCHECK(current() == NULL); |
| 27 #ifndef NDEBUG | |
| 28 memset(observer_counts_, 0, sizeof(observer_counts_)); | |
| 29 #endif | |
| 30 | |
| 31 lazy_tls_ptr.Pointer()->Set(this); | 27 lazy_tls_ptr.Pointer()->Set(this); |
| 32 } | 28 } |
| 33 | 29 |
| 34 void NotificationService::AddObserver(NotificationObserver* observer, | 30 void NotificationService::AddObserver(NotificationObserver* observer, |
| 35 NotificationType type, | 31 int type, |
| 36 const NotificationSource& source) { | 32 const NotificationSource& source) { |
| 37 DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT); | |
| 38 | |
| 39 // We have gotten some crashes where the observer pointer is NULL. The problem | 33 // We have gotten some crashes where the observer pointer is NULL. The problem |
| 40 // is that this happens when we actually execute a notification, so have no | 34 // is that this happens when we actually execute a notification, so have no |
| 41 // way of knowing who the bad observer was. We want to know when this happens | 35 // way of knowing who the bad observer was. We want to know when this happens |
| 42 // in release mode so we know what code to blame the crash on (since this is | 36 // in release mode so we know what code to blame the crash on (since this is |
| 43 // guaranteed to crash later). | 37 // guaranteed to crash later). |
| 44 CHECK(observer); | 38 CHECK(observer); |
| 45 | 39 |
| 46 NotificationObserverList* observer_list; | 40 NotificationObserverList* observer_list; |
| 47 if (HasKey(observers_[type.value], source)) { | 41 if (HasKey(observers_[type], source)) { |
| 48 observer_list = observers_[type.value][source.map_key()]; | 42 observer_list = observers_[type][source.map_key()]; |
| 49 } else { | 43 } else { |
| 50 observer_list = new NotificationObserverList; | 44 observer_list = new NotificationObserverList; |
| 51 observers_[type.value][source.map_key()] = observer_list; | 45 observers_[type][source.map_key()] = observer_list; |
| 52 } | 46 } |
| 53 | 47 |
| 54 observer_list->AddObserver(observer); | 48 observer_list->AddObserver(observer); |
| 55 #ifndef NDEBUG | 49 #ifndef NDEBUG |
| 56 ++observer_counts_[type.value]; | 50 ++observer_counts_[type]; |
| 57 #endif | 51 #endif |
| 58 } | 52 } |
| 59 | 53 |
| 60 void NotificationService::RemoveObserver(NotificationObserver* observer, | 54 void NotificationService::RemoveObserver(NotificationObserver* observer, |
| 61 NotificationType type, | 55 int type, |
| 62 const NotificationSource& source) { | 56 const NotificationSource& source) { |
| 63 DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT); | |
| 64 | |
| 65 // This is a very serious bug. An object is most likely being deleted on | 57 // This is a very serious bug. An object is most likely being deleted on |
| 66 // the wrong thread, and as a result another thread's NotificationService | 58 // the wrong thread, and as a result another thread's NotificationService |
| 67 // has its deleted pointer in its map. A garbge object will be called in the | 59 // has its deleted pointer in its map. A garbge object will be called in the |
| 68 // future. | 60 // future. |
| 69 // NOTE: when this check shows crashes, use BrowserThread::DeleteOnIOThread or | 61 // NOTE: when this check shows crashes, use BrowserThread::DeleteOnIOThread or |
| 70 // other variants as the trait on the object. | 62 // other variants as the trait on the object. |
| 71 CHECK(HasKey(observers_[type.value], source)); | 63 CHECK(HasKey(observers_[type], source)); |
| 72 | 64 |
| 73 NotificationObserverList* observer_list = | 65 NotificationObserverList* observer_list = |
| 74 observers_[type.value][source.map_key()]; | 66 observers_[type][source.map_key()]; |
| 75 if (observer_list) { | 67 if (observer_list) { |
| 76 observer_list->RemoveObserver(observer); | 68 observer_list->RemoveObserver(observer); |
| 77 #ifndef NDEBUG | 69 #ifndef NDEBUG |
| 78 --observer_counts_[type.value]; | 70 --observer_counts_[type]; |
| 79 #endif | 71 #endif |
| 80 } | 72 } |
| 81 | 73 |
| 82 // TODO(jhughes): Remove observer list from map if empty? | 74 // TODO(jhughes): Remove observer list from map if empty? |
| 83 } | 75 } |
| 84 | 76 |
| 85 void NotificationService::Notify(NotificationType type, | 77 void NotificationService::Notify(int type, |
| 86 const NotificationSource& source, | 78 const NotificationSource& source, |
| 87 const NotificationDetails& details) { | 79 const NotificationDetails& details) { |
| 88 DCHECK(type.value > NotificationType::ALL) << | 80 DCHECK(type > content::NOTIFICATION_ALL) << |
| 89 "Allowed for observing, but not posting."; | 81 "Allowed for observing, but not posting."; |
| 90 DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT); | |
| 91 | 82 |
| 92 // There's no particular reason for the order in which the different | 83 // There's no particular reason for the order in which the different |
| 93 // classes of observers get notified here. | 84 // classes of observers get notified here. |
| 94 | 85 |
| 95 // Notify observers of all types and all sources | 86 // Notify observers of all types and all sources |
| 96 if (HasKey(observers_[NotificationType::ALL], AllSources()) && | 87 if (HasKey(observers_[content::NOTIFICATION_ALL], AllSources()) && |
| 97 source != AllSources()) { | 88 source != AllSources()) { |
| 98 FOR_EACH_OBSERVER(NotificationObserver, | 89 FOR_EACH_OBSERVER(NotificationObserver, |
| 99 *observers_[NotificationType::ALL][AllSources().map_key()], | 90 *observers_[content::NOTIFICATION_ALL][AllSources().map_key()], |
| 100 Observe(type, source, details)); | 91 Observe(type, source, details)); |
| 101 } | 92 } |
| 102 | 93 |
| 103 // Notify observers of all types and the given source | 94 // Notify observers of all types and the given source |
| 104 if (HasKey(observers_[NotificationType::ALL], source)) { | 95 if (HasKey(observers_[content::NOTIFICATION_ALL], source)) { |
| 105 FOR_EACH_OBSERVER(NotificationObserver, | 96 FOR_EACH_OBSERVER(NotificationObserver, |
| 106 *observers_[NotificationType::ALL][source.map_key()], | 97 *observers_[content::NOTIFICATION_ALL][source.map_key()], |
| 107 Observe(type, source, details)); | 98 Observe(type, source, details)); |
| 108 } | 99 } |
| 109 | 100 |
| 110 // Notify observers of the given type and all sources | 101 // Notify observers of the given type and all sources |
| 111 if (HasKey(observers_[type.value], AllSources()) && | 102 if (HasKey(observers_[type], AllSources()) && |
| 112 source != AllSources()) { | 103 source != AllSources()) { |
| 113 FOR_EACH_OBSERVER(NotificationObserver, | 104 FOR_EACH_OBSERVER(NotificationObserver, |
| 114 *observers_[type.value][AllSources().map_key()], | 105 *observers_[type][AllSources().map_key()], |
| 115 Observe(type, source, details)); | 106 Observe(type, source, details)); |
| 116 } | 107 } |
| 117 | 108 |
| 118 // Notify observers of the given type and the given source | 109 // Notify observers of the given type and the given source |
| 119 if (HasKey(observers_[type.value], source)) { | 110 if (HasKey(observers_[type], source)) { |
| 120 FOR_EACH_OBSERVER(NotificationObserver, | 111 FOR_EACH_OBSERVER(NotificationObserver, |
| 121 *observers_[type.value][source.map_key()], | 112 *observers_[type][source.map_key()], |
| 122 Observe(type, source, details)); | 113 Observe(type, source, details)); |
| 123 } | 114 } |
| 124 } | 115 } |
| 125 | 116 |
| 126 | 117 |
| 127 NotificationService::~NotificationService() { | 118 NotificationService::~NotificationService() { |
| 128 lazy_tls_ptr.Pointer()->Set(NULL); | 119 lazy_tls_ptr.Pointer()->Set(NULL); |
| 129 | 120 |
| 130 #ifndef NDEBUG | 121 #ifndef NDEBUG |
| 131 for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) { | 122 for (size_t i = 0; i < observer_counts_.size(); i++) { |
| 132 if (observer_counts_[i] > 0) { | 123 if (observer_counts_[i] > 0) { |
| 133 // This may not be completely fixable -- see | 124 // This may not be completely fixable -- see |
| 134 // http://code.google.com/p/chromium/issues/detail?id=11010 . | 125 // http://code.google.com/p/chromium/issues/detail?id=11010 . |
| 135 VLOG(1) << observer_counts_[i] << " notification observer(s) leaked " | 126 VLOG(1) << observer_counts_[i] << " notification observer(s) leaked " |
| 136 "of notification type " << i; | 127 "of notification type " << i; |
| 137 } | 128 } |
| 138 } | 129 } |
| 139 #endif | 130 #endif |
| 140 | 131 |
| 141 for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) { | 132 for (size_t i = 0; i < observers_.size(); i++) { |
| 142 NotificationSourceMap omap = observers_[i]; | 133 NotificationSourceMap omap = observers_[i]; |
| 143 for (NotificationSourceMap::iterator it = omap.begin(); | 134 for (NotificationSourceMap::iterator it = omap.begin(); |
| 144 it != omap.end(); ++it) | 135 it != omap.end(); ++it) |
| 145 delete it->second; | 136 delete it->second; |
| 146 } | 137 } |
| 147 } | 138 } |
| 148 | 139 |
| 149 NotificationObserver::NotificationObserver() {} | 140 NotificationObserver::NotificationObserver() {} |
| 150 | 141 |
| 151 NotificationObserver::~NotificationObserver() {} | 142 NotificationObserver::~NotificationObserver() {} |
| OLD | NEW |