Skip to content

Commit

Permalink
SystemLayer::PostEvent add API to post a lambda event
Browse files Browse the repository at this point in the history
  • Loading branch information
kghost committed Sep 16, 2021
1 parent 8e86c9e commit 03efc11
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 49 deletions.
3 changes: 3 additions & 0 deletions src/include/platform/CHIPDeviceEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ enum InternalEventTypes
kEventTypeNotSet = kRange_Internal,
kNoOp,
kCallWorkFunct,
kChipLambdaEvent,
kChipSystemLayerEvent,
kCHIPoBLESubscribe,
kCHIPoBLEUnsubscribe,
Expand Down Expand Up @@ -302,6 +303,7 @@ typedef void (*AsyncWorkFunct)(intptr_t arg);
#include <ble/BleConfig.h>
#include <inet/InetLayer.h>
#include <system/SystemEvent.h>
#include <system/SystemLayer.h>
#include <system/SystemObject.h>
#include <system/SystemPacketBuffer.h>

Expand All @@ -318,6 +320,7 @@ struct ChipDeviceEvent final
union
{
ChipDevicePlatformEvent Platform;
System::LambdaBridge LambdaEvent;
struct
{
::chip::System::EventType Type;
Expand Down
4 changes: 4 additions & 0 deletions src/include/platform/internal/GenericPlatformManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ void GenericPlatformManagerImpl<ImplClass>::_DispatchEvent(const ChipDeviceEvent
Impl()->DispatchEventToSystemLayer(event);
break;

case DeviceEventType::kChipLambdaEvent:
event->LambdaEvent.LambdaProxy(static_cast<const void *>(event->LambdaEvent.LambdaBody));
break;

case DeviceEventType::kCallWorkFunct:
// If the event is a "call work function" event, call the specified function.
event->CallWorkFunct.WorkFunct(event->CallWorkFunct.Arg);
Expand Down
18 changes: 18 additions & 0 deletions src/lib/core/CHIPConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -2470,6 +2470,24 @@ extern const char CHIP_NON_PRODUCTION_MARKER[];
#define CHIP_DEVICE_CONTROLLER_SUBSCRIPTION_ATTRIBUTE_PATH_POOL_SIZE CHIP_IM_MAX_NUM_READ_CLIENT
#endif

/**
* @def CHIP_CONFIG_LAMBDA_EVENT_SIZE
*
* @brief The maximum size of the lambda which can be post into system event queue.
*/
#ifndef CHIP_CONFIG_LAMBDA_EVENT_SIZE
#define CHIP_CONFIG_LAMBDA_EVENT_SIZE (16)
#endif

/**
* @def CHIP_CONFIG_LAMBDA_EVENT_ALIGN
*
* @brief The maximum alignment of the lambda which can be post into system event queue.
*/
#ifndef CHIP_CONFIG_LAMBDA_EVENT_ALIGN
#define CHIP_CONFIG_LAMBDA_EVENT_ALIGN (sizeof(void *))
#endif

/**
* @}
*/
11 changes: 11 additions & 0 deletions src/platform/LwIPEventSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
/* this file behaves like a config.h, comes first */
#include <platform/internal/CHIPDeviceLayerInternal.h>

#include <type_traits>

#include <platform/PlatformManager.h>

#if CHIP_SYSTEM_CONFIG_USE_LWIP
Expand All @@ -34,6 +36,15 @@ namespace System {

using namespace ::chip::DeviceLayer;

CHIP_ERROR PlatformEventing::ScheduleLambdaBridge(System::Layer & aLayer, const LambdaBridge & bridge)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kChipLambdaEvent;
event.LambdaEvent = bridge;

return PlatformMgr().PostEvent(&event);
}

CHIP_ERROR PlatformEventing::PostEvent(System::Layer & aLayer, System::Object & aTarget, System::EventType aType,
uintptr_t aArgument)
{
Expand Down
2 changes: 2 additions & 0 deletions src/system/LwIPEventSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <lib/core/CHIPError.h>
#include <system/SystemEvent.h>
#include <system/SystemLayer.h>

namespace chip {
namespace System {
Expand All @@ -28,6 +29,7 @@ class Object;
class PlatformEventing
{
public:
static CHIP_ERROR ScheduleLambdaBridge(System::Layer & aLayer, const LambdaBridge & bridge);
static CHIP_ERROR PostEvent(System::Layer & aLayer, Object & aTarget, EventType aType, uintptr_t aArgument);
static CHIP_ERROR DispatchEvents(System::Layer & aLayer);
static CHIP_ERROR DispatchEvent(System::Layer & aLayer, Event aEvent);
Expand Down
10 changes: 0 additions & 10 deletions src/system/SystemEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,6 @@ typedef CHIP_SYSTEM_CONFIG_EVENT_OBJECT_TYPE Event;

#if CHIP_SYSTEM_CONFIG_USE_LWIP

/**
* The Inet layer event type definitions.
*
*/
enum
{
kEvent_ReleaseObj = _CHIP_SYSTEM_CONFIG_LWIP_EVENT(0), /**< The event for the drop of a System::Layer object */
kEvent_ScheduleWork = _CHIP_SYSTEM_CONFIG_LWIP_EVENT(1), /**< The event for scheduling work on the System Layer's thread. */
};

#endif // CHIP_SYSTEM_CONFIG_USE_LWIP

} // namespace System
Expand Down
42 changes: 42 additions & 0 deletions src/system/SystemLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
namespace chip {
namespace System {

struct LambdaBridge
{
void (*LambdaProxy)(const void * context);
alignas(CHIP_CONFIG_LAMBDA_EVENT_ALIGN) char LambdaBody[CHIP_CONFIG_LAMBDA_EVENT_SIZE];
};

class Layer;
using TimerCompleteCallback = void (*)(Layer * aLayer, void * appState);

Expand Down Expand Up @@ -195,6 +201,42 @@ class LayerLwIP : public Layer
*/
virtual CHIP_ERROR PostEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument) = 0;

/**
* This posts an event / message of the specified type with the provided argument to this instance's platform-specific event
* queue.
*
* @param[in] event A object encapsulate the context of a lambda
*
* @retval CHIP_NO_ERROR On success.
* @retval CHIP_ERROR_INCORRECT_STATE If the state of the Layer object is incorrect.
* @retval CHIP_ERROR_NO_MEMORY If the event queue is already full.
* @retval other Platform-specific errors generated indicating the reason for failure.
*/
virtual CHIP_ERROR ScheduleLambdaBridge(const LambdaBridge & event) = 0;

template <typename Lambda>
class LambdaProxy
{
public:
static void Call(const void * body) { (*static_cast<const Lambda *>(body))(); }
};

template <typename Lambda>
CHIP_ERROR ScheduleLambda(const Lambda & lambda)
{
LambdaBridge event;

// memcpy is used to move the lambda into the event queue, so it must be trivially copyable
static_assert(std::is_trivially_copyable<Lambda>::value);
static_assert(sizeof(Lambda) <= CHIP_CONFIG_LAMBDA_EVENT_SIZE);
static_assert(alignof(Lambda) <= CHIP_CONFIG_LAMBDA_EVENT_ALIGN);

event.LambdaProxy = &LambdaProxy<Lambda>::Call;
memcpy(event.LambdaBody, &lambda, sizeof(Lambda));

return ScheduleLambdaBridge(event);
}

protected:
// Provide access to private members of EventHandlerDelegate.
struct LwIPEventHandlerDelegate : public EventHandlerDelegate
Expand Down
48 changes: 14 additions & 34 deletions src/system/SystemLayerImplLwIP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,14 @@
namespace chip {
namespace System {

LayerLwIP::EventHandlerDelegate LayerImplLwIP::sSystemEventHandlerDelegate;

LayerImplLwIP::LayerImplLwIP() : mHandlingTimerComplete(false), mEventDelegateList(nullptr)
{
if (!sSystemEventHandlerDelegate.IsInitialized())
sSystemEventHandlerDelegate.Init(HandleSystemLayerEvent);
}
LayerImplLwIP::LayerImplLwIP() : mHandlingTimerComplete(false), mEventDelegateList(nullptr) {}

CHIP_ERROR LayerImplLwIP::Init()
{
VerifyOrReturnError(!mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);

RegisterLwIPErrorFormatter();

AddEventHandlerDelegate(sSystemEventHandlerDelegate);
ReturnErrorOnFailure(mTimerList.Init());

VerifyOrReturnError(mLayerState.Init(), CHIP_ERROR_INCORRECT_STATE);
Expand Down Expand Up @@ -100,7 +93,7 @@ CHIP_ERROR LayerImplLwIP::ScheduleWork(TimerCompleteCallback onComplete, void *
Timer * timer = Timer::New(*this, 0, onComplete, appState);
VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);

return PostEvent(*timer, chip::System::kEvent_ScheduleWork, 0);
return ScheduleLambda([timer] { timer->HandleComplete(); });
}

bool LayerLwIP::EventHandlerDelegate::IsInitialized() const
Expand All @@ -120,31 +113,6 @@ void LayerLwIP::EventHandlerDelegate::Prepend(const LayerLwIP::EventHandlerDeleg
aDelegateList = this;
}

/**
* This is the dispatch handler for system layer events.
*
* @param[in,out] aTarget A pointer to the CHIP System Layer object making the post request.
* @param[in] aEventType The type of event to post.
* @param[in,out] aArgument The argument associated with the event to post.
*/
CHIP_ERROR LayerImplLwIP::HandleSystemLayerEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument)
{
// Dispatch logic specific to the event type
switch (aEventType)
{
case kEvent_ReleaseObj:
aTarget.Release();
return CHIP_NO_ERROR;

case kEvent_ScheduleWork:
static_cast<Timer &>(aTarget).HandleComplete();
return CHIP_NO_ERROR;

default:
return CHIP_ERROR_UNEXPECTED_EVENT;
}
}

CHIP_ERROR LayerImplLwIP::AddEventHandlerDelegate(EventHandlerDelegate & aDelegate)
{
LwIPEventHandlerDelegate & lDelegate = static_cast<LwIPEventHandlerDelegate &>(aDelegate);
Expand All @@ -153,6 +121,18 @@ CHIP_ERROR LayerImplLwIP::AddEventHandlerDelegate(EventHandlerDelegate & aDelega
return CHIP_NO_ERROR;
}

CHIP_ERROR LayerImplLwIP::ScheduleLambdaBridge(const LambdaBridge & bridge)
{
VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);

CHIP_ERROR lReturn = PlatformEventing::ScheduleLambdaBridge(*this, bridge);
if (lReturn != CHIP_NO_ERROR)
{
ChipLogError(chipSystemLayer, "Failed to queue CHIP System Layer lambda event: %s", ErrorStr(lReturn));
}
return lReturn;
}

CHIP_ERROR LayerImplLwIP::PostEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument)
{
VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
Expand Down
5 changes: 1 addition & 4 deletions src/system/SystemLayerImplLwIP.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class LayerImplLwIP : public LayerLwIP

// LayerLwIP overrides.
CHIP_ERROR AddEventHandlerDelegate(EventHandlerDelegate & aDelegate);
CHIP_ERROR ScheduleLambdaBridge(const LambdaBridge & bridge) override;
CHIP_ERROR PostEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument);

public:
Expand All @@ -55,13 +56,9 @@ class LayerImplLwIP : public LayerLwIP
private:
friend class PlatformEventing;

static CHIP_ERROR HandleSystemLayerEvent(Object & aTarget, EventType aEventType, uintptr_t aArgument);

CHIP_ERROR DispatchEvent(Event aEvent);
CHIP_ERROR StartPlatformTimer(uint32_t aDelayMilliseconds);

static EventHandlerDelegate sSystemEventHandlerDelegate;

Timer::MutexedList mTimerList;
bool mHandlingTimerComplete; // true while handling any timer completion
const EventHandlerDelegate * mEventDelegateList;
Expand Down
2 changes: 1 addition & 1 deletion src/system/SystemObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ void Object::DeferredRelease(LayerLwIP * aSystemLayer, Object::ReleaseDeferralEr
{
VerifyOrReturn(aSystemLayer != nullptr, ChipLogError(chipSystemLayer, "aSystemLayer is nullptr"));

CHIP_ERROR lError = aSystemLayer->PostEvent(*this, chip::System::kEvent_ReleaseObj, 0);
CHIP_ERROR lError = aSystemLayer->ScheduleLambda([this] { this->Release(); });

if (lError != CHIP_NO_ERROR)
{
Expand Down

0 comments on commit 03efc11

Please sign in to comment.