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