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