Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2016-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file contains declarations of the
22 : * chip::System::Layer class and its related types, data and
23 : * functions.
24 : */
25 :
26 : #pragma once
27 :
28 : #include <type_traits>
29 : #include <utility>
30 :
31 : // Include configuration headers
32 : #include <system/SystemConfig.h>
33 :
34 : #include <lib/core/CHIPCallback.h>
35 : #include <lib/core/CriticalFailure.h>
36 :
37 : #include <lib/support/CodeUtils.h>
38 : #include <lib/support/DLLUtil.h>
39 : #include <lib/support/LambdaBridge.h>
40 : #include <system/SystemClock.h>
41 : #include <system/SystemError.h>
42 : #include <system/SystemEvent.h>
43 :
44 : #include <lib/support/IntrusiveList.h>
45 : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
46 : #include <system/SocketEvents.h>
47 : #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
48 :
49 : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
50 : #include <dispatch/dispatch.h>
51 : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
52 : #include <ev.h>
53 : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
54 :
55 : namespace chip {
56 : namespace System {
57 :
58 : class Layer;
59 : using TimerCompleteCallback = void (*)(Layer * aLayer, void * appState);
60 :
61 : /**
62 : * This provides access to timers according to the configured event handling model.
63 : *
64 : * The abstract class hierarchy is:
65 : * - Layer: Core timer methods.
66 : * - LayerFreeRTOS: Adds methods specific to CHIP_SYSTEM_CONFIG_USING_LWIP and CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT.
67 : * - LayerSockets: Adds I/O event methods specific to CHIP_SYSTEM_CONFIG_USING_SOCKETS.
68 : * - LayerSelectLoop: Adds methods for event-loop-based implementations.
69 : *
70 : * Threading notes:
71 : *
72 : * The SDK is not generally thread safe. System::Layer methods should only be called from
73 : * a single context, or otherwise externally synchronized. For platforms that use a CHIP
74 : * event loop thread, timer callbacks are invoked on that thread; for platforms that use
75 : * a CHIP lock, the lock is held.
76 : */
77 : class DLL_EXPORT Layer
78 : {
79 : public:
80 108 : Layer() = default;
81 108 : virtual ~Layer() = default;
82 :
83 : /**
84 : * Initialize the Layer.
85 : */
86 : virtual CriticalFailure Init() = 0;
87 :
88 : /**
89 : * Shut down the Layer.
90 : *
91 : * Some other layers hold pointers to System::Layer, so care must be taken
92 : * to ensure that they are not used after calling Shutdown().
93 : */
94 : virtual void Shutdown() = 0;
95 :
96 : /**
97 : * True if this Layer is initialized. No method on Layer or its abstract descendants, other than this and `Init()`,
98 : * may be called from general code unless this is true. (Individual Impls may have looser constraints internally.)
99 : */
100 : virtual bool IsInitialized() const = 0;
101 :
102 : /**
103 : * @brief
104 : * This method starts a one-shot timer. This method must be called while in the Matter context (from
105 : * the Matter event loop, or while holding the Matter stack lock).
106 : *
107 : * @note
108 : * Only a single timer is allowed to be started with the same @a aComplete and @a aAppState
109 : * arguments. If called with @a aComplete and @a aAppState identical to an existing timer,
110 : * the currently-running timer will first be cancelled.
111 : *
112 : * @param[in] aDelay Time before this timer fires.
113 : * @param[in] aComplete A pointer to the function called when timer expires.
114 : * @param[in] aAppState A pointer to the application state object used when timer expires.
115 : *
116 : * @return CHIP_NO_ERROR On success.
117 : * @return CHIP_ERROR_NO_MEMORY If a timer cannot be allocated.
118 : * @return Other Value indicating timer failed to start.
119 : */
120 : virtual CriticalFailure StartTimer(Clock::Timeout aDelay, TimerCompleteCallback aComplete, void * aAppState) = 0;
121 :
122 : /**
123 : * @brief
124 : * This method extends the timer expiry to the provided aDelay. This method must be called while in the Matter context
125 : * (from the Matter event loop, or while holding the Matter stack lock).
126 : * aDelay is not added to the Remaining time of the timer. The finish line is pushed back to aDelay.
127 : *
128 : * @note The goal of this method is that the timer remaining time cannot be shrunk and only extended to a new time
129 : * If the provided new Delay is smaller than the timer's remaining time, the timer is left untouched.
130 : * In the other case the method acts like StartTimer
131 : *
132 : * @param[in] aDelay Time before this timer fires.
133 : * @param[in] aComplete A pointer to the function called when timer expires.
134 : * @param[in] aAppState A pointer to the application state object used when timer expires.
135 : *
136 : * @return CHIP_NO_ERROR On success.
137 : * @return CHIP_ERROR_INVALID_ARGUMENT If the provided aDelay value is 0
138 : * @return CHIP_ERROR_NO_MEMORY If a timer cannot be allocated.
139 : * @return Other Value indicating timer failed to start.
140 : */
141 : virtual CHIP_ERROR ExtendTimerTo(Clock::Timeout aDelay, TimerCompleteCallback aComplete, void * aAppState) = 0;
142 :
143 : /**
144 : * @brief
145 : * This method searches for the timer matching the provided parameters.
146 : * and returns whether it is still "running" and waiting to trigger or not.
147 : *
148 : * @note This is used to verify by how long the ExtendTimer method extends the timer, as it may ignore an extension request
149 : * if it is shorter than the current timer's remaining time.
150 : *
151 : * @param[in] onComplete A pointer to the function called when timer expires.
152 : * @param[in] appState A pointer to the application state object used when timer expires.
153 : *
154 : * @return True if there is a current timer set to call, at some point in the future, the provided onComplete callback
155 : * with the corresponding appState context. False otherwise.
156 : */
157 : virtual bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) = 0;
158 :
159 : /**
160 : * @brief
161 : * This method searches for the timer matching the provided parameters
162 : * and returns the remaining time left before it expires.
163 : * @param[in] onComplete A pointer to the function called when timer expires.
164 : * @param[in] appState A pointer to the application state object used when timer expires.
165 : *
166 : * @return The remaining time left before the timer expires.
167 : */
168 : virtual Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) = 0;
169 :
170 : /**
171 : * @brief This method cancels a one-shot timer, started earlier through @p StartTimer(). This method must
172 : * be called while in the Matter context (from the Matter event loop, or while holding the Matter
173 : * stack lock).
174 : *
175 : * @note
176 : * The cancellation could fail silently if the timer specified by the combination of the callback
177 : * function and application state object couldn't be found.
178 : *
179 : * @param[in] aOnComplete A pointer to the callback function used in calling @p StartTimer().
180 : * @param[in] aAppState A pointer to the application state object used in calling @p StartTimer().
181 : *
182 : */
183 : virtual void CancelTimer(TimerCompleteCallback aOnComplete, void * aAppState) = 0;
184 :
185 : /**
186 : * @brief
187 : * Schedules a `TimerCompleteCallback` to be run as soon as possible in the Matter context.
188 : *
189 : * WARNING: This must only be called when already in the Matter context (from the Matter event loop, or
190 : * while holding the Matter stack lock). The `PlatformMgr::ScheduleWork()` equivalent method
191 : * is safe to call outside Matter context.
192 : *
193 : * @param[in] aComplete A pointer to a callback function to be called when this timer fires.
194 : * @param[in] aAppState A pointer to an application state object to be passed to the callback function as argument.
195 : *
196 : * @retval CHIP_ERROR_INCORRECT_STATE If the System::Layer has not been initialized.
197 : * @retval CHIP_ERROR_NO_MEMORY If the SystemLayer cannot allocate a new timer.
198 : * @retval CHIP_NO_ERROR On success.
199 : */
200 : virtual CriticalFailure ScheduleWork(TimerCompleteCallback aComplete, void * aAppState) = 0;
201 :
202 : /**
203 : * @brief
204 : * Schedules a lambda object to be run as soon as possible in the Matter context.
205 : *
206 : * This is safe to call from any context and will guarantee execution in Matter context.
207 : * Note that the Lambda's capture have to fit within `CHIP_CONFIG_LAMBDA_EVENT_SIZE` bytes.
208 : *
209 : * @param[in] lambda The Lambda to execute in Matter context.
210 : *
211 : * @retval CHIP_NO_ERROR On success.
212 : * @retval other Platform-specific errors generated indicating the reason for failure.
213 : */
214 : template <typename Lambda>
215 61 : CriticalFailure ScheduleLambda(const Lambda & lambda)
216 : {
217 : static_assert(std::is_invocable_v<Lambda>, "lambda argument must be an invocable with no arguments");
218 : LambdaBridge bridge;
219 61 : bridge.Initialize(lambda);
220 61 : return ScheduleLambdaBridge(std::move(bridge));
221 : }
222 :
223 : private:
224 : CriticalFailure ScheduleLambdaBridge(LambdaBridge && bridge);
225 :
226 : // Not copyable
227 : Layer(const Layer &) = delete;
228 : Layer & operator=(const Layer &) = delete;
229 : };
230 :
231 : #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT
232 :
233 : class LayerFreeRTOS : public Layer
234 : {
235 : };
236 :
237 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
238 :
239 : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
240 : class LayerSockets : public Layer
241 : {
242 : public:
243 : /**
244 : * Initialize watching for events on a file descriptor.
245 : *
246 : * Returns an opaque token through @a tokenOut that must be passed to subsequent operations for this file descriptor.
247 : * Multiple calls to start watching the same file descriptor will return the same token.
248 : * StopWatchingSocket() must be called before closing the file descriptor.
249 : */
250 : virtual CHIP_ERROR StartWatchingSocket(int fd, SocketWatchToken * tokenOut) = 0;
251 :
252 : /**
253 : * Register a callback function.
254 : *
255 : * The callback will be invoked (with the CHIP stack lock held) when requested event(s) are ready.
256 : */
257 : virtual CHIP_ERROR SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data) = 0;
258 :
259 : /**
260 : * Request a callback when the associated file descriptor is readable.
261 : */
262 : virtual CHIP_ERROR RequestCallbackOnPendingRead(SocketWatchToken token) = 0;
263 :
264 : /**
265 : * Request a callback when the associated file descriptor is writable.
266 : */
267 : virtual CHIP_ERROR RequestCallbackOnPendingWrite(SocketWatchToken token) = 0;
268 :
269 : /**
270 : * Cancel a request for a callback when the associated file descriptor is readable.
271 : */
272 : virtual CHIP_ERROR ClearCallbackOnPendingRead(SocketWatchToken token) = 0;
273 :
274 : /**
275 : * Cancel a request for a callback when the associated file descriptor is writable.
276 : */
277 : virtual CHIP_ERROR ClearCallbackOnPendingWrite(SocketWatchToken token) = 0;
278 :
279 : /**
280 : * Stop watching for events on the associated file descriptor.
281 : *
282 : * This MUST be called before the file descriptor is closed.
283 : * It is not necessary to clear callback requests before calling this function.
284 : */
285 : virtual CHIP_ERROR StopWatchingSocket(SocketWatchToken * tokenInOut) = 0;
286 :
287 : /**
288 : * Return a SocketWatchToken that is guaranteed not to be valid. Clients may use this to initialize variables.
289 : */
290 : virtual SocketWatchToken InvalidSocketWatchToken() = 0;
291 : };
292 : #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
293 :
294 : class LayerSelectLoop;
295 :
296 : /**
297 : * EventLoopHandlers can be registered with a LayerSelectLoop instance to enable
298 : * participation of those handlers in the processing cycle of the event loop. This makes
299 : * it possible to implement adapters that allow components utilizing a third-party event
300 : * loop API to participate in the Matter event loop, instead of having to run an entirely
301 : * separate event loop on another thread.
302 : *
303 : * Specifically, the `PrepareEvents` and `HandleEvents` methods of registered event loop
304 : * handlers will be called from the LayerSelectLoop methods of the same names.
305 : *
306 : * @see LayerSelectLoop::PrepareEvents
307 : * @see LayerSelectLoop::HandleEvents
308 : */
309 : class EventLoopHandler : public chip::IntrusiveListNodeBase<>
310 : {
311 : public:
312 2 : virtual ~EventLoopHandler() {}
313 :
314 : /**
315 : * Prepares events and returns the next requested wake time.
316 : */
317 0 : virtual Clock::Timestamp PrepareEvents(Clock::Timestamp now) { return Clock::Timestamp::max(); }
318 :
319 : /**
320 : * Handles / dispatches pending events.
321 : * Every call to this method will have been preceded by a call to `PrepareEvents`.
322 : */
323 : virtual void HandleEvents() = 0;
324 :
325 : private:
326 : // mState is provided exclusively for use by the LayerSelectLoop implementation
327 : // sub-class and can be accessed by it via the LayerSelectLoop::LoopHandlerState() helper.
328 : friend class LayerSelectLoop;
329 : intptr_t mState = 0;
330 : };
331 :
332 : class LayerSelectLoop :
333 : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
334 : public LayerSockets
335 : #else
336 : public Layer
337 : #endif
338 : {
339 : public:
340 : virtual void Signal() = 0;
341 : virtual void EventLoopBegins() = 0;
342 : virtual void PrepareEvents() = 0;
343 : virtual void WaitForEvents() = 0;
344 : virtual void HandleEvents() = 0;
345 : virtual void EventLoopEnds() = 0;
346 :
347 : virtual void AddLoopHandler(EventLoopHandler & handler) = 0;
348 : virtual void RemoveLoopHandler(EventLoopHandler & handler) = 0;
349 :
350 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
351 : virtual void SetLibEvLoop(struct ev_loop * aLibEvLoopP) = 0;
352 : virtual struct ev_loop * GetLibEvLoop() = 0;
353 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
354 :
355 : protected:
356 : // Expose EventLoopHandler.mState as a non-const reference to sub-classes
357 12 : decltype(EventLoopHandler::mState) & LoopHandlerState(EventLoopHandler & handler) { return handler.mState; }
358 : };
359 :
360 : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
361 : class LayerDispatch :
362 : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
363 : public LayerSockets
364 : #else
365 : public Layer
366 : #endif
367 : {
368 : public:
369 : virtual void SetDispatchQueue(dispatch_queue_t dispatchQueue) = 0;
370 : virtual dispatch_queue_t GetDispatchQueue() = 0;
371 : virtual void HandleDispatchQueueEvents(Clock::Timeout timeout) = 0;
372 :
373 : /**
374 : * Schedule a block to run asynchronously.
375 : *
376 : * @param block The block to be executed.
377 : *
378 : * @note This method is thread-safe and can be called from any dispatch queue.
379 : */
380 : virtual CriticalFailure ScheduleWorkWithBlock(dispatch_block_t block) = 0;
381 : virtual CriticalFailure StartTimerWithBlock(dispatch_block_t block, Clock::Timeout delay) = 0;
382 : };
383 : #endif
384 :
385 : } // namespace System
386 : } // namespace chip
|