Skip to content

Commit

Permalink
Pull up LayerLwIP::ScheduleLambda to SystemLayer (#11187)
Browse files Browse the repository at this point in the history
  • Loading branch information
kghost authored Nov 2, 2021
1 parent 94d0e9e commit 16cd474
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 65 deletions.
7 changes: 2 additions & 5 deletions src/include/platform/CHIPDeviceEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,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>
#include <lib/support/LambdaBridge.h>

namespace chip {
namespace DeviceLayer {
Expand All @@ -325,7 +322,7 @@ struct ChipDeviceEvent final
union
{
ChipDevicePlatformEvent Platform;
System::LambdaBridge LambdaEvent;
LambdaBridge LambdaEvent;
struct
{
::chip::System::EventType Type;
Expand Down
5 changes: 1 addition & 4 deletions src/include/platform/PlatformManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,9 @@

#include <platform/CHIPDeviceBuildConfig.h>
#include <platform/CHIPDeviceEvent.h>
#include <system/PlatformEventSupport.h>
#include <system/SystemLayer.h>

#if CHIP_SYSTEM_CONFIG_USE_LWIP
#include <system/LwIPEventSupport.h>
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP

namespace chip {

namespace Dnssd {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ void GenericPlatformManagerImpl<ImplClass>::_DispatchEvent(const ChipDeviceEvent
break;

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

case DeviceEventType::kCallWorkFunct:
Expand Down
53 changes: 53 additions & 0 deletions src/lib/support/LambdaBridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.
*/

#pragma once

#include <string.h>

#include <lib/core/CHIPConfig.h>

namespace chip {

class LambdaBridge
{
public:
// Use initialize instead of constructor because this class has to be trivial
template <typename Lambda>
void Initialize(const Lambda & lambda)
{
// 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, "lambda must be trivially copyable");
static_assert(sizeof(Lambda) <= CHIP_CONFIG_LAMBDA_EVENT_SIZE, "lambda too large");
static_assert(CHIP_CONFIG_LAMBDA_EVENT_ALIGN % alignof(Lambda) == 0, "lambda align too large");

// Implicit cast a capture-less lambda into a raw function pointer.
mLambdaProxy = [](const std::aligned_storage<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN> & body) {
(*reinterpret_cast<const Lambda *>(&body))();
};
memcpy(&mLambdaBody, &lambda, sizeof(Lambda));
}

void operator()() const { mLambdaProxy(mLambdaBody); }

private:
void (*mLambdaProxy)(const std::aligned_storage<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN> & body);
std::aligned_storage<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN> mLambdaBody;
};

static_assert(std::is_trivial<LambdaBridge>::value, "LambdaBridge is not trivial");

} // namespace chip
2 changes: 1 addition & 1 deletion src/platform/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ if (chip_device_platform != "none") {
"GeneralUtils.cpp",
"Globals.cpp",
"LockTracker.cpp",
"LwIPEventSupport.cpp",
"PersistedStorage.cpp",
"PlatformEventSupport.cpp",
"TestIdentity.cpp",
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ namespace System {

using namespace ::chip::DeviceLayer;

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

return PlatformMgr().PostEvent(&event);
}
Expand Down
3 changes: 2 additions & 1 deletion src/system/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ static_library("system") {
"SystemError.h",
"SystemEvent.h",
"SystemFaultInjection.h",
"SystemLayer.cpp",
"SystemLayer.h",
"SystemLayerImpl${chip_system_config_event_loop}.cpp",
"SystemLayerImpl${chip_system_config_event_loop}.h",
Expand Down Expand Up @@ -170,7 +171,7 @@ static_library("system") {
}

if (chip_system_config_use_lwip) {
sources += [ "LwIPEventSupport.h" ]
sources += [ "PlatformEventSupport.h" ]
}

if (chip_with_nlfaultinjection) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Object;
class PlatformEventing
{
public:
static CHIP_ERROR ScheduleLambdaBridge(System::Layer & aLayer, const LambdaBridge & bridge);
static CHIP_ERROR ScheduleLambdaBridge(System::Layer & aLayer, LambdaBridge && bridge);
static CHIP_ERROR PostEvent(System::Layer & aLayer, Object & aTarget, EventType aType, uintptr_t aArgument);
static CHIP_ERROR StartTimer(System::Layer & aLayer, System::Clock::Timeout aTimeout);
};
Expand Down
35 changes: 35 additions & 0 deletions src/system/SystemLayer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.
*/

#include <lib/support/CodeUtils.h>
#include <system/PlatformEventSupport.h>
#include <system/SystemLayer.h>

namespace chip {
namespace System {

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

} // namespace System
} // namespace chip
64 changes: 28 additions & 36 deletions src/system/SystemLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@

#pragma once

#include <type_traits>

// Include configuration headers
#include <system/SystemConfig.h>

#include <lib/core/CHIPCallback.h>

#include <lib/support/CodeUtils.h>
#include <lib/support/DLLUtil.h>
#include <lib/support/LambdaBridge.h>
#include <lib/support/ObjectLifeCycle.h>
#include <system/SystemClock.h>
#include <system/SystemError.h>
Expand All @@ -50,12 +53,6 @@
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 @@ -148,6 +145,31 @@ class DLL_EXPORT Layer
*/
virtual CHIP_ERROR ScheduleWork(TimerCompleteCallback aComplete, void * aAppState) = 0;

/**
* @brief
* Schedules a lambda even to be run as soon as possible in the CHIP context. This function is not thread-safe,
* it must be called with in the CHIP context
*
* @param[in] event A object encapsulate the context of a lambda
*
* @retval CHIP_NO_ERROR On success.
* @retval other Platform-specific errors generated indicating the reason for failure.
*/
CHIP_ERROR ScheduleLambdaBridge(LambdaBridge && event);

/**
* @brief
* Schedules a lambda object to be run as soon as possible in the CHIP context. This function is not thread-safe,
* it must be called with in the CHIP context
*/
template <typename Lambda>
CHIP_ERROR ScheduleLambda(const Lambda & lambda)
{
LambdaBridge bridge;
bridge.Initialize(lambda);
return ScheduleLambdaBridge(std::move(bridge));
}

private:
// Copy and assignment NOT DEFINED
Layer(const Layer &) = delete;
Expand Down Expand Up @@ -202,36 +224,6 @@ 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>
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);

// Implicit cast a capture-less lambda into a raw function pointer.
event.LambdaProxy = [](const void * body) { (*static_cast<const Lambda *>(body))(); };
memcpy(event.LambdaBody, &lambda, sizeof(Lambda));

return ScheduleLambdaBridge(event);
}

protected:
// Provide access to private members of EventHandlerDelegate.
struct LwIPEventHandlerDelegate : public EventHandlerDelegate
Expand Down
14 changes: 1 addition & 13 deletions src/system/SystemLayerImplLwIP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/

#include <lib/support/CodeUtils.h>
#include <system/LwIPEventSupport.h>
#include <system/PlatformEventSupport.h>
#include <system/SystemFaultInjection.h>
#include <system/SystemLayer.h>
#include <system/SystemLayerImplLwIP.h>
Expand Down Expand Up @@ -122,18 +122,6 @@ 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
1 change: 0 additions & 1 deletion src/system/SystemLayerImplLwIP.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ 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 Down

0 comments on commit 16cd474

Please sign in to comment.