Index: mojo/edk/system/watch.cc |
diff --git a/mojo/edk/system/watch.cc b/mojo/edk/system/watch.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cf08ac37ee5a0d5686fd64e0aaeee486c0c220ca |
--- /dev/null |
+++ b/mojo/edk/system/watch.cc |
@@ -0,0 +1,83 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "mojo/edk/system/watch.h" |
+ |
+#include "mojo/edk/system/request_context.h" |
+#include "mojo/edk/system/watcher_dispatcher.h" |
+ |
+namespace mojo { |
+namespace edk { |
+ |
+Watch::Watch(const scoped_refptr<WatcherDispatcher>& watcher, |
+ const scoped_refptr<Dispatcher>& dispatcher, |
+ uintptr_t context, |
+ MojoHandleSignals signals) |
+ : watcher_(watcher), |
+ dispatcher_(dispatcher), |
+ context_(context), |
+ signals_(signals) {} |
+ |
+bool Watch::NotifyState(const HandleSignalsState& state, |
+ bool allowed_to_call_callback) { |
+ AssertWatcherLockAcquired(); |
+ |
+ // NOTE: This method must NEVER call into |dispatcher_| directly, because it |
+ // may be called while |dispatcher_| holds a lock. |
+ |
+ MojoResult rv = MOJO_RESULT_SHOULD_WAIT; |
+ RequestContext* const request_context = RequestContext::current(); |
+ if (state.satisfies(signals_)) { |
+ rv = MOJO_RESULT_OK; |
+ if (allowed_to_call_callback && rv != last_known_result_) { |
+ request_context->AddWatchNotifyFinalizer(this, MOJO_RESULT_OK, state); |
+ } |
+ } else if (!state.can_satisfy(signals_)) { |
+ rv = MOJO_RESULT_FAILED_PRECONDITION; |
+ if (allowed_to_call_callback && rv != last_known_result_) { |
+ request_context->AddWatchNotifyFinalizer( |
+ this, MOJO_RESULT_FAILED_PRECONDITION, state); |
+ } |
+ } |
+ |
+ last_known_signals_state_ = |
+ *static_cast<const MojoHandleSignalsState*>(&state); |
+ last_known_result_ = rv; |
+ return ready(); |
+} |
+ |
+void Watch::Cancel() { |
+ RequestContext::current()->AddWatchCancelFinalizer(this); |
+} |
+ |
+void Watch::InvokeCallback(MojoResult result, |
+ const HandleSignalsState& state, |
+ MojoWatcherNotificationFlags flags) { |
+ // We hold the lock through invocation to ensure that only one notification |
+ // callback runs for this context at any given time. |
+ base::AutoLock lock(notification_lock_); |
+ if (result == MOJO_RESULT_CANCELLED) { |
+ // Make sure cancellation is the last notification we dispatch. |
+ DCHECK(!is_cancelled_); |
+ is_cancelled_ = true; |
+ } else if (is_cancelled_) { |
+ return; |
+ } |
+ |
+ // NOTE: This will acquire |watcher_|'s internal lock. It's safe because a |
+ // thread can only enter InvokeCallback() from within a RequestContext |
+ // destructor where no dispatcher locks are held. |
+ watcher_->InvokeWatchCallback(context_, result, state, flags); |
+} |
+ |
+Watch::~Watch() {} |
+ |
+#if DCHECK_IS_ON() |
+void Watch::AssertWatcherLockAcquired() const { |
+ watcher_->lock_.AssertAcquired(); |
+} |
+#endif |
+ |
+} // namespace edk |
+} // namespace mojo |