• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Watch(const scoped_refptr<WatcherDispatcher> & watcher,const scoped_refptr<Dispatcher> & dispatcher,uintptr_t context,MojoHandleSignals signals,MojoTriggerCondition condition)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 
NotifyState(const HandleSignalsState & state,bool allowed_to_call_callback)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 
Cancel()57 void Watch::Cancel() {
58   RequestContext::current()->AddWatchCancelFinalizer(this);
59 }
60 
InvokeCallback(MojoResult result,const HandleSignalsState & state,MojoTrapEventFlags flags)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 
~Watch()81 Watch::~Watch() {}
82 
83 #if DCHECK_IS_ON()
AssertWatcherLockAcquired() const84 void Watch::AssertWatcherLockAcquired() const {
85   watcher_->lock_.AssertAcquired();
86 }
87 #endif
88 
89 }  // namespace core
90 }  // namespace mojo
91