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