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