Skip to content

Commit 25fc34d

Browse files
Fix chip-tool threading asserts if an interactive command times out. (project-chip#29277)
* Fix chip-tool threading asserts if an interactive command times out. Since the Matter event loop is still running in interacive mode, we need to do the command cleanup on that event loop. * Fixes project-chip#29275 * Fixes project-chip#27535 * Address review comment.
1 parent 6991483 commit 25fc34d

File tree

6 files changed

+98
-27
lines changed

6 files changed

+98
-27
lines changed

examples/chip-tool/commands/common/CHIPCommand.cpp

+62-24
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <lib/support/CodeUtils.h>
2626
#include <lib/support/ScopedBuffer.h>
2727
#include <lib/support/TestGroupData.h>
28+
#include <platform/LockTracker.h>
2829

2930
#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
3031
#include "TraceDecoder.h"
@@ -222,17 +223,17 @@ CHIP_ERROR CHIPCommand::Run()
222223

223224
CHIP_ERROR err = StartWaiting(GetWaitDuration());
224225

225-
bool deferCleanup = (IsInteractive() && DeferInteractiveCleanup());
226-
227-
Shutdown();
228-
229-
if (deferCleanup)
226+
if (IsInteractive())
230227
{
231-
sDeferredCleanups.insert(this);
228+
bool timedOut;
229+
// Give it 2 hours to run our cleanup; that should never get hit in practice.
230+
CHIP_ERROR cleanupErr = RunOnMatterQueue(RunCommandCleanup, chip::System::Clock::Seconds16(7200), &timedOut);
231+
VerifyOrDie(cleanupErr == CHIP_NO_ERROR);
232+
VerifyOrDie(!timedOut);
232233
}
233234
else
234235
{
235-
Cleanup();
236+
CleanupAfterRun();
236237
}
237238

238239
MaybeTearDownStack();
@@ -504,6 +505,56 @@ void CHIPCommand::RunQueuedCommand(intptr_t commandArg)
504505
}
505506
}
506507

508+
void CHIPCommand::RunCommandCleanup(intptr_t commandArg)
509+
{
510+
auto * command = reinterpret_cast<CHIPCommand *>(commandArg);
511+
command->CleanupAfterRun();
512+
command->StopWaiting();
513+
}
514+
515+
void CHIPCommand::CleanupAfterRun()
516+
{
517+
assertChipStackLockedByCurrentThread();
518+
bool deferCleanup = (IsInteractive() && DeferInteractiveCleanup());
519+
520+
Shutdown();
521+
522+
if (deferCleanup)
523+
{
524+
sDeferredCleanups.insert(this);
525+
}
526+
else
527+
{
528+
Cleanup();
529+
}
530+
}
531+
532+
CHIP_ERROR CHIPCommand::RunOnMatterQueue(MatterWorkCallback callback, chip::System::Clock::Timeout timeout, bool * timedOut)
533+
{
534+
{
535+
std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
536+
mWaitingForResponse = true;
537+
}
538+
539+
auto err = chip::DeviceLayer::PlatformMgr().ScheduleWork(callback, reinterpret_cast<intptr_t>(this));
540+
if (CHIP_NO_ERROR != err)
541+
{
542+
{
543+
std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
544+
mWaitingForResponse = false;
545+
}
546+
return err;
547+
}
548+
549+
auto waitingUntil = std::chrono::system_clock::now() + std::chrono::duration_cast<std::chrono::seconds>(timeout);
550+
{
551+
std::unique_lock<std::mutex> lk(cvWaitingForResponseMutex);
552+
*timedOut = !cvWaitingForResponse.wait_until(lk, waitingUntil, [this]() { return !this->mWaitingForResponse; });
553+
}
554+
555+
return CHIP_NO_ERROR;
556+
}
557+
507558
#if !CONFIG_USE_SEPARATE_EVENTLOOP
508559
static void OnResponseTimeout(chip::System::Layer *, void * appState)
509560
{
@@ -526,28 +577,15 @@ CHIP_ERROR CHIPCommand::StartWaiting(chip::System::Clock::Timeout duration)
526577
}
527578
else
528579
{
529-
{
530-
std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
531-
mWaitingForResponse = true;
532-
}
533-
534-
auto err = chip::DeviceLayer::PlatformMgr().ScheduleWork(RunQueuedCommand, reinterpret_cast<intptr_t>(this));
580+
bool timedOut;
581+
CHIP_ERROR err = RunOnMatterQueue(RunQueuedCommand, duration, &timedOut);
535582
if (CHIP_NO_ERROR != err)
536583
{
537-
{
538-
std::lock_guard<std::mutex> lk(cvWaitingForResponseMutex);
539-
mWaitingForResponse = false;
540-
}
541584
return err;
542585
}
543-
544-
auto waitingUntil = std::chrono::system_clock::now() + std::chrono::duration_cast<std::chrono::seconds>(duration);
586+
if (timedOut)
545587
{
546-
std::unique_lock<std::mutex> lk(cvWaitingForResponseMutex);
547-
if (!cvWaitingForResponse.wait_until(lk, waitingUntil, [this]() { return !this->mWaitingForResponse; }))
548-
{
549-
mCommandExitStatus = CHIP_ERROR_TIMEOUT;
550-
}
588+
mCommandExitStatus = CHIP_ERROR_TIMEOUT;
551589
}
552590
}
553591
if (!IsInteractive())

