blob: 810209ddc2031c519567b201d603e3e6cbaf5ee9 [file] [log] [blame]
/*
*
* Copyright (c) 2025 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 dispatch.
*/
#pragma once
#include "system/SystemConfig.h"
#include <lib/support/ObjectLifeCycle.h>
#include <system/SystemLayer.h>
#include <system/SystemTimer.h>
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
#include <mutex>
#include <vector>
#endif
namespace chip {
namespace System {
class LayerImplDispatch : public LayerDispatch
{
public:
LayerImplDispatch() = default;
~LayerImplDispatch() override { VerifyOrDie(mLayerState.Destroy()); }
// Layer overrides.
CriticalFailure Init() override;
void Shutdown() override;
bool IsInitialized() const override { return mLayerState.IsInitialized(); }
CriticalFailure StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
CHIP_ERROR ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override;
Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override;
void CancelTimer(TimerCompleteCallback onComplete, void * appState) override;
CriticalFailure ScheduleWork(TimerCompleteCallback onComplete, void * appState) override;
// LayerDispatch overrides.
void SetDispatchQueue(dispatch_queue_t dispatchQueue) override { mDispatchQueue = dispatchQueue; };
dispatch_queue_t GetDispatchQueue() override { return mDispatchQueue; };
void HandleDispatchQueueEvents(Clock::Timeout timeout) override;
CriticalFailure ScheduleWorkWithBlock(dispatch_block_t block) override;
CriticalFailure StartTimerWithBlock(dispatch_block_t block, Clock::Timeout delay) override;
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
// LayerSockets 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<SocketWatchToken>(nullptr); }
#endif
protected:
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
struct SelectSets
{
fd_set mReadSet;
fd_set mWriteSet;
fd_set mErrorSet;
};
struct SocketWatch
{
int mFD;
SocketEvents mPendingIO;
SocketWatchCallback mCallback;
intptr_t mCallbackData;
dispatch_source_t mRdSource = nullptr;
dispatch_source_t mWrSource = nullptr;
bool IsActive() const { return mFD != kInvalidFd; }
void PrepareEvents(SelectSets & sets, int & maxFd) const;
void HandleEvents(const SelectSets & sets) const;
void Clear();
};
class SocketWatchPool
{
public:
CHIP_ERROR Allocate(int fd, SocketWatch *& outWatch);
CHIP_ERROR Release(SocketWatch * watch);
void Clear();
bool PrepareEvents(SelectSets & sets, timeval timeout) const;
void HandleEvents(const SelectSets & sets) const;
private:
static constexpr int kSocketWatchMax = (INET_CONFIG_ENABLE_TCP_ENDPOINT ? INET_CONFIG_NUM_TCP_ENDPOINTS : 0) +
(INET_CONFIG_ENABLE_UDP_ENDPOINT ? INET_CONFIG_NUM_UDP_ENDPOINTS : 0);
SocketWatch mPool[kSocketWatchMax];
};
SocketWatchPool mSocketWatchPool;
void HandleSocketsAndTimerEvents(Clock::Timeout timeout);
CHIP_ERROR RequestCallback(SocketWatchToken token, SocketEventFlags flag);
CHIP_ERROR ClearCallback(SocketWatchToken token, SocketEventFlags flag);
#endif
TimerPool<TimerList::Node> mTimerPool;
TimerList mTimerList;
// List of expired timers being processed right now. Stored in a member so
// we can cancel them.
TimerList mExpiredTimers;
void EnableTimer(const char * source, TimerList::Node *);
void DisableTimer(const char * source, TimerList::Node *);
CriticalFailure StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState, bool shouldCancel);
void HandleTimerEvents(Clock::Timeout timeout);
ObjectLifeCycle mLayerState;
dispatch_queue_t mDispatchQueue = nullptr;
private:
inline bool HasTimerSource(TimerList::Node * timer)
{
#if !CONFIG_BUILD_FOR_HOST_UNIT_TEST
VerifyOrDie(nullptr != timer->mTimerSource);
#endif
return nullptr != timer->mTimerSource;
}
inline bool HasDispatchQueue(dispatch_queue_t queue)
{
#if !CONFIG_BUILD_FOR_HOST_UNIT_TEST
VerifyOrDie(nullptr != queue);
#endif
return nullptr != queue;
}
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
std::mutex mTestQueueMutex;
std::vector<dispatch_block_t> mTestQueuedBlocks;
#endif
};
using LayerImpl = LayerImplDispatch;
} // namespace System
} // namespace chip