1 // Copyright 2015 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.
5 #include "ipc/mojo/async_handle_waiter.h"
7 #include "base/atomic_ref_count.h"
9 #include "base/bind_helpers.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
17 class AsyncHandleWaiterContextTraits
{
19 static void Destruct(const AsyncHandleWaiter::Context
* context
);
22 // The thread-safe part of |AsyncHandleWaiter|.
23 // As |AsyncWait()| invokes the given callback from an arbitrary thread,
24 // |HandleIsReady()| and the bound |this| have to be thread-safe.
25 class AsyncHandleWaiter::Context
26 : public base::RefCountedThreadSafe
<AsyncHandleWaiter::Context
,
27 AsyncHandleWaiterContextTraits
>,
28 public base::MessageLoopForIO::IOObserver
{
30 Context(base::WeakPtr
<AsyncHandleWaiter
> waiter
)
31 : io_runner_(base::MessageLoopForIO::current()->task_runner()),
33 last_result_(MOJO_RESULT_INTERNAL
),
35 should_invoke_callback_(false) {
36 base::MessageLoopForIO::current()->AddIOObserver(this);
39 void HandleIsReady(MojoResult result
) {
40 last_result_
= result
;
42 // If the signaling happens in the IO handler, use |IOObserver| callback
43 // to invoke the callback.
44 if (IsCalledFromIOHandler()) {
45 should_invoke_callback_
= true;
49 io_runner_
->PostTask(FROM_HERE
,
50 base::Bind(&Context::InvokeWaiterCallback
, this));
54 friend void base::DeletePointer
<const Context
>(const Context
* self
);
55 friend class AsyncHandleWaiterContextTraits
;
56 friend class base::RefCountedThreadSafe
<Context
>;
59 DCHECK(base::MessageLoopForIO::current()->task_runner() == io_runner_
);
60 base::MessageLoopForIO::current()->RemoveIOObserver(this);
63 bool IsCalledFromIOHandler() const {
64 base::MessageLoop
* loop
= base::MessageLoop::current();
67 if (loop
->task_runner() != io_runner_
)
69 return io_loop_level_
> 0;
72 // Called from |io_runner_| thus safe to touch |waiter_|.
73 void InvokeWaiterCallback() {
74 MojoResult result
= last_result_
;
75 last_result_
= MOJO_RESULT_INTERNAL
;
77 waiter_
->InvokeCallback(result
);
80 // IOObserver implementation:
82 void WillProcessIOEvent() override
{
83 DCHECK(io_loop_level_
!= 0 || !should_invoke_callback_
);
84 DCHECK_GE(io_loop_level_
, 0);
88 void DidProcessIOEvent() override
{
89 DCHECK_GE(io_loop_level_
, 1);
91 // Leaving a nested loop.
92 if (io_loop_level_
> 1) {
97 // The zero |waiter_| indicates that |this| have lost the owner and can be
98 // under destruction. So we cannot wrap it with a |scoped_refptr| anymore.
100 should_invoke_callback_
= false;
105 // We have to protect |this| because |AsyncHandleWaiter| can be
106 // deleted during the callback.
107 scoped_refptr
<Context
> protect(this);
108 while (should_invoke_callback_
) {
109 should_invoke_callback_
= false;
110 InvokeWaiterCallback();
116 // Only |io_runner_| is accessed from arbitrary threads. Others are touched
117 // only from the IO thread.
118 const scoped_refptr
<base::TaskRunner
> io_runner_
;
120 const base::WeakPtr
<AsyncHandleWaiter
> waiter_
;
121 MojoResult last_result_
;
123 bool should_invoke_callback_
;
125 DISALLOW_COPY_AND_ASSIGN(Context
);
128 AsyncHandleWaiter::AsyncHandleWaiter(base::Callback
<void(MojoResult
)> callback
)
129 : callback_(callback
),
130 weak_factory_(this) {
131 context_
= new Context(weak_factory_
.GetWeakPtr());
134 AsyncHandleWaiter::~AsyncHandleWaiter() {
137 MojoResult
AsyncHandleWaiter::Wait(MojoHandle handle
,
138 MojoHandleSignals signals
) {
139 return mojo::embedder::AsyncWait(
140 handle
, signals
, base::Bind(&Context::HandleIsReady
, context_
));
143 void AsyncHandleWaiter::InvokeCallback(MojoResult result
) {
144 callback_
.Run(result
);
147 base::MessageLoopForIO::IOObserver
* AsyncHandleWaiter::GetIOObserverForTest() {
148 return context_
.get();
151 base::Callback
<void(MojoResult
)> AsyncHandleWaiter::GetWaitCallbackForTest() {
152 return base::Bind(&Context::HandleIsReady
, context_
);
156 void AsyncHandleWaiterContextTraits::Destruct(
157 const AsyncHandleWaiter::Context
* context
) {
158 context
->io_runner_
->PostTask(
160 base::Bind(&base::DeletePointer
<const AsyncHandleWaiter::Context
>,
161 base::Unretained(context
)));
164 } // namespace internal