examples/chip-tool/commands/common/CHIPCommand.h

+12
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,18 @@ class CHIPCommand : public Command
220220
static const chip::Credentials::AttestationTrustStore * sTrustStore;
221221

222222
static void RunQueuedCommand(intptr_t commandArg);
223+
typedef decltype(RunQueuedCommand) MatterWorkCallback;
224+
static void RunCommandCleanup(intptr_t commandArg);
225+
226+
// Do cleanup after a commmand is done running. Must happen with the
227+
// Matter stack locked.
228+
void CleanupAfterRun();
229+
230+
// Run the given callback on the Matter thread. Return whether we managed
231+
// to successfully dispatch it to the Matter thread. If we did, *timedOut
232+
// will be set to whether we timed out or whether our mWaitingForResponse
233+
// got set to false by the callback itself.
234+
CHIP_ERROR RunOnMatterQueue(MatterWorkCallback callback, chip::System::Clock::Timeout timeout, bool * timedOut);
223235

224236
CHIP_ERROR mCommandExitStatus = CHIP_ERROR_INTERNAL;
225237

src/app/CommandSender.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "InteractionModelEngine.h"
2727
#include "StatusResponse.h"
2828
#include <app/TimedRequest.h>
29+
#include <platform/LockTracker.h>
2930
#include <protocols/Protocols.h>
3031
#include <protocols/interaction_model/Constants.h>
3132

@@ -36,7 +37,14 @@ CommandSender::CommandSender(Callback * apCallback, Messaging::ExchangeManager *
3637
bool aSuppressResponse) :
3738
mExchangeCtx(*this),
3839
mpCallback(apCallback), mpExchangeMgr(apExchangeMgr), mSuppressResponse(aSuppressResponse), mTimedRequest(aIsTimedRequest)
39-
{}
40+
{
41+
assertChipStackLockedByCurrentThread();
42+
}
43+
44+
CommandSender::~CommandSender()
45+
{
46+
assertChipStackLockedByCurrentThread();
47+
}
4048

4149
CHIP_ERROR CommandSender::AllocateBuffer()
4250
{

src/app/CommandSender.h

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class CommandSender final : public Messaging::ExchangeDelegate
123123
*/
124124
CommandSender(Callback * apCallback, Messaging::ExchangeManager * apExchangeMgr, bool aIsTimedRequest = false,
125125
bool aSuppressResponse = false);
126+
~CommandSender();
126127
CHIP_ERROR PrepareCommand(const CommandPathParams & aCommandPathParams, bool aStartDataStruct = true);
127128
CHIP_ERROR FinishCommand(bool aEndDataStruct = true);
128129
TLV::TLVWriter * GetCommandDataIBTLVWriter();

src/app/ReadClient.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <lib/support/FibonacciUtils.h>
3333
#include <messaging/ReliableMessageMgr.h>
3434
#include <messaging/ReliableMessageProtocolConfig.h>
35+
#include <platform/LockTracker.h>
3536

3637
namespace chip {
3738
namespace app {
@@ -44,6 +45,8 @@ ReadClient::ReadClient(InteractionModelEngine * apImEngine, Messaging::ExchangeM
4445
mpCallback(apCallback), mOnConnectedCallback(HandleDeviceConnected, this),
4546
mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this)
4647
{
48+
assertChipStackLockedByCurrentThread();
49+
4750
mpExchangeMgr = apExchangeMgr;
4851
mInteractionType = aInteractionType;
4952

@@ -89,6 +92,8 @@ void ReadClient::StopResubscription()
8992

9093
ReadClient::~ReadClient()
9194
{
95+
assertChipStackLockedByCurrentThread();
96+
9297
if (IsSubscriptionType())
9398
{
9499
StopResubscription();

src/app/WriteClient.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <messaging/ExchangeHolder.h>
3737
#include <messaging/ExchangeMgr.h>
3838
#include <messaging/Flags.h>
39+
#include <platform/LockTracker.h>
3940
#include <protocols/Protocols.h>
4041
#include <system/SystemPacketBuffer.h>
4142
#include <system/TLVPacketBufferBackingStore.h>
@@ -127,16 +128,22 @@ class WriteClient : public Messaging::ExchangeDelegate
127128
mpExchangeMgr(apExchangeMgr),
128129
mExchangeCtx(*this), mpCallback(apCallback), mTimedWriteTimeoutMs(aTimedWriteTimeoutMs),
129130
mSuppressResponse(aSuppressResponse)
130-
{}
131+
{
132+
assertChipStackLockedByCurrentThread();
133+
}
131134

132135
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
133136
WriteClient(Messaging::ExchangeManager * apExchangeMgr, Callback * apCallback, const Optional<uint16_t> & aTimedWriteTimeoutMs,
134137
uint16_t aReservedSize) :
135138
mpExchangeMgr(apExchangeMgr),
136139
mExchangeCtx(*this), mpCallback(apCallback), mTimedWriteTimeoutMs(aTimedWriteTimeoutMs), mReservedSize(aReservedSize)
137-
{}
140+
{
141+
assertChipStackLockedByCurrentThread();
142+
}
138143
#endif
139144

145+
~WriteClient() { assertChipStackLockedByCurrentThread(); }
146+
140147
/**
141148
* Encode an attribute value that can be directly encoded using DataModel::Encode. Will create a new chunk when necessary.
142149
*/

0 commit comments

Comments
 (0)