Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / ipc / chromium / src / base / object_watcher.cc
blobb749829a0ea5d918db707d93a528d1630d0b1145
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
7 #include "base/object_watcher.h"
9 #include "base/logging.h"
11 namespace base {
13 //-----------------------------------------------------------------------------
15 class ObjectWatcher::Watch : public mozilla::Runnable {
16 public:
17 ObjectWatcher* watcher; // The associated ObjectWatcher instance
18 HANDLE object; // The object being watched
19 HANDLE wait_object; // Returned by RegisterWaitForSingleObject
20 MessageLoop* origin_loop; // Used to get back to the origin thread
21 Delegate* delegate; // Delegate to notify when signaled
22 bool did_signal; // DoneWaiting was called
24 Watch() : mozilla::Runnable("ObjectWatcher::Watch") {}
26 NS_IMETHOD Run() override {
27 // The watcher may have already been torn down, in which case we need to
28 // just get out of dodge.
29 if (!watcher) return NS_OK;
31 DCHECK(did_signal);
32 watcher->StopWatching();
34 delegate->OnObjectSignaled(object);
36 return NS_OK;
40 //-----------------------------------------------------------------------------
42 ObjectWatcher::ObjectWatcher() : watch_(nullptr) {}
44 ObjectWatcher::~ObjectWatcher() { StopWatching(); }
46 bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
47 if (watch_) {
48 NOTREACHED() << "Already watching an object";
49 return false;
52 RefPtr<Watch> watch = new Watch;
53 watch->watcher = this;
54 watch->object = object;
55 watch->origin_loop = MessageLoop::current();
56 watch->delegate = delegate;
57 watch->did_signal = false;
59 // Since our job is to just notice when an object is signaled and report the
60 // result back to this thread, we can just run on a Windows wait thread.
61 DWORD wait_flags = WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE;
63 if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting,
64 watch.get(), INFINITE, wait_flags)) {
65 NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError();
66 return false;
69 watch_ = watch.forget();
71 // We need to know if the current message loop is going away so we can
72 // prevent the wait thread from trying to access a dead message loop.
73 MessageLoop::current()->AddDestructionObserver(this);
74 return true;
77 bool ObjectWatcher::StopWatching() {
78 if (!watch_) return false;
80 // Make sure ObjectWatcher is used in a single-threaded fashion.
81 DCHECK(watch_->origin_loop == MessageLoop::current());
83 // If DoneWaiting is in progress, we wait for it to finish. We know whether
84 // DoneWaiting happened or not by inspecting the did_signal flag.
85 if (!UnregisterWaitEx(watch_->wait_object, INVALID_HANDLE_VALUE)) {
86 NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError();
87 return false;
90 // Make sure that we see any mutation to did_signal. This should be a no-op
91 // since we expect that UnregisterWaitEx resulted in a memory barrier, but
92 // just to be sure, we're going to be explicit.
93 MemoryBarrier();
95 // If the watch has been posted, then we need to make sure it knows not to do
96 // anything once it is run.
97 watch_->watcher = NULL;
99 watch_ = nullptr;
101 MessageLoop::current()->RemoveDestructionObserver(this);
102 return true;
105 HANDLE ObjectWatcher::GetWatchedObject() {
106 if (!watch_) return NULL;
108 return watch_->object;
111 // static
112 void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
113 DCHECK(!timed_out);
115 Watch* watch = static_cast<Watch*>(param);
116 RefPtr<Watch> addrefedWatch = watch;
118 // Record that we ran this function.
119 watch->did_signal = true;
121 // We rely on the locking in PostTask() to ensure that a memory barrier is
122 // provided, which in turn ensures our change to did_signal can be observed
123 // on the target thread.
124 if (watch->origin_loop->IsAcceptingTasks()) {
125 watch->origin_loop->PostTask(addrefedWatch.forget());
129 void ObjectWatcher::WillDestroyCurrentMessageLoop() {
130 // Need to shutdown the watch so that we don't try to access the MessageLoop
131 // after this point.
132 StopWatching();
135 } // namespace base