From 0e3594b9d0413f02ad8f7094b43dea50b7279273 Mon Sep 17 00:00:00 2001 From: Kevin Schoedel <67607049+kpschoedel@users.noreply.github.com> Date: Mon, 19 Jul 2021 15:44:08 -0400 Subject: [PATCH] Move WakeIOThread() functionality to WatchableEventManager (#8456) #### Problem System::Layer contains `WakeIOThread()` and `mWakeEvent` which are really implementation details of `WatchableEventManager`. #### Change overview - Replace `System::Layer::WakeIOThread()` with `WatchableEventManager::Signal()`, because not every implementation will necessarily implement the nudge by waking a thread. - Split `SystemSockets.h` into `WatchableEventManager.h`, `WatchableSocket.h`, and `WakeEvent.h`; likewise split the various implementation files. - Make the `System::WakeEvent` public API independent of the file-descriptor implementation. For the present, `mHandleSelectThread` remains in `System::Layer` until timers are integrated and the transitional `HandleTimeout()` is removed. #### Testing Sanity check with chip-tool. CI should verify that functionality does not regress. --- src/controller/CHIPDeviceController.cpp | 6 +- .../java/CHIPDeviceController-JNI.cpp | 2 +- .../GenericPlatformManagerImpl_POSIX.cpp | 6 +- .../GenericPlatformManagerImpl_Zephyr.cpp | 2 +- src/inet/EndPointBasis.h | 2 +- src/inet/RawEndPoint.cpp | 2 +- src/inet/TCPEndPoint.cpp | 6 +- src/platform/Linux/MdnsImpl.h | 2 +- src/platform/mbed/PlatformManagerImpl.cpp | 7 +- src/system/BUILD.gn | 9 +- src/system/SystemConfig.h | 8 - src/system/SystemLayer.cpp | 45 ---- src/system/SystemLayer.h | 12 +- src/system/SystemTimer.cpp | 8 +- .../{SystemSockets.cpp => WakeEvent.cpp} | 5 +- src/system/WakeEvent.h | 69 ++++++ src/system/WatchableEventManager.h | 72 ++++++ src/system/WatchableEventManagerLibevent.cpp | 196 +++++++++++++++ src/system/WatchableEventManagerLibevent.h | 73 ++++++ src/system/WatchableEventManagerSelect.cpp | 233 ++++++++++++++++++ src/system/WatchableEventManagerSelect.h | 92 +++++++ .../{SystemSockets.h => WatchableSocket.h} | 63 +---- src/system/WatchableSocketLibevent.cpp | 148 +---------- src/system/WatchableSocketLibevent.h | 42 +--- src/system/WatchableSocketSelect.cpp | 205 ++------------- src/system/WatchableSocketSelect.h | 69 +----- src/system/tests/TestSystemWakeEvent.cpp | 27 +- 27 files changed, 845 insertions(+), 566 deletions(-) rename src/system/{SystemSockets.cpp => WakeEvent.cpp} (97%) create mode 100644 src/system/WakeEvent.h create mode 100644 src/system/WatchableEventManager.h create mode 100644 src/system/WatchableEventManagerLibevent.cpp create mode 100644 src/system/WatchableEventManagerLibevent.h create mode 100644 src/system/WatchableEventManagerSelect.cpp create mode 100644 src/system/WatchableEventManagerSelect.h rename src/system/{SystemSockets.h => WatchableSocket.h} (77%) diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 282c8e1887276e..a41dec0c091a9e 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -549,11 +549,11 @@ CHIP_ERROR DeviceController::ServiceEventSignal() { VerifyOrReturnError(mState == State::Initialized, CHIP_ERROR_INCORRECT_STATE); -#if CONFIG_DEVICE_LAYER && CHIP_SYSTEM_CONFIG_USE_IO_THREAD - DeviceLayer::SystemLayer.WakeIOThread(); +#if CONFIG_DEVICE_LAYER && (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) + DeviceLayer::SystemLayer.WatchableEvents().Signal(); #else ReturnErrorOnFailure(CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); -#endif // CONFIG_DEVICE_LAYER && CHIP_SYSTEM_CONFIG_USE_IO_THREAD +#endif // CONFIG_DEVICE_LAYER && (CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK) return CHIP_NO_ERROR; } diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index 262d7402705886..c1baa070b74639 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -206,7 +206,7 @@ void JNI_OnUnload(JavaVM * jvm, void * reserved) if (sIOThread != PTHREAD_NULL) { sShutdown = true; - sSystemLayer.WakeIOThread(); + sSystemLayer.WatchableEvents().Signal(); StackUnlockGuard unlockGuard(JniReferences::GetInstance().GetStackLock()); pthread_join(sIOThread, NULL); diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp index c48eb5e3e39eca..44200995b8a569 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp @@ -127,9 +127,7 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::_PostEvent(const ChipDeviceEve { mChipEventQueue.Push(*event); -#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD - SystemLayer.WakeIOThread(); // Trigger wake select on CHIP thread -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD + SystemLayer.WatchableEvents().Signal(); // Trigger wake select on CHIP thread } template <class ImplClass> @@ -259,7 +257,7 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StopEventLoopTask() // SystemLayer. // Impl()->LockChipStack(); - SystemLayer.WakeIOThread(); + SystemLayer.WatchableEvents().Signal(); Impl()->UnlockChipStack(); pthread_mutex_lock(&mStateLock); diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp index fb67c1a44fdb24..749ece712f3e0c 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl_Zephyr.cpp @@ -109,7 +109,7 @@ void GenericPlatformManagerImpl_Zephyr<ImplClass>::_PostEvent(const ChipDeviceEv // k_msgq_put takes `void*` instead of `const void*`. Nonetheless, it should be safe to // const_cast here and there are components in Zephyr itself which do the same. if (k_msgq_put(&mChipEventQueue, const_cast<ChipDeviceEvent *>(event), K_NO_WAIT) == 0) - SystemLayer.WakeIOThread(); // Trigger wake on CHIP thread + SystemLayer.WatchableEvents().Signal(); // Trigger wake on CHIP thread else ChipLogError(DeviceLayer, "Failed to post event to CHIP Platform event queue"); } diff --git a/src/inet/EndPointBasis.h b/src/inet/EndPointBasis.h index 0baa1a8be6260c..2d7411351e7c42 100644 --- a/src/inet/EndPointBasis.h +++ b/src/inet/EndPointBasis.h @@ -35,7 +35,7 @@ #include <support/DLLUtil.h> #if CHIP_SYSTEM_CONFIG_USE_SOCKETS -#include <system/SystemSockets.h> +#include <system/WatchableSocket.h> #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK diff --git a/src/inet/RawEndPoint.cpp b/src/inet/RawEndPoint.cpp index 16d461d7675d6f..c1df86b95721ed 100644 --- a/src/inet/RawEndPoint.cpp +++ b/src/inet/RawEndPoint.cpp @@ -48,7 +48,7 @@ #endif // CHIP_SYSTEM_CONFIG_USE_LWIP #if CHIP_SYSTEM_CONFIG_USE_SOCKETS -#include <system/SystemSockets.h> +#include <system/WatchableSocket.h> #if HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif // HAVE_SYS_SOCKET_H diff --git a/src/inet/TCPEndPoint.cpp b/src/inet/TCPEndPoint.cpp index 5d488352b4063c..1a24f17e39937c 100644 --- a/src/inet/TCPEndPoint.cpp +++ b/src/inet/TCPEndPoint.cpp @@ -833,10 +833,10 @@ void TCPEndPoint::EnableReceive() DriveReceiving(); -#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK // Wake the thread waiting for I/O so that it can include the socket. - SystemLayer().WakeIOThread(); -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD + SystemLayer().WatchableEvents().Signal(); +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK } /** diff --git a/src/platform/Linux/MdnsImpl.h b/src/platform/Linux/MdnsImpl.h index 042aa214626877..7360c148b6ed4b 100644 --- a/src/platform/Linux/MdnsImpl.h +++ b/src/platform/Linux/MdnsImpl.h @@ -34,7 +34,7 @@ #include <avahi-common/watch.h> #include "lib/mdns/platform/Mdns.h" -#include "system/SystemSockets.h" +#include "system/WatchableSocket.h" struct AvahiWatch { diff --git a/src/platform/mbed/PlatformManagerImpl.cpp b/src/platform/mbed/PlatformManagerImpl.cpp index 2b0384772d1134..cfe4b7c8d55351 100644 --- a/src/platform/mbed/PlatformManagerImpl.cpp +++ b/src/platform/mbed/PlatformManagerImpl.cpp @@ -46,8 +46,9 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) mQueue.~EventQueue(); new (&mQueue) events::EventQueue(event_size * CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE); - mQueue.background( - [&](int t) { MbedEventTimeout::AttachTimeout([&] { SystemLayer.WakeIOThread(); }, std::chrono::milliseconds{ t }); }); + mQueue.background([&](int t) { + MbedEventTimeout::AttachTimeout([&] { SystemLayer.WatchableEvents().Signal(); }, std::chrono::milliseconds{ t }); + }); // Reinitialize the Mutexes mThisStateMutex.~Mutex(); @@ -211,7 +212,7 @@ CHIP_ERROR PlatformManagerImpl::_StopEventLoopTask() // Wake from select so it unblocks processing LockChipStack(); - SystemLayer.WakeIOThread(); + SystemLayer.WatchableEvents().Signal(); UnlockChipStack(); osStatus err = osOK; diff --git a/src/system/BUILD.gn b/src/system/BUILD.gn index 3695867d85c400..387ea3c89465aa 100644 --- a/src/system/BUILD.gn +++ b/src/system/BUILD.gn @@ -96,6 +96,7 @@ buildconfig_header("system_buildconfig") { } if (chip_system_config_use_sockets) { + defines += [ "CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE=<system/WatchableEventManager${chip_system_config_sockets_event_loop}.h>" ] defines += [ "CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE=<system/WatchableSocket${chip_system_config_sockets_event_loop}.h>" ] } } @@ -142,8 +143,6 @@ static_library("system") { "SystemObject.h", "SystemPacketBuffer.cpp", "SystemPacketBuffer.h", - "SystemSockets.cpp", - "SystemSockets.h", "SystemStats.cpp", "SystemStats.h", "SystemTimer.cpp", @@ -151,6 +150,10 @@ static_library("system") { "TLVPacketBufferBackingStore.cpp", "TLVPacketBufferBackingStore.h", "TimeSource.h", + "WakeEvent.cpp", + "WakeEvent.h", + "WatchableEventManager.h", + "WatchableSocket.h", ] cflags = [ "-Wconversion" ] @@ -165,6 +168,8 @@ static_library("system") { if (chip_system_config_use_sockets) { sources += [ + "WatchableEventManager${chip_system_config_sockets_event_loop}.cpp", + "WatchableEventManager${chip_system_config_sockets_event_loop}.h", "WatchableSocket${chip_system_config_sockets_event_loop}.cpp", "WatchableSocket${chip_system_config_sockets_event_loop}.h", ] diff --git a/src/system/SystemConfig.h b/src/system/SystemConfig.h index 2ad29e073af22c..35573ec09ba594 100644 --- a/src/system/SystemConfig.h +++ b/src/system/SystemConfig.h @@ -111,14 +111,6 @@ // clang-format off -#ifndef CHIP_SYSTEM_CONFIG_USE_IO_THREAD -#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK -#define CHIP_SYSTEM_CONFIG_USE_IO_THREAD 1 -#else -#define CHIP_SYSTEM_CONFIG_USE_IO_THREAD 0 -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD - /** * @def CHIP_SYSTEM_CONFIG_TRANSFER_INETLAYER_PROJECT_CONFIGURATION * diff --git a/src/system/SystemLayer.cpp b/src/system/SystemLayer.cpp index 681e8288db1d19..a527234dd23918 100644 --- a/src/system/SystemLayer.cpp +++ b/src/system/SystemLayer.cpp @@ -133,11 +133,6 @@ CHIP_ERROR Layer::Init() this->AddEventHandlerDelegate(sSystemEventHandlerDelegate); #endif // CHIP_SYSTEM_CONFIG_USE_LWIP -#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK - // Create an event to allow an arbitrary thread to wake the thread in the select loop. - ReturnErrorOnFailure(this->mWakeEvent.Open(mWatchableEvents)); -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK - this->mLayerState = kLayerState_Initialized; return CHIP_NO_ERROR; @@ -148,10 +143,6 @@ CHIP_ERROR Layer::Shutdown() if (this->mLayerState == kLayerState_NotInitialized) return CHIP_ERROR_INCORRECT_STATE; -#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK - ReturnErrorOnFailure(mWakeEvent.Close()); -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK - for (size_t i = 0; i < Timer::sPool.Size(); ++i) { Timer * lTimer = Timer::sPool.Get(*this, i); @@ -455,42 +446,6 @@ void Layer::HandleTimeout() #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK -#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD - -/** - * Wake up the I/O thread by writing a single byte to the wake pipe. - * - * @note - * If @p WakeIOThread() is being called from within an I/O event callback, then writing to the wake pipe can be skipped, - * since the I/O thread is already awake. - * - * Furthermore, we don't care if this write fails as the only reasonably likely failure is that the pipe is full, in which - * case the select calling thread is going to wake up anyway. - */ -void Layer::WakeIOThread() -{ - CHIP_ERROR lReturn; - - if (this->State() != kLayerState_Initialized) - return; - -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING - if (pthread_equal(this->mHandleSelectThread, pthread_self())) - { - return; - } -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING - - // Send notification to wake up the select call. - lReturn = this->mWakeEvent.Notify(); - if (lReturn != CHIP_NO_ERROR) - { - ChipLogError(chipSystemLayer, "System wake event notify failed: %s", ErrorStr(lReturn)); - } -} - -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD - #if CHIP_SYSTEM_CONFIG_USE_LWIP LwIPEventHandlerDelegate Layer::sSystemEventHandlerDelegate; diff --git a/src/system/SystemLayer.h b/src/system/SystemLayer.h index e2eba02ed60e94..7ab9ae174d5fd7 100644 --- a/src/system/SystemLayer.h +++ b/src/system/SystemLayer.h @@ -39,7 +39,8 @@ // Include dependent headers #if CHIP_SYSTEM_CONFIG_USE_SOCKETS -#include <system/SystemSockets.h> +#include <system/WakeEvent.h> +#include <system/WatchableEventManager.h> #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING @@ -136,14 +137,11 @@ class DLL_EXPORT Layer Clock & GetClock() { return mClock; } -#if CHIP_SYSTEM_CONFIG_USE_SOCKETS +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK WatchableEventManager & WatchableEvents() { return mWatchableEvents; } bool GetTimeout(struct timeval & aSleepTime); // TODO(#5556): Integrate timer platform details with WatchableEventManager. void HandleTimeout(); // TODO(#5556): Integrate timer platform details with WatchableEventManager. -#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS -#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD - void WakeIOThread(); -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK #if CHIP_SYSTEM_CONFIG_USE_LWIP typedef CHIP_ERROR (*EventHandler)(Object & aTarget, EventType aEventType, uintptr_t aArgument); @@ -172,8 +170,8 @@ class DLL_EXPORT Layer #if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK WatchableEventManager mWatchableEvents; - WakeEvent mWakeEvent; #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING + friend class WatchableEventManager; std::atomic<pthread_t> mHandleSelectThread; #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK diff --git a/src/system/SystemTimer.cpp b/src/system/SystemTimer.cpp index e55c659f70f333..1191f6135626b7 100644 --- a/src/system/SystemTimer.cpp +++ b/src/system/SystemTimer.cpp @@ -184,9 +184,9 @@ CHIP_ERROR Timer::Start(uint32_t aDelayMilliseconds, OnCompleteFunct aOnComplete } #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH -#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD - lLayer.WakeIOThread(); -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK + lLayer.WatchableEvents().Signal(); +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK return CHIP_NO_ERROR; @@ -220,7 +220,7 @@ CHIP_ERROR Timer::ScheduleWork(OnCompleteFunct aOnComplete, void * aAppState) else { #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH - lLayer.WakeIOThread(); + lLayer.WatchableEvents().Signal(); #if CHIP_SYSTEM_CONFIG_USE_DISPATCH } #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH diff --git a/src/system/SystemSockets.cpp b/src/system/WakeEvent.cpp similarity index 97% rename from src/system/SystemSockets.cpp rename to src/system/WakeEvent.cpp index bea24b6536aca2..e0e387a7c273ca 100644 --- a/src/system/SystemSockets.cpp +++ b/src/system/WakeEvent.cpp @@ -21,12 +21,15 @@ * data stream built on top of two file descriptors. */ -#include <system/SystemSockets.h> +#include <system/SystemConfig.h> #if CHIP_SYSTEM_CONFIG_USE_SOCKETS +#include <system/WakeEvent.h> + // Include additional CHIP headers #include <support/CodeUtils.h> +#include <system/SystemError.h> // Include system and language headers #include <errno.h> diff --git a/src/system/WakeEvent.h b/src/system/WakeEvent.h new file mode 100644 index 00000000000000..54465ede3bf3ce --- /dev/null +++ b/src/system/WakeEvent.h @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file declares the abstraction of socket (file descriptor) events. + */ + +#pragma once + +// Include configuration headers +#include <system/SystemConfig.h> + +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + +#include <core/CHIPError.h> +#include <system/WatchableSocket.h> + +namespace chip { +namespace System { + +class WakeEventTest; +class WatchableEventManager; + +/** + * @class WakeEvent + * + * An instance of this type can be used by a WatchableEventManager to allow other threads + * to wake its event loop thread via WatchableEventManager::Signal(). + */ +class WakeEvent +{ +public: + CHIP_ERROR Open(WatchableEventManager & watchState); /**< Initialize the pipeline */ + CHIP_ERROR Close(); /**< Close both ends of the pipeline. */ + + CHIP_ERROR Notify(); /**< Set the event. */ + void Confirm(); /**< Clear the event. */ + +private: + friend class WakeEventTest; + + int GetReadFD() const { return mFD.GetFD(); } + static void Confirm(WatchableSocket & socket) { reinterpret_cast<WakeEvent *>(socket.GetCallbackData())->Confirm(); } + +#if CHIP_SYSTEM_CONFIG_USE_POSIX_PIPE + int mWriteFD; +#endif + WatchableSocket mFD; +}; + +} // namespace System +} // namespace chip + +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS diff --git a/src/system/WatchableEventManager.h b/src/system/WatchableEventManager.h new file mode 100644 index 00000000000000..bf226453974cd2 --- /dev/null +++ b/src/system/WatchableEventManager.h @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file declares the abstraction for managing a collection of socket (file descriptor) events. + */ + +#pragma once + +// Include configuration headers +#include <system/SystemConfig.h> + +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + +namespace chip { + +namespace System { + +class Layer; + +/** + * @class WatchableEventManager + * + * An instance of this type is contained in System::Layer. Its purpose is to hold socket-event system state + * or methods available to every associated instance of WatchableSocket. + * + * It MUST provide at least three methods: + * + * - void Init(System::Layer & systemLayer) -- called from System::Layer::Init() + * - void Shutdown() -- called from System::Layer::Shutdown() + * - void Signal() -- called to indicate that event monitoring may need to be refreshed or resumed. + * + * Other contents depend on the contract between socket-event implementation and platform layer implementation. + * For POSIX-like platforms, WatchableEventManager provides a set of functions called from the event loop: + * + * - void EventLoopBegins() -- Called before the first iterations of the event loop. + * - void PrepareEvents() -- Called at the start of each iteration of the event loop. + * - void WaitForEvents() -- Called on each iteration of the event loop, between PrepareEvents() and HandleEvents(). + * Uniquely, this method gets called with the CHIP stack NOT locked, so it can block. + * For example, the select()-based implementation calls select() here. + * - void HandleEvents() -- Called at the end of each iteration of the event loop. + * - void EventLoopEnds() -- Called after the last iteration of the event loop. + */ +class WatchableEventManager; + +} // namespace System +} // namespace chip + +#define INCLUDING_CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE 1 +#ifdef CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE +#include CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE +#else // CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE +#include <system/WatchableEventManagerSelect.h> +#endif // CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE +#undef INCLUDING_CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE + +#endif // CHIP_SYSTEM_CONFIG_USE_EVENT_MANAGERS diff --git a/src/system/WatchableEventManagerLibevent.cpp b/src/system/WatchableEventManagerLibevent.cpp new file mode 100644 index 00000000000000..8517b290a54c27 --- /dev/null +++ b/src/system/WatchableEventManagerLibevent.cpp @@ -0,0 +1,196 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file implements WatchableEventManager using libevent. + */ + +#include <platform/CHIPDeviceBuildConfig.h> +#include <support/CodeUtils.h> +#include <system/SystemLayer.h> +#include <system/WatchableEventManager.h> +#include <system/WatchableSocket.h> + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ + +namespace chip { +namespace Mdns { +void GetMdnsTimeout(timeval & timeout); +void HandleMdnsTimeout(); +} // namespace Mdns +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ + +#ifndef CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS +#define CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS 1 // TODO(#5556): default to off +#endif + +namespace chip { +namespace System { + +namespace { + +System::SocketEvents SocketEventsFromLibeventFlags(short eventFlags) +{ + return System::SocketEvents() + .Set(SocketEventFlags::kRead, eventFlags & EV_READ) + .Set(SocketEventFlags::kWrite, eventFlags & EV_WRITE); +} + +void TimeoutCallbackHandler(evutil_socket_t fd, short eventFlags, void * data) +{ + event * const ev = reinterpret_cast<event *>(data); + evtimer_del(ev); +} + +} // anonymous namespace + +void WatchableEventManager::Init(System::Layer & systemLayer) +{ +#if CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS + static bool enabled_event_debug_mode = false; + if (!enabled_event_debug_mode) + { + enabled_event_debug_mode = true; + event_enable_debug_mode(); + } +#endif // CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS + + mEventBase = event_base_new(); + mTimeoutEvent = evtimer_new(mEventBase, TimeoutCallbackHandler, event_self_cbarg()); + mActiveSockets = nullptr; + mSystemLayer = &systemLayer; +} + +void WatchableEventManager::PrepareEvents() +{ + // TODO(#5556): Integrate timer platform details with WatchableEventManager. + timeval nextTimeout = { 0, 0 }; + PrepareEventsWithTimeout(nextTimeout); +} + +void WatchableEventManager::PrepareEventsWithTimeout(struct timeval & nextTimeout) +{ + // TODO(#5556): Integrate timer platform details with WatchableEventManager. + mSystemLayer->GetTimeout(nextTimeout); + if (nextTimeout.tv_sec || nextTimeout.tv_usec) + { + evtimer_add(mTimeoutEvent, &nextTimeout); + } +} + +void WatchableEventManager::WaitForEvents() +{ + VerifyOrDie(mEventBase != nullptr); + event_base_loop(mEventBase, EVLOOP_ONCE); +} + +void WatchableEventManager::HandleEvents() +{ + mSystemLayer->HandleTimeout(); + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ + chip::Mdns::HandleMdnsTimeout(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ + + while (mActiveSockets != nullptr) + { + WatchableSocket * const watcher = mActiveSockets; + mActiveSockets = watcher->mActiveNext; + watcher->InvokeCallback(); + } +} + +void WatchableEventManager::Shutdown() +{ + event_base_loopbreak(mEventBase); + event_free(mTimeoutEvent); + mTimeoutEvent = nullptr; + event_base_free(mEventBase); + mEventBase = nullptr; +} + +void WatchableEventManager::Signal() +{ + /* + * Wake up the I/O thread by writing a single byte to the wake pipe. + * + * If p WakeIOThread() is being called from within an I/O event callback, then writing to the wake pipe can be skipped, + * since the I/O thread is already awake. + * + * Furthermore, we don't care if this write fails as the only reasonably likely failure is that the pipe is full, in which + * case the select calling thread is going to wake up anyway. + */ +#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING + if (pthread_equal(mSystemLayer->mHandleSelectThread, pthread_self())) + { + return; + } +#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING + + // Send notification to wake up the select call. + CHIP_ERROR status = mWakeEvent.Notify(); + if (status != CHIP_NO_ERROR) + { + ChipLogError(chipSystemLayer, "System wake event notify failed: %" CHIP_ERROR_FORMAT, ChipError::FormatError(status)); + } +} + +// static +void WatchableEventManager::LibeventCallbackHandler(evutil_socket_t fd, short eventFlags, void * data) +{ + WatchableSocket * const watcher = reinterpret_cast<WatchableSocket *>(data); + VerifyOrDie(watcher != nullptr); + VerifyOrDie(watcher->mFD == fd); + + watcher->mPendingIO = SocketEventsFromLibeventFlags(eventFlags); + + // Add to active list. + WatchableSocket ** pp = &watcher->mSharedState->mActiveSockets; + while (*pp != nullptr) + { + if (*pp == watcher) + { + return; + } + pp = &(*pp)->mActiveNext; + } + *pp = watcher; + watcher->mActiveNext = nullptr; +} + +void WatchableEventManager::RemoveFromQueueIfPresent(WatchableSocket * watcher) +{ + VerifyOrDie(watcher != nullptr); + VerifyOrDie(watcher->mSharedState == this); + + WatchableSocket ** pp = &mActiveSockets; + while (*pp != nullptr) + { + if (*pp == watcher) + { + *pp = watcher->mActiveNext; + return; + } + pp = &(*pp)->mActiveNext; + } +} + +} // namespace System +} // namespace chip diff --git a/src/system/WatchableEventManagerLibevent.h b/src/system/WatchableEventManagerLibevent.h new file mode 100644 index 00000000000000..828b3565a6a273 --- /dev/null +++ b/src/system/WatchableEventManagerLibevent.h @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file declares an implementation of WatchableEvents using libevent. + */ + +#pragma once + +#if !INCLUDING_CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE +#error "This file should only be included from <system/WatchableEventManager.h>" +#include <system/WatchableEventManager.h> +#endif // !INCLUDING_CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE + +#include <event2/event.h> + +namespace chip { + +namespace System { + +class WatchableEventManager +{ +public: + WatchableEventManager() : mActiveSockets(nullptr), mSystemLayer(nullptr), mEventBase(nullptr), mTimeoutEvent(nullptr) {} + void Init(Layer & systemLayer); + void Shutdown(); + void Signal(); + + void EventLoopBegins() {} + void PrepareEvents(); + void WaitForEvents(); + void HandleEvents(); + void EventLoopEnds() {} + + // TODO(#5556): Some unit tests supply a timeout at low level, due to originally using select(); these should a proper timer. + void PrepareEventsWithTimeout(timeval & nextTimeout); + +private: + /* + * In this implementation, libevent invokes LibeventCallbackHandler from beneath WaitForEvents(), + * which means that the CHIP stack is unlocked. LibeventCallbackHandler adds the WatchableSocket + * to a queue (implemented as a simple intrusive list to avoid dynamic memory allocation), and + * then HandleEvents() invokes the WatchableSocket callbacks. + */ + friend class WatchableSocket; + static void LibeventCallbackHandler(evutil_socket_t fd, short eventFlags, void * data); + void RemoveFromQueueIfPresent(WatchableSocket * watcher); + WatchableSocket * mActiveSockets; ///< List of sockets activated by libevent. + + Layer * mSystemLayer; + event_base * mEventBase; ///< libevent shared state. + event * mTimeoutEvent; + + WakeEvent mWakeEvent; +}; + +} // namespace System +} // namespace chip diff --git a/src/system/WatchableEventManagerSelect.cpp b/src/system/WatchableEventManagerSelect.cpp new file mode 100644 index 00000000000000..f1f975b3bbd18e --- /dev/null +++ b/src/system/WatchableEventManagerSelect.cpp @@ -0,0 +1,233 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2014-2017 Nest Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file implements WatchableEventManager using select(). + */ + +#include <platform/LockTracker.h> +#include <support/CodeUtils.h> +#include <system/SystemLayer.h> +#include <system/WatchableEventManager.h> +#include <system/WatchableSocket.h> + +#include <errno.h> + +#define DEFAULT_MIN_SLEEP_PERIOD (60 * 60 * 24 * 30) // Month [sec] + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ + +namespace chip { +namespace Mdns { +void GetMdnsTimeout(timeval & timeout); +void HandleMdnsTimeout(); +} // namespace Mdns +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ + +namespace chip { +namespace System { + +void WatchableEventManager::Init(Layer & systemLayer) +{ + mSystemLayer = &systemLayer; + mMaxFd = -1; + FD_ZERO(&mRequest.mReadSet); + FD_ZERO(&mRequest.mWriteSet); + FD_ZERO(&mRequest.mErrorSet); + + // Create an event to allow an arbitrary thread to wake the thread in the select loop. + mWakeEvent.Open(*this); +} + +void WatchableEventManager::Shutdown() +{ + mWakeEvent.Close(); + mSystemLayer = nullptr; +} + +void WatchableEventManager::Signal() +{ + /* + * Wake up the I/O thread by writing a single byte to the wake pipe. + * + * If p WakeIOThread() is being called from within an I/O event callback, then writing to the wake pipe can be skipped, + * since the I/O thread is already awake. + * + * Furthermore, we don't care if this write fails as the only reasonably likely failure is that the pipe is full, in which + * case the select calling thread is going to wake up anyway. + */ +#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING + if (pthread_equal(mSystemLayer->mHandleSelectThread, pthread_self())) + { + return; + } +#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING + + // Send notification to wake up the select call. + CHIP_ERROR status = mWakeEvent.Notify(); + if (status != CHIP_NO_ERROR) + { + ChipLogError(chipSystemLayer, "System wake event notify failed: %" CHIP_ERROR_FORMAT, ChipError::FormatError(status)); + } +} + +/** + * Set the read, write or exception bit flags for the specified socket based on its status in + * the corresponding file descriptor sets. + * + * @param[in] socket The file descriptor for which the bit flags are being set. + * + * @param[in] readfds A pointer to the set of readable file descriptors. + * + * @param[in] writefds A pointer to the set of writable file descriptors. + * + * @param[in] exceptfds A pointer to the set of file descriptors with errors. + */ +SocketEvents WatchableEventManager::SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds, + const fd_set & exceptfds) +{ + SocketEvents res; + + if (socket >= 0) + { + // POSIX does not define the fd_set parameter of FD_ISSET() as const, even though it isn't modified. + if (FD_ISSET(socket, const_cast<fd_set *>(&readfds))) + res.Set(SocketEventFlags::kRead); + if (FD_ISSET(socket, const_cast<fd_set *>(&writefds))) + res.Set(SocketEventFlags::kWrite); + if (FD_ISSET(socket, const_cast<fd_set *>(&exceptfds))) + res.Set(SocketEventFlags::kExcept); + } + + return res; +} + +bool WatchableEventManager::HasAny(int fd) +{ + return FD_ISSET(fd, &mRequest.mReadSet) || FD_ISSET(fd, &mRequest.mWriteSet) || FD_ISSET(fd, &mRequest.mErrorSet); +} + +void WatchableEventManager::Set(int fd, fd_set * fds) +{ + FD_SET(fd, fds); + if (fd > mMaxFd) + { + mMaxFd = fd; + } + // Wake the thread calling select so that it starts selecting on the new socket. + Signal(); +} + +void WatchableEventManager::Clear(int fd, fd_set * fds) +{ + FD_CLR(fd, fds); + if (fd == mMaxFd) + { + MaybeLowerMaxFd(); + } + // Wake the thread calling select so that it starts selecting on the new socket. + Signal(); +} + +void WatchableEventManager::Reset(int fd) +{ + FD_CLR(fd, &mRequest.mReadSet); + FD_CLR(fd, &mRequest.mWriteSet); + FD_CLR(fd, &mRequest.mErrorSet); + if (fd == mMaxFd) + { + MaybeLowerMaxFd(); + } +} + +void WatchableEventManager::MaybeLowerMaxFd() +{ + int fd; + for (fd = mMaxFd; fd >= 0; --fd) + { + if (HasAny(fd)) + { + break; + } + } + mMaxFd = fd; +} + +void WatchableEventManager::PrepareEvents() +{ + assertChipStackLockedByCurrentThread(); + + // Max out this duration and let CHIP set it appropriately. + mNextTimeout.tv_sec = DEFAULT_MIN_SLEEP_PERIOD; + mNextTimeout.tv_usec = 0; + PrepareEventsWithTimeout(mNextTimeout); +} + +void WatchableEventManager::PrepareEventsWithTimeout(struct timeval & nextTimeout) +{ + // TODO(#5556): Integrate timer platform details with WatchableEventManager. + mSystemLayer->GetTimeout(nextTimeout); + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ && !__MBED__ + chip::Mdns::GetMdnsTimeout(nextTimeout); +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ + + mSelected = mRequest; +} + +void WatchableEventManager::WaitForEvents() +{ + mSelectResult = select(mMaxFd + 1, &mSelected.mReadSet, &mSelected.mWriteSet, &mSelected.mErrorSet, &mNextTimeout); +} + +void WatchableEventManager::HandleEvents() +{ + assertChipStackLockedByCurrentThread(); + + if (mSelectResult < 0) + { + ChipLogError(DeviceLayer, "select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno))); + return; + } + + VerifyOrDie(mSystemLayer != nullptr); + mSystemLayer->HandleTimeout(); + + for (WatchableSocket * watchable = mAttachedSockets; watchable != nullptr; watchable = watchable->mAttachedNext) + { + watchable->SetPendingIO( + SocketEventsFromFDs(watchable->GetFD(), mSelected.mReadSet, mSelected.mWriteSet, mSelected.mErrorSet)); + } + for (WatchableSocket * watchable = mAttachedSockets; watchable != nullptr; watchable = watchable->mAttachedNext) + { + if (watchable->mPendingIO.HasAny()) + { + watchable->InvokeCallback(); + } + } + +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ && !__MBED__ + chip::Mdns::HandleMdnsTimeout(); +#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ +} + +} // namespace System +} // namespace chip diff --git a/src/system/WatchableEventManagerSelect.h b/src/system/WatchableEventManagerSelect.h new file mode 100644 index 00000000000000..a7bc285b8536a3 --- /dev/null +++ b/src/system/WatchableEventManagerSelect.h @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file declares an implementation of WatchableEventManager using select(). + */ + +#pragma once + +#if !INCLUDING_CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE +#error "This file should only be included from <system/WatchableEventManager.h>" +#include <system/WatchableEventManager.h> +#endif // !INCLUDING_CHIP_SYSTEM_WATCHABLE_EVENT_MANAGER_CONFIG_FILE + +#include <sys/select.h> + +#include <support/BitFlags.h> +#include <support/logging/CHIPLogging.h> +#include <system/WakeEvent.h> + +namespace chip { +namespace System { + +class WatchableSocket; + +class WatchableEventManager +{ +public: + void Init(System::Layer & systemLayer); + void Shutdown(); + void Signal(); + + void EventLoopBegins() {} + void PrepareEvents(); + void WaitForEvents(); + void HandleEvents(); + void EventLoopEnds() {} + + // TODO(#5556): Some unit tests supply a timeout at low level, due to originally using select(); these should a proper timer. + void PrepareEventsWithTimeout(timeval & nextTimeout); + + static SocketEvents SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds, const fd_set & exceptfds); + +protected: + friend class WatchableSocket; + + void Set(int fd, fd_set * fds); + void Clear(int fd, fd_set * fds); + + Layer * mSystemLayer = nullptr; + WatchableSocket * mAttachedSockets = nullptr; + + // TODO(#5556): Integrate timer platform details with WatchableEventManager. + struct timeval mNextTimeout; + + // Members for select loop + struct SelectSets + { + fd_set mReadSet; + fd_set mWriteSet; + fd_set mErrorSet; + }; + SelectSets mRequest; + SelectSets mSelected; + int mMaxFd; + int mSelectResult; ///< return value from select() + + WakeEvent mWakeEvent; + +private: + bool HasAny(int fd); + void MaybeLowerMaxFd(); + void Reset(int fd); +}; + +} // namespace System +} // namespace chip diff --git a/src/system/SystemSockets.h b/src/system/WatchableSocket.h similarity index 77% rename from src/system/SystemSockets.h rename to src/system/WatchableSocket.h index c2ee88d1b7f1c2..32ed69aa21a8e6 100644 --- a/src/system/SystemSockets.h +++ b/src/system/WatchableSocket.h @@ -17,7 +17,7 @@ /** * @file - * This file declares the abstraction of socket (file descriptor) events. + * This file declares the WatchableSocket abstraction of socket (file descriptor) events. */ #pragma once @@ -27,16 +27,16 @@ #if CHIP_SYSTEM_CONFIG_USE_SOCKETS -#include <support/BitFlags.h> -#include <system/SystemError.h> - #include <unistd.h> +#include <support/BitFlags.h> + namespace chip { namespace System { class Layer; +class WatchableEventManager; enum class SocketEventFlags : uint8_t { @@ -48,30 +48,6 @@ enum class SocketEventFlags : uint8_t using SocketEvents = BitFlags<SocketEventFlags>; -/** - * @class WatchableEventManager - * - * An instance of this type is contained in System::Layer. Its purpose is to hold socket-event system state - * or methods available to every associated instance of WatchableSocket. - * - * It MUST provide at least two methods: - * - * void Init(System::Layer & systemLayer) -- called from System::Layer::Init() - * void Shutdown() -- called from System::Layer::Shutdown() - * - * Other contents depend on the contract between socket-event implementation and platform layer implementation. - * For POSIX-like platforms, WatchableEventManager provides a set of functions called from the event loop: - * - * void EventLoopBegins() -- Called before the first iterations of the event loop. - * void PrepareEvents() -- Called at the start of each iteration of the event loop. - * void WaitForEvents() -- Called on each iteration of the event loop, between PrepareEvents() and HandleEvents(). - * Uniquely, this method gets called with the CHIP stack NOT locked, so it can block. - * For example, the select()-based implementation calls select() here. - * void HandleEvents() -- Called at the end of each iteration of the event loop. - * void EventLoopEnds() -- Called after the last iteration of the event loop. - */ -class WatchableEventManager; - /** * @class WatchableSocket * @@ -306,35 +282,4 @@ class WatchableSocketBasis #endif // CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE #undef INCLUDING_CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE -namespace chip { -namespace System { - -/** - * @class WakeEvent - * - * An instance of this type is contained in System::Layer. Its purpose is to allow other threads - * to wake the event loop thread via System::Layer::WakeIOThread(). - */ -class WakeEvent -{ -public: - CHIP_ERROR Open(WatchableEventManager & watchState); /**< Initialize the pipeline */ - CHIP_ERROR Close(); /**< Close both ends of the pipeline. */ - - int GetNotifFD() const { return mFD.GetFD(); } - - CHIP_ERROR Notify(); /**< Set the event. */ - void Confirm(); /**< Clear the event. */ - static void Confirm(WatchableSocket & socket) { reinterpret_cast<WakeEvent *>(socket.GetCallbackData())->Confirm(); } - -private: -#if CHIP_SYSTEM_CONFIG_USE_POSIX_PIPE - int mWriteFD; -#endif - WatchableSocket mFD; -}; - -} // namespace System -} // namespace chip - #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS diff --git a/src/system/WatchableSocketLibevent.cpp b/src/system/WatchableSocketLibevent.cpp index a420c7de069ac5..0913c97857432b 100644 --- a/src/system/WatchableSocketLibevent.cpp +++ b/src/system/WatchableSocketLibevent.cpp @@ -17,154 +17,18 @@ /** * @file - * This file implements WatchableEvents using libevent. + * This file implements WatchableSocket using libevent. */ #include <platform/CHIPDeviceBuildConfig.h> #include <support/CodeUtils.h> #include <system/SystemLayer.h> -#include <system/SystemSockets.h> - -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ - -namespace chip { -namespace Mdns { -void GetMdnsTimeout(timeval & timeout); -void HandleMdnsTimeout(); -} // namespace Mdns -} // namespace chip - -#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ - -#ifndef CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS -#define CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS 1 // TODO(#5556): default to off -#endif +#include <system/WatchableEventManager.h> +#include <system/WatchableSocket.h> namespace chip { namespace System { -namespace { - -System::SocketEvents SocketEventsFromLibeventFlags(short eventFlags) -{ - return System::SocketEvents() - .Set(SocketEventFlags::kRead, eventFlags & EV_READ) - .Set(SocketEventFlags::kWrite, eventFlags & EV_WRITE); -} - -void TimeoutCallbackHandler(evutil_socket_t fd, short eventFlags, void * data) -{ - event * const ev = reinterpret_cast<event *>(data); - evtimer_del(ev); -} - -} // anonymous namespace - -void WatchableEventManager::Init(System::Layer & systemLayer) -{ -#if CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS - static bool enabled_event_debug_mode = false; - if (!enabled_event_debug_mode) - { - enabled_event_debug_mode = true; - event_enable_debug_mode(); - } -#endif // CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS - - mEventBase = event_base_new(); - mTimeoutEvent = evtimer_new(mEventBase, TimeoutCallbackHandler, event_self_cbarg()); - mActiveSockets = nullptr; - mSystemLayer = &systemLayer; -} - -void WatchableEventManager::PrepareEvents() -{ - // TODO(#5556): Integrate timer platform details with WatchableEventManager. - timeval nextTimeout = { 0, 0 }; - PrepareEventsWithTimeout(nextTimeout); -} - -void WatchableEventManager::PrepareEventsWithTimeout(struct timeval & nextTimeout) -{ - // TODO(#5556): Integrate timer platform details with WatchableEventManager. - mSystemLayer->GetTimeout(nextTimeout); - if (nextTimeout.tv_sec || nextTimeout.tv_usec) - { - evtimer_add(mTimeoutEvent, &nextTimeout); - } -} - -void WatchableEventManager::WaitForEvents() -{ - VerifyOrDie(mEventBase != nullptr); - event_base_loop(mEventBase, EVLOOP_ONCE); -} - -void WatchableEventManager::HandleEvents() -{ - mSystemLayer->HandleTimeout(); - -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ - chip::Mdns::HandleMdnsTimeout(); -#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ - - while (mActiveSockets != nullptr) - { - WatchableSocket * const watcher = mActiveSockets; - mActiveSockets = watcher->mActiveNext; - watcher->InvokeCallback(); - } -} - -void WatchableEventManager::Shutdown() -{ - event_base_loopbreak(mEventBase); - event_free(mTimeoutEvent); - mTimeoutEvent = nullptr; - event_base_free(mEventBase); - mEventBase = nullptr; -} - -// static -void WatchableEventManager::LibeventCallbackHandler(evutil_socket_t fd, short eventFlags, void * data) -{ - WatchableSocket * const watcher = reinterpret_cast<WatchableSocket *>(data); - VerifyOrDie(watcher != nullptr); - VerifyOrDie(watcher->mFD == fd); - - watcher->mPendingIO = SocketEventsFromLibeventFlags(eventFlags); - - // Add to active list. - WatchableSocket ** pp = &watcher->mSharedState->mActiveSockets; - while (*pp != nullptr) - { - if (*pp == watcher) - { - return; - } - pp = &(*pp)->mActiveNext; - } - *pp = watcher; - watcher->mActiveNext = nullptr; -} - -void WatchableEventManager::RemoveFromQueueIfPresent(WatchableSocket * watcher) -{ - VerifyOrDie(watcher != nullptr); - VerifyOrDie(watcher->mSharedState == this); - - WatchableSocket ** pp = &mActiveSockets; - while (*pp != nullptr) - { - if (*pp == watcher) - { - *pp = watcher->mActiveNext; - return; - } - pp = &(*pp)->mActiveNext; - } -} - void WatchableSocket::OnInit() { mEvent = nullptr; @@ -176,6 +40,12 @@ void WatchableSocket::OnAttach() evutil_make_socket_nonblocking(mFD); } +void WatchableSocket::OnClose() +{ + UpdateWatch(0); + mSharedState->RemoveFromQueueIfPresent(this); +} + void WatchableSocket::SetWatch(short eventFlags) { const short oldFlags = mEvent ? event_get_events(mEvent) : 0; diff --git a/src/system/WatchableSocketLibevent.h b/src/system/WatchableSocketLibevent.h index 563e9d794ceeb7..be2448af810190 100644 --- a/src/system/WatchableSocketLibevent.h +++ b/src/system/WatchableSocketLibevent.h @@ -23,7 +23,8 @@ #pragma once #if !INCLUDING_CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE -#error "This file should only be included from <system/SystemSockets.h>" +#error "This file should only be included from <system/WatchableSocket.h>" +#include <system/WatchableSocket.h> #endif // !INCLUDING_CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE #include <event2/event.h> @@ -32,49 +33,14 @@ namespace chip { namespace System { -class WatchableEventManager -{ -public: - WatchableEventManager() : mActiveSockets(nullptr), mSystemLayer(nullptr), mEventBase(nullptr), mTimeoutEvent(nullptr) {} - void Init(Layer & systemLayer); - void Shutdown(); - - void EventLoopBegins() {} - void PrepareEvents(); - void WaitForEvents(); - void HandleEvents(); - void EventLoopEnds() {} - - // TODO(#5556): Some unit tests supply a timeout at low level, due to originally using select(); these should a proper timer. - void PrepareEventsWithTimeout(timeval & nextTimeout); - -private: - /* - * In this implementation, libevent invokes LibeventCallbackHandler from beneath WaitForEvents(), - * which means that the CHIP stack is unlocked. LibeventCallbackHandler adds the WatchableSocket - * to a queue (implemented as a simple intrusive list to avoid dynamic memory allocation), and - * then HandleEvents() invokes the WatchableSocket callbacks. - */ - friend class WatchableSocket; - static void LibeventCallbackHandler(evutil_socket_t fd, short eventFlags, void * data); - void RemoveFromQueueIfPresent(WatchableSocket * watcher); - WatchableSocket * mActiveSockets; ///< List of sockets activated by libevent. - - Layer * mSystemLayer; - event_base * mEventBase; ///< libevent shared state. - event * mTimeoutEvent; -}; +class WatchableEventManager; class WatchableSocket : public WatchableSocketBasis<WatchableSocket> { public: void OnInit(); void OnAttach(); - void OnClose() - { - UpdateWatch(0); - mSharedState->RemoveFromQueueIfPresent(this); - } + void OnClose(); void OnRequestCallbackOnPendingRead() { SetWatch(EV_READ); } void OnRequestCallbackOnPendingWrite() { SetWatch(EV_WRITE); } void OnClearCallbackOnPendingRead() { ClearWatch(EV_READ); } diff --git a/src/system/WatchableSocketSelect.cpp b/src/system/WatchableSocketSelect.cpp index 0b28fd8c3d12d3..04f8dbb72020c8 100644 --- a/src/system/WatchableSocketSelect.cpp +++ b/src/system/WatchableSocketSelect.cpp @@ -18,193 +18,20 @@ /** * @file - * This file implements WatchableEvents using select(). + * This file implements WatchableSocket using select(). */ #include <platform/LockTracker.h> #include <support/CodeUtils.h> #include <system/SystemLayer.h> -#include <system/SystemSockets.h> +#include <system/WatchableEventManager.h> +#include <system/WatchableSocket.h> #include <errno.h> -#define DEFAULT_MIN_SLEEP_PERIOD (60 * 60 * 24 * 30) // Month [sec] - -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ - -namespace chip { -namespace Mdns { -void GetMdnsTimeout(timeval & timeout); -void HandleMdnsTimeout(); -} // namespace Mdns -} // namespace chip - -#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ - namespace chip { namespace System { -void WatchableEventManager::Init(Layer & systemLayer) -{ - mSystemLayer = &systemLayer; - mMaxFd = -1; - FD_ZERO(&mRequest.mReadSet); - FD_ZERO(&mRequest.mWriteSet); - FD_ZERO(&mRequest.mErrorSet); -} - -void WatchableEventManager::Shutdown() -{ - mSystemLayer = nullptr; -} - -/** - * Set the read, write or exception bit flags for the specified socket based on its status in - * the corresponding file descriptor sets. - * - * @param[in] socket The file descriptor for which the bit flags are being set. - * - * @param[in] readfds A pointer to the set of readable file descriptors. - * - * @param[in] writefds A pointer to the set of writable file descriptors. - * - * @param[in] exceptfds A pointer to the set of file descriptors with errors. - */ -SocketEvents WatchableEventManager::SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds, - const fd_set & exceptfds) -{ - SocketEvents res; - - if (socket >= 0) - { - // POSIX does not define the fd_set parameter of FD_ISSET() as const, even though it isn't modified. - if (FD_ISSET(socket, const_cast<fd_set *>(&readfds))) - res.Set(SocketEventFlags::kRead); - if (FD_ISSET(socket, const_cast<fd_set *>(&writefds))) - res.Set(SocketEventFlags::kWrite); - if (FD_ISSET(socket, const_cast<fd_set *>(&exceptfds))) - res.Set(SocketEventFlags::kExcept); - } - - return res; -} - -bool WatchableEventManager::HasAny(int fd) -{ - return FD_ISSET(fd, &mRequest.mReadSet) || FD_ISSET(fd, &mRequest.mWriteSet) || FD_ISSET(fd, &mRequest.mErrorSet); -} - -void WatchableEventManager::WakeSelect() -{ -#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD - mSystemLayer->WakeIOThread(); -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD -} - -void WatchableEventManager::Set(int fd, fd_set * fds) -{ - FD_SET(fd, fds); - if (fd > mMaxFd) - { - mMaxFd = fd; - } - // Wake the thread calling select so that it starts selecting on the new socket. - WakeSelect(); -} - -void WatchableEventManager::Clear(int fd, fd_set * fds) -{ - FD_CLR(fd, fds); - if (fd == mMaxFd) - { - MaybeLowerMaxFd(); - } - // Wake the thread calling select so that it starts selecting on the new socket. - WakeSelect(); -} - -void WatchableEventManager::Reset(int fd) -{ - FD_CLR(fd, &mRequest.mReadSet); - FD_CLR(fd, &mRequest.mWriteSet); - FD_CLR(fd, &mRequest.mErrorSet); - if (fd == mMaxFd) - { - MaybeLowerMaxFd(); - } -} - -void WatchableEventManager::MaybeLowerMaxFd() -{ - int fd; - for (fd = mMaxFd; fd >= 0; --fd) - { - if (HasAny(fd)) - { - break; - } - } - mMaxFd = fd; -} - -void WatchableEventManager::PrepareEvents() -{ - assertChipStackLockedByCurrentThread(); - - // Max out this duration and let CHIP set it appropriately. - mNextTimeout.tv_sec = DEFAULT_MIN_SLEEP_PERIOD; - mNextTimeout.tv_usec = 0; - PrepareEventsWithTimeout(mNextTimeout); -} - -void WatchableEventManager::PrepareEventsWithTimeout(struct timeval & nextTimeout) -{ - // TODO(#5556): Integrate timer platform details with WatchableEventManager. - mSystemLayer->GetTimeout(nextTimeout); - -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ && !__MBED__ - chip::Mdns::GetMdnsTimeout(nextTimeout); -#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ - - mSelected = mRequest; -} - -void WatchableEventManager::WaitForEvents() -{ - mSelectResult = select(mMaxFd + 1, &mSelected.mReadSet, &mSelected.mWriteSet, &mSelected.mErrorSet, &mNextTimeout); -} - -void WatchableEventManager::HandleEvents() -{ - assertChipStackLockedByCurrentThread(); - - if (mSelectResult < 0) - { - ChipLogError(DeviceLayer, "select failed: %s\n", ErrorStr(System::MapErrorPOSIX(errno))); - return; - } - - VerifyOrDie(mSystemLayer != nullptr); - mSystemLayer->HandleTimeout(); - - for (WatchableSocket * watchable = mAttachedSockets; watchable != nullptr; watchable = watchable->mAttachedNext) - { - watchable->SetPendingIO( - SocketEventsFromFDs(watchable->GetFD(), mSelected.mReadSet, mSelected.mWriteSet, mSelected.mErrorSet)); - } - for (WatchableSocket * watchable = mAttachedSockets; watchable != nullptr; watchable = watchable->mAttachedNext) - { - if (watchable->mPendingIO.HasAny()) - { - watchable->InvokeCallback(); - } - } - -#if CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ && !__MBED__ - chip::Mdns::HandleMdnsTimeout(); -#endif // CHIP_DEVICE_CONFIG_ENABLE_MDNS && !__ZEPHYR__ -} - void WatchableSocket::OnAttach() { mSharedState->Reset(mFD); @@ -230,10 +57,30 @@ void WatchableSocket::OnClose() pp = &(*pp)->mAttachedNext; } -#if CHIP_SYSTEM_CONFIG_USE_IO_THREAD +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK // Wake the thread calling select so that it stops selecting on the socket. - mSharedState->WakeSelect(); -#endif // CHIP_SYSTEM_CONFIG_USE_IO_THREAD + mSharedState->Signal(); +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK +} + +void WatchableSocket::OnRequestCallbackOnPendingRead() +{ + mSharedState->Set(mFD, &mSharedState->mRequest.mReadSet); +} + +void WatchableSocket::OnRequestCallbackOnPendingWrite() +{ + mSharedState->Set(mFD, &mSharedState->mRequest.mWriteSet); +} + +void WatchableSocket::OnClearCallbackOnPendingRead() +{ + mSharedState->Clear(mFD, &mSharedState->mRequest.mReadSet); +} + +void WatchableSocket::OnClearCallbackOnPendingWrite() +{ + mSharedState->Clear(mFD, &mSharedState->mRequest.mWriteSet); } /** diff --git a/src/system/WatchableSocketSelect.h b/src/system/WatchableSocketSelect.h index 1df1e190e5a782..266ad7e69682a7 100644 --- a/src/system/WatchableSocketSelect.h +++ b/src/system/WatchableSocketSelect.h @@ -17,71 +17,24 @@ /** * @file - * This file declares an implementation of WatchableEvents using select(). + * This file declares an implementation of WatchableSocket using select(). */ #pragma once +#if !INCLUDING_CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE +#error "This file should only be included from <system/WatchableSocket.h>" +#include <system/WatchableSocket.h> +#endif // !INCLUDING_CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE + #include <sys/select.h> #include <support/BitFlags.h> - -#if !INCLUDING_CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE -#error "This file should only be included from <system/SystemSockets.h>" -#endif // !INCLUDING_CHIP_SYSTEM_WATCHABLE_SOCKET_CONFIG_FILE +#include <support/logging/CHIPLogging.h> namespace chip { - namespace System { -class WatchableEventManager -{ -public: - void Init(System::Layer & systemLayer); - void Shutdown(); - - void EventLoopBegins() {} - void PrepareEvents(); - void WaitForEvents(); - void HandleEvents(); - void EventLoopEnds() {} - - // TODO(#5556): Some unit tests supply a timeout at low level, due to originally using select(); these should a proper timer. - void PrepareEventsWithTimeout(timeval & nextTimeout); - - static SocketEvents SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds, const fd_set & exceptfds); - -protected: - friend class WatchableSocket; - - void Set(int fd, fd_set * fds); - void Clear(int fd, fd_set * fds); - - Layer * mSystemLayer = nullptr; - WatchableSocket * mAttachedSockets = nullptr; - - // TODO(#5556): Integrate timer platform details with WatchableEventManager. - struct timeval mNextTimeout; - - // Members for select loop - struct SelectSets - { - fd_set mReadSet; - fd_set mWriteSet; - fd_set mErrorSet; - }; - SelectSets mRequest; - SelectSets mSelected; - int mMaxFd; - int mSelectResult; ///< return value from select() - -private: - bool HasAny(int fd); - void MaybeLowerMaxFd(); - void Reset(int fd); - void WakeSelect(); -}; - class WatchableSocket : public WatchableSocketBasis<WatchableSocket> { public: @@ -89,10 +42,10 @@ class WatchableSocket : public WatchableSocketBasis<WatchableSocket> void OnAttach(); void OnClose(); - void OnRequestCallbackOnPendingRead() { mSharedState->Set(mFD, &mSharedState->mRequest.mReadSet); } - void OnRequestCallbackOnPendingWrite() { mSharedState->Set(mFD, &mSharedState->mRequest.mWriteSet); } - void OnClearCallbackOnPendingRead() { mSharedState->Clear(mFD, &mSharedState->mRequest.mReadSet); } - void OnClearCallbackOnPendingWrite() { mSharedState->Clear(mFD, &mSharedState->mRequest.mWriteSet); } + void OnRequestCallbackOnPendingRead(); + void OnRequestCallbackOnPendingWrite(); + void OnClearCallbackOnPendingRead(); + void OnClearCallbackOnPendingWrite(); void SetPendingIO(SocketEvents events) { mPendingIO = events; } void SetFDs(int & nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds); diff --git a/src/system/tests/TestSystemWakeEvent.cpp b/src/system/tests/TestSystemWakeEvent.cpp index 19104e1cd2e93b..4dbfd0c31ea563 100644 --- a/src/system/tests/TestSystemWakeEvent.cpp +++ b/src/system/tests/TestSystemWakeEvent.cpp @@ -33,7 +33,7 @@ #include <support/UnitTestRegistration.h> #include <system/SystemError.h> #include <system/SystemLayer.h> -#include <system/SystemSockets.h> +#include <system/WatchableSocket.h> #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING #include <pthread.h> @@ -42,6 +42,17 @@ using namespace chip::System; #if CHIP_SYSTEM_CONFIG_USE_SOCKETS + +namespace chip { +namespace System { +class WakeEventTest +{ +public: + static int GetReadFD(const WakeEvent & wakeEvent) { return wakeEvent.GetReadFD(); } +}; +} // namespace System +} // namespace chip + namespace { struct TestContext @@ -65,15 +76,15 @@ struct TestContext FD_ZERO(&mReadSet); FD_ZERO(&mWriteSet); FD_ZERO(&mErrorSet); - FD_SET(mWakeEvent.GetNotifFD(), &mReadSet); - return select(mWakeEvent.GetNotifFD() + 1, &mReadSet, &mWriteSet, &mErrorSet, &timeout); + FD_SET(WakeEventTest::GetReadFD(mWakeEvent), &mReadSet); + return select(WakeEventTest::GetReadFD(mWakeEvent) + 1, &mReadSet, &mWriteSet, &mErrorSet, &timeout); } }; void TestOpen(nlTestSuite * inSuite, void * aContext) { TestContext & lContext = *static_cast<TestContext *>(aContext); - NL_TEST_ASSERT(inSuite, lContext.mWakeEvent.GetNotifFD() >= 0); + NL_TEST_ASSERT(inSuite, WakeEventTest::GetReadFD(lContext.mWakeEvent) >= 0); NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 0); } @@ -85,11 +96,11 @@ void TestNotify(nlTestSuite * inSuite, void * aContext) // Check that select() succeeds after Notify() has been called lContext.mWakeEvent.Notify(); NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 1); - NL_TEST_ASSERT(inSuite, FD_ISSET(lContext.mWakeEvent.GetNotifFD(), &lContext.mReadSet)); + NL_TEST_ASSERT(inSuite, FD_ISSET(WakeEventTest::GetReadFD(lContext.mWakeEvent), &lContext.mReadSet)); // ...and state of the event is not cleared automatically NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 1); - NL_TEST_ASSERT(inSuite, FD_ISSET(lContext.mWakeEvent.GetNotifFD(), &lContext.mReadSet)); + NL_TEST_ASSERT(inSuite, FD_ISSET(WakeEventTest::GetReadFD(lContext.mWakeEvent), &lContext.mReadSet)); } void TestConfirm(nlTestSuite * inSuite, void * aContext) @@ -99,7 +110,7 @@ void TestConfirm(nlTestSuite * inSuite, void * aContext) // Check that select() succeeds after Notify() has been called lContext.mWakeEvent.Notify(); NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 1); - NL_TEST_ASSERT(inSuite, FD_ISSET(lContext.mWakeEvent.GetNotifFD(), &lContext.mReadSet)); + NL_TEST_ASSERT(inSuite, FD_ISSET(WakeEventTest::GetReadFD(lContext.mWakeEvent), &lContext.mReadSet)); // Check that Confirm() clears state of the event lContext.mWakeEvent.Confirm(); @@ -136,7 +147,7 @@ void TestClose(nlTestSuite * inSuite, void * aContext) TestContext & lContext = *static_cast<TestContext *>(aContext); lContext.mWakeEvent.Close(); - const auto notifFD = lContext.mWakeEvent.GetNotifFD(); + const auto notifFD = WakeEventTest::GetReadFD(lContext.mWakeEvent); // Check that Close() has cleaned up itself and reopen is possible NL_TEST_ASSERT(inSuite, lContext.mWakeEvent.Open(lContext.mWatchableEvents) == CHIP_NO_ERROR);