summaryrefslogtreecommitdiffstats
path: root/base/object_watcher.cc
diff options
context:
space:
mode:
authordarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-04 17:46:47 +0000
committerdarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-04 17:46:47 +0000
commitb49054718ac2c49f629427c41a4ff2a6ba4bdb09 (patch)
tree0611d3d1d64574356dd3705ee66f7309a251bec3 /base/object_watcher.cc
parent1c15248a5f6ffd48c99bca9d2fbd6d4b375e991c (diff)
downloadchromium_src-b49054718ac2c49f629427c41a4ff2a6ba4bdb09.zip
chromium_src-b49054718ac2c49f629427c41a4ff2a6ba4bdb09.tar.gz
chromium_src-b49054718ac2c49f629427c41a4ff2a6ba4bdb09.tar.bz2
Revise the ObjectWatcher API to be one-to-one with the object being watched. This greatly simplifies the implementation and API.
Now consumers can use ObjectWatcher as a "smart pointer" class, which automatically cleans-up after itself when it goes out of scope. I also switched away from the Task based API to one that is more compatible with MessageLoop::WatchObject. That allows me to make minimal changes to existing code, and it also means that consumers do not have to allocate Task objects to use this API. In this CL, I included changes to make a couple consumers use ObjectWatcher instead of ML::WatchObject. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@322 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/object_watcher.cc')
-rw-r--r--base/object_watcher.cc74
1 files changed, 35 insertions, 39 deletions
diff --git a/base/object_watcher.cc b/base/object_watcher.cc
index c16f917..5e8c27b 100644
--- a/base/object_watcher.cc
+++ b/base/object_watcher.cc
@@ -41,7 +41,7 @@ struct ObjectWatcher::Watch : public Task {
HANDLE object; // The object being watched
HANDLE wait_object; // Returned by RegisterWaitForSingleObject
MessageLoop* origin_loop; // Used to get back to the origin thread
- scoped_ptr<Task> task; // Task to notify when signaled
+ Delegate* delegate; // Delegate to notify when signaled
bool did_signal; // DoneWaiting was called
virtual void Run() {
@@ -50,42 +50,33 @@ struct ObjectWatcher::Watch : public Task {
if (!watcher)
return;
- // Put this on the stack since CancelWatch deletes task. It is a good
- // to call CancelWatch before running the task because we want to allow
- // the consumer to call AddWatch again inside Run.
- Task* task_to_run = task.release();
-
- watcher->CancelWatch(object);
+ DCHECK(did_signal);
+ watcher->StopWatching();
- task_to_run->ResetBirthTime();
- task_to_run->Run();
- delete task_to_run;
+ delegate->OnObjectSignaled(object);
}
};
//-----------------------------------------------------------------------------
-ObjectWatcher::ObjectWatcher() {
+ObjectWatcher::ObjectWatcher() : watch_(NULL) {
}
ObjectWatcher::~ObjectWatcher() {
- // Cancel any watches that may still exist.
- while (!watches_.empty())
- CancelWatch(watches_.begin()->first);
+ StopWatching();
}
-bool ObjectWatcher::AddWatch(const tracked_objects::Location& from_here,
- HANDLE object, Task* task) {
- task->SetBirthPlace(from_here);
-
- linked_ptr<Watch>& watch = watches_[object];
- CHECK(!watch.get()) << "Already watched!";
+bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
+ if (watch_) {
+ NOTREACHED() << "Already watching an object";
+ return false;
+ }
- watch.reset(new Watch());
+ Watch* watch = new Watch;
watch->watcher = this;
watch->object = object;
watch->origin_loop = MessageLoop::current();
- watch->task.reset(task);
+ watch->delegate = delegate;
watch->did_signal = false;
// Since our job is to just notice when an object is signaled and report the
@@ -93,44 +84,46 @@ bool ObjectWatcher::AddWatch(const tracked_objects::Location& from_here,
DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE;
if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting,
- watch.get(), INFINITE, wait_flags)) {
+ watch, INFINITE, wait_flags)) {
NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError();
- watches_.erase(object);
+ delete watch;
return false;
}
+ watch_ = watch;
return true;
}
-bool ObjectWatcher::CancelWatch(HANDLE object) {
- WatchMap::iterator i = watches_.find(object);
- if (i == watches_.end())
+bool ObjectWatcher::StopWatching() {
+ if (!watch_)
return false;
- Watch* watch = i->second.get();
+ // Make sure ObjectWatcher is used in a single-threaded fashion.
+ DCHECK(watch_->origin_loop == MessageLoop::current());
// If DoneWaiting is in progress, we wait for it to finish. We know whether
// DoneWaiting happened or not by inspecting the did_signal flag.
- if (!UnregisterWaitEx(watch->wait_object, INVALID_HANDLE_VALUE)) {
+ if (!UnregisterWaitEx(watch_->wait_object, INVALID_HANDLE_VALUE)) {
NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError();
return false;
}
- // If DoneWaiting was called, then the watch would have been posted as a
- // task, and will therefore be deleted by the MessageLoop. Otherwise, we
- // need to take care to delete it here.
- if (watch->did_signal)
- i->second.release();
+ // Make sure that we see any mutation to did_signal. This should be a no-op
+ // since we expect that UnregisterWaitEx resulted in a memory barrier, but
+ // just to be sure, we're going to be explicit.
+ MemoryBarrier();
// If the watch has been posted, then we need to make sure it knows not to do
// anything once it is run.
- watch->watcher = NULL;
+ watch_->watcher = NULL;
- // Delete the task object now so that everything, from the perspective of the
- // consumer, is cleaned up once we return from CancelWatch.
- watch->task.reset();
+ // If DoneWaiting was called, then the watch would have been posted as a
+ // task, and will therefore be deleted by the MessageLoop. Otherwise, we
+ // need to take care to delete it here.
+ if (!watch_->did_signal)
+ delete watch_;
- watches_.erase(i);
+ watch_ = NULL;
return true;
}
@@ -143,6 +136,9 @@ void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
// Record that we ran this function.
watch->did_signal = true;
+ // We rely on the locking in PostTask() to ensure that a memory barrier is
+ // provided, which in turn ensures our change to did_signal can be observed
+ // on the target thread.
watch->origin_loop->PostTask(FROM_HERE, watch);
}