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

Side by Side Diff: chrome/browser/sync/util/event_sys-inl.h

Issue 251080: Sync: Remove pthreads from event_sys code. Remove asynch version of GaiaAuthe... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/sync/util/event_sys.h ('k') | chrome/browser/sync/util/event_sys_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 #ifndef CHROME_BROWSER_SYNC_UTIL_EVENT_SYS_INL_H_ 5 #ifndef CHROME_BROWSER_SYNC_UTIL_EVENT_SYS_INL_H_
6 #define CHROME_BROWSER_SYNC_UTIL_EVENT_SYS_INL_H_ 6 #define CHROME_BROWSER_SYNC_UTIL_EVENT_SYS_INL_H_
7 7
8 #include <map> 8 #include <map>
9 9
10 #include "base/atomicops.h" 10 #include "base/atomicops.h"
11 #include "base/basictypes.h" 11 #include "base/basictypes.h"
12 #include "base/condition_variable.h"
13 #include "base/lock.h"
12 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/message_loop.h"
13 #include "base/port.h" 16 #include "base/port.h"
14 #include "chrome/browser/sync/util/compat_pthread.h"
15 #include "chrome/browser/sync/util/event_sys.h" 17 #include "chrome/browser/sync/util/event_sys.h"
16 #include "chrome/browser/sync/util/pthread_helpers.h"
17 #include "chrome/browser/sync/util/sync_types.h" 18 #include "chrome/browser/sync/util/sync_types.h"
18 19
19 // How to use Channels: 20 // How to use Channels:
20 21
21 // 0. Assume Bob is the name of the class from which you want to broadcast 22 // 0. Assume Bob is the name of the class from which you want to broadcast
22 // events. 23 // events.
23 // 1. Choose an EventType. This could be an Enum or something more complicated. 24 // 1. Choose an EventType. This could be an Enum or something more complicated.
24 // 2. Create an EventTraits class for your EventType. It must have 25 // 2. Create an EventTraits class for your EventType. It must have
25 // two members: 26 // two members:
26 // 27 //
(...skipping 24 matching lines...) Expand all
51 // An Event Channel is a source, or broadcaster of events. Listeners subscribe 52 // An Event Channel is a source, or broadcaster of events. Listeners subscribe
52 // by calling the AddListener() method. The owner of the channel calls the 53 // by calling the AddListener() method. The owner of the channel calls the
53 // NotifyListeners() method. 54 // NotifyListeners() method.
54 // 55 //
55 // Don't inherit from this class. Just make an event_channel member and an 56 // Don't inherit from this class. Just make an event_channel member and an
56 // event_channel() accessor. 57 // event_channel() accessor.
57 58
58 // No reason why CallbackWaiters has to be templatized. 59 // No reason why CallbackWaiters has to be templatized.
59 class CallbackWaiters { 60 class CallbackWaiters {
60 public: 61 public:
61 CallbackWaiters() : waiter_count_(0), callback_done_(false) { 62 CallbackWaiters() : waiter_count_(0),
63 callback_done_(false),
64 condvar_(&mutex_) {
62 } 65 }
63 ~CallbackWaiters() { 66 ~CallbackWaiters() {
64 DCHECK_EQ(0, waiter_count_); 67 DCHECK_EQ(0, waiter_count_);
65 } 68 }
66 void WaitForCallbackToComplete(PThreadMutex* listeners_mutex) { 69 void WaitForCallbackToComplete(Lock* listeners_mutex) {
67 { 70 {
68 PThreadScopedLock<PThreadMutex> lock(&mutex_); 71 AutoLock lock(mutex_);
69 waiter_count_ += 1; 72 waiter_count_ += 1;
70 listeners_mutex->Unlock(); 73 listeners_mutex->Release();
71 while (!callback_done_) 74 while (!callback_done_)
72 pthread_cond_wait(&condvar_.condvar_, &mutex_.mutex_); 75 condvar_.Wait();
73 waiter_count_ -= 1; 76 waiter_count_ -= 1;
74 if (0 != waiter_count_) 77 if (0 != waiter_count_)
75 return; 78 return;
76 } 79 }
77 delete this; 80 delete this;
78 } 81 }
79 82
80 void Signal() { 83 void Signal() {
81 PThreadScopedLock<PThreadMutex> lock(&mutex_); 84 AutoLock lock(mutex_);
82 callback_done_ = true; 85 callback_done_ = true;
83 pthread_cond_broadcast(&condvar_.condvar_); 86 condvar_.Broadcast();
84 } 87 }
85 88
86 protected: 89 protected:
87 int waiter_count_; 90 int waiter_count_;
88 bool callback_done_; 91 bool callback_done_;
89 PThreadMutex mutex_; 92 Lock mutex_;
90 PThreadCondVar condvar_; 93 ConditionVariable condvar_;
91 }; 94 };
92 95
93 template <typename EventTraitsType, typename NotifyLock, 96 template <typename EventTraitsType, typename NotifyLock,
94 typename ScopedNotifyLocker> 97 typename ScopedNotifyLocker>
95 class EventChannel { 98 class EventChannel {
96 public: 99 public:
97 typedef EventTraitsType EventTraits; 100 typedef EventTraitsType EventTraits;
98 typedef typename EventTraits::EventType EventType; 101 typedef typename EventTraits::EventType EventType;
99 typedef EventListener<EventType> Listener; 102 typedef EventListener<EventType> Listener;
100 103
101 protected: 104 protected:
102 typedef std::map<Listener*, bool> Listeners; 105 typedef std::map<Listener*, bool> Listeners;
103 typedef PThreadScopedLock<PThreadMutex> ScopedListenersLock;
104 106
105 public: 107 public:
106 // The shutdown event gets send in the EventChannel's destructor. 108 // The shutdown event gets send in the EventChannel's destructor.
107 explicit EventChannel(const EventType& shutdown_event) 109 explicit EventChannel(const EventType& shutdown_event)
108 : current_listener_callback_(NULL), 110 : current_listener_callback_(NULL),
109 callback_waiters_(NULL), 111 callback_waiters_(NULL),
110 shutdown_event_(shutdown_event) { 112 shutdown_event_(shutdown_event) {
111 } 113 }
112 114
113 ~EventChannel() { 115 ~EventChannel() {
114 // Tell all the listeners that the channel is being deleted. 116 // Tell all the listeners that the channel is being deleted.
115 NotifyListeners(shutdown_event_); 117 NotifyListeners(shutdown_event_);
116 118
117 // Make sure all the listeners have been disconnected. Otherwise, they 119 // Make sure all the listeners have been disconnected. Otherwise, they
118 // will try to call RemoveListener() at a later date. 120 // will try to call RemoveListener() at a later date.
119 #ifdef DEBUG 121 #ifdef DEBUG
120 ScopedListenersLock lock(&listeners_mutex_); 122 AutoLock lock(listeners_mutex_);
121 for (typename Listeners::iterator i = listeners_.begin(); 123 for (typename Listeners::iterator i = listeners_.begin();
122 i != listeners_.end(); ++i) { 124 i != listeners_.end(); ++i) {
123 DCHECK(i->second) << "Listener not disconnected"; 125 DCHECK(i->second) << "Listener not disconnected";
124 } 126 }
125 #endif 127 #endif
126 } 128 }
127 129
128 // Never call this twice for the same listener. 130 // Never call this twice for the same listener.
129 // 131 //
130 // Thread safe. 132 // Thread safe.
131 void AddListener(Listener* listener) { 133 void AddListener(Listener* listener) {
132 ScopedListenersLock lock(&listeners_mutex_); 134 AutoLock lock(listeners_mutex_);
133 typename Listeners::iterator found = listeners_.find(listener); 135 typename Listeners::iterator found = listeners_.find(listener);
134 if (found == listeners_.end()) { 136 if (found == listeners_.end()) {
135 listeners_.insert(std::make_pair(listener, 137 listeners_.insert(std::make_pair(listener,
136 false)); // Not dead yet. 138 false)); // Not dead yet.
137 } else { 139 } else {
138 DCHECK(found->second) << "Attempted to add the same listener twice."; 140 DCHECK(found->second) << "Attempted to add the same listener twice.";
139 found->second = false; // Not dead yet. 141 found->second = false; // Not dead yet.
140 } 142 }
141 } 143 }
142 144
143 // If listener's callback is currently executing, this method waits until the 145 // If listener's callback is currently executing, this method waits until the
144 // callback completes before returning. 146 // callback completes before returning.
145 // 147 //
146 // Thread safe. 148 // Thread safe.
147 void RemoveListener(Listener* listener) { 149 void RemoveListener(Listener* listener) {
148 bool wait = false; 150 bool wait = false;
149 listeners_mutex_.Lock(); 151 listeners_mutex_.Acquire();
150 typename Listeners::iterator found = listeners_.find(listener); 152 typename Listeners::iterator found = listeners_.find(listener);
151 if (found != listeners_.end()) { 153 if (found != listeners_.end()) {
152 found->second = true; // Mark as dead. 154 found->second = true; // Mark as dead.
153 wait = (found->first == current_listener_callback_ && 155 wait = (found->first == current_listener_callback_ &&
154 (!pthread_equal(current_listener_callback_thread_id_, 156 (MessageLoop::current() != current_listener_callback_message_loop_));
155 pthread_self())));
156 } 157 }
157 if (!wait) { 158 if (!wait) {
158 listeners_mutex_.Unlock(); 159 listeners_mutex_.Release();
159 return; 160 return;
160 } 161 }
161 if (NULL == callback_waiters_) 162 if (NULL == callback_waiters_)
162 callback_waiters_ = new CallbackWaiters; 163 callback_waiters_ = new CallbackWaiters;
163 callback_waiters_->WaitForCallbackToComplete(&listeners_mutex_); 164 callback_waiters_->WaitForCallbackToComplete(&listeners_mutex_);
164 } 165 }
165 166
166 // Blocks until all listeners have been notified. 167 // Blocks until all listeners have been notified.
167 // 168 //
168 // NOT thread safe. Must only be called by one thread at a time. 169 // NOT thread safe. Must only be called by one thread at a time.
169 void NotifyListeners(const EventType& event) { 170 void NotifyListeners(const EventType& event) {
170 ScopedNotifyLocker lock_notify(&notify_lock_); 171 ScopedNotifyLocker lock_notify(notify_lock_);
171 listeners_mutex_.Lock(); 172 listeners_mutex_.Acquire();
172 DCHECK(NULL == current_listener_callback_); 173 DCHECK(NULL == current_listener_callback_);
173 current_listener_callback_thread_id_ = pthread_self(); 174 current_listener_callback_message_loop_ = MessageLoop::current();
174 typename Listeners::iterator i = listeners_.begin(); 175 typename Listeners::iterator i = listeners_.begin();
175 while (i != listeners_.end()) { 176 while (i != listeners_.end()) {
176 if (i->second) { // Clean out dead listeners 177 if (i->second) { // Clean out dead listeners
177 listeners_.erase(i++); 178 listeners_.erase(i++);
178 continue; 179 continue;
179 } 180 }
180 current_listener_callback_ = i->first; 181 current_listener_callback_ = i->first;
181 listeners_mutex_.Unlock(); 182 listeners_mutex_.Release();
182 183
183 i->first->HandleEvent(event); 184 i->first->HandleEvent(event);
184 185
185 listeners_mutex_.Lock(); 186 listeners_mutex_.Acquire();
186 current_listener_callback_ = NULL; 187 current_listener_callback_ = NULL;
187 if (NULL != callback_waiters_) { 188 if (NULL != callback_waiters_) {
188 callback_waiters_->Signal(); 189 callback_waiters_->Signal();
189 callback_waiters_ = NULL; 190 callback_waiters_ = NULL;
190 } 191 }
191 192
192 ++i; 193 ++i;
193 } 194 }
194 listeners_mutex_.Unlock(); 195 listeners_mutex_.Release();
195 } 196 }
196 197
197 // A map iterator remains valid until the element it points to gets removed 198 // A map iterator remains valid until the element it points to gets removed
198 // from the map, so a map is perfect for our needs. 199 // from the map, so a map is perfect for our needs.
199 // 200 //
200 // Map value is a bool, true means the Listener is dead. 201 // Map value is a bool, true means the Listener is dead.
201 Listeners listeners_; 202 Listeners listeners_;
202 // NULL means no callback is currently being called. 203 // NULL means no callback is currently being called.
203 Listener* current_listener_callback_; 204 Listener* current_listener_callback_;
204 // Only valid when current_listener is not NULL. 205 // Only valid when current_listener is not NULL.
205 // The thread on which the callback is executing. 206 // The thread on which the callback is executing.
206 pthread_t current_listener_callback_thread_id_; 207 MessageLoop* current_listener_callback_message_loop_;
207 // Win32 Event that is usually NULL. Only created when another thread calls 208 // Win32 Event that is usually NULL. Only created when another thread calls
208 // Remove while in callback. Owned and closed by the thread calling Remove(). 209 // Remove while in callback. Owned and closed by the thread calling Remove().
209 CallbackWaiters* callback_waiters_; 210 CallbackWaiters* callback_waiters_;
210 211
211 PThreadMutex listeners_mutex_; // Protects all members above. 212 Lock listeners_mutex_; // Protects all members above.
212 const EventType shutdown_event_; 213 const EventType shutdown_event_;
213 NotifyLock notify_lock_; 214 NotifyLock notify_lock_;
214 215
215 DISALLOW_COPY_AND_ASSIGN(EventChannel); 216 DISALLOW_COPY_AND_ASSIGN(EventChannel);
216 }; 217 };
217 218
218 // An EventListenerHookup hooks up a method in your class to an EventChannel. 219 // An EventListenerHookup hooks up a method in your class to an EventChannel.
219 // Deleting the hookup disconnects from the EventChannel. 220 // Deleting the hookup disconnects from the EventChannel.
220 // 221 //
221 // Contains complexity of inheriting from Listener class and managing lifetimes. 222 // Contains complexity of inheriting from Listener class and managing lifetimes.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 CallbackObject* cbobject, 333 CallbackObject* cbobject,
333 CallbackMethod cbmethod, 334 CallbackMethod cbmethod,
334 CallbackArg0 arg0) { 335 CallbackArg0 arg0) {
335 return new ArgHookup<EventChannel, 336 return new ArgHookup<EventChannel,
336 typename EventChannel::EventTraits, 337 typename EventChannel::EventTraits,
337 CallbackObject, CallbackMethod, CallbackArg0>(channel, cbobject, 338 CallbackObject, CallbackMethod, CallbackArg0>(channel, cbobject,
338 cbmethod, arg0); 339 cbmethod, arg0);
339 } 340 }
340 341
341 #endif // CHROME_BROWSER_SYNC_UTIL_EVENT_SYS_INL_H_ 342 #endif // CHROME_BROWSER_SYNC_UTIL_EVENT_SYS_INL_H_
OLDNEW
« no previous file with comments | « chrome/browser/sync/util/event_sys.h ('k') | chrome/browser/sync/util/event_sys_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698