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 "base/waitable_event_watcher.h" | 5 #include "base/waitable_event_watcher.h" |
6 | 6 |
7 #include "base/condition_variable.h" | 7 #include "base/condition_variable.h" |
8 #include "base/lock.h" | 8 #include "base/lock.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/waitable_event.h" | 10 #include "base/waitable_event.h" |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 // We can always return true because an AsyncWaiter is never in two | 73 // We can always return true because an AsyncWaiter is never in two |
74 // different wait-lists at the same time. | 74 // different wait-lists at the same time. |
75 return true; | 75 return true; |
76 } | 76 } |
77 | 77 |
78 // See StopWatching for discussion | 78 // See StopWatching for discussion |
79 bool Compare(void* tag) { | 79 bool Compare(void* tag) { |
80 return tag == flag_.get(); | 80 return tag == flag_.get(); |
81 } | 81 } |
82 | 82 |
| 83 private: |
83 MessageLoop *const message_loop_; | 84 MessageLoop *const message_loop_; |
84 Task *const cb_task_; | 85 Task *const cb_task_; |
85 scoped_refptr<Flag> flag_; | 86 scoped_refptr<Flag> flag_; |
86 }; | 87 }; |
87 | 88 |
88 // ----------------------------------------------------------------------------- | 89 // ----------------------------------------------------------------------------- |
89 // For async waits we need to make a callback in a MessageLoop thread. We do | 90 // For async waits we need to make a callback in a MessageLoop thread. We do |
90 // this by posting this task, which calls the delegate and keeps track of when | 91 // this by posting this task, which calls the delegate and keeps track of when |
91 // the event is canceled. | 92 // the event is canceled. |
92 // ----------------------------------------------------------------------------- | 93 // ----------------------------------------------------------------------------- |
93 class AsyncCallbackTask : public Task { | 94 class AsyncCallbackTask : public Task { |
94 public: | 95 public: |
95 AsyncCallbackTask(Flag* flag, WaitableEventWatcher::Delegate* delegate, | 96 AsyncCallbackTask(Flag* flag, WaitableEventWatcher::Delegate* delegate, |
96 WaitableEvent* event) | 97 WaitableEvent* event) |
97 : flag_(flag), | 98 : flag_(flag), |
98 delegate_(delegate), | 99 delegate_(delegate), |
99 event_(event) { | 100 event_(event) { |
100 } | 101 } |
101 | 102 |
102 void Run() { | 103 void Run() { |
103 // Runs in MessageLoop thread. | 104 // Runs in MessageLoop thread. |
104 if (!flag_->value()) | 105 if (!flag_->value()) { |
| 106 // This is to let the WaitableEventWatcher know that the event has occured |
| 107 // because it needs to be able to return NULL from GetWatchedObject |
| 108 flag_->Set(); |
105 delegate_->OnWaitableEventSignaled(event_); | 109 delegate_->OnWaitableEventSignaled(event_); |
106 | 110 } |
107 // This is to let the WaitableEventWatcher know that the event has occured | |
108 // because it needs to be able to return NULL from GetWatchedEvent | |
109 flag_->Set(); | |
110 | 111 |
111 // We are deleted by the MessageLoop | 112 // We are deleted by the MessageLoop |
112 } | 113 } |
113 | 114 |
114 private: | 115 private: |
115 scoped_refptr<Flag> flag_; | 116 scoped_refptr<Flag> flag_; |
116 WaitableEventWatcher::Delegate *const delegate_; | 117 WaitableEventWatcher::Delegate *const delegate_; |
117 WaitableEvent *const event_; | 118 WaitableEvent *const event_; |
118 }; | 119 }; |
119 | 120 |
(...skipping 11 matching lines...) Expand all Loading... |
131 // ----------------------------------------------------------------------------- | 132 // ----------------------------------------------------------------------------- |
132 // The Handle is how the user cancels a wait. After deleting the Handle we | 133 // The Handle is how the user cancels a wait. After deleting the Handle we |
133 // insure that the delegate cannot be called. | 134 // insure that the delegate cannot be called. |
134 // ----------------------------------------------------------------------------- | 135 // ----------------------------------------------------------------------------- |
135 bool WaitableEventWatcher::StartWatching | 136 bool WaitableEventWatcher::StartWatching |
136 (WaitableEvent* event, WaitableEventWatcher::Delegate* delegate) { | 137 (WaitableEvent* event, WaitableEventWatcher::Delegate* delegate) { |
137 MessageLoop *const current_ml = MessageLoop::current(); | 138 MessageLoop *const current_ml = MessageLoop::current(); |
138 DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a " | 139 DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a " |
139 "current MessageLoop"; | 140 "current MessageLoop"; |
140 | 141 |
| 142 // A user may call StartWatching from within the callback function. In this |
| 143 // case, we won't know that we have finished watching, expect that the Flag |
| 144 // will have been set in AsyncCallbackTask::Run() |
| 145 if (cancel_flag_.get() && cancel_flag_->value()) { |
| 146 if (message_loop_) { |
| 147 message_loop_->RemoveDestructionObserver(this); |
| 148 message_loop_ = NULL; |
| 149 } |
| 150 |
| 151 cancel_flag_ = NULL; |
| 152 } |
| 153 |
141 DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching"; | 154 DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching"; |
142 | 155 |
143 cancel_flag_ = new Flag; | 156 cancel_flag_ = new Flag; |
144 callback_task_ = new AsyncCallbackTask(cancel_flag_, delegate, event); | 157 callback_task_ = new AsyncCallbackTask(cancel_flag_, delegate, event); |
145 | 158 |
146 AutoLock locked(event->lock_); | 159 AutoLock locked(event->lock_); |
147 | 160 |
148 if (event->signaled_) { | 161 if (event->signaled_) { |
149 if (!event->manual_reset_) | 162 if (!event->manual_reset_) |
150 event->signaled_ = false; | 163 event->signaled_ = false; |
(...skipping 16 matching lines...) Expand all Loading... |
167 | 180 |
168 void WaitableEventWatcher::StopWatching() { | 181 void WaitableEventWatcher::StopWatching() { |
169 if (message_loop_) { | 182 if (message_loop_) { |
170 message_loop_->RemoveDestructionObserver(this); | 183 message_loop_->RemoveDestructionObserver(this); |
171 message_loop_ = NULL; | 184 message_loop_ = NULL; |
172 } | 185 } |
173 | 186 |
174 if (!cancel_flag_.get()) // if not currently watching... | 187 if (!cancel_flag_.get()) // if not currently watching... |
175 return; | 188 return; |
176 | 189 |
| 190 if (cancel_flag_->value()) { |
| 191 // In this case, the event has fired, but we haven't figured that out yet. |
| 192 // The WaitableEvent may have been deleted too. |
| 193 cancel_flag_ = NULL; |
| 194 return; |
| 195 } |
| 196 |
177 if (!event_) { | 197 if (!event_) { |
178 // We have no WaitableEvent. This means that we never enqueued a Waiter on | 198 // We have no WaitableEvent. This means that we never enqueued a Waiter on |
179 // an event because the event was already signaled when StartWatching was | 199 // an event because the event was already signaled when StartWatching was |
180 // called. | 200 // called. |
181 // | 201 // |
182 // In this case, a task was enqueued on the MessageLoop and will run. | 202 // In this case, a task was enqueued on the MessageLoop and will run. |
183 // We set the flag in case the task hasn't yet run. The flag will stop the | 203 // We set the flag in case the task hasn't yet run. The flag will stop the |
184 // delegate getting called. If the task has run then we have the last | 204 // delegate getting called. If the task has run then we have the last |
185 // reference to the flag and it will be deleted immedately after. | 205 // reference to the flag and it will be deleted immedately after. |
186 cancel_flag_->Set(); | 206 cancel_flag_->Set(); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 // ----------------------------------------------------------------------------- | 264 // ----------------------------------------------------------------------------- |
245 // This is called when the MessageLoop which the callback will be run it is | 265 // This is called when the MessageLoop which the callback will be run it is |
246 // deleted. We need to cancel the callback as if we had been deleted, but we | 266 // deleted. We need to cancel the callback as if we had been deleted, but we |
247 // will still be deleted at some point in the future. | 267 // will still be deleted at some point in the future. |
248 // ----------------------------------------------------------------------------- | 268 // ----------------------------------------------------------------------------- |
249 void WaitableEventWatcher::WillDestroyCurrentMessageLoop() { | 269 void WaitableEventWatcher::WillDestroyCurrentMessageLoop() { |
250 StopWatching(); | 270 StopWatching(); |
251 } | 271 } |
252 | 272 |
253 } // namespace base | 273 } // namespace base |
OLD | NEW |