Skip to content

Commit 6437a59

Browse files
committed
pass an out pointer to capture function return result
1 parent 38d3ed7 commit 6437a59

File tree

3 files changed

+37
-40
lines changed

3 files changed

+37
-40
lines changed

src/lib/support/LambdaBridge.h

+20-26
Original file line numberDiff line numberDiff line change
@@ -28,47 +28,41 @@ class LambdaBridge
2828
public:
2929
// Use initialize instead of constructor because this class has to be trivial
3030
template <typename Lambda>
31-
void Initialize(const Lambda & lambda)
31+
void Initialize(const Lambda & lambda, CHIP_ERROR * Error_Value = nullptr)
3232
{
33+
// LambdaBridge accepts either Lambdas without arguments or those with `CHIP_ERROR *` as argument.
34+
mpError = Error_Value;
35+
3336
// memcpy is used to move the lambda into the event queue, so it must be trivially copyable
3437
static_assert(std::is_trivially_copyable<Lambda>::value, "lambda must be trivially copyable");
3538
static_assert(sizeof(Lambda) <= CHIP_CONFIG_LAMBDA_EVENT_SIZE, "lambda too large");
3639
static_assert(CHIP_CONFIG_LAMBDA_EVENT_ALIGN % alignof(Lambda) == 0, "lambda align too large");
3740

3841
// Implicit cast a capture-less lambda into a raw function pointer.
39-
if constexpr (std::is_same_v<decltype(lambda()), void>)
40-
{
41-
mLambdaVoidProxy = [](const LambdaStorage & body) { (*reinterpret_cast<const Lambda *>(&body))(); };
42-
}
43-
else if constexpr (std::is_same_v<decltype(lambda()), CHIP_ERROR>)
44-
{
45-
mLambdaProxy = [](const LambdaStorage & body) { return (*reinterpret_cast<const Lambda *>(&body))(); };
46-
}
42+
mLambdaProxy = [](const LambdaStorage & body, CHIP_ERROR * apError) {
43+
// Check if lambda has CHIP_ERROR * as argument, if not, call it without arguments
44+
if constexpr (std::is_invocable<Lambda, CHIP_ERROR *>::value)
45+
{
46+
// Call the lambda with CHIP_ERROR* argument
47+
(*reinterpret_cast<const Lambda *>(&body))(apError);
48+
}
49+
else
50+
{
51+
// Call the lambda with no arguments
52+
(*reinterpret_cast<const Lambda *>(&body))();
53+
}
54+
};
4755

4856
::memcpy(&mLambdaBody, &lambda, sizeof(Lambda));
4957
}
5058

51-
void operator()() const
52-
{
53-
if (mLambdaVoidProxy != nullptr)
54-
{
55-
mLambdaVoidProxy(mLambdaBody);
56-
}
57-
}
58-
CHIP_ERROR CallLambdaWithErrorReturn() const
59-
{
60-
if (mLambdaProxy != nullptr)
61-
{
62-
return mLambdaProxy(mLambdaBody);
63-
}
64-
return CHIP_ERROR_INTERNAL; // Return an error if the proxy is not for CHIP_ERROR
65-
}
59+
void operator()() const { mLambdaProxy(mLambdaBody, mpError); }
6660

6761
private:
6862
using LambdaStorage = std::aligned_storage_t<CHIP_CONFIG_LAMBDA_EVENT_SIZE, CHIP_CONFIG_LAMBDA_EVENT_ALIGN>;
69-
void (*mLambdaVoidProxy)(const LambdaStorage & body);
70-
CHIP_ERROR (*mLambdaProxy)(const LambdaStorage & body);
63+
void (*mLambdaProxy)(const LambdaStorage & body, CHIP_ERROR * mpError);
7164
LambdaStorage mLambdaBody;
65+
CHIP_ERROR * mpError;
7266
};
7367

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

src/platform/Linux/PlatformManagerImpl.cpp

+3-7
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ void PlatformManagerImpl::_Shutdown()
281281
}
282282

