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 106 : CHIP_ERROR LayerImplSelect::Init()
56 : {
57 106 : VerifyOrReturnError(mLayerState.SetInitializing(), CHIP_ERROR_INCORRECT_STATE);
58 :
59 106 : RegisterPOSIXErrorFormatter();
60 :
61 6890 : for (auto & w : mSocketWatchPool)
62 : {
63 6784 : w.Clear();
64 : }
65 :
66 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
67 106 : 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 106 : ReturnErrorOnFailure(mWakeEvent.Open(*this));
73 : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
74 :
75 106 : VerifyOrReturnError(mLayerState.SetInitialized(), CHIP_ERROR_INCORRECT_STATE);
76 106 : return CHIP_NO_ERROR;
77 : }
78 :
79 106 : void LayerImplSelect::Shutdown()
80 : {
81 106 : 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 106 : mTimerList.Clear();
100 106 : mTimerPool.ReleaseAll();
101 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
102 :
103 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
104 106 : mWakeEvent.Close(*this);
105 : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
106 :
107 106 : mLayerState.ResetFromShuttingDown(); // Return to uninitialized state to permit re-initialization.
108 : }
109 :
110 49533811 : 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 49533811 : if (pthread_equal(mHandleSelectThread, pthread_self()))
126 : {
127 51252 : return;
128 : }
129 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
130 :
131 : // Send notification to wake up the select call.
132 49482559 : CHIP_ERROR status = mWakeEvent.Notify();
133 49482559 : 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 24900560 : CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
142 : {
143 24900560 : assertChipStackLockedByCurrentThread();
144 :
145 24900560 : VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
146 :
147 24900559 : CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_TimeoutImmediate, delay = System::Clock::kZero);
148 :
149 24900559 : CancelTimer(onComplete, appState);
150 :
151 24900559 : TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp() + delay, onComplete, appState);
152 24900559 : 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 24900559 : if (mTimerList.Add(timer) == timer)
171 : {
172 : // The new timer is the earliest, so the time until the next event has probably changed.
173 24626025 : Signal();
174 : }
175 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
176 :
177 24900559 : 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 : // Just call StartTimer; it will invoke CancelTimer(), then start a new timer. That handles
190 : // all the various "timer was about to fire" edge cases correctly too.
191 11 : return StartTimer(delay, onComplete, appState);
192 : }
193 :
194 3 : return CHIP_NO_ERROR;
195 : }
196 :
197 22 : bool LayerImplSelect::IsTimerActive(TimerCompleteCallback onComplete, void * appState)
198 : {
199 22 : bool timerIsActive = (mTimerList.GetRemainingTime(onComplete, appState) > Clock::kZero);
200 :
201 22 : if (!timerIsActive)
202 : {
203 : // check if the timer is in the mExpiredTimers list about to be fired.
204 8 : for (TimerList::Node * timer = mExpiredTimers.Earliest(); timer != nullptr; timer = timer->mNextTimer)
205 : {
206 0 : if (timer->GetCallback().GetOnComplete() == onComplete && timer->GetCallback().GetAppState() == appState)
207 : {
208 0 : return true;
209 : }
210 : }
211 : }
212 :
213 22 : return timerIsActive;
214 : }
215 :
216 4 : Clock::Timeout LayerImplSelect::GetRemainingTime(TimerCompleteCallback onComplete, void * appState)
217 : {
218 4 : return mTimerList.GetRemainingTime(onComplete, appState);
219 : }
220 :
221 24952490 : void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appState)
222 : {
223 24952490 : assertChipStackLockedByCurrentThread();
224 :
225 24952490 : VerifyOrReturn(mLayerState.IsInitialized());
226 :
227 24952490 : TimerList::Node * timer = mTimerList.Remove(onComplete, appState);
228 24952490 : if (timer == nullptr)
229 : {
230 : // The timer was not in our "will fire in the future" list, but it might
231 : // be in the "we're about to fire these" chunk we already grabbed from
232 : // that list. Check for it there too, and if found there we still want
233 : // to cancel it.
234 52230 : timer = mExpiredTimers.Remove(onComplete, appState);
235 : }
236 24952490 : VerifyOrReturn(timer != nullptr);
237 :
238 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
239 : VerifyOrDie(mLibEvLoopP != nullptr);
240 : ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
241 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
242 :
243 24900277 : mTimerPool.Release(timer);
244 : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
245 : // LIBEV builds does not include an I/O wakeup thread, so must not call Signal().
246 24900277 : Signal();
247 : #endif
248 : }
249 :
250 16696 : CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void * appState)
251 : {
252 16696 : assertChipStackLockedByCurrentThread();
253 :
254 16696 : VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
255 :
256 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
257 : // schedule as timer with no delay, but do NOT cancel previous timers with same onComplete/appState!
258 : TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
259 : VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
260 : VerifyOrDie(mLibEvLoopP != nullptr);
261 : ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
262 : timer->mLibEvTimer.data = timer;
263 : auto t = Clock::Milliseconds64(0).count();
264 : ev_timer_set(&timer->mLibEvTimer, static_cast<double>(t) / 1E3, 0.);
265 : (void) mTimerList.Add(timer);
266 : ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
267 : #else
268 : // Ideally we would not use a timer here at all, but if we try to just
269 : // ScheduleLambda the lambda needs to capture the following:
270 : // 1) onComplete
271 : // 2) appState
272 : // 3) The `this` pointer, because onComplete needs to be passed a pointer to
273 : // the System::Layer.
274 : //
275 : // On a 64-bit system that's 24 bytes, but lambdas passed to ScheduleLambda
276 : // are capped at CHIP_CONFIG_LAMBDA_EVENT_SIZE which is 16 bytes.
277 : //
278 : // So for now use a timer as a poor-man's closure that captures `this` and
279 : // onComplete and appState in a single pointer, so we fit inside the size
280 : // limit.
281 : //
282 : // TODO: We could do something here where we compile-time condition on the
283 : // sizes of things and use a direct ScheduleLambda if it would fit and this
284 : // setup otherwise.
285 : //
286 : // TODO: But also, unit tests seem to do SystemLayer::ScheduleWork without
287 : // actually running a useful event loop (in the PlatformManager sense),
288 : // which breaks if we use ScheduleLambda here, since that does rely on the
289 : // PlatformManager event loop. So for now, keep scheduling an expires-ASAP
290 : // timer, but just make sure we don't cancel existing timers with the same
291 : // callback and appState, so ScheduleWork invocations don't stomp on each
292 : // other.
293 16696 : TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
294 16696 : VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
295 :
296 16696 : if (mTimerList.Add(timer) == timer)
297 : {
298 : // The new timer is the earliest, so the time until the next event has probably changed.
299 7114 : Signal();
300 : }
301 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
302 :
303 16696 : return CHIP_NO_ERROR;
304 : }
305 :
306 215 : CHIP_ERROR LayerImplSelect::StartWatchingSocket(int fd, SocketWatchToken * tokenOut)
307 : {
308 : // Find a free slot.
309 215 : SocketWatch * watch = nullptr;
310 13975 : for (auto & w : mSocketWatchPool)
311 : {
312 13760 : if (w.mFD == fd)
313 : {
314 : // Already registered, return the existing token
315 0 : *tokenOut = reinterpret_cast<SocketWatchToken>(&w);
316 0 : return CHIP_NO_ERROR;
317 : }
318 13760 : if ((w.mFD == kInvalidFd) && (watch == nullptr))
319 : {
320 215 : watch = &w;
321 : }
322 : }
323 215 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_ENDPOINT_POOL_FULL);
324 :
325 215 : watch->mFD = fd;
326 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
327 : ev_io_init(&watch->mIoWatcher, &LayerImplSelect::HandleLibEvIoWatcher, 0, 0);
328 : watch->mIoWatcher.data = watch;
329 : watch->mLayerImplSelectP = this;
330 : #endif
331 :
332 215 : *tokenOut = reinterpret_cast<SocketWatchToken>(watch);
333 215 : return CHIP_NO_ERROR;
334 : }
335 :
336 214 : CHIP_ERROR LayerImplSelect::SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data)
337 : {
338 214 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
339 214 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
340 :
341 214 : watch->mCallback = callback;
342 214 : watch->mCallbackData = data;
343 214 : return CHIP_NO_ERROR;
344 : }
345 :
346 214 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingRead(SocketWatchToken token)
347 : {
348 214 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
349 214 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
350 :
351 214 : watch->mPendingIO.Set(SocketEventFlags::kRead);
352 :
353 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
354 : VerifyOrDie(mLibEvLoopP != nullptr);
355 : int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
356 : (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
357 : if (!ev_is_active(&watch->mIoWatcher))
358 : {
359 : // First time actually using that watch
360 : ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
361 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
362 : }
363 : else
364 : {
365 : // already active, just change flags
366 : // Note: changing flags only reliably works when the watcher is stopped
367 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
368 : ev_io_modify(&watch->mIoWatcher, evs);
369 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
370 : }
371 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
372 :
373 214 : return CHIP_NO_ERROR;
374 : }
375 :
376 27 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingWrite(SocketWatchToken token)
377 : {
378 27 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
379 27 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
380 :
381 27 : watch->mPendingIO.Set(SocketEventFlags::kWrite);
382 :
383 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
384 : VerifyOrDie(mLibEvLoopP != nullptr);
385 : int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
386 : (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
387 : if (!ev_is_active(&watch->mIoWatcher))
388 : {
389 : // First time actually using that watch
390 : ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
391 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
392 : }
393 : else
394 : {
395 : // already active, just change flags
396 : // Note: changing flags only reliably works when the watcher is stopped
397 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
398 : ev_io_modify(&watch->mIoWatcher, evs);
399 : ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
400 : }
401 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
402 :
403 27 : return CHIP_NO_ERROR;
404 : }
405 :
406 9 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingRead(SocketWatchToken token)
407 : {
408 9 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
409 9 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
410 :
411 9 : watch->mPendingIO.Clear(SocketEventFlags::kRead);
412 :
413 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
414 : if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
415 : {
416 : // all flags cleared now, stop watching
417 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
418 : }
419 : #endif
420 :
421 9 : return CHIP_NO_ERROR;
422 : }
423 :
424 5 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingWrite(SocketWatchToken token)
425 : {
426 5 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
427 5 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
428 :
429 5 : watch->mPendingIO.Clear(SocketEventFlags::kWrite);
430 :
431 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
432 : if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
433 : {
434 : // all flags cleared now, stop watching
435 : ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
436 : }
437 : #endif
438 :
439 5 : return CHIP_NO_ERROR;
440 : }
441 :
442 215 : CHIP_ERROR LayerImplSelect::StopWatchingSocket(SocketWatchToken * tokenInOut)
443 : {
444 215 : SocketWatch * watch = reinterpret_cast<SocketWatch *>(*tokenInOut);
445 215 : *tokenInOut = InvalidSocketWatchToken();
446 :
447 215 : VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
448 215 : VerifyOrReturnError(watch->mFD >= 0, CHIP_ERROR_INCORRECT_STATE);
449 :
450 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
451 : watch->DisableAndClear();
452 : #else
453 215 : watch->Clear();
454 :
455 : // Wake the thread calling select so that it stops selecting on the socket.
456 215 : Signal();
457 : #endif
458 :
459 215 : return CHIP_NO_ERROR;
460 : }
461 :
462 : /**
463 : * Set the read, write or exception bit flags for the specified socket based on its status in
464 : * the corresponding file descriptor sets.
465 : *
466 : * @param[in] socket The file descriptor for which the bit flags are being set.
467 : *
468 : * @param[in] readfds A pointer to the set of readable file descriptors.
469 : *
470 : * @param[in] writefds A pointer to the set of writable file descriptors.
471 : *
472 : * @param[in] exceptfds A pointer to the set of file descriptors with errors.
473 : */
474 24853317 : SocketEvents LayerImplSelect::SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds,
475 : const fd_set & exceptfds)
476 : {
477 24853317 : SocketEvents res;
478 :
479 24853317 : if (socket >= 0)
480 : {
481 : // POSIX does not define the fd_set parameter of FD_ISSET() as const, even though it isn't modified.
482 24853317 : if (FD_ISSET(socket, const_cast<fd_set *>(&readfds)))
483 24853245 : res.Set(SocketEventFlags::kRead);
484 24853317 : if (FD_ISSET(socket, const_cast<fd_set *>(&writefds)))
485 11 : res.Set(SocketEventFlags::kWrite);
486 24853317 : if (FD_ISSET(socket, const_cast<fd_set *>(&exceptfds)))
487 0 : res.Set(SocketEventFlags::kExcept);
488 : }
489 :
490 24853317 : return res;
491 : }
492 :
493 : enum : intptr_t
494 : {
495 : kLoopHandlerInactive = 0, // default value for EventLoopHandler::mState
496 : kLoopHandlerPending,
497 : kLoopHandlerActive,
498 : };
499 :
500 2 : void LayerImplSelect::AddLoopHandler(EventLoopHandler & handler)
501 : {
502 : // Add the handler as pending because this method can be called at any point
503 : // in a PrepareEvents() / WaitForEvents() / HandleEvents() sequence.
504 : // It will be marked active when we call PrepareEvents() on it for the first time.
505 2 : auto & state = LoopHandlerState(handler);
506 2 : VerifyOrDie(state == kLoopHandlerInactive);
507 2 : state = kLoopHandlerPending;
508 2 : mLoopHandlers.PushBack(&handler);
509 2 : }
510 :
511 2 : void LayerImplSelect::RemoveLoopHandler(EventLoopHandler & handler)
512 : {
513 2 : mLoopHandlers.Remove(&handler);
514 2 : LoopHandlerState(handler) = kLoopHandlerInactive;
515 2 : }
516 :
517 24853218 : void LayerImplSelect::PrepareEvents()
518 : {
519 24853218 : assertChipStackLockedByCurrentThread();
520 :
521 24853218 : const Clock::Timestamp currentTime = SystemClock().GetMonotonicTimestamp();
522 24853218 : Clock::Timestamp awakenTime = currentTime + kDefaultMinSleepPeriod;
523 :
524 24853218 : TimerList::Node * timer = mTimerList.Earliest();
525 24853218 : if (timer)
526 : {
527 24853201 : awakenTime = std::min(awakenTime, timer->AwakenTime());
528 : }
529 :
530 : // Activate added EventLoopHandlers and call PrepareEvents on active handlers.
531 24853218 : auto loopIter = mLoopHandlers.begin();
532 24853222 : while (loopIter != mLoopHandlers.end())
533 : {
534 4 : auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
535 4 : switch (auto & state = LoopHandlerState(loop))
536 : {
537 2 : case kLoopHandlerPending:
538 2 : state = kLoopHandlerActive;
539 : [[fallthrough]];
540 4 : case kLoopHandlerActive:
541 4 : awakenTime = std::min(awakenTime, loop.PrepareEvents(currentTime));
542 4 : break;
543 : }
544 : }
545 :
546 24853218 : const Clock::Timestamp sleepTime = (awakenTime > currentTime) ? (awakenTime - currentTime) : Clock::kZero;
547 24853218 : Clock::ToTimeval(sleepTime, mNextTimeout);
548 :
549 24853218 : mMaxFd = -1;
550 :
551 : // NOLINTBEGIN(clang-analyzer-security.insecureAPI.bzero)
552 : //
553 : // NOTE: darwin uses bzero to clear out FD sets. This is not a security concern.
554 422504706 : FD_ZERO(&mSelected.mReadSet);
555 422504706 : FD_ZERO(&mSelected.mWriteSet);
556 422504706 : FD_ZERO(&mSelected.mErrorSet);
557 : // NOLINTEND(clang-analyzer-security.insecureAPI.bzero)
558 :
559 1615459170 : for (auto & w : mSocketWatchPool)
560 : {
561 1590605952 : if (w.mFD != kInvalidFd)
562 : {
563 24853318 : if (mMaxFd < w.mFD)
564 : {
565 24853318 : mMaxFd = w.mFD;
566 : }
567 24853318 : if (w.mPendingIO.Has(SocketEventFlags::kRead))
568 : {
569 24853307 : FD_SET(w.mFD, &mSelected.mReadSet);
570 : }
571 24853318 : if (w.mPendingIO.Has(SocketEventFlags::kWrite))
572 : {
573 11 : FD_SET(w.mFD, &mSelected.mWriteSet);
574 : }
575 : }
576 : }
577 24853218 : }
578 :
579 24853218 : void LayerImplSelect::WaitForEvents()
580 : {
581 24853218 : mSelectResult = select(mMaxFd + 1, &mSelected.mReadSet, &mSelected.mWriteSet, &mSelected.mErrorSet, &mNextTimeout);
582 24853218 : }
583 :
584 24853218 : void LayerImplSelect::HandleEvents()
585 : {
586 24853218 : assertChipStackLockedByCurrentThread();
587 :
588 24853218 : if (!IsSelectResultValid())
589 : {
590 0 : ChipLogError(DeviceLayer, "Select failed: %" CHIP_ERROR_FORMAT, CHIP_ERROR_POSIX(errno).Format());
591 0 : return;
592 : }
593 :
594 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
595 24853218 : mHandleSelectThread = pthread_self();
596 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
597 :
598 : // Obtain the list of currently expired timers. Any new timers added by timer callback are NOT handled on this pass,
599 : // since that could result in infinite handling of new timers blocking any other progress.
600 24853218 : VerifyOrDieWithMsg(mExpiredTimers.Empty(), DeviceLayer, "Re-entry into HandleEvents from a timer callback?");
601 24853218 : mExpiredTimers = mTimerList.ExtractEarlier(Clock::Timeout(1) + SystemClock().GetMonotonicTimestamp());
602 24853218 : TimerList::Node * timer = nullptr;
603 24870151 : while ((timer = mExpiredTimers.PopEarliest()) != nullptr)
604 : {
605 16933 : mTimerPool.Invoke(timer);
606 : }
607 :
608 : // Process socket events, if any
609 24853218 : if (mSelectResult > 0)
610 : {
611 1615458390 : for (auto & w : mSocketWatchPool)
612 : {
613 1590605184 : if (w.mFD != kInvalidFd && w.mCallback != nullptr)
614 : {
615 24853317 : SocketEvents events = SocketEventsFromFDs(w.mFD, mSelected.mReadSet, mSelected.mWriteSet, mSelected.mErrorSet);
616 24853317 : if (events.HasAny())
617 : {
618 24853256 : w.mCallback(events, w.mCallbackData);
619 : }
620 : }
621 : }
622 : }
623 :
624 : // Call HandleEvents for active loop handlers
625 24853218 : auto loopIter = mLoopHandlers.begin();
626 24853222 : while (loopIter != mLoopHandlers.end())
627 : {
628 4 : auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
629 4 : if (LoopHandlerState(loop) == kLoopHandlerActive)
630 : {
631 3 : loop.HandleEvents();
632 : }
633 : }
634 :
635 : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
636 24853218 : mHandleSelectThread = PTHREAD_NULL;
637 : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
638 : }
639 :
640 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
641 :
642 : void LayerImplSelect::HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents)
643 : {
644 : TimerList::Node * timer = static_cast<TimerList::Node *>(t->data);
645 : VerifyOrDie(timer != nullptr);
646 : LayerImplSelect * layerP = dynamic_cast<LayerImplSelect *>(timer->mCallback.mSystemLayer);
647 : VerifyOrDie(layerP != nullptr);
648 : layerP->mTimerList.Remove(timer);
649 : layerP->mTimerPool.Invoke(timer);
650 : }
651 :
652 : void LayerImplSelect::HandleLibEvIoWatcher(EV_P_ struct ev_io * i, int revents)
653 : {
654 : SocketWatch * watch = static_cast<SocketWatch *>(i->data);
655 : if (watch != nullptr && watch->mCallback != nullptr && watch->mLayerImplSelectP != nullptr)
656 : {
657 : SocketEvents events;
658 : if (revents & EV_READ)
659 : {
660 : events.Set(SocketEventFlags::kRead);
661 : }
662 : if (revents & EV_WRITE)
663 : {
664 : events.Set(SocketEventFlags::kWrite);
665 : }
666 : if (events.HasAny())
667 : {
668 : watch->mCallback(events, watch->mCallbackData);
669 : }
670 : }
671 : }
672 :
673 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
674 :
675 6999 : void LayerImplSelect::SocketWatch::Clear()
676 : {
677 6999 : mFD = kInvalidFd;
678 6999 : mPendingIO.ClearAll();
679 6999 : mCallback = nullptr;
680 6999 : mCallbackData = 0;
681 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
682 : mLayerImplSelectP = nullptr;
683 : #endif
684 6999 : }
685 :
686 : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
687 : void LayerImplSelect::SocketWatch::DisableAndClear()
688 : {
689 : if (mLayerImplSelectP != nullptr && mLayerImplSelectP->mLibEvLoopP != nullptr)
690 : {
691 : ev_io_stop(mLayerImplSelectP->mLibEvLoopP, &mIoWatcher);
692 : }
693 : Clear();
694 : }
695 : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
696 :
697 : } // namespace System
698 : } // namespace chip
|