summaryrefslogtreecommitdiffstats
path: root/base/waitable_event_watcher_posix.cc
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 18:28:19 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 18:28:19 +0000
commitc891ab9654f7e78ce33e84294431a04c5de3abd1 (patch)
tree6d26437c65e6ec92aa3736206b5473a02edbe388 /base/waitable_event_watcher_posix.cc
parent546dc8d90051f5d8d0c38fd70e52f8674e0762a7 (diff)
downloadchromium_src-c891ab9654f7e78ce33e84294431a04c5de3abd1.zip
chromium_src-c891ab9654f7e78ce33e84294431a04c5de3abd1.tar.gz
chromium_src-c891ab9654f7e78ce33e84294431a04c5de3abd1.tar.bz2
POSIX: allow WaitableEvents to be deleted while watching them.
On Windows, one can close a HANDLE which is currently being waited on. The MSDN documentation says that the resulting behaviour is 'undefined', but it doesn't crash. Currently, on POSIX, one couldn't use WaitableEventWatcher to watch an event which gets deleted. This mismatch has bitten us several times now. This patch allows WaitableEvents to be deleted while a WaitableEventWatcher is still watching them. It applies only to watchers, the usual Wait() and WaitMany() calls still require that all their target be valid until the end of the call. http://crbug.com/8809 Review URL: http://codereview.chromium.org/53026 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12576 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/waitable_event_watcher_posix.cc')
-rw-r--r--base/waitable_event_watcher_posix.cc24
1 files changed, 13 insertions, 11 deletions
diff --git a/base/waitable_event_watcher_posix.cc b/base/waitable_event_watcher_posix.cc
index 10d47b7..1910c5f 100644
--- a/base/waitable_event_watcher_posix.cc
+++ b/base/waitable_event_watcher_posix.cc
@@ -155,12 +155,13 @@ bool WaitableEventWatcher::StartWatching
cancel_flag_ = new Flag;
callback_task_ = new AsyncCallbackTask(cancel_flag_, delegate, event);
+ WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get();
- AutoLock locked(event->lock_);
+ AutoLock locked(kernel->lock_);
- if (event->signaled_) {
- if (!event->manual_reset_)
- event->signaled_ = false;
+ if (kernel->signaled_) {
+ if (!kernel->manual_reset_)
+ kernel->signaled_ = false;
// No hairpinning - we can't call the delegate directly here. We have to
// enqueue a task on the MessageLoop as normal.
@@ -172,6 +173,7 @@ bool WaitableEventWatcher::StartWatching
current_ml->AddDestructionObserver(this);
event_ = event;
+ kernel_ = kernel;
waiter_ = new AsyncWaiter(current_ml, callback_task_, cancel_flag_);
event->Enqueue(waiter_);
@@ -194,9 +196,9 @@ void WaitableEventWatcher::StopWatching() {
return;
}
- if (!event_) {
- // We have no WaitableEvent. This means that we never enqueued a Waiter on
- // an event because the event was already signaled when StartWatching was
+ if (!kernel_.get()) {
+ // We have no kernel. This means that we never enqueued a Waiter on an
+ // event because the event was already signaled when StartWatching was
// called.
//
// In this case, a task was enqueued on the MessageLoop and will run.
@@ -208,9 +210,9 @@ void WaitableEventWatcher::StopWatching() {
return;
}
- AutoLock locked(event_->lock_);
- // We have a lock on the WaitableEvent. No one else can signal the event while
- // we have it.
+ AutoLock locked(kernel_->lock_);
+ // We have a lock on the kernel. No one else can signal the event while we
+ // have it.
// We have a possible ABA issue here. If Dequeue was to compare only the
// pointer values then it's possible that the AsyncWaiter could have been
@@ -224,7 +226,7 @@ void WaitableEventWatcher::StopWatching() {
// have a reference to the Flag, its memory cannot be reused while this object
// still exists. So if we find a waiter with the correct pointer value, and
// which shares a Flag pointer, we have a real match.
- if (event_->Dequeue(waiter_, cancel_flag_.get())) {
+ if (kernel_->Dequeue(waiter_, cancel_flag_.get())) {
// Case 2: the waiter hasn't been signaled yet; it was still on the wait
// list. We've removed it, thus we can delete it and the task (which cannot
// have been enqueued with the MessageLoop because the waiter was never