283283
#if CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
284-
CHIP_ERROR PlatformManagerImpl::_GLibMatterContextInvokeSync(LambdaBridge && bridge)
284+
void PlatformManagerImpl::_GLibMatterContextInvokeSync(LambdaBridge && bridge)
285285
{
286286
// Because of TSAN false positives, we need to use a mutex to synchronize access to all members of
287287
// the GLibMatterContextInvokeData object (including constructor and destructor). This is a temporary
@@ -301,22 +301,18 @@ CHIP_ERROR PlatformManagerImpl::_GLibMatterContextInvokeSync(LambdaBridge && bri
301301
std::unique_lock<std::mutex> lock_(PlatformMgrImpl().mGLibMainLoopCallbackIndirectionMutex);
302302

303303
lock_.unlock();
304-
auto result = data->bridge.CallLambdaWithErrorReturn();
304+
data->bridge();
305305
lock_.lock();
306306

307-
data->mDone = true;
308-
data->mFuncResult = result;
307+
data->mDone = true;
309308
data->mDoneCond.notify_one();
310309

311310
return G_SOURCE_REMOVE;
312311
},
313312
&invokeData, nullptr);
314313

315314
lock.lock();
316-
317315
invokeData.mDoneCond.wait(lock, [&invokeData]() { return invokeData.mDone; });
318-
319-
return invokeData.mFuncResult;
320316
}
321317
#endif // CHIP_DEVICE_CONFIG_WITH_GLIB_MAIN_LOOP
322318

src/platform/Linux/PlatformManagerImpl.h

+14-7
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,16 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener
6969
template <typename T>
7070
CHIP_ERROR GLibMatterContextInvokeSync(CHIP_ERROR (*func)(T *), T * userData)
7171
{
72-
auto lambda = [func, userData]() -> CHIP_ERROR { return func(userData); };
72+
CHIP_ERROR LambdaErrorReturn;
73+
74+
// wrapping the function pointer and userData into a Lambda, to be stored and passed as a LambdaBridge
75+
auto lambda = [func, userData](CHIP_ERROR * apErrorReturn) { *apErrorReturn = func(userData); };
7376

7477
LambdaBridge bridge;
75-
bridge.Initialize(lambda);
76-
return _GLibMatterContextInvokeSync(std::move(bridge));
78+
bridge.Initialize(lambda, &LambdaErrorReturn);
79+
_GLibMatterContextInvokeSync(std::move(bridge));
80+
81+
return LambdaErrorReturn;
7782
}
7883

7984
unsigned int GLibMatterContextAttachSource(GSource * source)
@@ -107,7 +112,6 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener
107112
struct GLibMatterContextInvokeData
108113
{
109114
LambdaBridge bridge;
110-
CHIP_ERROR mFuncResult;
111115
// Sync primitives to wait for the function to be executed
112116
std::condition_variable mDoneCond;
113117
bool mDone = false;
@@ -116,10 +120,13 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener
116120
/**
117121
* @brief Invoke a function on the Matter GLib context.
118122
*
119-
* @note This function does not provide type safety for the user data. Please,
120-
* use the GLibMatterContextInvokeSync() template function instead.
123+
* @param[in] bridge a LambdaBridge object that holds the lambda to be invoked within the GLib context.
124+
*
125+
* @note This function moves the LambdaBridge into the GLib context for invocation.
126+
* The LambdaBridge is created and initialised in GLibMatterContextInvokeSync().
127+
* use the GLibMatterContextInvokeSync() template function instead of this one.
121128
*/
122-
CHIP_ERROR _GLibMatterContextInvokeSync(LambdaBridge && bridge);
129+
void _GLibMatterContextInvokeSync(LambdaBridge && bridge);
123130

124131
// XXX: Mutex for guarding access to glib main event loop callback indirection
125132
// synchronization primitives. This is a workaround to suppress TSAN warnings.

0 commit comments

Comments
 (0)