13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/win/object_watcher.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base {
103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace win {
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//-----------------------------------------------------------------------------
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct ObjectWatcher::Watch : public Task {
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ObjectWatcher* watcher;    // The associated ObjectWatcher instance
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HANDLE object;             // The object being watched
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HANDLE wait_object;        // Returned by RegisterWaitForSingleObject
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop* origin_loop;  // Used to get back to the origin thread
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Delegate* delegate;        // Delegate to notify when signaled
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool did_signal;           // DoneWaiting was called
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void Run() {
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The watcher may have already been torn down, in which case we need to
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // just get out of dodge.
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!watcher)
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(did_signal);
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    watcher->StopWatching();
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegate->OnObjectSignaled(object);
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//-----------------------------------------------------------------------------
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottObjectWatcher::ObjectWatcher() : watch_(NULL) {
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottObjectWatcher::~ObjectWatcher() {
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  StopWatching();
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (watch_) {
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED() << "Already watching an object";
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Watch* watch = new Watch;
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch->watcher = this;
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch->object = object;
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch->origin_loop = MessageLoop::current();
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch->delegate = delegate;
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch->did_signal = false;
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Since our job is to just notice when an object is signaled and report the
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // result back to this thread, we can just run on a Windows wait thread.
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE;
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting,
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   watch, INFINITE, wait_flags)) {
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError();
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delete watch;
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch_ = watch;
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We need to know if the current message loop is going away so we can
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // prevent the wait thread from trying to access a dead message loop.
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop::current()->AddDestructionObserver(this);
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool ObjectWatcher::StopWatching() {
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!watch_)
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Make sure ObjectWatcher is used in a single-threaded fashion.
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(watch_->origin_loop == MessageLoop::current());
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If DoneWaiting is in progress, we wait for it to finish.  We know whether
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // DoneWaiting happened or not by inspecting the did_signal flag.
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!UnregisterWaitEx(watch_->wait_object, INVALID_HANDLE_VALUE)) {
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError();
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Make sure that we see any mutation to did_signal.  This should be a no-op
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // since we expect that UnregisterWaitEx resulted in a memory barrier, but
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // just to be sure, we're going to be explicit.
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MemoryBarrier();
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If the watch has been posted, then we need to make sure it knows not to do
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // anything once it is run.
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch_->watcher = NULL;
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If DoneWaiting was called, then the watch would have been posted as a
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // task, and will therefore be deleted by the MessageLoop.  Otherwise, we
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // need to take care to delete it here.
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!watch_->did_signal)
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delete watch_;
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch_ = NULL;
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop::current()->RemoveDestructionObserver(this);
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHANDLE ObjectWatcher::GetWatchedObject() {
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!watch_)
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return watch_->object;
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!timed_out);
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Watch* watch = static_cast<Watch*>(param);
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Record that we ran this function.
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch->did_signal = true;
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We rely on the locking in PostTask() to ensure that a memory barrier is
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // provided, which in turn ensures our change to did_signal can be observed
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // on the target thread.
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  watch->origin_loop->PostTask(FROM_HERE, watch);
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ObjectWatcher::WillDestroyCurrentMessageLoop() {
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Need to shutdown the watch so that we don't try to access the MessageLoop
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // after this point.
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  StopWatching();
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace win
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace base
141