Skip to content

Commit 8eaca94

Browse files
Decouple InteractionModelEngine from TimedHandler (project-chip#32076)
* Decouple TimedHandler.h/cpp from InteractionModelEngine * Restyle * Use override instead of virtual * Update comment - re-add a variant of the previous comment explaining why mTimeLimit is last * Pull in the IM pointers support, to make less RAM/BSS usage for embedded * Fix typo and kick restyler * Restyle * Previous align was better * fix name for handler --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com>
1 parent 274719d commit 8eaca94

11 files changed

+385
-41
lines changed

src/app/BUILD.gn

+11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ declare_args() {
4242
chip_im_force_fabric_quota_check = false
4343

4444
enable_eventlist_attribute = false
45+
46+
# Systems that can spare a bit of RAM for InteractionModelEngine/delegate
47+
# pointers should do so (allows InteractionModelEngine decoupling and less usage
48+
# of global pointers)
49+
chip_im_static_global_interaction_model_engine =
50+
current_os != "linux" && current_os != "mac" && current_os != "ios" &&
51+
current_os != "android"
4552
}
4653

4754
buildconfig_header("app_buildconfig") {
@@ -57,6 +64,7 @@ buildconfig_header("app_buildconfig") {
5764
"CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION=${chip_subscription_timeout_resumption}",
5865
"CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE=${enable_eventlist_attribute}",
5966
"CHIP_CONFIG_ENABLE_READ_CLIENT=${chip_enable_read_client}",
67+
"CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE=${chip_im_static_global_interaction_model_engine}",
6068
]
6169

6270
visibility = [ ":app_config" ]
@@ -129,6 +137,8 @@ static_library("interaction-model") {
129137
"CASESessionManager.h",
130138
"DeviceProxy.cpp",
131139
"DeviceProxy.h",
140+
"InteractionModelDelegatePointers.cpp",
141+
"InteractionModelDelegatePointers.h",
132142
"InteractionModelEngine.cpp",
133143
"InteractionModelEngine.h",
134144
"InteractionModelTimeout.h",
@@ -161,6 +171,7 @@ static_library("interaction-model") {
161171
"${chip_root}/src/app/icd/server:observer",
162172
"${chip_root}/src/lib/address_resolve",
163173
"${chip_root}/src/lib/support",
174+
"${chip_root}/src/lib/support:static-support",
164175
"${chip_root}/src/protocols/interaction_model",
165176
"${chip_root}/src/protocols/secure_channel",
166177
"${chip_root}/src/system",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
#include "InteractionModelDelegatePointers.h"
19+
20+
#if CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE
21+
22+
// TODO: It would be nice to not need to couple the pointers class
23+
// to the global interaction model engine
24+
#include "InteractionModelEngine.h"
25+
26+
namespace chip {
27+
28+
template <>
29+
app::TimedHandlerDelegate * GlobalInstanceProvider<app::TimedHandlerDelegate>::InstancePointer()
30+
{
31+
return app::InteractionModelEngine::GetInstance();
32+
}
33+
34+
} // namespace chip
35+
36+
#endif
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
#pragma once
19+
20+
#include <app/AppConfig.h>
21+
#include <lib/support/static_support_smart_ptr.h>
22+
23+
namespace chip {
24+
25+
#if CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE
26+
27+
template <class T>
28+
using InteractionModelDelegatePointer = chip::CheckedGlobalInstanceReference<T>;
29+
30+
#else
31+
32+
template <class T>
33+
using InteractionModelDelegatePointer = chip::SimpleInstanceReference<T>;
34+
35+
#endif // CHIP_CONFIG_STATIC_GLOBAL_INTERATION_MODEL_ENGINE
36+
37+
} // namespace chip

src/app/InteractionModelEngine.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ CHIP_ERROR InteractionModelEngine::OnTimedRequest(Messaging::ExchangeContext * a
840840
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload,
841841
Protocols::InteractionModel::Status & aStatus)
842842
{
843-
TimedHandler * handler = mTimedHandlers.CreateObject();
843+
TimedHandler * handler = mTimedHandlers.CreateObject(this);
844844
if (handler == nullptr)
845845
{
846846
ChipLogProgress(InteractionModel, "no resource for Timed interaction");

src/app/InteractionModelEngine.h

+6-19
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
8080
public CommandHandler::Callback,
8181
public ReadHandler::ManagementCallback,
8282
public FabricTable::Delegate,
83-
public SubscriptionsInfoProvider
83+
public SubscriptionsInfoProvider,
84+
public TimedHandlerDelegate
8485
{
8586
public:
8687
/**
@@ -218,26 +219,12 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
218219
}
219220
void UnregisterReadHandlerAppCallback() { mpReadHandlerApplicationCallback = nullptr; }
220221

221-
/**
222-
* Called when a timed interaction has failed (i.e. the exchange it was
223-
* happening on has closed while the exchange delegate was the timed
224-
* handler).
225-
*/
226-
void OnTimedInteractionFailed(TimedHandler * apTimedHandler);
227-
228-
/**
229-
* Called when a timed invoke is received. This function takes over all
230-
* handling of the exchange, status reporting, and so forth.
231-
*/
222+
// TimedHandlerDelegate implementation
223+
void OnTimedInteractionFailed(TimedHandler * apTimedHandler) override;
232224
void OnTimedInvoke(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext,
233-
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload);
234-
235-
/**
236-
* Called when a timed write is received. This function takes over all
237-
* handling of the exchange, status reporting, and so forth.
238-
*/
225+
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) override;
239226
void OnTimedWrite(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext,
240-
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload);
227+
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) override;
241228

242229
#if CHIP_CONFIG_ENABLE_READ_CLIENT
243230
/**

src/app/TimedHandler.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
*/
1818

1919
#include "TimedHandler.h"
20-
#include <app/InteractionModelEngine.h>
20+
#include <app/InteractionModelTimeout.h>
2121
#include <app/MessageDef/TimedRequestMessage.h>
2222
#include <app/StatusResponse.h>
2323
#include <lib/core/TLV.h>
@@ -74,19 +74,17 @@ CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchang
7474

7575
if (aPayloadHeader.HasMessageType(MsgType::InvokeCommandRequest))
7676
{
77-
auto * imEngine = InteractionModelEngine::GetInstance();
7877
ChipLogDetail(DataManagement, "Handing timed invoke to IM engine: handler %p exchange " ChipLogFormatExchange, this,
7978
ChipLogValueExchange(aExchangeContext));
80-
imEngine->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
79+
mDelegate->OnTimedInvoke(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
8180
return CHIP_NO_ERROR;
8281
}
8382

8483
if (aPayloadHeader.HasMessageType(MsgType::WriteRequest))
8584
{
86-
auto * imEngine = InteractionModelEngine::GetInstance();
8785
ChipLogDetail(DataManagement, "Handing timed write to IM engine: handler %p exchange " ChipLogFormatExchange, this,
8886
ChipLogValueExchange(aExchangeContext));
89-
imEngine->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
87+
mDelegate->OnTimedWrite(this, aExchangeContext, aPayloadHeader, std::move(aPayload));
9088
return CHIP_NO_ERROR;
9189
}
9290
}
@@ -101,7 +99,7 @@ CHIP_ERROR TimedHandler::OnMessageReceived(Messaging::ExchangeContext * aExchang
10199

102100
void TimedHandler::OnExchangeClosing(Messaging::ExchangeContext *)
103101
{
104-
InteractionModelEngine::GetInstance()->OnTimedInteractionFailed(this);
102+
mDelegate->OnTimedInteractionFailed(this);
105103
}
106104

107105
CHIP_ERROR TimedHandler::HandleTimedRequestAction(Messaging::ExchangeContext * aExchangeContext,

src/app/TimedHandler.h

+53-15
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,21 @@
1515
* See the License for the specific language governing permissions and
1616
* limitations under the License.
1717
*/
18-
19-
/**
20-
* @file
21-
* Definition of a handler for timed interactions.
22-
*
23-
*/
24-
2518
#pragma once
2619

20+
#include <app/InteractionModelDelegatePointers.h>
2721
#include <messaging/ExchangeContext.h>
2822
#include <messaging/ExchangeDelegate.h>
2923
#include <system/SystemClock.h>
3024
#include <system/SystemLayer.h>
3125
#include <system/SystemPacketBuffer.h>
3226
#include <transport/raw/MessageHeader.h>
3327

28+
namespace chip {
29+
namespace app {
30+
31+
class TimedHandler;
32+
3433
/**
3534
* A TimedHandler handles a Timed Request action and then waits for a
3635
* subsequent Invoke or Write action and hands those on to
@@ -43,14 +42,37 @@
4342
* either the exchange is closed or the interaction is handed on to the
4443
* InteractionModelEngine.
4544
*/
45+
class TimedHandlerDelegate
46+
{
47+
public:
48+
virtual ~TimedHandlerDelegate() = default;
4649

47-
namespace chip {
48-
namespace app {
50+
/**
51+
* Called when a timed invoke is received. This function takes over all
52+
* handling of the exchange, status reporting, and so forth.
53+
*/
54+
virtual void OnTimedInvoke(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext,
55+
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) = 0;
56+
57+
/**
58+
* Called when a timed write is received. This function takes over all
59+
* handling of the exchange, status reporting, and so forth.
60+
*/
61+
virtual void OnTimedWrite(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext,
62+
const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload) = 0;
63+
64+
/**
65+
* Called when a timed interaction has failed (i.e. the exchange it was
66+
* happening on has closed while the exchange delegate was the timed
67+
* handler).
68+
*/
69+
virtual void OnTimedInteractionFailed(TimedHandler * apTimedHandler) = 0;
70+
};
4971

5072
class TimedHandler : public Messaging::ExchangeDelegate
5173
{
5274
public:
53-
TimedHandler() {}
75+
TimedHandler(TimedHandlerDelegate * delegate) : mDelegate(delegate) {}
5476
~TimedHandler() override {}
5577

5678
// ExchangeDelegate implementation.
@@ -83,15 +105,31 @@ class TimedHandler : public Messaging::ExchangeDelegate
83105
kExpectingFollowingAction, // Expecting write or invoke.
84106
};
85107

86-
// Because we have a vtable pointer and mTimeLimit needs to be 8-byte
87-
// aligned on ARM, putting mState first here means we fit in 16 bytes on
88-
// 32-bit ARM, whereas if we put it second we'd be 24 bytes.
89-
// On platforms where either vtable pointers are 8 bytes or 64-bit ints can
90-
// be 4-byte-aligned the ordering here does not matter.
91108
State mState = State::kExpectingTimedAction;
109+
110+
/// This may be "fake" pointer or a real delegate pointer, depending
111+
/// on CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE setting.
112+
///
113+
/// When this is not a real pointer, it checks that the value is always
114+
/// set to the global InteractionModelEngine and the size of this
115+
/// member is 1 byte.
116+
InteractionModelDelegatePointer<TimedHandlerDelegate> mDelegate;
117+
92118
// We keep track of the time limit for message reception, in case our
93119
// exchange's "response expected" timer gets delayed and does not fire when
94120
// the time runs out.
121+
//
122+
// NOTE: mTimeLimit needs to be 8-byte aligned on ARM so we place this last,
123+
// to allow previous values to potentially use remaining packing space.
124+
// Rationale:
125+
// - vtable is 4-byte aligned on 32-bit arm
126+
// - mTimeLimit requires 8-byte aligment
127+
// => As a result we may gain 4 bytes if we place mTimeLimit last.
128+
// Expectation of memory layout:
129+
// - vtable pointer (4 bytes & 4 byte alignment)
130+
// - other members (2 bytes on embedded "global pointer" arm)
131+
// (2 bytes padding for 8-byte alignment)
132+
// - mTimeLimit (8 bytes & 8 byte alignment)
95133
System::Clock::Timestamp mTimeLimit;
96134
};
97135

src/lib/support/BUILD.gn

+4
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ source_set("type-traits") {
171171
sources = [ "TypeTraits.h" ]
172172
}
173173

174+
source_set("static-support") {
175+
sources = [ "static_support_smart_ptr.h" ]
176+
}
177+
174178
static_library("support") {
175179
output_name = "libSupportLayer"
176180

0 commit comments

Comments
 (0)