• 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 #ifndef MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_
6 #define MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_
7 
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/location.h"
11 #include "base/macros.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/sequence_checker.h"
15 #include "base/threading/sequenced_task_runner_handle.h"
16 #include "mojo/public/c/system/types.h"
17 #include "mojo/public/cpp/system/handle_signals_state.h"
18 #include "mojo/public/cpp/system/system_export.h"
19 #include "mojo/public/cpp/system/trap.h"
20 
21 namespace base {
22 class SequencedTaskRunner;
23 }
24 
25 namespace mojo {
26 
27 // This provides a convenient sequence-bound watcher implementation to safely
28 // watch a single handle, dispatching state change notifications to an arbitrary
29 // SequencedTaskRunner running on the same sequence as the SimpleWatcher.
30 //
31 // SimpleWatcher exposes the concept of "arming" from the low-level Watcher API.
32 // In general, a SimpleWatcher must be "armed" in order to dispatch a single
33 // notification, and must then be rearmed before it will dispatch another. For
34 // more details, see the documentation for ArmingPolicy and the Arm() and
35 // ArmOrNotify() methods below.
36 class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher {
37  public:
38   // A callback to be called any time a watched handle changes state in some
39   // interesting way. The |result| argument indicates one of the following
40   // conditions depending on its value:
41   //
42   //   |MOJO_RESULT_OK|: One or more of the signals being watched is satisfied.
43   //
44   //   |MOJO_RESULT_FAILED_PRECONDITION|: None of the signals being watched can
45   //       ever be satisfied again.
46   //
47   //   |MOJO_RESULT_CANCELLED|: The watched handle has been closed. No further
48   //       notifications will be fired, as this equivalent to an implicit
49   //       CancelWatch().
50   //
51   // Note that unlike the first two conditions, this callback may be invoked
52   // with |MOJO_RESULT_CANCELLED| even while the SimpleWatcher is disarmed.
53   using ReadyCallback = base::RepeatingCallback<void(MojoResult result)>;
54 
55   // Like above but also receives the last known handle signal state at the time
56   // of the notification.
57   using ReadyCallbackWithState =
58       base::RepeatingCallback<void(MojoResult result,
59                                    const HandleSignalsState& state)>;
60 
61   // Selects how this SimpleWatcher is to be armed.
62   enum class ArmingPolicy {
63     // The SimpleWatcher is armed automatically on Watch() and rearmed again
64     // after every invocation of the ReadyCallback. There is no need to manually
65     // call Arm() on a SimpleWatcher using this policy. This mode is equivalent
66     // to calling ArmOrNotify() once after Watch() and once again after every
67     // dispatched notification in MANUAL mode.
68     //
69     // This provides a reasonable approximation of edge-triggered behavior,
70     // mitigating (but not completely eliminating) the potential for redundant
71     // notifications.
72     //
73     // NOTE: It is important when using AUTOMATIC policy that your ReadyCallback
74     // always attempt to change the state of the handle (e.g. read available
75     // messages on a message pipe.) Otherwise this will result in a potentially
76     // large number of avoidable redundant tasks.
77     //
78     // For perfect edge-triggered behavior, use MANUAL policy and manually Arm()
79     // the SimpleWatcher as soon as it becomes possible to do so again.
80     AUTOMATIC,
81 
82     // The SimpleWatcher is never armed automatically. Arm() or ArmOrNotify()
83     // must be called manually before any non-cancellation notification can be
84     // dispatched to the ReadyCallback. See the documentation for Arm() and
85     // ArmNotify() methods below for more details.
86     MANUAL,
87   };
88 
89   SimpleWatcher(const base::Location& from_here,
90                 ArmingPolicy arming_policy,
91                 scoped_refptr<base::SequencedTaskRunner> runner =
92                     base::SequencedTaskRunnerHandle::Get());
93   ~SimpleWatcher();
94 
95   // Indicates if the SimpleWatcher is currently watching a handle.
96   bool IsWatching() const;
97 
98   // Starts watching |handle|. A SimpleWatcher may only watch one handle at a
99   // time, but it is safe to call this more than once as long as the previous
100   // watch has been cancelled (i.e. |IsWatching()| returns |false|.)
101   //
102   // If |handle| is not a valid watchable (message or data pipe) handle or
103   // |signals| is not a valid set of signals to watch, this returns
104   // |MOJO_RESULT_INVALID_ARGUMENT|.
105   //
106   // Otherwise |MOJO_RESULT_OK| is returned and the handle will be watched until
107   // either |handle| is closed, the SimpleWatcher is destroyed, or Cancel() is
108   // explicitly called.
109   //
110   // Once the watch is started, |callback| may be called at any time on the
111   // current sequence until |Cancel()| is called or the handle is closed. Note
112   // that |callback| can be called for results other than
113   // |MOJO_RESULT_CANCELLED| only if the SimpleWatcher is currently armed. Use
114   // ArmingPolicy to configure how a SimpleWatcher is armed.
115   //
116   // |MOJO_RESULT_CANCELLED| may be dispatched even while the SimpleWatcher
117   // is disarmed, and no further notifications will be dispatched after that.
118   //
119   // Destroying the SimpleWatcher implicitly calls |Cancel()|.
120   MojoResult Watch(Handle handle,
121                    MojoHandleSignals signals,
122                    MojoTriggerCondition condition,
123                    const ReadyCallbackWithState& callback);
124 
125   // DEPRECATED: Please use the above signature instead.
126   //
127   // This watches a handle for |signals| to be satisfied, provided with a
128   // callback which takes only a MojoResult value corresponding to the result of
129   // a notification.
Watch(Handle handle,MojoHandleSignals signals,const ReadyCallback & callback)130   MojoResult Watch(Handle handle,
131                    MojoHandleSignals signals,
132                    const ReadyCallback& callback) {
133     return Watch(handle, signals, MOJO_WATCH_CONDITION_SATISFIED,
134                  base::Bind(&DiscardReadyState, callback));
135   }
136 
137   // Cancels the current watch. Once this returns, the ReadyCallback previously
138   // passed to |Watch()| will never be called again for this SimpleWatcher.
139   //
140   // Note that when cancelled with an explicit call to |Cancel()| the
141   // ReadyCallback will not be invoked with a |MOJO_RESULT_CANCELLED| result.
142   void Cancel();
143 
144   // Manually arms the SimpleWatcher.
145   //
146   // Arming the SimpleWatcher allows it to fire a single notification regarding
147   // some future relevant change in the watched handle's state. It's only valid
148   // to call Arm() while a handle is being watched (see Watch() above.)
149   //
150   // SimpleWatcher is always disarmed immediately before invoking its
151   // ReadyCallback and must be rearmed again before another notification can
152   // fire.
153   //
154   // If the watched handle already meets the watched signaling conditions -
155   // i.e., if it would have notified immediately once armed - the SimpleWatcher
156   // is NOT armed, and this call fails with a return value of
157   // |MOJO_RESULT_FAILED_PRECONDITION|. In that case, what would have been the
158   // result code for that immediate notification is instead placed in
159   // |*ready_result| if |ready_result| is non-null, and the last known signaling
160   // state of the handle is placed in |*ready_state| if |ready_state| is
161   // non-null.
162   //
163   // If the watcher is successfully armed (or was already armed), this returns
164   // |MOJO_RESULT_OK| and |ready_result| and |ready_state| are ignored.
165   MojoResult Arm(MojoResult* ready_result = nullptr,
166                  HandleSignalsState* ready_state = nullptr);
167 
168   // Manually arms the SimpleWatcher OR posts a task to invoke the ReadyCallback
169   // with the ready result of the failed arming attempt.
170   //
171   // This is meant as a convenient helper for a common usage of Arm(), and it
172   // ensures that the ReadyCallback will be invoked asynchronously again as soon
173   // as the watch's conditions are satisfied, assuming the SimpleWatcher isn't
174   // cancelled first.
175   //
176   // Unlike Arm() above, this can never fail.
177   void ArmOrNotify();
178 
handle()179   Handle handle() const { return handle_; }
ready_callback()180   ReadyCallbackWithState ready_callback() const { return callback_; }
181 
182   // Sets the tag used by the heap profiler.
183   // |tag| must be a const string literal.
set_heap_profiler_tag(const char * heap_profiler_tag)184   void set_heap_profiler_tag(const char* heap_profiler_tag) {
185     heap_profiler_tag_ = heap_profiler_tag;
186   }
187 
188  private:
189   class Context;
190 
DiscardReadyState(const ReadyCallback & callback,MojoResult result,const HandleSignalsState & state)191   static void DiscardReadyState(const ReadyCallback& callback,
192                                 MojoResult result,
193                                 const HandleSignalsState& state) {
194     callback.Run(result);
195   }
196 
197   void OnHandleReady(int watch_id,
198                      MojoResult result,
199                      const HandleSignalsState& state);
200 
201   SEQUENCE_CHECKER(sequence_checker_);
202 
203   // The policy used to determine how this SimpleWatcher is armed.
204   const ArmingPolicy arming_policy_;
205 
206   // The TaskRunner of this SimpleWatcher's owning sequence. This field is safe
207   // to access from any sequence.
208   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
209 
210   // Whether |task_runner_| is the same as
211   // base::SequencedTaskRunnerHandle::Get() for the thread.
212   const bool is_default_task_runner_;
213 
214   ScopedTrapHandle trap_handle_;
215 
216   // A thread-safe context object corresponding to the currently active watch,
217   // if any.
218   scoped_refptr<Context> context_;
219 
220   // Fields below must only be accessed on the SimpleWatcher's owning sequence.
221 
222   // The handle currently under watch. Not owned.
223   Handle handle_;
224 
225   // A simple counter to disambiguate notifications from multiple watch contexts
226   // in the event that this SimpleWatcher cancels and watches multiple times.
227   int watch_id_ = 0;
228 
229   // The callback to call when the handle is signaled.
230   ReadyCallbackWithState callback_;
231 
232   // Tag used to ID memory allocations that originated from notifications in
233   // this watcher.
234   const char* heap_profiler_tag_ = nullptr;
235 
236   base::WeakPtrFactory<SimpleWatcher> weak_factory_;
237 
238   DISALLOW_COPY_AND_ASSIGN(SimpleWatcher);
239 };
240 
241 }  // namespace mojo
242 
243 #endif  // MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_
244