diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index b13ecf7baef255..5f74d1e64adce8 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -111,9 +111,6 @@ 'src/lib/support/CHIPListUtils.h': {'set'}, 'src/platform/DeviceSafeQueue.h': {'queue'}, - # libevent itself is unsuitable for small platforms. - 'src/system/SystemLayerImplLibevent.h': {'list', 'vector'}, - # Only uses for zero-cost types. 'src/system/SystemClock.h': {'chrono'}, 'src/platform/mbed/MbedEventTimeout.h': {'chrono'}, diff --git a/src/system/BUILD.gn b/src/system/BUILD.gn index c05b19a2b62a06..068478691c7de7 100644 --- a/src/system/BUILD.gn +++ b/src/system/BUILD.gn @@ -205,9 +205,6 @@ static_library("system") { if (chip_system_config_use_sockets) { sources += [ "SocketEvents.h" ] - if (chip_system_config_event_loop == "Libevent") { - libs = [ "event" ] - } } if (chip_with_nlfaultinjection) { diff --git a/src/system/SystemLayerImplLibevent.cpp b/src/system/SystemLayerImplLibevent.cpp deleted file mode 100644 index b8dcda3527ae26..00000000000000 --- a/src/system/SystemLayerImplLibevent.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/* - * - * 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 System::Layer using libevent. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifndef CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS -#define CHIP_CONFIG_LIBEVENT_DEBUG_CHECKS 1 -#endif - -// Choose an approximation of PTHREAD_NULL if pthread.h doesn't define one. -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL) -#define PTHREAD_NULL 0 -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL) - -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); -} - -} // anonymous namespace - -CHIP_ERROR LayerImplLibevent::Init(System::Layer & systemLayer) -{ - VerifyOrReturnError(mLayerState.SetInitializing(), CHIP_ERROR_INCORRECT_STATE); - - RegisterPOSIXErrorFormatter(); - -#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 - - mSystemLayer = &systemLayer; - mEventBase = event_base_new(); - VerifyOrReturnError(mEventBase != nullptr, CHIP_ERROR_NO_MEMORY); - -#if !__ZEPHYR__ - mMdnsTimeoutEvent = evtimer_new(mEventBase, MdnsTimeoutCallbackHandler, this); - VerifyOrReturnError(mMdnsTimeoutEvent != nullptr, CHIP_ERROR_NO_MEMORY); -#endif // !__ZEPHYR__ - -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING - mHandleSelectThread = PTHREAD_NULL; -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING - - Mutex::Init(mTimerListMutex); - - VerifyOrReturnError(mLayerState.SetInitialized(), CHIP_ERROR_INCORRECT_STATE); - return CHIP_NO_ERROR; -} - -#if !__ZEPHYR__ - -// static -void LayerImplLibevent::MdnsTimeoutCallbackHandler(evutil_socket_t fd, short eventFlags, void * data) -{ - reinterpret_cast(data)->MdnsTimeoutCallbackHandler(); -} - -void LayerImplLibevent::MdnsTimeoutCallbackHandler() -{ -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING - mHandleSelectThread = pthread_self(); -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING - - chip::Dnssd::HandleMdnsTimeout(); - -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING - mHandleSelectThread = PTHREAD_NULL; -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING -} -#endif // !__ZEPHYR__ - -CHIP_ERROR LayerImplLibevent::Shutdown() -{ - VerifyOrReturnError(mLayerState.SetShuttingDown(), CHIP_ERROR_INCORRECT_STATE); - - event_base_loopbreak(mEventBase); - -#if !__ZEPHYR__ - if (mMdnsTimeoutEvent != nullptr) - { - event_free(mMdnsTimeoutEvent); - mMdnsTimeoutEvent = nullptr; - } -#endif // !__ZEPHYR__ - - mTimerListMutex.Lock(); - mTimers.clear(); - mTimerListMutex.Unlock(); - - mSocketWatches.clear(); - - event_base_free(mEventBase); - mEventBase = nullptr; - mSystemLayer = nullptr; - - mLayerState.ResetFromShuttingDown(); // Return to uninitialized state to permit re-initialization. - return CHIP_NO_ERROR; -} - -void LayerImplLibevent::Signal() -{ - /* - * Wake up the I/O thread by writing a single byte to the wake pipe. - * - * If this 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(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, status.Format()); - } -} - -CHIP_ERROR LayerImplLibevent::StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) -{ - VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE); - - std::lock_guard lock(mTimerListMutex); - mTimers.push_back(std::make_unique(this, onComplete, appState)); - LibeventTimer * timer = mTimers.back().get(); - if (timer == nullptr) - { - mTimers.pop_back(); - return CHIP_ERROR_NO_MEMORY; - } - - event * e = evtimer_new(mEventBase, TimerCallbackHandler, timer); - VerifyOrReturnError(e != nullptr, CHIP_ERROR_NO_MEMORY); - timer->mEvent = e; - - timeval tv; - Clock::ToTimeval(delay, tv); - int status = evtimer_add(e, &tv); - VerifyOrReturnError(status == 0, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; -} - -void LayerImplLibevent::CancelTimer(TimerCompleteCallback onComplete, void * appState) -{ - VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE); - - std::lock_guard lock(mTimerListMutex); - auto it = std::find_if(mTimers.begin(), mTimers.end(), [onComplete, appState](const std::unique_ptr & timer) { - return timer->mOnComplete == onComplete && timer->mCallbackData == appState; - }); - if (it != mTimers.end()) - { - LibeventTimer * timer = it->get(); - mActiveTimers.remove(timer); - mTimers.remove_if([timer](const std::unique_ptr & t) { return t.get() == timer; }); - } -} - -CHIP_ERROR LayerImplLibevent::ScheduleWork(TimerCompleteCallback onComplete, void * appState) -{ - assertChipStackLockedByCurrentThread(); - VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE); - - return StartTimer(Clock::kZero, onComplete, appState); -} - -// static -void LayerImplLibevent::TimerCallbackHandler(evutil_socket_t fd, short eventFlags, void * data) -{ - // Copy the necessary timer information and remove it from the list. - LibeventTimer * timer = reinterpret_cast(data); - Layer * systemLayer = timer->mEventManager->mSystemLayer; - TimerCompleteCallback onComplete = timer->mOnComplete; - void * callbackData = timer->mCallbackData; - systemLayer->CancelTimer(onComplete, callbackData); - if (onComplete) - { - onComplete(systemLayer, callbackData); - } -} - -LayerImplLibevent::LibeventTimer::~LibeventTimer() -{ - mEventManager = nullptr; - mOnComplete = nullptr; - mCallbackData = nullptr; - if (mEvent) - { - if (evtimer_pending(mEvent, nullptr)) - { - event_del(mEvent); - } - event_free(mEvent); - mEvent = nullptr; - } -}; - -CHIP_ERROR LayerImplLibevent::StartWatchingSocket(int fd, SocketWatchToken * tokenOut) -{ - mSocketWatches.push_back(std::make_unique(this, fd)); - SocketWatch * watch = mSocketWatches.back().get(); - if (watch == nullptr) - { - mSocketWatches.pop_back(); - return CHIP_ERROR_NO_MEMORY; - } - - *tokenOut = reinterpret_cast(watch); - return CHIP_NO_ERROR; -} - -CHIP_ERROR LayerImplLibevent::SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data) -{ - SocketWatch * watch = reinterpret_cast(token); - VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - watch->mCallback = callback; - watch->mCallbackData = data; - return CHIP_NO_ERROR; -} - -CHIP_ERROR LayerImplLibevent::RequestCallbackOnPendingRead(SocketWatchToken token) -{ - return SetWatch(token, EV_READ); -} - -CHIP_ERROR LayerImplLibevent::RequestCallbackOnPendingWrite(SocketWatchToken token) -{ - return SetWatch(token, EV_WRITE); -} - -CHIP_ERROR LayerImplLibevent::ClearCallbackOnPendingRead(SocketWatchToken token) -{ - return ClearWatch(token, EV_READ); -} - -CHIP_ERROR LayerImplLibevent::ClearCallbackOnPendingWrite(SocketWatchToken token) -{ - return ClearWatch(token, EV_WRITE); -} - -CHIP_ERROR LayerImplLibevent::StopWatchingSocket(SocketWatchToken * tokenInOut) -{ - SocketWatch * watch = reinterpret_cast(*tokenInOut); - VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - *tokenInOut = InvalidSocketWatchToken(); - - mActiveSocketWatches.remove(watch); - mSocketWatches.remove_if([watch](const std::unique_ptr & w) { return w.get() == watch; }); - return CHIP_NO_ERROR; -} - -SocketWatchToken InvalidSocketWatchToken() -{ - return reinterpret_cast(nullptr); -} - -CHIP_ERROR LayerImplLibevent::SetWatch(SocketWatchToken token, short eventFlags) -{ - SocketWatch * watch = reinterpret_cast(token); - VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - const short oldFlags = watch->mEvent ? event_get_events(watch->mEvent) : 0; - return UpdateWatch(watch, static_cast(EV_PERSIST | oldFlags | eventFlags)); -} - -CHIP_ERROR LayerImplLibevent::ClearWatch(SocketWatchToken token, short eventFlags) -{ - SocketWatch * watch = reinterpret_cast(token); - VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - const short oldFlags = watch->mEvent ? event_get_events(watch->mEvent) : 0; - return UpdateWatch(watch, static_cast(EV_PERSIST | (oldFlags & ~eventFlags))); -} - -CHIP_ERROR LayerImplLibevent::UpdateWatch(SocketWatch * watch, short eventFlags) -{ - if (watch->mEvent != nullptr) - { - if (event_get_events(watch->mEvent) == eventFlags) - { - // No update needed. - return CHIP_NO_ERROR; - } - if (event_pending(watch->mEvent, EV_TIMEOUT | EV_READ | EV_WRITE | EV_SIGNAL, nullptr)) - { - event_del(watch->mEvent); - } - event_free(watch->mEvent); - watch->mEvent = nullptr; - } - - if (eventFlags) - { - // libevent requires the socket to already be non-blocking. - int flags = ::fcntl(watch->mFD, F_GETFL, 0); - if ((flags & O_NONBLOCK) == 0) - { - int status = ::fcntl(watch->mFD, F_SETFL, flags | O_NONBLOCK); - VerifyOrReturnError(status == 0, CHIP_ERROR_POSIX(errno)); - } - watch->mEvent = event_new(mEventBase, watch->mFD, eventFlags, SocketCallbackHandler, watch); - VerifyOrReturnError(watch->mEvent != nullptr, CHIP_ERROR_NO_MEMORY); - int status = event_add(watch->mEvent, nullptr); - VerifyOrReturnError(status == 0, CHIP_ERROR_INTERNAL); - } - - return CHIP_NO_ERROR; -} - -// static -void LayerImplLibevent::SocketCallbackHandler(evutil_socket_t fd, short eventFlags, void * data) -{ - SocketWatch * const watch = reinterpret_cast(data); - VerifyOrDie(watch != nullptr); - VerifyOrDie(watch->mFD == fd); - - watch->mPendingIO = SocketEventsFromLibeventFlags(eventFlags); - watch->mEventManager->mActiveSocketWatches.push_back(watch); -} - -LayerImplLibevent::SocketWatch::~SocketWatch() -{ - mEventManager = nullptr; - mFD = kInvalidFd; - mCallback = nullptr; - mCallbackData = 0; - if (mEvent) - { - if (event_pending(mEvent, EV_TIMEOUT | EV_READ | EV_WRITE | EV_SIGNAL, nullptr)) - { - event_del(mEvent); - } - event_free(mEvent); - mEvent = nullptr; - } -} - -void LayerImplLibevent::PrepareEvents() -{ -#if !__ZEPHYR__ && !__MBED__ - timeval mdnsTimeout = { 0, 0 }; - chip::Dnssd::GetMdnsTimeout(mdnsTimeout); - if (mdnsTimeout.tv_sec || mdnsTimeout.tv_usec) - { - evtimer_add(mMdnsTimeoutEvent, &mdnsTimeout); - } -#endif // !__ZEPHYR__ && !__MBED__ -} - -void LayerImplLibevent::WaitForEvents() -{ - VerifyOrDie(mEventBase != nullptr); - event_base_loop(mEventBase, EVLOOP_ONCE); -} - -void LayerImplLibevent::HandleEvents() -{ -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING - mHandleSelectThread = pthread_self(); -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING - - while (!mActiveSocketWatches.empty()) - { - SocketWatch * const watch = mActiveSocketWatches.front(); - mActiveSocketWatches.pop_front(); - if (watch->mPendingIO.HasAny() && watch->mCallback != nullptr) - { - watch->mCallback(watch->mPendingIO, watch->mCallbackData); - } - } - -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING - mHandleSelectThread = PTHREAD_NULL; -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING -} - -} // namespace System -} // namespace chip diff --git a/src/system/SystemLayerImplLibevent.h b/src/system/SystemLayerImplLibevent.h deleted file mode 100644 index 2f5d5439123a0d..00000000000000 --- a/src/system/SystemLayerImplLibevent.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * 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 System::Layer using libevent. - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING -#include -#include -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING - -namespace chip { - -namespace System { - -class LayerImplLibevent : public LayerSocketsLoop -{ -public: - LayerImplLibevent() : mEventBase(nullptr), mMdnsTimeoutEvent(nullptr) {} - ~LayerImplLibevent() = default; - - // Layer overrides. - CHIP_ERROR Init() override; - CHIP_ERROR Shutdown() override; - bool IsInitialized() const override { return mLayerState.IsInitialized(); } - CHIP_ERROR StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override; - void CancelTimer(TimerCompleteCallback onComplete, void * appState) override; - CHIP_ERROR ScheduleWork(TimerCompleteCallback onComplete, void * appState) override; - - // LayerSocket overrides. - CHIP_ERROR StartWatchingSocket(int fd, SocketWatchToken * tokenOut) override; - CHIP_ERROR SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data) override; - CHIP_ERROR RequestCallbackOnPendingRead(SocketWatchToken token) override; - CHIP_ERROR RequestCallbackOnPendingWrite(SocketWatchToken token) override; - CHIP_ERROR ClearCallbackOnPendingRead(SocketWatchToken token) override; - CHIP_ERROR ClearCallbackOnPendingWrite(SocketWatchToken token) override; - CHIP_ERROR StopWatchingSocket(SocketWatchToken * tokenInOut) override; - SocketWatchToken InvalidSocketWatchToken() override { return reinterpret_cast(nullptr); } - - // LayerSocketLoop overrides. - void Signal() override; - void EventLoopBegins() override {} - void PrepareEvents() override; - void WaitForEvents() override; - void HandleEvents() override; - void EventLoopEnds() override {} - -private: - /* - * In this implementation, libevent invokes TimerCallbackHandler and SocketCallbackHandler from beneath WaitForEvents(), - * which means that the CHIP stack is unlocked. These handles add the LibeventTimer or SocketWatch respectively to a list, - * then HandleEvents() invokes the client callbacks. - */ - struct LibeventTimer - { - LibeventTimer(LayerImplLibevent * layer, TimerCompleteCallback onComplete, void * data) : - mEventManager(layer), mOnComplete(onComplete), mCallbackData(data), mEvent(nullptr) - {} - ~LibeventTimer(); - LayerImplLibevent * mEventManager; - TimerCompleteCallback mOnComplete; - void * mCallbackData; - event * mEvent; - }; - static void TimerCallbackHandler(evutil_socket_t fd, short eventFlags, void * data); - - struct SocketWatch - { - SocketWatch(LayerImplLibevent * layer, int fd) : - mEventManager(layer), mFD(fd), mCallback(nullptr), mCallbackData(0), mEvent(nullptr) - {} - ~SocketWatch(); - LayerImplLibevent * mEventManager; - int mFD; - SocketEvents mPendingIO; - SocketWatchCallback mCallback; - intptr_t mCallbackData; - event * mEvent; - }; - CHIP_ERROR SetWatch(SocketWatchToken token, short eventFlags); - CHIP_ERROR ClearWatch(SocketWatchToken token, short eventFlags); - CHIP_ERROR UpdateWatch(SocketWatch * watch, short eventFlags); - static void SocketCallbackHandler(evutil_socket_t fd, short eventFlags, void * data); - - event_base * mEventBase; ///< libevent shared state. - - std::list> mTimers; - std::list mActiveTimers; - Mutex mTimerListMutex; - - std::list> mSocketWatches; - std::list mActiveSocketWatches; - - ObjectLifeCycle mLayerState; - WakeEvent mWakeEvent; - -#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING - std::atomic mHandleSelectThread; -#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING - -#if !__ZEPHYR__ - static void MdnsTimeoutCallbackHandler(evutil_socket_t fd, short eventFlags, void * data); - void MdnsTimeoutCallbackHandler(); -#endif // !__ZEPHYR__ - event * mMdnsTimeoutEvent; -}; - -using LayerImpl = LayerImplLibevent; - -} // namespace System -} // namespace chip