File: simple_watcher.h

package info (click to toggle)
chromium 135.0.7049.95-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 5,959,392 kB
  • sloc: cpp: 34,198,526; ansic: 7,100,035; javascript: 3,985,800; python: 1,395,489; asm: 896,754; xml: 722,891; pascal: 180,504; sh: 94,909; perl: 88,388; objc: 79,739; sql: 53,020; cs: 41,358; fortran: 24,137; makefile: 22,501; php: 13,699; tcl: 10,142; yacc: 8,822; ruby: 7,350; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; awk: 197; sed: 36
file content (239 lines) | stat: -rw-r--r-- 10,120 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_
#define MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/system/handle_signals_state.h"
#include "mojo/public/cpp/system/system_export.h"
#include "mojo/public/cpp/system/trap.h"

namespace base {
class SequencedTaskRunner;
}

namespace mojo {

// This provides a convenient sequence-bound watcher implementation to safely
// watch a single handle, dispatching state change notifications to an arbitrary
// SequencedTaskRunner running on the same sequence as the SimpleWatcher.
//
// SimpleWatcher exposes the concept of "arming" from the low-level Watcher API.
// In general, a SimpleWatcher must be "armed" in order to dispatch a single
// notification, and must then be rearmed before it will dispatch another. For
// more details, see the documentation for ArmingPolicy and the Arm() and
// ArmOrNotify() methods below.
class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher {
 public:
  // A callback to be called any time a watched handle changes state in some
  // interesting way. The |result| argument indicates one of the following
  // conditions depending on its value:
  //
  //   |MOJO_RESULT_OK|: One or more of the signals being watched is satisfied.
  //
  //   |MOJO_RESULT_FAILED_PRECONDITION|: None of the signals being watched can
  //       ever be satisfied again.
  //
  //   |MOJO_RESULT_CANCELLED|: The watched handle has been closed. No further
  //       notifications will be fired, as this equivalent to an implicit
  //       CancelWatch().
  //
  // Note that unlike the first two conditions, this callback may be invoked
  // with |MOJO_RESULT_CANCELLED| even while the SimpleWatcher is disarmed.
  using ReadyCallback = base::RepeatingCallback<void(MojoResult result)>;

  // Like above but also receives the last known handle signal state at the time
  // of the notification.
  using ReadyCallbackWithState =
      base::RepeatingCallback<void(MojoResult result,
                                   const HandleSignalsState& state)>;

  // Selects how this SimpleWatcher is to be armed.
  enum class ArmingPolicy {
    // The SimpleWatcher is armed automatically on Watch() and rearmed again
    // after every invocation of the ReadyCallback. There is no need to manually
    // call Arm() on a SimpleWatcher using this policy. This mode is equivalent
    // to calling ArmOrNotify() once after Watch() and once again after every
    // dispatched notification in MANUAL mode.
    //
    // This provides a reasonable approximation of edge-triggered behavior,
    // mitigating (but not completely eliminating) the potential for redundant
    // notifications.
    //
    // NOTE: It is important when using AUTOMATIC policy that your ReadyCallback
    // always attempt to change the state of the handle (e.g. read available
    // messages on a message pipe.) Otherwise this will result in a potentially
    // large number of avoidable redundant tasks.
    //
    // For perfect edge-triggered behavior, use MANUAL policy and manually Arm()
    // the SimpleWatcher as soon as it becomes possible to do so again.
    AUTOMATIC,

    // The SimpleWatcher is never armed automatically. Arm() or ArmOrNotify()
    // must be called manually before any non-cancellation notification can be
    // dispatched to the ReadyCallback. See the documentation for Arm() and
    // ArmNotify() methods below for more details.
    MANUAL,
  };

  SimpleWatcher(const base::Location& from_here,
                ArmingPolicy arming_policy,
                scoped_refptr<base::SequencedTaskRunner> runner =
                    base::SequencedTaskRunner::GetCurrentDefault(),
                const char* handler_tag = nullptr);

  SimpleWatcher(const SimpleWatcher&) = delete;
  SimpleWatcher& operator=(const SimpleWatcher&) = delete;

  ~SimpleWatcher();

  // Indicates if the SimpleWatcher is currently watching a handle.
  bool IsWatching() const;

