Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * This file declares an implementation of System::Layer using select().
21 : */
22 :
23 : #pragma once
24 :
25 : #include "system/SystemConfig.h"
26 :
27 : #if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
28 : #include <sys/select.h>
29 : #endif
30 :
31 : #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKETS
32 : #include <inet/ZephyrSocket.h> // nogncheck
33 : #endif
34 :
35 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
36 : #include <atomic>
37 : #include <pthread.h>
38 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
39 :
40 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
41 : #include <ev.h>
42 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
43 :
44 : #include <lib/support/IntrusiveList.h>
45 : #include <lib/support/ObjectLifeCycle.h>
46 : #include <system/SystemLayer.h>
47 : #include <system/SystemTimer.h>
48 : #include <system/WakeEvent.h>
49 :
50 : namespace chip {
51 : namespace System {
52 :
53 : class LayerImplSelect : public LayerSelectLoop
54 : {
55 : public:
56 7280 : LayerImplSelect() = default;
57 112 : ~LayerImplSelect() override { VerifyOrDie(mLayerState.Destroy()); }
58 :
59 : // Layer overrides.
60 : CriticalFailure Init() override;
61 : void Shutdown() override;
62 233 : bool IsInitialized() const override { return mLayerState.IsInitialized(); }
63 : CriticalFailure StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
64 : CHIP_ERROR ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
65 : bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override;
66 : Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override;
67 : void CancelTimer(TimerCompleteCallback onComplete, void * appState) override;
68 : CriticalFailure ScheduleWork(TimerCompleteCallback onComplete, void * appState) override;
69 :
70 : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
71 : // LayerSocket overrides.
72 : CHIP_ERROR StartWatchingSocket(int fd, SocketWatchToken * tokenOut) override;
73 : CHIP_ERROR SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data) override;
74 : CHIP_ERROR RequestCallbackOnPendingRead(SocketWatchToken token) override;
75 : CHIP_ERROR RequestCallbackOnPendingWrite(SocketWatchToken token) override;
76 : CHIP_ERROR ClearCallbackOnPendingRead(SocketWatchToken token) override;
77 : CHIP_ERROR ClearCallbackOnPendingWrite(SocketWatchToken token) override;
78 : CHIP_ERROR StopWatchingSocket(SocketWatchToken * tokenInOut) override;
79 156 : SocketWatchToken InvalidSocketWatchToken() override { return reinterpret_cast<SocketWatchToken>(nullptr); }
80 : #endif
81 :
82 : // LayerSelectLoop overrides.
83 : void Signal() override;
84 78 : void EventLoopBegins() override {}
85 : void PrepareEvents() override;
86 : void WaitForEvents() override;
87 : void HandleEvents() override;
88 78 : void EventLoopEnds() override {}
89 :
90 : void AddLoopHandler(EventLoopHandler & handler) override;
91 : void RemoveLoopHandler(EventLoopHandler & handler) override;
92 :
93 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
94 : virtual void SetLibEvLoop(struct ev_loop * aLibEvLoopP) override { mLibEvLoopP = aLibEvLoopP; };
95 : virtual struct ev_loop * GetLibEvLoop() override { return mLibEvLoopP; };
96 : static void HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents);
97 : static void HandleLibEvIoWatcher(EV_P_ struct ev_io * i, int revents);
98 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
99 :
100 : // Expose the result of WaitForEvents() for non-blocking socket implementations.
101 23475032 : bool IsSelectResultValid() const { return mSelectResult >= 0; }
102 :
103 : /**
104 : * @brief Abstract interface for an event source compatible with a select()-based event loop.
105 : *
106 : * This interface defines the contract for objects that wish to register file descriptors
107 : * and timeouts for monitoring. It is designed to be managed by a selection layer (e.g., LayerImplSelect).
108 : */
109 : struct EventSource : public IntrusiveListNodeBase<IntrusiveMode::Strict>
110 : {
111 : /**
112 : * @brief Virtual destructor to ensure proper cleanup of derived classes.
113 : */
114 7 : virtual ~EventSource() = default;
115 :
116 : /**
117 : * @brief Prepares the file descriptor sets and timeout before the select() call.
118 : *
119 : * This method is called by the event loop to gather all file descriptors and the
120 : * minimum required timeout from all registered sources.
121 : *
122 : * @param[in,out] maxfd The highest-numbered file descriptor. Must be updated if
123 : * this source adds a descriptor larger than the current value.
124 : * @param[in,out] readfds Set of file descriptors to be watched for read readiness.
125 : * @param[in,out] writefds Set of file descriptors to be watched for write readiness.
126 : * @param[in,out] exceptfds Set of file descriptors to be watched for error conditions.
127 : * @param[in,out] timeout The maximum time to wait for an event.
128 : *
129 : * @warning **Timeout Modification Logic:**
130 : * To ensure all sources are handled correctly, you must follow these rules:
131 : * - **DO NOT** modify @p timeout if this source's desired timeout is **larger** than the current value.
132 : * - **ONLY** modify @p timeout if this source's desired timeout is **smaller** than the current value.
133 : *
134 : * This ensures the event loop wakes up in time for the earliest pending event among all sources.
135 : */
136 : virtual void PrepareEvents(int & maxfd, fd_set & readfds, fd_set & writefds, fd_set & exceptfds,
137 : struct timeval & timeout) = 0;
138 :
139 : /**
140 : * @brief Processes the results after the select() call returns.
141 : *
142 : * The event loop calls this method to allow the source to check if its descriptors
143 : * are set in the resulting masks and perform the associated I/O or logic.
144 : *
145 : * @param[in] readfds The set of descriptors ready for reading.
146 : * @param[in] writefds The set of descriptors ready for writing.
147 : * @param[in] exceptfds The set of descriptors with pending error conditions.
148 : */
149 : virtual void ProcessEvents(const fd_set & readfds, const fd_set & writefds, const fd_set & exceptfds) = 0;
150 : };
151 :
152 : /**
153 : * @brief Register an EventSource with this LayerImplSelect instance.
154 : *
155 : * Adds the given EventSource to the internal list of sources that will be
156 : * consulted when preparing and handling events in the select()-based loop.
157 : *
158 : * Thread-safety: This method is not thread-safe and MUST be called with
159 : * the ChipStack lock held.
160 : *
161 : * Ownership: LayerImplSelect does not take ownership of @p source.
162 : * The caller is responsible for ensuring that the EventSource object
163 : * remains valid for as long as it is registered.
164 : *
165 : * Lifecycle: The EventSource MUST either outlive its registration (i.e.,
166 : * remain alive until after it is removed) or be explicitly removed using
167 : * EventSourceRemove() before it is destroyed.
168 : */
169 : void EventSourceAdd(EventSource * source);
170 :
171 : /**
172 : * @brief Unregister a previously added EventSource.
173 : *
174 : * Removes the given EventSource from the internal list of sources that are
175 : * monitored by the select()-based loop.
176 : *
177 : * Thread-safety: This method is not thread-safe and MUST be called with
178 : * the ChipStack lock held.
179 : *
180 : * Ownership: This method does not delete or otherwise destroy @p source;
181 : * ownership remains with the caller.
182 : *
183 : * Lifecycle: EventSourceRemove() MUST be called before destroying an
184 : * EventSource that has been registered with EventSourceAdd(). It is safe
185 : * to call EventSourceRemove() multiple times with the same pointer; calls
186 : * after the source has been removed have no effect.
187 : */
188 : void EventSourceRemove(EventSource * source);
189 :
190 : /**
191 : * @brief Clear all registered EventSource instances.
192 : *
193 : * Removes all EventSource objects from the internal list maintained by
194 : * LayerImplSelect.
195 : *
196 : * Thread-safety: This method is not thread-safe and MUST be called with
197 : * the ChipStack lock held.
198 : *
199 : * Ownership: This method does not delete or destroy any EventSource
200 : * instances; it only clears their registration with the loop.
201 : *
202 : * Lifecycle: After this call returns, all previously registered
203 : * EventSource instances are no longer tracked by the event loop. The
204 : * objects themselves remain the responsibility of the caller.
205 : */
206 : void EventSourceClear();
207 :
208 : protected:
209 : IntrusiveList<EventSource> mSources;
210 : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
211 : static SocketEvents SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds, const fd_set & exceptfds);
212 :
213 : static constexpr int kSocketWatchMax = (INET_CONFIG_ENABLE_TCP_ENDPOINT ? INET_CONFIG_NUM_TCP_ENDPOINTS : 0) +
214 : (INET_CONFIG_ENABLE_UDP_ENDPOINT ? INET_CONFIG_NUM_UDP_ENDPOINTS : 0);
215 :
216 : struct SocketWatch
217 : {
218 : void Clear();
219 : int mFD;
220 : SocketEvents mPendingIO;
221 : SocketWatchCallback mCallback;
222 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
223 : struct ev_io mIoWatcher;
224 : LayerImplSelect * mLayerImplSelectP;
225 : void DisableAndClear();
226 : #endif
227 :
228 : intptr_t mCallbackData;
229 : };
230 : SocketWatch mSocketWatchPool[kSocketWatchMax];
231 : #endif
232 :
233 : TimerPool<TimerList::Node> mTimerPool;
234 : TimerList mTimerList;
235 : // List of expired timers being processed right now. Stored in a member so
236 : // we can cancel them.
237 : TimerList mExpiredTimers;
238 : timeval mNextTimeout;
239 :
240 : IntrusiveList<EventLoopHandler> mLoopHandlers;
241 :
242 : // Members for select loop
243 : struct SelectSets
244 : {
245 : fd_set mReadSet;
246 : fd_set mWriteSet;
247 : fd_set mErrorSet;
248 : };
249 : SelectSets mSelected;
250 : int mMaxFd;
251 :
252 : // Return value from select(), carried between WaitForEvents() and HandleEvents().
253 : int mSelectResult;
254 :
255 : ObjectLifeCycle mLayerState;
256 :
257 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
258 : std::atomic<pthread_t> mHandleSelectThread;
259 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
260 :
261 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
262 : struct ev_loop * mLibEvLoopP;
263 : #else
264 : WakeEvent mWakeEvent;
265 : #endif
266 : };
267 :
268 : using LayerImpl = LayerImplSelect;
269 :
270 : } // namespace System
271 : } // namespace chip
|