Home | History | Annotate | Download | only in core
      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