  // Starts watching |handle|. A SimpleWatcher may only watch one handle at a
  // time, but it is safe to call this more than once as long as the previous
  // watch has been cancelled (i.e. |IsWatching()| returns |false|.)
  //
  // If |handle| is not a valid watchable (message or data pipe) handle or
  // |signals| is not a valid set of signals to watch, this returns
  // |MOJO_RESULT_INVALID_ARGUMENT|.
  //
  // Otherwise |MOJO_RESULT_OK| is returned and the handle will be watched until
  // either |handle| is closed, the SimpleWatcher is destroyed, or Cancel() is
  // explicitly called.
  //
  // Once the watch is started, |callback| may be called at any time on the
  // current sequence until |Cancel()| is called or the handle is closed. Note
  // that |callback| can be called for results other than
  // |MOJO_RESULT_CANCELLED| only if the SimpleWatcher is currently armed. Use
  // ArmingPolicy to configure how a SimpleWatcher is armed.
  //
  // |MOJO_RESULT_CANCELLED| may be dispatched even while the SimpleWatcher
  // is disarmed, and no further notifications will be dispatched after that.
  //
  // Destroying the SimpleWatcher implicitly calls |Cancel()|.
  MojoResult Watch(Handle handle,
                   MojoHandleSignals signals,
                   MojoTriggerCondition condition,
                   ReadyCallbackWithState callback);

  // DEPRECATED: Please use the above signature instead.
  //
  // This watches a handle for |signals| to be satisfied, provided with a
  // callback which takes only a MojoResult value corresponding to the result of
  // a notification.
  MojoResult Watch(Handle handle,
                   MojoHandleSignals signals,
                   ReadyCallback callback) {
    return Watch(handle, signals, MOJO_WATCH_CONDITION_SATISFIED,
                 base::BindRepeating(&DiscardReadyState, std::move(callback)));
  }

  // Cancels the current watch. Once this returns, the ReadyCallback previously
  // passed to |Watch()| will never be called again for this SimpleWatcher.
  //
  // Note that when cancelled with an explicit call to |Cancel()| the
  // ReadyCallback will not be invoked with a |MOJO_RESULT_CANCELLED| result.
  void Cancel();

  // Manually arms the SimpleWatcher.
  //
  // Arming the SimpleWatcher allows it to fire a single notification regarding
  // some future relevant change in the watched handle's state. It's only valid
  // to call Arm() while a handle is being watched (see Watch() above.)
  //
  // SimpleWatcher is always disarmed immediately before invoking its
  // ReadyCallback and must be rearmed again before another notification can
  // fire.
  //
  // If the watched handle already meets the watched signaling conditions -
  // i.e., if it would have notified immediately once armed - the SimpleWatcher
  // is NOT armed, and this call fails with a return value of
  // |MOJO_RESULT_FAILED_PRECONDITION|. In that case, what would have been the
  // result code for that immediate notification is instead placed in
  // |*ready_result| if |ready_result| is non-null, and the last known signaling
  // state of the handle is placed in |*ready_state| if |ready_state| is
  // non-null.
  //
  // If the watcher is successfully armed (or was already armed), this returns
  // |MOJO_RESULT_OK| and |ready_result| and |ready_state| are ignored.
  MojoResult Arm(MojoResult* ready_result = nullptr,
                 HandleSignalsState* ready_state = nullptr);

  // Manually arms the SimpleWatcher OR posts a task to invoke the ReadyCallback
  // with the ready result of the failed arming attempt.
  //
  // This is meant as a convenient helper for a common usage of Arm(), and it
  // ensures that the ReadyCallback will be invoked asynchronously again as soon
  // as the watch's conditions are satisfied, assuming the SimpleWatcher isn't
  // cancelled first.
  //
  // Unlike Arm() above, this can never fail.
  void ArmOrNotify();

  Handle handle() const { return handle_; }
  ReadyCallbackWithState ready_callback() const { return callback_; }

 private:
  class Context;

  static void DiscardReadyState(const ReadyCallback& callback,
                                MojoResult result,
                                const HandleSignalsState& state) {
    callback.Run(result);
  }

  void OnHandleReady(int watch_id,
                     MojoResult result,
                     const HandleSignalsState& state);

  SEQUENCE_CHECKER(sequence_checker_);

  // The policy used to determine how this SimpleWatcher is armed.
  const ArmingPolicy arming_policy_;

  // The TaskRunner of this SimpleWatcher's owning sequence. This field is safe
  // to access from any sequence.
  const scoped_refptr<base::SequencedTaskRunner> task_runner_;

  // Whether |task_runner_| is the same as
  // base::SequencedTaskRunner::GetCurrentDefault() for the thread.
  const bool is_default_task_runner_;

  ScopedTrapHandle trap_handle_;

  // A thread-safe context object corresponding to the currently active watch,
  // if any.
  scoped_refptr<Context> context_;

  // Fields below must only be accessed on the SimpleWatcher's owning sequence.

  // The handle currently under watch. Not owned.
  Handle handle_;

  // A simple counter to disambiguate notifications from multiple watch contexts
  // in the event that this SimpleWatcher cancels and watches multiple times.
  int watch_id_ = 0;

  // The callback to call when the handle is signaled.
  ReadyCallbackWithState callback_;

  // Tag used to ID memory allocations that originated from notifications in
  // this watcher.
  const char* handler_tag_ = nullptr;

  base::WeakPtrFactory<SimpleWatcher> weak_factory_{this};
};

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_