Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: ipc/mojo/async_handle_waiter.cc

Issue 973213002: Make AsyncHandleWaiter reenterancy-safe (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Landing Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ipc/mojo/async_handle_waiter.h ('k') | ipc/mojo/async_handle_waiter_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 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
OLDNEW
« no previous file with comments | « ipc/mojo/async_handle_waiter.h ('k') | ipc/mojo/async_handle_waiter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698