| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/common/notification_registrar.h" | 5 #include "chrome/common/notification_registrar.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "chrome/common/notification_service.h" | 10 #include "chrome/common/notification_service.h" |
| 11 | 11 |
| 12 struct NotificationRegistrar::Record { | 12 struct NotificationRegistrar::Record { |
| 13 bool operator==(const Record& other) const; | 13 bool operator==(const Record& other) const; |
| 14 | 14 |
| 15 NotificationObserver* observer; | 15 NotificationObserver* observer; |
| 16 NotificationType type; | 16 NotificationType type; |
| 17 NotificationSource source; | 17 NotificationSource source; |
| 18 }; | 18 }; |
| 19 | 19 |
| 20 bool NotificationRegistrar::Record::operator==(const Record& other) const { | 20 bool NotificationRegistrar::Record::operator==(const Record& other) const { |
| 21 return observer == other.observer && | 21 return observer == other.observer && |
| 22 type == other.type && | 22 type == other.type && |
| 23 source == other.source; | 23 source == other.source; |
| 24 } | 24 } |
| 25 | 25 |
| 26 NotificationRegistrar::NotificationRegistrar() { | 26 NotificationRegistrar::NotificationRegistrar() { |
| 27 if (!ChromeThread::GetCurrentThreadIdentifier(&thread_id_)) { |
| 28 // If we are not created in well known thread, GetCurrentThreadIdentifier |
| 29 // fails. Assign thread_id_ to an ID not used. |
| 30 thread_id_ = ChromeThread::ID_COUNT; |
| 31 } |
| 27 } | 32 } |
| 28 | 33 |
| 29 NotificationRegistrar::~NotificationRegistrar() { | 34 NotificationRegistrar::~NotificationRegistrar() { |
| 30 RemoveAll(); | 35 RemoveAll(); |
| 31 } | 36 } |
| 32 | 37 |
| 33 void NotificationRegistrar::Add(NotificationObserver* observer, | 38 void NotificationRegistrar::Add(NotificationObserver* observer, |
| 34 NotificationType type, | 39 NotificationType type, |
| 35 const NotificationSource& source) { | 40 const NotificationSource& source) { |
| 36 Record record = { observer, type, source }; | 41 Record record = { observer, type, source }; |
| 37 DCHECK(std::find(registered_.begin(), registered_.end(), record) == | 42 DCHECK(std::find(registered_.begin(), registered_.end(), record) == |
| 38 registered_.end()) << "Duplicate registration."; | 43 registered_.end()) << "Duplicate registration."; |
| 39 registered_.push_back(record); | 44 registered_.push_back(record); |
| 40 | 45 |
| 46 if (ChromeThread::IsWellKnownThread(thread_id_)) { |
| 47 if (!ChromeThread::CurrentlyOn(thread_id_)) { |
| 48 // We are created on a well known thread, but this function is called |
| 49 // on a different thread. This could be a bug, or maybe the object is |
| 50 // passed around. |
| 51 // To be safe, reset thread_id_ so we don't call CHECK during remove. |
| 52 thread_id_ = ChromeThread::ID_COUNT; |
| 53 } |
| 54 } |
| 55 |
| 41 NotificationService::current()->AddObserver(observer, type, source); | 56 NotificationService::current()->AddObserver(observer, type, source); |
| 42 } | 57 } |
| 43 | 58 |
| 44 void NotificationRegistrar::Remove(NotificationObserver* observer, | 59 void NotificationRegistrar::Remove(NotificationObserver* observer, |
| 45 NotificationType type, | 60 NotificationType type, |
| 46 const NotificationSource& source) { | 61 const NotificationSource& source) { |
| 47 Record record = { observer, type, source }; | 62 Record record = { observer, type, source }; |
| 48 RecordVector::iterator found = std::find( | 63 RecordVector::iterator found = std::find( |
| 49 registered_.begin(), registered_.end(), record); | 64 registered_.begin(), registered_.end(), record); |
| 50 if (found == registered_.end()) { | 65 if (found == registered_.end()) { |
| 51 NOTREACHED() << "Trying to remove unregistered observer of type " << | 66 NOTREACHED() << "Trying to remove unregistered observer of type " << |
| 52 type.value << " from list of size " << registered_.size() << "."; | 67 type.value << " from list of size " << registered_.size() << "."; |
| 53 return; | 68 return; |
| 54 } | 69 } |
| 55 registered_.erase(found); | 70 registered_.erase(found); |
| 56 | 71 |
| 72 CheckCalledOnValidWellKnownThread(); |
| 73 |
| 57 // This can be NULL if our owner outlives the NotificationService, e.g. if our | 74 // This can be NULL if our owner outlives the NotificationService, e.g. if our |
| 58 // owner is a Singleton. | 75 // owner is a Singleton. |
| 59 NotificationService* service = NotificationService::current(); | 76 NotificationService* service = NotificationService::current(); |
| 60 if (service) | 77 if (service) |
| 61 service->RemoveObserver(observer, type, source); | 78 service->RemoveObserver(observer, type, source); |
| 62 } | 79 } |
| 63 | 80 |
| 64 void NotificationRegistrar::RemoveAll() { | 81 void NotificationRegistrar::RemoveAll() { |
| 65 // Early-exit if no registrations, to avoid calling | 82 // Early-exit if no registrations, to avoid calling |
| 66 // NotificationService::current. If we've constructed an object with a | 83 // NotificationService::current. If we've constructed an object with a |
| 67 // NotificationRegistrar member, but haven't actually used the notification | 84 // NotificationRegistrar member, but haven't actually used the notification |
| 68 // service, and we reach prgram exit, then calling current() below could try | 85 // service, and we reach prgram exit, then calling current() below could try |
| 69 // to initialize the service's lazy TLS pointer during exit, which throws | 86 // to initialize the service's lazy TLS pointer during exit, which throws |
| 70 // wrenches at things. | 87 // wrenches at things. |
| 71 if (registered_.empty()) | 88 if (registered_.empty()) |
| 72 return; | 89 return; |
| 73 | 90 |
| 91 CheckCalledOnValidWellKnownThread(); |
| 92 |
| 74 // This can be NULL if our owner outlives the NotificationService, e.g. if our | 93 // This can be NULL if our owner outlives the NotificationService, e.g. if our |
| 75 // owner is a Singleton. | 94 // owner is a Singleton. |
| 76 NotificationService* service = NotificationService::current(); | 95 NotificationService* service = NotificationService::current(); |
| 77 if (service) { | 96 if (service) { |
| 78 for (size_t i = 0; i < registered_.size(); i++) { | 97 for (size_t i = 0; i < registered_.size(); i++) { |
| 79 service->RemoveObserver(registered_[i].observer, | 98 service->RemoveObserver(registered_[i].observer, |
| 80 registered_[i].type, | 99 registered_[i].type, |
| 81 registered_[i].source); | 100 registered_[i].source); |
| 82 } | 101 } |
| 83 } | 102 } |
| 84 registered_.clear(); | 103 registered_.clear(); |
| 85 } | 104 } |
| 86 | 105 |
| 87 bool NotificationRegistrar::IsEmpty() const { | 106 bool NotificationRegistrar::IsEmpty() const { |
| 88 return registered_.empty(); | 107 return registered_.empty(); |
| 89 } | 108 } |
| 109 |
| 110 void NotificationRegistrar::CheckCalledOnValidWellKnownThread() { |
| 111 if (ChromeThread::IsWellKnownThread(thread_id_)) { |
| 112 CHECK(ChromeThread::CurrentlyOn(thread_id_)); |
| 113 } |
| 114 } |
| OLD | NEW |