OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ipc/mojo/async_handle_waiter.h" | 5 #include "ipc/mojo/async_handle_waiter.h" |
6 | 6 |
7 #include "base/atomic_ref_count.h" | 7 #include "base/atomic_ref_count.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/message_loop/message_loop.h" | |
13 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" | 12 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" |
14 | 13 |
15 namespace IPC { | 14 namespace IPC { |
16 namespace internal { | 15 namespace internal { |
17 | 16 |
18 class AsyncHandleWaiterContextTraits { | 17 class AsyncHandleWaiterContextTraits { |
19 public: | 18 public: |
20 static void Destruct(const AsyncHandleWaiter::Context* context); | 19 static void Destruct(const AsyncHandleWaiter::Context* context); |
21 }; | 20 }; |
22 | 21 |
23 // The thread-safe part of |AsyncHandleWaiter|. | 22 // The thread-safe part of |AsyncHandleWaiter|. |
24 // As |AsyncWait()| invokes the given callback from an arbitrary thread, | 23 // As |AsyncWait()| invokes the given callback from an arbitrary thread, |
25 // |HandleIsReady()| and the bound |this| have to be thread-safe. | 24 // |HandleIsReady()| and the bound |this| have to be thread-safe. |
26 class AsyncHandleWaiter::Context | 25 class AsyncHandleWaiter::Context |
27 : public base::RefCountedThreadSafe<AsyncHandleWaiter::Context, | 26 : public base::RefCountedThreadSafe<AsyncHandleWaiter::Context, |
28 AsyncHandleWaiterContextTraits>, | 27 AsyncHandleWaiterContextTraits>, |
29 public base::MessageLoopForIO::IOObserver { | 28 public base::MessageLoopForIO::IOObserver { |
30 public: | 29 public: |
31 Context(base::WeakPtr<AsyncHandleWaiter> waiter) | 30 Context(base::WeakPtr<AsyncHandleWaiter> waiter) |
32 : io_runner_(base::MessageLoopForIO::current()->task_runner()), | 31 : io_runner_(base::MessageLoopForIO::current()->task_runner()), |
33 waiter_(waiter), | 32 waiter_(waiter), |
34 last_result_(MOJO_RESULT_INTERNAL), | 33 last_result_(MOJO_RESULT_INTERNAL), |
35 processing_(false), | 34 io_loop_level_(0), |
36 should_invoke_callback_(false) { | 35 should_invoke_callback_(false) { |
37 base::MessageLoopForIO::current()->AddIOObserver(this); | 36 base::MessageLoopForIO::current()->AddIOObserver(this); |
38 } | 37 } |
39 | 38 |
40 void HandleIsReady(MojoResult result) { | 39 void HandleIsReady(MojoResult result) { |
41 last_result_ = result; | 40 last_result_ = result; |
42 | 41 |
43 // If the signaling happens in the IO handler, use |IOObserver| callback | 42 // If the signaling happens in the IO handler, use |IOObserver| callback |
44 // to invoke the callback. | 43 // to invoke the callback. |
45 if (IsCalledFromIOHandler()) { | 44 if (IsCalledFromIOHandler()) { |
(...skipping 14 matching lines...) Expand all Loading... | |
60 DCHECK(base::MessageLoopForIO::current()->task_runner() == io_runner_); | 59 DCHECK(base::MessageLoopForIO::current()->task_runner() == io_runner_); |
61 base::MessageLoopForIO::current()->RemoveIOObserver(this); | 60 base::MessageLoopForIO::current()->RemoveIOObserver(this); |
62 } | 61 } |
63 | 62 |
64 bool IsCalledFromIOHandler() const { | 63 bool IsCalledFromIOHandler() const { |
65 base::MessageLoop* loop = base::MessageLoop::current(); | 64 base::MessageLoop* loop = base::MessageLoop::current(); |
66 if (!loop) | 65 if (!loop) |
67 return false; | 66 return false; |
68 if (loop->task_runner() != io_runner_) | 67 if (loop->task_runner() != io_runner_) |
69 return false; | 68 return false; |
70 return processing_; | 69 return 0 < io_loop_level_; |
viettrungluu
2015/03/05 01:10:45
nit: io_loop_level_ > 0
| |
71 } | 70 } |
72 | 71 |
73 // Called from |io_runner_| thus safe to touch |waiter_|. | 72 // Called from |io_runner_| thus safe to touch |waiter_|. |
74 void InvokeWaiterCallback() { | 73 void InvokeWaiterCallback() { |
75 MojoResult result = last_result_; | 74 MojoResult result = last_result_; |
76 last_result_ = MOJO_RESULT_INTERNAL; | 75 last_result_ = MOJO_RESULT_INTERNAL; |
77 if (waiter_) | 76 if (waiter_) |
78 waiter_->InvokeCallback(result); | 77 waiter_->InvokeCallback(result); |
79 } | 78 } |
80 | 79 |
81 // IOObserver implementation: | 80 // IOObserver implementation: |
82 | 81 |
83 void WillProcessIOEvent() override { | 82 void WillProcessIOEvent() override { |
84 DCHECK(!should_invoke_callback_); | 83 DCHECK(io_loop_level_ != 0 || !should_invoke_callback_); |
85 DCHECK(!processing_); | 84 DCHECK_GE(io_loop_level_, 0); |
86 processing_ = true; | 85 io_loop_level_++; |
87 } | 86 } |
88 | 87 |
89 void DidProcessIOEvent() override { | 88 void DidProcessIOEvent() override { |
90 DCHECK(processing_); | 89 DCHECK_GE(io_loop_level_, 1); |
90 | |
91 // Leaving a nested loop. | |
92 if (io_loop_level_ > 1) { | |
93 io_loop_level_--; | |
94 return; | |
95 } | |
91 | 96 |
92 // The zero |waiter_| indicates that |this| have lost the owner and can be | 97 // The zero |waiter_| indicates that |this| have lost the owner and can be |
93 // under destruction. So we cannot wrap it with a |scoped_refptr| anymore. | 98 // under destruction. So we cannot wrap it with a |scoped_refptr| anymore. |
94 if (!waiter_) { | 99 if (!waiter_) { |
95 should_invoke_callback_ = false; | 100 should_invoke_callback_ = false; |
96 processing_ = false; | 101 io_loop_level_--; |
97 return; | 102 return; |
98 } | 103 } |
99 | 104 |
100 // We have to protect |this| because |AsyncHandleWaiter| can be | 105 // We have to protect |this| because |AsyncHandleWaiter| can be |
101 // deleted during the callback. | 106 // deleted during the callback. |
102 scoped_refptr<Context> protect(this); | 107 scoped_refptr<Context> protect(this); |
103 while (should_invoke_callback_) { | 108 while (should_invoke_callback_) { |
104 should_invoke_callback_ = false; | 109 should_invoke_callback_ = false; |
105 InvokeWaiterCallback(); | 110 InvokeWaiterCallback(); |
106 } | 111 } |
107 | 112 |
108 processing_ = false; | 113 io_loop_level_--; |
109 } | 114 } |
110 | 115 |
111 // Only |io_runner_| is accessed from arbitrary threads. Others are touched | 116 // Only |io_runner_| is accessed from arbitrary threads. Others are touched |
112 // only from the IO thread. | 117 // only from the IO thread. |
113 const scoped_refptr<base::TaskRunner> io_runner_; | 118 const scoped_refptr<base::TaskRunner> io_runner_; |
114 | 119 |
115 const base::WeakPtr<AsyncHandleWaiter> waiter_; | 120 const base::WeakPtr<AsyncHandleWaiter> waiter_; |
116 MojoResult last_result_; | 121 MojoResult last_result_; |
117 bool processing_; | 122 int io_loop_level_; |
118 bool should_invoke_callback_; | 123 bool should_invoke_callback_; |
119 | 124 |
120 DISALLOW_COPY_AND_ASSIGN(Context); | 125 DISALLOW_COPY_AND_ASSIGN(Context); |
121 }; | 126 }; |
122 | 127 |
123 AsyncHandleWaiter::AsyncHandleWaiter(base::Callback<void(MojoResult)> callback) | 128 AsyncHandleWaiter::AsyncHandleWaiter(base::Callback<void(MojoResult)> callback) |
124 : callback_(callback), | 129 : callback_(callback), |
125 weak_factory_(this) { | 130 weak_factory_(this) { |
126 context_ = new Context(weak_factory_.GetWeakPtr()); | 131 context_ = new Context(weak_factory_.GetWeakPtr()); |
127 } | 132 } |
128 | 133 |
129 AsyncHandleWaiter::~AsyncHandleWaiter() { | 134 AsyncHandleWaiter::~AsyncHandleWaiter() { |
130 } | 135 } |
131 | 136 |
132 MojoResult AsyncHandleWaiter::Wait(MojoHandle handle, | 137 MojoResult AsyncHandleWaiter::Wait(MojoHandle handle, |
133 MojoHandleSignals signals) { | 138 MojoHandleSignals signals) { |
134 return mojo::embedder::AsyncWait( | 139 return mojo::embedder::AsyncWait( |
135 handle, signals, base::Bind(&Context::HandleIsReady, context_)); | 140 handle, signals, base::Bind(&Context::HandleIsReady, context_)); |
136 } | 141 } |
137 | 142 |
138 void AsyncHandleWaiter::InvokeCallback(MojoResult result) { | 143 void AsyncHandleWaiter::InvokeCallback(MojoResult result) { |
139 callback_.Run(result); | 144 callback_.Run(result); |
140 } | 145 } |
141 | 146 |
147 base::MessageLoopForIO::IOObserver* AsyncHandleWaiter::GetIOObserverForTest() { | |
148 return context_.get(); | |
149 } | |
150 | |
151 base::Callback<void(MojoResult)> AsyncHandleWaiter::GetWaitCallbackForTest() { | |
152 return base::Bind(&Context::HandleIsReady, context_); | |
153 } | |
154 | |
142 // static | 155 // static |
143 void AsyncHandleWaiterContextTraits::Destruct( | 156 void AsyncHandleWaiterContextTraits::Destruct( |
144 const AsyncHandleWaiter::Context* context) { | 157 const AsyncHandleWaiter::Context* context) { |
145 context->io_runner_->PostTask( | 158 context->io_runner_->PostTask( |
146 FROM_HERE, | 159 FROM_HERE, |
147 base::Bind(&base::DeletePointer<const AsyncHandleWaiter::Context>, | 160 base::Bind(&base::DeletePointer<const AsyncHandleWaiter::Context>, |
148 base::Unretained(context))); | 161 base::Unretained(context))); |
149 } | 162 } |
150 | 163 |
151 } // namespace internal | 164 } // namespace internal |
152 } // namespace IPC | 165 } // namespace IPC |
OLD | NEW |