• 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/public/cpp/system/handle_signal_tracker.h"
6 
7 #include "base/synchronization/lock.h"
8 #include "mojo/public/cpp/system/handle_signals_state.h"
9 
10 namespace mojo {
11 
HandleSignalTracker(Handle handle,MojoHandleSignals signals)12 HandleSignalTracker::HandleSignalTracker(Handle handle,
13                                          MojoHandleSignals signals)
14     : high_watcher_(FROM_HERE,
15                     SimpleWatcher::ArmingPolicy::MANUAL,
16                     base::SequencedTaskRunnerHandle::Get()),
17       low_watcher_(FROM_HERE,
18                    SimpleWatcher::ArmingPolicy::MANUAL,
19                    base::SequencedTaskRunnerHandle::Get()) {
20   MojoResult rv = high_watcher_.Watch(
21       handle, signals, MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
22       base::Bind(&HandleSignalTracker::OnNotify, base::Unretained(this)));
23   DCHECK_EQ(MOJO_RESULT_OK, rv);
24 
25   rv = low_watcher_.Watch(
26       handle, signals, MOJO_TRIGGER_CONDITION_SIGNALS_UNSATISFIED,
27       base::Bind(&HandleSignalTracker::OnNotify, base::Unretained(this)));
28   DCHECK_EQ(MOJO_RESULT_OK, rv);
29 
30   last_known_state_ = handle.QuerySignalsState();
31 
32   Arm();
33 }
34 
35 HandleSignalTracker::~HandleSignalTracker() = default;
36 
Arm()37 void HandleSignalTracker::Arm() {
38   // Arm either the low watcher or high watcher. We cycle until one of them
39   // succeeds, which should almost always happen within two iterations.
40   bool arm_low_watcher = true;
41   for (;;) {
42     MojoResult ready_result;
43     SimpleWatcher& watcher = arm_low_watcher ? low_watcher_ : high_watcher_;
44     MojoResult result = watcher.Arm(&ready_result, &last_known_state_);
45     if (result == MOJO_RESULT_OK) {
46       // Successfully armed one of the watchers, so we can go back to waiting
47       // for a notification.
48       return;
49     }
50 
51     DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
52     if (ready_result == MOJO_RESULT_FAILED_PRECONDITION && !arm_low_watcher) {
53       // The high watcher failed to arm because the watched signal will never
54       // be satisfied again. We can also return in this case, and
55       // |last_known_state_| will remain with its current value indefinitely.
56       return;
57     }
58     arm_low_watcher = !arm_low_watcher;
59   }
60 }
61 
OnNotify(MojoResult result,const HandleSignalsState & state)62 void HandleSignalTracker::OnNotify(MojoResult result,
63                                    const HandleSignalsState& state) {
64   last_known_state_ = state;
65   Arm();
66   if (notification_callback_)
67     notification_callback_.Run(state);
68 }
69 
70 }  // namespace mojo
71