Commit 58e6cc73 authored by rockot's avatar rockot Committed by Commit bot

Mojo: Don't hold a watch context ref in SimpleWatcher posted task

In test environments it's fairly common for task runners to be
torn down without flushing posted tasks. If there's e.g. a binding
object on the test function stack that gets destroyed on unwind,
this might end up posting a SimpleWatcher notification task that
then never runs.

Currently we disambiguate watch contexts in SimpleWatcher by
retaining a ref to the Context in said notification task and comparing
to the currently known Context instance on the SimpleWatcher's thread.
This can lead to indirect leaks in the aforementioned testing scenario.

This CL instead introduces a sequence number in SimpleWatcher which is
incremented every time a new watch is started. This sequence number is
used to disambiguate notifications which might have come from a previous
watch, thus avoiding the unnecessary ref count on Context.

BUG=702180
R=yzshen@chromium.org

Review-Url: https://codereview.chromium.org/2754863002
Cr-Commit-Position: refs/heads/master@{#457455}
parent bb383d15
...@@ -26,8 +26,10 @@ class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> { ...@@ -26,8 +26,10 @@ class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> {
WatcherHandle watcher_handle, WatcherHandle watcher_handle,
Handle handle, Handle handle,
MojoHandleSignals signals, MojoHandleSignals signals,
int watch_id,
MojoResult* watch_result) { MojoResult* watch_result) {
scoped_refptr<Context> context = new Context(watcher, task_runner); scoped_refptr<Context> context =
new Context(watcher, task_runner, watch_id);
// If MojoWatch succeeds, it assumes ownership of a reference to |context|. // If MojoWatch succeeds, it assumes ownership of a reference to |context|.
// In that case, this reference is balanced in CallNotify() when |result| is // In that case, this reference is balanced in CallNotify() when |result| is
...@@ -69,8 +71,11 @@ class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> { ...@@ -69,8 +71,11 @@ class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> {
friend class base::RefCountedThreadSafe<Context>; friend class base::RefCountedThreadSafe<Context>;
Context(base::WeakPtr<SimpleWatcher> weak_watcher, Context(base::WeakPtr<SimpleWatcher> weak_watcher,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) scoped_refptr<base::SingleThreadTaskRunner> task_runner,
: weak_watcher_(weak_watcher), task_runner_(task_runner) {} int watch_id)
: weak_watcher_(weak_watcher),
task_runner_(task_runner),
watch_id_(watch_id) {}
~Context() {} ~Context() {}
void Notify(MojoResult result, void Notify(MojoResult result,
...@@ -95,16 +100,17 @@ class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> { ...@@ -95,16 +100,17 @@ class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> {
// System notifications will trigger from the task runner passed to // System notifications will trigger from the task runner passed to
// mojo::edk::InitIPCSupport(). In Chrome this happens to always be the // mojo::edk::InitIPCSupport(). In Chrome this happens to always be the
// default task runner for the IO thread. // default task runner for the IO thread.
weak_watcher_->OnHandleReady(make_scoped_refptr(this), result); weak_watcher_->OnHandleReady(watch_id_, result);
} else { } else {
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, base::Bind(&SimpleWatcher::OnHandleReady, weak_watcher_, FROM_HERE, base::Bind(&SimpleWatcher::OnHandleReady, weak_watcher_,
make_scoped_refptr(this), result)); watch_id_, result));
} }
} }
const base::WeakPtr<SimpleWatcher> weak_watcher_; const base::WeakPtr<SimpleWatcher> weak_watcher_;
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
const int watch_id_;
base::Lock lock_; base::Lock lock_;
bool enable_cancellation_notifications_ = true; bool enable_cancellation_notifications_ = true;
...@@ -145,11 +151,12 @@ MojoResult SimpleWatcher::Watch(Handle handle, ...@@ -145,11 +151,12 @@ MojoResult SimpleWatcher::Watch(Handle handle,
callback_ = callback; callback_ = callback;
handle_ = handle; handle_ = handle;
watch_id_ += 1;
MojoResult watch_result = MOJO_RESULT_UNKNOWN; MojoResult watch_result = MOJO_RESULT_UNKNOWN;
context_ = context_ = Context::Create(weak_factory_.GetWeakPtr(), task_runner_,
Context::Create(weak_factory_.GetWeakPtr(), task_runner_, watcher_handle_.get(), handle_, signals, watch_id_,
watcher_handle_.get(), handle_, signals, &watch_result); &watch_result);
if (!context_) { if (!context_) {
handle_.set_value(kInvalidHandleValue); handle_.set_value(kInvalidHandleValue);
callback_.Reset(); callback_.Reset();
...@@ -227,16 +234,15 @@ void SimpleWatcher::ArmOrNotify() { ...@@ -227,16 +234,15 @@ void SimpleWatcher::ArmOrNotify() {
DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv); DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, rv);
task_runner_->PostTask(FROM_HERE, base::Bind(&SimpleWatcher::OnHandleReady, task_runner_->PostTask(FROM_HERE, base::Bind(&SimpleWatcher::OnHandleReady,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
context_, ready_result)); watch_id_, ready_result));
} }
void SimpleWatcher::OnHandleReady(scoped_refptr<const Context> context, void SimpleWatcher::OnHandleReady(int watch_id, MojoResult result) {
MojoResult result) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
// This notification may be for a previously watched context, in which case // This notification may be for a previously watched context, in which case
// we just ignore it. // we just ignore it.
if (context != context_) if (watch_id != watch_id_)
return; return;
ReadyCallback callback = callback_; ReadyCallback callback = callback_;
......
...@@ -164,7 +164,7 @@ class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher { ...@@ -164,7 +164,7 @@ class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher {
private: private:
class Context; class Context;
void OnHandleReady(scoped_refptr<const Context> context, MojoResult result); void OnHandleReady(int watch_id, MojoResult result);
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
...@@ -190,6 +190,10 @@ class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher { ...@@ -190,6 +190,10 @@ class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher {
// The handle currently under watch. Not owned. // The handle currently under watch. Not owned.
Handle handle_; Handle handle_;
// A simple counter to disambiguate notifications from multiple watch contexts
// in the event that this SimpleWatcher cancels and watches multiple times.
int watch_id_ = 0;
// The callback to call when the handle is signaled. // The callback to call when the handle is signaled.
ReadyCallback callback_; ReadyCallback callback_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment