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