Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2014-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 implements Layer using select().
22 : */
23 :
24 : #include <lib/support/CodeUtils.h>
25 : #include <lib/support/TimeUtils.h>
26 : #include <platform/LockTracker.h>
27 : #include <system/SystemFaultInjection.h>
28 : #include <system/SystemLayer.h>
29 : #include <system/SystemLayerImplSelect.h>
30 :
31 : #include <algorithm>
32 : #include <errno.h>
33 :
34 : // Choose an approximation of PTHREAD_NULL if pthread.h doesn't define one.
35 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL)
36 : #define PTHREAD_NULL 0
37 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL)
38 :
39 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
40 : // older libev do not yet have ev_io_modify
41 : #ifndef ev_io_modify
42 : #define ev_io_modify(ev, events_) \
43 : do \
44 : { \
45 : (ev)->events = ((ev)->events & EV__IOFDSET) | (events_); \
46 : } while (0)
47 : #endif // ev_io_modify
48 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
49 :
50 : namespace chip {
51 : namespace System {
52 :
53 : constexpr Clock::Seconds64 kDefaultMinSleepPeriod = Clock::Seconds64(60 * 60 * 24 * 30); // Month [sec]
54 :
55 104 : CHIP_ERROR LayerImplSelect::Init()
56 : {
57 104 : VerifyOrReturnError(mLayerState.SetInitializing(), CHIP_ERROR_INCORRECT_STATE);
58 :
59 104 : RegisterPOSIXErrorFormatter();
60 :
61 6760 : for (auto & w : mSocketWatchPool)
62 : {
63 6656 : w.Clear();
64 : }
65 :
66 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
67 104 : mHandleSelectThread = PTHREAD_NULL;
68 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
69 :
70 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
71 : // Create an event to allow an arbitrary thread to wake the thread in the select loop.
72 104 : ReturnErrorOnFailure(mWakeEvent.Open(*this));
73 : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
74 :
75 104 : VerifyOrReturnError(mLayerState.SetInitialized(), CHIP_ERROR_INCORRECT_STATE);
76 104 : return CHIP_NO_ERROR;
77 : }
78 :
79 104 : void LayerImplSelect::Shutdown()
80 : {
81 104 : VerifyOrReturn(mLayerState.SetShuttingDown());
82 :
83 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
84 : TimerList::Node * timer;
85 : while ((timer = mTimerList.PopEarliest()) != nullptr)
86 : {
87 : if (ev_is_active(&timer->mLibEvTimer))
88 : {
89 : ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
90 : }
91 : }
92 : mTimerPool.ReleaseAll();
93 :
94 : for (auto & w : mSocketWatchPool)
95 : {
96 : w.DisableAndClear();
97 : }
98 : #else
99 104 : mTimerList.Clear();
100 104 : mTimerPool.ReleaseAll();
101 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
102 :
103 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
104 104 : mWakeEvent.Close(*this);
105 : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
106 :
107 104 : mLayerState.ResetFromShuttingDown(); // Return to uninitialized state to permit re-initialization.
108 : }
109 :
110 43541017 : void LayerImplSelect::Signal()
111 : {
112 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
113 : ChipLogError(DeviceLayer, "Signal() should not be called in CHIP_SYSTEM_CONFIG_USE_LIBEV builds (might be ok in tests)");
114 : #else
115 : /*
116 : * Wake up the I/O thread by writing a single byte to the wake pipe.
117 : *
118 : * If this is being called from within an I/O event callback, then writing to the wake pipe can be skipped,
119 : * since the I/O thread is already awake.
120 : *
121 : * Furthermore, we don't care if this write fails as the only reasonably likely failure is that the pipe is full, in which
122 : * case the select calling thread is going to wake up anyway.
123 : */
124 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
125 43541017 : if (pthread_equal(mHandleSelectThread, pthread_self()))
126 : {
127 51176 : return;
128 : }
129 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
130 :
131 : // Send notification to wake up the select call.
132 43489841 : CHIP_ERROR status = mWakeEvent.Notify();
133 43489841 : if (status != CHIP_NO_ERROR)
134 : {
135 :
136 11 : ChipLogError(chipSystemLayer, "System wake event notify failed: %" CHIP_ERROR_FORMAT, status.Format());
137 : }
138 : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
139 : }
140 :
141 21889379 : CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
142 : {
143 21889379 : assertChipStackLockedByCurrentThread();
144 :
145 21889379 : VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
146 :
147 21889378 : CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_TimeoutImmediate, delay = System::Clock::kZero);
148 :
149 21889378 : CancelTimer(onComplete, appState);
150 :
151 21889378 : TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp() + delay, onComplete, appState);
152 21889378 : VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
153 :
154 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
155 : VerifyOrDie(mLibEvLoopP != nullptr);
156 : ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
157 : timer->mLibEvTimer.data = timer;
158 : auto t = Clock::Milliseconds64(delay).count();
159 : // Note: libev uses the time when events started processing as the "now" reference for relative timers,
160 : // for efficiency reasons. This point in time is represented by ev_now().
161 : // The real time is represented by ev_time().
162 : // Without correction, this leads to timers firing a bit too early relative to the time StartTimer()
163 : // is called. So the relative value passed to ev_timer_set() is adjusted (increased) here.
164 : // Note: Still, slightly early (and of course, late) firing timers are something the caller MUST be prepared for,
165 : // because edge cases like system clock adjustments may cause them even with the correction applied here.
166 : ev_timer_set(&timer->mLibEvTimer, (static_cast<double>(t) / 1E3) + ev_time() - ev_now(mLibEvLoopP), 0.);
167 : (void) mTimerList.Add(timer);
168 : ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
169 : #else
170 21889378 : if (mTimerList.Add(timer) == timer)
171 : {
172 : // The new timer is the earliest, so the time until the next event has probably changed.
173 21644436 : Signal();
174 : }
175 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
176 :
177 21889378 : return CHIP_NO_ERROR;
178 : }
179 :
180 15 : CHIP_ERROR LayerImplSelect::ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
181 : {
182 15 : VerifyOrReturnError(delay.count() > 0, CHIP_ERROR_INVALID_ARGUMENT);
183 :
184 14 : assertChipStackLockedByCurrentThread();
185 :
186 14 : Clock::Timeout remainingTime = mTimerList.GetRemainingTime(onComplete, appState);
187 14 : if (remainingTime.count() < delay.count())
188 : {
189 11 : if (remainingTime == Clock::kZero)
190 : {
191 : // If remaining time is Clock::kZero, it might possible that our timer is in
192 : // the mExpiredTimers list and about to be fired. Remove it from that list, since we are extending it.
193 1 : mExpiredTimers.Remove(onComplete, appState);
194 : }
195 11 : return StartTimer(delay, onComplete, appState);
196 : }
197 :
198 3 : return CHIP_NO_ERROR;
199 : }
200 :
201 22 : bool LayerImplSelect::IsTimerActive(TimerCompleteCallback onComplete, void * appState)
202 : {
203 22 : bool timerIsActive = (mTimerList.GetRemainingTime(onComplete, appState) > Clock::kZero);
204 :
205 22 : if (!timerIsActive)
206 : {
207 : // check if the timer is in the mExpiredTimers list about to be fired.
208 8 : for (TimerList::Node * timer = mExpiredTimers.Earliest(); timer != nullptr; timer = timer->mNextTimer)
209 : {
210 0 : if (timer->GetCallback().GetOnComplete() == onComplete && timer->GetCallback().GetAppState() == appState)
211 : {
212 0 : return true;
213 : }
214 : }
215 : }
216 :
217 22 : return timerIsActive;
218 : }
219 :
220 4 : Clock::Timeout LayerImplSelect::GetRemainingTime(TimerCompleteCallback onComplete, void * appState)
221 : {
222 4 : return mTimerList.GetRemainingTime(onComplete, appState);
223 : }
224 :
225 21941213 : void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appState)
226 : {
227 21941213 : assertChipStackLockedByCurrentThread();
228 :
229 21941213 : VerifyOrReturn(mLayerState.IsInitialized());
230 :
231 21941213 : TimerList::Node * timer = mTimerList.Remove(onComplete, appState);
232 21941213 : if (timer == nullptr)
233 : {
234 : // The timer was not in our "will fire in the future" list, but it might
235 : // be in the "we're about to fire these" chunk we already grabbed from
236 : // that list. Check for it there too, and if found there we still want
237 : // to cancel it.
238 52126 : timer = mExpiredTimers.Remove(onComplete, appState);
239 : }
240 21941213 : VerifyOrReturn(timer != nullptr);
241 :
242 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
243 : VerifyOrDie(mLibEvLoopP != nullptr);
244 : ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
245 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
246 :
247 21889104 : mTimerPool.Release(timer);
248 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
249 : // LIBEV builds does not include an I/O wakeup thread, so must not call Signal().
250 21889104 : Signal();
251 : #endif
252 : }
253 :
254 16667 : CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void * appState)
255 : {
256 16667 : assertChipStackLockedByCurrentThread();
257 :
258 16667 : VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
259 :
260 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
261 : // schedule as timer with no delay, but do NOT cancel previous timers with same onComplete/appState!
262 : TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
263 : VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
264 : VerifyOrDie(mLibEvLoopP != nullptr);
265 : ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
266 : timer->mLibEvTimer.data = timer;
267 : auto t = Clock::Milliseconds64(0).count();
268 : ev_timer_set(&timer->mLibEvTimer, static_cast<double>(t) / 1E3, 0.);
269 : (void) mTimerList.Add(timer);
270 : ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
271 : #else
272 : // Ideally we would not use a timer here at all, but if we try to just
273 : // ScheduleLambda the lambda needs to capture the following:
274 : // 1) onComplete
275 : // 2) appState
276 : // 3) The `this` pointer, because onComplete needs to be passed a pointer to
277 : // the System::Layer.
278 : //
279 : // On a 64-bit system that's 24 bytes, but lambdas passed to ScheduleLambda
280 : // are capped at CHIP_CONFIG_LAMBDA_EVENT_SIZE which is 16 bytes.
281 : //
282 : // So for now use a timer as a poor-man's closure that captures `this` and
283 : // onComplete and appState in a single pointer, so we fit inside the size
284 : // limit.
285 : //
286 : // TODO: We could do something here where we compile-time condition on the
287 : // sizes of things and use a direct ScheduleLambda if it would fit and this
288 : // setup otherwise.
289 : //
290 : // TODO: But also, unit tests seem to do SystemLayer::ScheduleWork without
291 : // actually running a useful event loop (in the PlatformManager sense),
292 : // which breaks if we use ScheduleLambda here, since that does rely on the
293 : // PlatformManager event loop. So for now, keep scheduling an expires-ASAP
294 : // timer, but just make sure we don't cancel existing timers with the same
295 : // callback and appState, so ScheduleWork invocations don't stomp on each
296 : // other.
297 16667 : TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
298 16667 : VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
299 :
300 16667 : if (mTimerList.Add(timer) == timer)
301 : {
302 : // The new timer is the earliest, so the time until the next event has probably changed.
303 7093 : Signal();
304 : }
305 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
306 :
307 16667 : return CHIP_NO_ERROR;
308 : }
309 :
310 213 : CHIP_ERROR LayerImplSelect::StartWatchingSocket(int fd, SocketWatchToken * tokenOut)
311 : {
312 : // Find a free slot.
313 213 : SocketWatch * watch = nullptr;
314 13845 : for (auto & w : mSocketWatchPool)
315 : {
316 13632 : if (w.mFD == fd)
317 : {
318 : // Already registered, return the existing token
319 0 : *tokenOut = reinterpret_cast<SocketWatchToken>(&w);
320 0 : return CHIP_NO_ERROR;
321 : }
322 13632 : if ((w.mFD == kInvalidFd) && (watch == nullptr))
323 : {
324 213 : watch = &w;
325 : }
326 : }
327 213 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_ENDPOINT_POOL_FULL);
328 :
329 213 : watch->mFD = fd;
330 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
331 : ev_io_init(&watch->mIoWatcher, &LayerImplSelect::HandleLibEvIoWatcher, 0, 0);
332 : watch->mIoWatcher.data = watch;
333 : watch->mLayerImplSelectP = this;
334 : #endif
335 :
336 213 : *tokenOut = reinterpret_cast<SocketWatchToken>(watch);
337 213 : return CHIP_NO_ERROR;
338 : }
339 :
340 212 : CHIP_ERROR LayerImplSelect::SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data)
341 : {
342 212 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
343 212 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
344 :
345 212 : watch->mCallback = callback;
346 212 : watch->mCallbackData = data;
347 212 : return CHIP_NO_ERROR;
348 : }
349 :
350 212 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingRead(SocketWatchToken token)
351 : {
352 212 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
353 212 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
354 :
355 212 : watch->mPendingIO.Set(SocketEventFlags::kRead);
356 :
357 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
358 : VerifyOrDie(mLibEvLoopP != nullptr);
359 : int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
360 : (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
361 : if (!ev_is_active(&watch->mIoWatcher))
362 : {
363 : // First time actually using that watch
364 : ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
365 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
366 : }
367 : else
368 : {
369 : // already active, just change flags
370 : // Note: changing flags only reliably works when the watcher is stopped
371 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
372 : ev_io_modify(&watch->mIoWatcher, evs);
373 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
374 : }
375 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
376 :
377 212 : return CHIP_NO_ERROR;
378 : }
379 :
380 27 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingWrite(SocketWatchToken token)
381 : {
382 27 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
383 27 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
384 :
385 27 : watch->mPendingIO.Set(SocketEventFlags::kWrite);
386 :
387 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
388 : VerifyOrDie(mLibEvLoopP != nullptr);
389 : int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
390 : (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
391 : if (!ev_is_active(&watch->mIoWatcher))
392 : {
393 : // First time actually using that watch
394 : ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
395 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
396 : }
397 : else
398 : {
399 : // already active, just change flags
400 : // Note: changing flags only reliably works when the watcher is stopped
401 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
402 : ev_io_modify(&watch->mIoWatcher, evs);
403 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
404 : }
405 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
406 :
407 27 : return CHIP_NO_ERROR;
408 : }
409 :
410 9 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingRead(SocketWatchToken token)
411 : {
412 9 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
413 9 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
414 :
415 9 : watch->mPendingIO.Clear(SocketEventFlags::kRead);
416 :
417 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
418 : if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
419 : {
420 : // all flags cleared now, stop watching
421 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
422 : }
423 : #endif
424 :
425 9 : return CHIP_NO_ERROR;
426 : }
427 :
428 5 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingWrite(SocketWatchToken token)
429 : {
430 5 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
431 5 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
432 :
433 5 : watch->mPendingIO.Clear(SocketEventFlags::kWrite);
434 :
435 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
436 : if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
437 : {
438 : // all flags cleared now, stop watching
439 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
440 : }
441 : #endif
442 :
443 5 : return CHIP_NO_ERROR;
444 : }
445 :
446 213 : CHIP_ERROR LayerImplSelect::StopWatchingSocket(SocketWatchToken * tokenInOut)
447 : {
448 213 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(*tokenInOut);
449 213 : *tokenInOut = InvalidSocketWatchToken();
450 :
451 213 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
452 213 : VerifyOrReturnError(watch->mFD >= 0, CHIP_ERROR_INCORRECT_STATE);
453 :
454 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
455 : watch->DisableAndClear();
456 : #else
457 213 : watch->Clear();
458 :
459 : // Wake the thread calling select so that it stops selecting on the socket.
460 213 : Signal();
461 : #endif
462 :
463 213 : return CHIP_NO_ERROR;
464 : }
465 :
466 : /**
467 : * Set the read, write or exception bit flags for the specified socket based on its status in
468 : * the corresponding file descriptor sets.
469 : *
470 : * @param[in] socket The file descriptor for which the bit flags are being set.
471 : *
472 : * @param[in] readfds A pointer to the set of readable file descriptors.
473 : *
474 : * @param[in] writefds A pointer to the set of writable file descriptors.
475 : *
476 : * @param[in] exceptfds A pointer to the set of file descriptors with errors.
477 : */
478 21842204 : SocketEvents LayerImplSelect::SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds,
479 : const fd_set & exceptfds)
480 : {
481 21842204 : SocketEvents res;
482 :
483 21842204 : if (socket >= 0)
484 : {
485 : // POSIX does not define the fd_set parameter of FD_ISSET() as const, even though it isn't modified.
486 21842204 : if (FD_ISSET(socket, const_cast<fd_set *>(&readfds)))
487 21842132 : res.Set(SocketEventFlags::kRead);
488 21842204 : if (FD_ISSET(socket, const_cast<fd_set *>(&writefds)))
489 11 : res.Set(SocketEventFlags::kWrite);
490 21842204 : if (FD_ISSET(socket, const_cast<fd_set *>(&exceptfds)))
491 0 : res.Set(SocketEventFlags::kExcept);
492 : }
493 :
494 21842204 : return res;
495 : }
496 :
497 : enum : intptr_t
498 : {
499 : kLoopHandlerInactive = 0, // default value for EventLoopHandler::mState
500 : kLoopHandlerPending,
501 : kLoopHandlerActive,
502 : };
503 :
504 2 : void LayerImplSelect::AddLoopHandler(EventLoopHandler & handler)
505 : {
506 : // Add the handler as pending because this method can be called at any point
507 : // in a PrepareEvents() / WaitForEvents() / HandleEvents() sequence.
508 : // It will be marked active when we call PrepareEvents() on it for the first time.
509 2 : auto & state = LoopHandlerState(handler);
510 2 : VerifyOrDie(state == kLoopHandlerInactive);
511 2 : state = kLoopHandlerPending;
512 2 : mLoopHandlers.PushBack(&handler);
513 2 : }
514 :
515 2 : void LayerImplSelect::RemoveLoopHandler(EventLoopHandler & handler)
516 : {
517 2 : mLoopHandlers.Remove(&handler);
518 2 : LoopHandlerState(handler) = kLoopHandlerInactive;
519 2 : }
520 :
521 21842105 : void LayerImplSelect::PrepareEvents()
522 : {
523 21842105 : assertChipStackLockedByCurrentThread();
524 :
525 21842105 : const Clock::Timestamp currentTime = SystemClock().GetMonotonicTimestamp();
526 21842105 : Clock::Timestamp awakenTime = currentTime + kDefaultMinSleepPeriod;
527 :
528 21842105 : TimerList::Node * timer = mTimerList.Earliest();
529 21842105 : if (timer)
530 : {
531 21842088 : awakenTime = std::min(awakenTime, timer->AwakenTime());
532 : }
533 :
534 : // Activate added EventLoopHandlers and call PrepareEvents on active handlers.
535 21842105 : auto loopIter = mLoopHandlers.begin();
536 21842109 : while (loopIter != mLoopHandlers.end())
537 : {
538 4 : auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
539 4 : switch (auto & state = LoopHandlerState(loop))
540 : {
541 2 : case kLoopHandlerPending:
542 2 : state = kLoopHandlerActive;
543 : [[fallthrough]];
544 4 : case kLoopHandlerActive:
545 4 : awakenTime = std::min(awakenTime, loop.PrepareEvents(currentTime));
546 4 : break;
547 : }
548 : }
549 :
550 21842105 : const Clock::Timestamp sleepTime = (awakenTime > currentTime) ? (awakenTime - currentTime) : Clock::kZero;
551 21842105 : Clock::ToTimeval(sleepTime, mNextTimeout);
552 :
553 21842105 : mMaxFd = -1;
554 :
555 : // NOLINTBEGIN(clang-analyzer-security.insecureAPI.bzero)
556 : //
557 : // NOTE: darwin uses bzero to clear out FD sets. This is not a security concern.
558 371315785 : FD_ZERO(&mSelected.mReadSet);
559 371315785 : FD_ZERO(&mSelected.mWriteSet);
560 371315785 : FD_ZERO(&mSelected.mErrorSet);
561 : // NOLINTEND(clang-analyzer-security.insecureAPI.bzero)
562 :
563 1419736825 : for (auto & w : mSocketWatchPool)
564 : {
565 1397894720 : if (w.mFD != kInvalidFd)
566 : {
567 21842205 : if (mMaxFd < w.mFD)
568 : {
569 21842205 : mMaxFd = w.mFD;
570 : }
571 21842205 : if (w.mPendingIO.Has(SocketEventFlags::kRead))
572 : {
573 21842194 : FD_SET(w.mFD, &mSelected.mReadSet);
574 : }
575 21842205 : if (w.mPendingIO.Has(SocketEventFlags::kWrite))
576 : {
577 11 : FD_SET(w.mFD, &mSelected.mWriteSet);
578 : }
579 : }
580 : }
581 21842105 : }
582 :
583 21842105 : void LayerImplSelect::WaitForEvents()
584 : {
585 21842105 : mSelectResult = select(mMaxFd + 1, &mSelected.mReadSet, &mSelected.mWriteSet, &mSelected.mErrorSet, &mNextTimeout);
586 21842105 : }
587 :
588 21842105 : void LayerImplSelect::HandleEvents()
589 : {
590 21842105 : assertChipStackLockedByCurrentThread();
591 :
592 21842105 : if (!IsSelectResultValid())
593 : {
594 0 : ChipLogError(DeviceLayer, "Select failed: %" CHIP_ERROR_FORMAT, CHIP_ERROR_POSIX(errno).Format());
595 0 : return;
596 : }
597 :
598 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
599 21842105 : mHandleSelectThread = pthread_self();
600 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
601 :
602 : // Obtain the list of currently expired timers. Any new timers added by timer callback are NOT handled on this pass,
603 : // since that could result in infinite handling of new timers blocking any other progress.
604 21842105 : VerifyOrDieWithMsg(mExpiredTimers.Empty(), DeviceLayer, "Re-entry into HandleEvents from a timer callback?");
605 21842105 : mExpiredTimers = mTimerList.ExtractEarlier(Clock::Timeout(1) + SystemClock().GetMonotonicTimestamp());
606 21842105 : TimerList::Node * timer = nullptr;
607 21859001 : while ((timer = mExpiredTimers.PopEarliest()) != nullptr)
608 : {
609 16896 : mTimerPool.Invoke(timer);
610 : }
611 :
612 : // Process socket events, if any
613 21842105 : if (mSelectResult > 0)
614 : {
615 1419736045 : for (auto & w : mSocketWatchPool)
616 : {
617 1397893952 : if (w.mFD != kInvalidFd && w.mCallback != nullptr)
618 : {
619 21842204 : SocketEvents events = SocketEventsFromFDs(w.mFD, mSelected.mReadSet, mSelected.mWriteSet, mSelected.mErrorSet);
620 21842204 : if (events.HasAny())
621 : {
622 21842143 : w.mCallback(events, w.mCallbackData);
623 : }
624 : }
625 : }
626 : }
627 :
628 : // Call HandleEvents for active loop handlers
629 21842105 : auto loopIter = mLoopHandlers.begin();
630 21842109 : while (loopIter != mLoopHandlers.end())
631 : {
632 4 : auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
633 4 : if (LoopHandlerState(loop) == kLoopHandlerActive)
634 : {
635 3 : loop.HandleEvents();
636 : }
637 : }
638 :
639 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
640 21842105 : mHandleSelectThread = PTHREAD_NULL;
641 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
642 : }
643 :
644 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
645 :
646 : void LayerImplSelect::HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents)
647 : {
648 : TimerList::Node * timer = static_cast<TimerList::Node *>(t->data);
649 : VerifyOrDie(timer != nullptr);
650 : LayerImplSelect * layerP = dynamic_cast<LayerImplSelect *>(timer->mCallback.mSystemLayer);
651 : VerifyOrDie(layerP != nullptr);
652 : layerP->mTimerList.Remove(timer);
653 : layerP->mTimerPool.Invoke(timer);
654 : }
655 :
656 : void LayerImplSelect::HandleLibEvIoWatcher(EV_P_ struct ev_io * i, int revents)
657 : {
658 : SocketWatch * watch = static_cast<SocketWatch *>(i->data);
659 : if (watch != nullptr && watch->mCallback != nullptr && watch->mLayerImplSelectP != nullptr)
660 : {
661 : SocketEvents events;
662 : if (revents & EV_READ)
663 : {
664 : events.Set(SocketEventFlags::kRead);
665 : }
666 : if (revents & EV_WRITE)
667 : {
668 : events.Set(SocketEventFlags::kWrite);
669 : }
670 : if (events.HasAny())
671 : {
672 : watch->mCallback(events, watch->mCallbackData);
673 : }
674 : }
675 : }
676 :
677 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
678 :
679 6869 : void LayerImplSelect::SocketWatch::Clear()
680 : {
681 6869 : mFD = kInvalidFd;
682 6869 : mPendingIO.ClearAll();
683 6869 : mCallback = nullptr;
684 6869 : mCallbackData = 0;
685 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
686 : mLayerImplSelectP = nullptr;
687 : #endif
688 6869 : }
689 :
690 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
691 : void LayerImplSelect::SocketWatch::DisableAndClear()
692 : {
693 : if (mLayerImplSelectP != nullptr && mLayerImplSelectP->mLibEvLoopP != nullptr)
694 : {
695 : ev_io_stop(mLayerImplSelectP->mLibEvLoopP, &mIoWatcher);
696 : }
697 : Clear();
698 : }
699 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
700 :
701 : } // namespace System
702 : } // namespace chip
|