Index: mojo/public/cpp/system/watcher.cc |
diff --git a/mojo/public/cpp/system/watcher.cc b/mojo/public/cpp/system/watcher.cc |
index 55dcf4023e2b719ea7e9fe28451c5280f05e9654..0022145d9b4aac5c18fd4f02b5df1fa6445e9e0a 100644 |
--- a/mojo/public/cpp/system/watcher.cc |
+++ b/mojo/public/cpp/system/watcher.cc |
@@ -13,8 +13,10 @@ |
namespace mojo { |
Watcher::Watcher(const tracked_objects::Location& from_here, |
+ ArmingPolicy arming_policy, |
scoped_refptr<base::SingleThreadTaskRunner> runner) |
- : task_runner_(std::move(runner)), |
+ : arming_policy_(arming_policy), |
+ task_runner_(std::move(runner)), |
is_default_task_runner_(task_runner_ == |
base::ThreadTaskRunnerHandle::Get()), |
heap_profiler_tag_(from_here.file_name()), |
@@ -26,6 +28,9 @@ Watcher::Watcher(const tracked_objects::Location& from_here, |
Watcher::~Watcher() { |
if(IsWatching()) |
Cancel(); |
+ |
+ if (was_deleted_flag_) |
+ *was_deleted_flag_ = true; |
} |
bool Watcher::IsWatching() const { |
@@ -42,9 +47,9 @@ MojoResult Watcher::Start(Handle handle, |
callback_ = callback; |
handle_ = handle; |
- MojoResult result = MojoWatch(handle_.value(), signals, |
- &Watcher::CallOnHandleReady, |
- reinterpret_cast<uintptr_t>(this)); |
+ MojoResult result = |
+ MojoRegisterWatcher(handle_.value(), signals, &Watcher::CallOnHandleReady, |
+ reinterpret_cast<uintptr_t>(this)); |
if (result != MOJO_RESULT_OK) { |
handle_.set_value(kInvalidHandleValue); |
callback_.Reset(); |
@@ -53,18 +58,21 @@ MojoResult Watcher::Start(Handle handle, |
return result; |
} |
+ if (arming_policy_ == ArmingPolicy::AUTOMATIC) |
+ ArmOrNotify(); |
+ |
return MOJO_RESULT_OK; |
} |
void Watcher::Cancel() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- // The watch may have already been cancelled if the handle was closed. |
+ // The watcher may have already been cancelled if the handle was closed. |
if (!handle_.is_valid()) |
return; |
MojoResult result = |
- MojoCancelWatch(handle_.value(), reinterpret_cast<uintptr_t>(this)); |
+ MojoUnregisterWatcher(handle_.value(), reinterpret_cast<uintptr_t>(this)); |
// |result| may be MOJO_RESULT_INVALID_ARGUMENT if |handle_| has closed, but |
// OnHandleReady has not yet been called. |
DCHECK(result == MOJO_RESULT_INVALID_ARGUMENT || result == MOJO_RESULT_OK); |
@@ -72,6 +80,39 @@ void Watcher::Cancel() { |
callback_.Reset(); |
} |
+MojoResult Watcher::Arm() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ return MojoArmWatcher(handle_.value(), reinterpret_cast<uintptr_t>(this)); |
+} |
+ |
+void Watcher::ArmOrNotify() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ // Already cancelled, nothing to do. |
+ if (!IsWatching()) |
+ return; |
+ |
+ MojoResult result = Arm(); |
+ switch (result) { |
+ case MOJO_RESULT_OK: |
+ // We're armed. Nothing else to do. |
+ return; |
+ case MOJO_RESULT_ALREADY_EXISTS: |
+ // Signals are already satisfied. We post a notification of success. |
+ result = MOJO_RESULT_OK; |
+ break; |
+ case MOJO_RESULT_FAILED_PRECONDITION: |
+ // Signals are unsatisfiable. We post a notification to indicate this. |
+ break; |
+ default: |
+ NOTREACHED(); |
+ return; |
+ } |
+ |
+ task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&Watcher::OnHandleReady, weak_self_, result)); |
+} |
+ |
void Watcher::OnHandleReady(MojoResult result) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
@@ -84,7 +125,29 @@ void Watcher::OnHandleReady(MojoResult result) { |
// NOTE: It's legal for |callback| to delete |this|. |
if (!callback.is_null()) { |
TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event(heap_profiler_tag_); |
+ |
+ bool was_deleted = false; |
+ was_deleted_flag_ = &was_deleted; |
callback.Run(result); |
+ if (was_deleted) |
+ return; |
+ was_deleted_flag_ = nullptr; |
+ if (arming_policy_ == ArmingPolicy::AUTOMATIC && IsWatching()) |
+ ArmOrNotify(); |
+ } |
+} |
+ |
+void Watcher::OnHandleReadyFromAnyThread(MojoResult result, |
+ MojoWatchNotificationFlags flags) { |
+ if ((flags & MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM) && |
+ task_runner_->RunsTasksOnCurrentThread() && is_default_task_runner_) { |
+ // System notifications will trigger from the task runner passed to |
+ // mojo::edk::InitIPCSupport(). In Chrome this happens to always be the |
+ // default task runner for the IO thread. |
+ OnHandleReady(result); |
+ } else { |
+ task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&Watcher::OnHandleReady, weak_self_, result)); |
} |
} |
@@ -97,21 +160,9 @@ void Watcher::CallOnHandleReady(uintptr_t context, |
// will never be run after the Watcher's destructor. |
// |
// TODO: Maybe we should also expose |signals_state| through the Watcher API. |
- // Current HandleWatcher users have no need for it, so it's omitted here. |
- Watcher* watcher = reinterpret_cast<Watcher*>(context); |
- |
- if ((flags & MOJO_WATCH_NOTIFICATION_FLAG_FROM_SYSTEM) && |
- watcher->task_runner_->RunsTasksOnCurrentThread() && |
- watcher->is_default_task_runner_) { |
- // System notifications will trigger from the task runner passed to |
- // mojo::edk::InitIPCSupport(). In Chrome this happens to always be the |
- // default task runner for the IO thread. |
- watcher->OnHandleReady(result); |
- } else { |
- watcher->task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&Watcher::OnHandleReady, watcher->weak_self_, result)); |
- } |
+ // Current users have no need for it, so it's omitted here. |
+ auto* watcher = reinterpret_cast<Watcher*>(context); |
+ watcher->OnHandleReadyFromAnyThread(result, flags); |
} |
} // namespace mojo |