OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "mojo/public/cpp/system/watcher.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/location.h" | |
9 #include "base/macros.h" | |
10 #include "base/message_loop/message_loop.h" | |
11 #include "base/thread_task_runner_handle.h" | |
12 #include "mojo/public/c/system/functions.h" | |
13 | |
14 namespace mojo { | |
15 | |
16 class Watcher::MessageLoopObserver | |
17 : public base::MessageLoop::DestructionObserver { | |
18 public: | |
19 explicit MessageLoopObserver(Watcher* watcher) : watcher_(watcher) { | |
20 base::MessageLoop::current()->AddDestructionObserver(this); | |
21 } | |
22 | |
23 ~MessageLoopObserver() override { | |
24 StopObservingIfNecessary(); | |
25 } | |
26 | |
27 private: | |
28 // base::MessageLoop::DestructionObserver: | |
29 void WillDestroyCurrentMessageLoop() override { | |
30 StopObservingIfNecessary(); | |
31 if (watcher_->IsWatching()) | |
32 watcher_->OnHandleReady(MOJO_RESULT_ABORTED); | |
33 } | |
34 | |
35 void StopObservingIfNecessary() { | |
36 if (is_observing_) { | |
37 is_observing_ = false; | |
38 base::MessageLoop::current()->RemoveDestructionObserver(this); | |
39 } | |
40 } | |
41 | |
42 bool is_observing_ = true; | |
43 Watcher* watcher_; | |
44 | |
45 DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver); | |
46 }; | |
47 | |
48 Watcher::Watcher() | |
49 : task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
50 weak_factory_(this) { | |
51 weak_self_ = weak_factory_.GetWeakPtr(); | |
52 } | |
53 | |
54 Watcher::~Watcher() { | |
55 if(IsWatching()) | |
56 Cancel(); | |
57 } | |
58 | |
59 bool Watcher::IsWatching() const { | |
60 DCHECK(thread_checker_.CalledOnValidThread()); | |
61 return handle_.is_valid(); | |
62 } | |
63 | |
64 MojoResult Watcher::Start(Handle handle, | |
65 MojoHandleSignals signals, | |
66 const ReadyCallback& callback) { | |
67 DCHECK(thread_checker_.CalledOnValidThread()); | |
68 DCHECK(!IsWatching()); | |
69 DCHECK(!callback.is_null()); | |
70 | |
71 message_loop_observer_.reset(new MessageLoopObserver(this)); | |
72 callback_ = callback; | |
73 handle_ = handle; | |
74 MojoResult result = MojoWatch(handle_.value(), signals, | |
75 &Watcher::CallOnHandleReady, | |
76 reinterpret_cast<uintptr_t>(this)); | |
77 if (result != MOJO_RESULT_OK) { | |
78 handle_.set_value(kInvalidHandleValue); | |
79 callback_.Reset(); | |
80 message_loop_observer_.reset(); | |
81 DCHECK(result == MOJO_RESULT_FAILED_PRECONDITION || | |
82 result == MOJO_RESULT_INVALID_ARGUMENT); | |
83 return result; | |
84 } | |
85 | |
86 return MOJO_RESULT_OK; | |
87 } | |
88 | |
89 void Watcher::Cancel() { | |
90 DCHECK(thread_checker_.CalledOnValidThread()); | |
91 | |
92 // The watch may have already been cancelled if the handle was closed. | |
93 if (!handle_.is_valid()) | |
94 return; | |
95 | |
96 MojoResult result = | |
97 MojoCancelWatch(handle_.value(), reinterpret_cast<uintptr_t>(this)); | |
98 message_loop_observer_.reset(); | |
99 DCHECK_EQ(result, MOJO_RESULT_OK); | |
100 handle_.set_value(kInvalidHandleValue); | |
101 callback_.Reset(); | |
102 } | |
103 | |
104 void Watcher::OnHandleReady(MojoResult result) { | |
105 DCHECK(thread_checker_.CalledOnValidThread()); | |
106 | |
107 ReadyCallback callback = callback_; | |
108 if (result == MOJO_RESULT_CANCELLED) { | |
109 message_loop_observer_.reset(); | |
110 handle_.set_value(kInvalidHandleValue); | |
111 callback_.Reset(); | |
112 } | |
113 | |
114 // NOTE: It's legal for |callback| to delete |this|. | |
115 if (!callback.is_null()) | |
116 callback.Run(result); | |
117 } | |
118 | |
119 // static | |
120 void Watcher::CallOnHandleReady(uintptr_t context, | |
121 MojoResult result, | |
122 MojoHandleSignalsState signals_state) { | |
123 // NOTE: It is safe to assume the Watcher still exists because this callback | |
124 // will never be run after the Watcher's destructor. | |
125 // | |
126 // TODO: Maybe we should also expose |signals_state| throught he Watcher API. | |
127 // Current HandleWatcher users have no need for it, so it's omitted here. | |
128 Watcher* watcher = reinterpret_cast<Watcher*>(context); | |
129 watcher->task_runner_->PostTask( | |
130 FROM_HERE, | |
131 base::Bind(&Watcher::OnHandleReady, watcher->weak_self_, result)); | |
132 } | |
133 | |
134 } // namespace mojo | |
OLD | NEW |