1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "mojo/core/watch.h" 6 7 #include "mojo/core/request_context.h" 8 #include "mojo/core/watcher_dispatcher.h" 9 10 namespace mojo { 11 namespace core { 12 13 Watch::Watch(const scoped_refptr<WatcherDispatcher>& watcher, 14 const scoped_refptr<Dispatcher>& dispatcher, 15 uintptr_t context, 16 MojoHandleSignals signals, 17 MojoTriggerCondition condition) 18 : watcher_(watcher), 19 dispatcher_(dispatcher), 20 context_(context), 21 signals_(signals), 22 condition_(condition) {} 23 24 bool Watch::NotifyState(const HandleSignalsState& state, 25 bool allowed_to_call_callback) { 26 AssertWatcherLockAcquired(); 27 28 // NOTE: This method must NEVER call into |dispatcher_| directly, because it 29 // may be called while |dispatcher_| holds a lock. 30 MojoResult rv = MOJO_RESULT_SHOULD_WAIT; 31 RequestContext* const request_context = RequestContext::current(); 32 const bool notify_success = 33 (state.satisfies_any(signals_) && 34 condition_ == MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED) || 35 (!state.satisfies_all(signals_) && 36 condition_ == MOJO_TRIGGER_CONDITION_SIGNALS_UNSATISFIED); 37 if (notify_success) { 38 rv = MOJO_RESULT_OK; 39 if (allowed_to_call_callback && rv != last_known_result_) { 40 request_context->AddWatchNotifyFinalizer(this, MOJO_RESULT_OK, state); 41 } 42 } else if (condition_ == MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED && 43 !state.can_satisfy_any(signals_)) { 44 rv = MOJO_RESULT_FAILED_PRECONDITION; 45 if (allowed_to_call_callback && rv != last_known_result_) { 46 request_context->AddWatchNotifyFinalizer( 47 this, MOJO_RESULT_FAILED_PRECONDITION, state); 48 } 49 } 50 51 last_known_signals_state_ = 52 *static_cast<const MojoHandleSignalsState*>(&state); 53 last_known_result_ = rv; 54 return ready(); 55 } 56 57 void Watch::Cancel() { 58 RequestContext::current()->AddWatchCancelFinalizer(this); 59 } 60 61 void Watch::InvokeCallback(MojoResult result, 62 const HandleSignalsState& state, 63 MojoTrapEventFlags flags) { 64 // We hold the lock through invocation to ensure that only one notification 65 // callback runs for this context at any given time. 66 base::AutoLock lock(notification_lock_); 67 68 // Ensure that no notifications are dispatched beyond cancellation. 69 if (is_cancelled_) 70 return; 71 72 if (result == MOJO_RESULT_CANCELLED) 73 is_cancelled_ = true; 74 75 // NOTE: This will acquire |watcher_|'s internal lock. It's safe because a 76 // thread can only enter InvokeCallback() from within a RequestContext 77 // destructor where no dispatcher locks are held. 78 watcher_->InvokeWatchCallback(context_, result, state, flags); 79 } 80 81 Watch::~Watch() {} 82 83 #if DCHECK_IS_ON() 84 void Watch::AssertWatcherLockAcquired() const { 85 watcher_->lock_.AssertAcquired(); 86 } 87 #endif 88 89 } // namespace core 90 } // namespace mojo 91