15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event_watcher.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WaitableEventWatcher (async waits). 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The basic design is that we add an AsyncWaiter to the wait-list of the event. 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// That AsyncWaiter has a pointer to MessageLoop, and a Task to be posted to it. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The MessageLoop ends up running the task, which calls the delegate. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Since the wait can be canceled, we have a thread-safe Flag object which is 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// set when the wait has been canceled. At each stage in the above, we check the 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// flag before going onto the next stage. Since the wait may only be canceled in 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the MessageLoop which runs the Task, we are assured that the delegate cannot 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be called after canceling... 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A thread-safe, reference-counted, write-once flag. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Flag : public RefCountedThreadSafe<Flag> { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Flag() { flag_ = false; } 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Set() { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock locked(lock_); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flag_ = true; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool value() const { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock locked(lock_); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return flag_; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class RefCountedThreadSafe<Flag>; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~Flag() {} 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable Lock lock_; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool flag_; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Flag); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is an asynchronous waiter which posts a task to a MessageLoop when 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// fired. An AsyncWaiter may only be in a single wait-list. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class AsyncWaiter : public WaitableEvent::Waiter { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AsyncWaiter(MessageLoop* message_loop, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::Closure& callback, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Flag* flag) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : message_loop_(message_loop), 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_(callback), 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flag_(flag) { } 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool Fire(WaitableEvent* event) OVERRIDE { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Post the callback if we haven't been cancelled. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!flag_->value()) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop_->PostTask(FROM_HERE, callback_); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We are removed from the wait-list by the WaitableEvent itself. It only 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // remains to delete ourselves. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete this; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can always return true because an AsyncWaiter is never in two 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // different wait-lists at the same time. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See StopWatching for discussion 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool Compare(void* tag) OVERRIDE { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tag == flag_.get(); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop *const message_loop_; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Closure callback_; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<Flag> flag_; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For async waits we need to make a callback in a MessageLoop thread. We do 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this by posting a callback, which calls the delegate and keeps track of when 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the event is canceled. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncCallbackHelper(Flag* flag, 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const WaitableEventWatcher::EventCallback& callback, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitableEvent* event) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Runs in MessageLoop thread. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!flag->value()) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is to let the WaitableEventWatcher know that the event has occured 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because it needs to be able to return NULL from GetWatchedObject 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flag->Set(); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback.Run(event); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WaitableEventWatcher::WaitableEventWatcher() 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : message_loop_(NULL), 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_(NULL), 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waiter_(NULL), 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event_(NULL) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WaitableEventWatcher::~WaitableEventWatcher() { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopWatching(); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The Handle is how the user cancels a wait. After deleting the Handle we 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// insure that the delegate cannot be called. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool WaitableEventWatcher::StartWatching( 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WaitableEvent* event, 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const EventCallback& callback) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop *const current_ml = MessageLoop::current(); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a " 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "current MessageLoop"; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A user may call StartWatching from within the callback function. In this 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // case, we won't know that we have finished watching, expect that the Flag 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will have been set in AsyncCallbackHelper(). 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cancel_flag_.get() && cancel_flag_->value()) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message_loop_) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop_->RemoveDestructionObserver(this); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop_ = NULL; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_ = NULL; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching"; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_ = new Flag; 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_ = callback; 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) internal_callback_ = 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&AsyncCallbackHelper, cancel_flag_, callback_, event); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get(); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock locked(kernel->lock_); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event_ = event; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kernel->signaled_) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!kernel->manual_reset_) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kernel->signaled_ = false; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No hairpinning - we can't call the delegate directly here. We have to 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // enqueue a task on the MessageLoop as normal. 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_ml->PostTask(FROM_HERE, internal_callback_); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop_ = current_ml; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_ml->AddDestructionObserver(this); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kernel_ = kernel; 171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) waiter_ = new AsyncWaiter(current_ml, internal_callback_, cancel_flag_.get()); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event->Enqueue(waiter_); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WaitableEventWatcher::StopWatching() { 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_.Reset(); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message_loop_) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop_->RemoveDestructionObserver(this); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_loop_ = NULL; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!cancel_flag_.get()) // if not currently watching... 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cancel_flag_->value()) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In this case, the event has fired, but we haven't figured that out yet. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The WaitableEvent may have been deleted too. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_ = NULL; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!kernel_.get()) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have no kernel. This means that we never enqueued a Waiter on an 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // event because the event was already signaled when StartWatching was 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In this case, a task was enqueued on the MessageLoop and will run. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We set the flag in case the task hasn't yet run. The flag will stop the 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // delegate getting called. If the task has run then we have the last 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reference to the flag and it will be deleted immedately after. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_->Set(); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_ = NULL; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock locked(kernel_->lock_); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have a lock on the kernel. No one else can signal the event while we 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have it. 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have a possible ABA issue here. If Dequeue was to compare only the 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pointer values then it's possible that the AsyncWaiter could have been 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fired, freed and the memory reused for a different Waiter which was 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // enqueued in the same wait-list. We would think that that waiter was our 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // AsyncWaiter and remove it. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To stop this, Dequeue also takes a tag argument which is passed to the 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // virtual Compare function before the two are considered a match. So we need 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a tag which is good for the lifetime of this handle: the Flag. Since we 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have a reference to the Flag, its memory cannot be reused while this object 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // still exists. So if we find a waiter with the correct pointer value, and 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which shares a Flag pointer, we have a real match. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kernel_->Dequeue(waiter_, cancel_flag_.get())) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Case 2: the waiter hasn't been signaled yet; it was still on the wait 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // list. We've removed it, thus we can delete it and the task (which cannot 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have been enqueued with the MessageLoop because the waiter was never 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // signaled) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete waiter_; 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) internal_callback_.Reset(); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_ = NULL; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Case 3: the waiter isn't on the wait-list, thus it was signaled. It may 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not have run yet, so we set the flag to tell it not to bother enqueuing the 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // task on the MessageLoop, but to delete it instead. The Waiter deletes 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // itself once run. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_->Set(); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancel_flag_ = NULL; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the waiter has already run then the task has been enqueued. If the Task 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hasn't yet run, the flag will stop the delegate from getting called. (This 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is thread safe because one may only delete a Handle from the MessageLoop 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread.) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the delegate has already been called then we have nothing to do. The 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // task has been deleted by the MessageLoop. 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WaitableEvent* WaitableEventWatcher::GetWatchedEvent() { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!cancel_flag_.get()) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cancel_flag_->value()) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return event_; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is called when the MessageLoop which the callback will be run it is 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// deleted. We need to cancel the callback as if we had been deleted, but we 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// will still be deleted at some point in the future. 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------- 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WaitableEventWatcher::WillDestroyCurrentMessageLoop() { 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopWatching(); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 272