Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix data races in chip-tool on Darwin #7829

Merged
merged 4 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 105 additions & 105 deletions examples/chip-tool/commands/clusters/Commands.h

Large diffs are not rendered by default.

31 changes: 7 additions & 24 deletions examples/chip-tool/commands/clusters/ModelCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@

using namespace ::chip;

namespace {
constexpr uint16_t kWaitDurationInSeconds = 10;
} // namespace

void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId,
chip::TLV::TLVReader & aReader, Command * apCommandObj)
{
Expand All @@ -37,29 +33,16 @@ void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aC
"Default DispatchSingleClusterCommand is called, this should be replaced by actual dispatched for cluster commands");
}

CHIP_ERROR ModelCommand::Run(NodeId localId, NodeId remoteId)
CHIP_ERROR ModelCommand::Run()
{
CHIP_ERROR err = CHIP_NO_ERROR;

//
// Set this to true first BEFORE we send commands to ensure we don't
// end up in a situation where the response comes back faster than we can
// set the variable to true, which will cause it to block indefinitely.
//
UpdateWaitForResponse(true);

{
chip::DeviceLayer::StackLock lock;

err = GetExecContext()->commissioner->GetConnectedDevice(remoteId, &mOnDeviceConnectedCallback,
&mOnDeviceConnectionFailureCallback);
VerifyOrExit(err == CHIP_NO_ERROR,
ChipLogError(chipTool, "Failed in initiating connection to the device: %" PRIu64 ", error %d", remoteId, err));
}

WaitForResponse(kWaitDurationInSeconds);
auto * ctx = GetExecContext();

VerifyOrExit(GetCommandExitStatus(), err = CHIP_ERROR_INTERNAL);
err = ctx->commissioner->GetConnectedDevice(ctx->remoteId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
VerifyOrExit(
err == CHIP_NO_ERROR,
ChipLogError(chipTool, "Failed in initiating connection to the device: %" PRIu64 ", error %d", ctx->remoteId, err));

exit:
return err;
Expand All @@ -78,5 +61,5 @@ void ModelCommand::OnDeviceConnectionFailureFn(void * context, NodeId deviceId,
ModelCommand * command = reinterpret_cast<ModelCommand *>(context);
ChipLogError(chipTool, "Failed in connecting to the device %" PRIu64 ". Error %d", deviceId, error);
VerifyOrReturn(command != nullptr, ChipLogError(chipTool, "ModelCommand context is null"));
command->SetCommandExitStatus(false);
command->SetCommandExitStatus(error);
}
3 changes: 2 additions & 1 deletion examples/chip-tool/commands/clusters/ModelCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class ModelCommand : public Command
void AddArguments() { AddArgument("endpoint-id", CHIP_ZCL_ENDPOINT_MIN, CHIP_ZCL_ENDPOINT_MAX, &mEndPointId); }

/////////// Command Interface /////////
CHIP_ERROR Run(NodeId localId, NodeId remoteId) override;
CHIP_ERROR Run() override;
uint16_t GetWaitDurationInSeconds() const override { return 10; }

virtual CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endPointId) = 0;

Expand Down
25 changes: 20 additions & 5 deletions examples/chip-tool/commands/common/Command.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class Command
ChipDeviceCommissioner * commissioner;
chip::Controller::ExampleOperationalCredentialsIssuer * opCredsIssuer;
PersistentStorage * storage;
chip::NodeId localId;
chip::NodeId remoteId;
};

Command(const char * commandName) : mName(commandName) {}
Expand Down Expand Up @@ -162,10 +164,23 @@ class Command
return AddArgument(name, min, max, reinterpret_cast<void *>(out), Number_uint64);
}

virtual CHIP_ERROR Run(NodeId localId, NodeId remoteId) = 0;
// Will be called in a setting in which it's safe to touch the CHIP
// stack. The rules for Run() are as follows:
//
// 1) If error is returned, Run() must not call SetCommandExitStatus.
// 2) If success is returned Run() must either have called
// SetCommandExitStatus() or scheduled async work that will do that.
virtual CHIP_ERROR Run() = 0;

bool GetCommandExitStatus() const { return mCommandExitStatus; }
void SetCommandExitStatus(bool status)
// Get the wait duration, in seconds, before the command times out.
virtual uint16_t GetWaitDurationInSeconds() const = 0;

// Shut down the command, in case any work needs to be done after the event
// loop has been stopped.
virtual void Shutdown() {}

CHIP_ERROR GetCommandExitStatus() const { return mCommandExitStatus; }
void SetCommandExitStatus(CHIP_ERROR status)
{
mCommandExitStatus = status;
UpdateWaitForResponse(false);
Expand All @@ -183,8 +198,8 @@ class Command
size_t AddArgument(const char * name, int64_t min, uint64_t max, void * out, ArgumentType type);
size_t AddArgument(const char * name, int64_t min, uint64_t max, void * out);

bool mCommandExitStatus = false;
const char * mName = nullptr;
CHIP_ERROR mCommandExitStatus = CHIP_ERROR_INTERNAL;
const char * mName = nullptr;
std::vector<Argument> mArgs;

std::condition_variable cvWaitingForResponse;
Expand Down
35 changes: 31 additions & 4 deletions examples/chip-tool/commands/common/Commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ int Commands::Run(NodeId localId, NodeId remoteId, int argc, char ** argv)
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::Controller::CommissionerInitParams initParams;
Command * command = nullptr;

err = chip::Platform::MemoryInit();
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Memory failure: %s", chip::ErrorStr(err)));
Expand Down Expand Up @@ -72,14 +73,19 @@ int Commands::Run(NodeId localId, NodeId remoteId, int argc, char ** argv)
err = mController.ServiceEvents();
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Run Loop: %s", chip::ErrorStr(err)));

err = RunCommand(localId, remoteId, argc, argv);
err = RunCommand(localId, remoteId, argc, argv, &command);
SuccessOrExit(err);

exit:
#if CONFIG_DEVICE_LAYER
chip::DeviceLayer::PlatformMgr().StopEventLoopTask();
#endif

if (command)
{
command->Shutdown();
}

//
// We can call DeviceController::Shutdown() safely without grabbing the stack lock
// since the CHIP thread and event queue have been stopped, preventing any thread
Expand All @@ -90,7 +96,7 @@ int Commands::Run(NodeId localId, NodeId remoteId, int argc, char ** argv)
return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE;
}

CHIP_ERROR Commands::RunCommand(NodeId localId, NodeId remoteId, int argc, char ** argv)
CHIP_ERROR Commands::RunCommand(NodeId localId, NodeId remoteId, int argc, char ** argv, Command ** ranCommand)
{
CHIP_ERROR err = CHIP_NO_ERROR;
std::map<std::string, CommandsVector>::iterator cluster;
Expand Down Expand Up @@ -158,10 +164,21 @@ CHIP_ERROR Commands::RunCommand(NodeId localId, NodeId remoteId, int argc, char
execContext.commissioner = &mController;
execContext.opCredsIssuer = &mOpCredsIssuer;
execContext.storage = &mStorage;
execContext.localId = localId;
execContext.remoteId = remoteId;
woody-apple marked this conversation as resolved.
Show resolved Hide resolved

command->SetExecutionContext(execContext);

err = command->Run(localId, remoteId);
*ranCommand = command;

//
// Set this to true first BEFORE we send commands to ensure we don't end
// up in a situation where the response comes back faster than we can
// set the variable to true, which will cause it to block indefinitely.
//
command->UpdateWaitForResponse(true);
chip::DeviceLayer::PlatformMgr().ScheduleWork(RunQueuedCommand, reinterpret_cast<intptr_t>(command));
command->WaitForResponse(command->GetWaitDurationInSeconds());
err = command->GetCommandExitStatus();
if (err != CHIP_NO_ERROR)
{
ChipLogError(chipTool, "Run command failure: %s", chip::ErrorStr(err));
Expand All @@ -173,6 +190,16 @@ CHIP_ERROR Commands::RunCommand(NodeId localId, NodeId remoteId, int argc, char
return err;
}

void Commands::RunQueuedCommand(intptr_t commandArg)
{
auto * command = reinterpret_cast<Command *>(commandArg);
CHIP_ERROR err = command->Run();
if (err != CHIP_NO_ERROR)
{
command->SetCommandExitStatus(err);
}
}

std::map<std::string, Commands::CommandsVector>::iterator Commands::GetCluster(std::string clusterName)
{
for (auto & cluster : mClusters)
Expand Down
6 changes: 5 additions & 1 deletion examples/chip-tool/commands/common/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ class Commands
int Run(NodeId localId, NodeId remoteId, int argc, char ** argv);

private:
CHIP_ERROR RunCommand(NodeId localId, NodeId remoteId, int argc, char ** argv);
// *ranCommand will be set to the command we ran if we get as far as running
// it. If it's not null, we need to call Shutdown() on the command after we
// shut down the event loop.
CHIP_ERROR RunCommand(NodeId localId, NodeId remoteId, int argc, char ** argv, Command ** ranCommand);
static void RunQueuedCommand(intptr_t commandArg);
std::map<std::string, CommandsVector>::iterator GetCluster(std::string clusterName);
Command * GetCommand(CommandsVector & commands, std::string commandName);
Command * GetGlobalCommand(CommandsVector & commands, std::string commandName, std::string attributeName);
Expand Down
6 changes: 3 additions & 3 deletions examples/chip-tool/commands/discover/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ class Resolve : public DiscoverCommand, public chip::Mdns::ResolverDelegate
nodeData.mAddress.ToString(addrBuffer);
ChipLogProgress(chipTool, "NodeId Resolution: %" PRIu64 " Address: %s, Port: %" PRIu16, nodeData.mPeerId.GetNodeId(),
addrBuffer, nodeData.mPort);
SetCommandExitStatus(true);
SetCommandExitStatus(CHIP_NO_ERROR);
}

void OnNodeIdResolutionFailed(const chip::PeerId & peerId, CHIP_ERROR error) override
{
ChipLogProgress(chipTool, "NodeId Resolution: failed!");
SetCommandExitStatus(false);
SetCommandExitStatus(CHIP_ERROR_INTERNAL);
}
void OnNodeDiscoveryComplete(const chip::Mdns::DiscoveredNodeData & nodeData) override {}
};
Expand Down Expand Up @@ -82,7 +82,7 @@ class Update : public DiscoverCommand
ChipLogError(chipTool, "Failed to update the device address: %s", chip::ErrorStr(error));
}

SetCommandExitStatus(CHIP_NO_ERROR == error);
SetCommandExitStatus(error);
}
};

Expand Down
33 changes: 3 additions & 30 deletions examples/chip-tool/commands/discover/DiscoverCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,8 @@

#include "DiscoverCommand.h"

constexpr uint16_t kWaitDurationInSeconds = 30;

CHIP_ERROR DiscoverCommand::Run(NodeId localId, NodeId remoteId)
CHIP_ERROR DiscoverCommand::Run()
{
CHIP_ERROR err;

//
// Set this to true first BEFORE we send commands to ensure we don't
// end up in a situation where the response comes back faster than we can
// set the variable to true, which will cause it to block indefinitely.
//
UpdateWaitForResponse(true);

{
chip::DeviceLayer::StackLock lock;

GetExecContext()->commissioner->RegisterDeviceAddressUpdateDelegate(this);
err = RunCommand(mNodeId, mFabricId);
SuccessOrExit(err);
}

WaitForResponse(kWaitDurationInSeconds);

exit:
if (err != CHIP_NO_ERROR)
{
return err;
}

VerifyOrReturnError(GetCommandExitStatus(), CHIP_ERROR_INTERNAL);
return CHIP_NO_ERROR;
GetExecContext()->commissioner->RegisterDeviceAddressUpdateDelegate(this);
return RunCommand(mNodeId, mFabricId);
}
3 changes: 2 additions & 1 deletion examples/chip-tool/commands/discover/DiscoverCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class DiscoverCommand : public Command, public chip::Controller::DeviceAddressUp
void OnAddressUpdateComplete(NodeId nodeId, CHIP_ERROR error) override{};

/////////// Command Interface /////////
CHIP_ERROR Run(NodeId localId, NodeId remoteId) override;
CHIP_ERROR Run() override;
uint16_t GetWaitDurationInSeconds() const override { return 30; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Just wondering about the different GetWaitDurationInSeconds values here and in following command interfaces. How were they determined?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bzbarsky-apple can you follow up here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept the existing values, which I suspect were determined by "this should not take longer than, oh I guess this long" or so.


virtual CHIP_ERROR RunCommand(NodeId remoteId, uint64_t fabricId) = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,13 @@

using namespace ::chip;

constexpr uint16_t kWaitDurationInSeconds = 3;

CHIP_ERROR DiscoverCommissionersCommand::Run(NodeId localId, NodeId remoteId)
CHIP_ERROR DiscoverCommissionersCommand::Run()
{
//
// Set this to true first BEFORE we send commands to ensure we don't
// end up in a situation where the response comes back faster than we can
// set the variable to true, which will cause it to block indefinitely.
//
UpdateWaitForResponse(true);

{
chip::DeviceLayer::StackLock lock;

ReturnErrorOnFailure(mCommissionableNodeController.DiscoverCommissioners());
}

WaitForResponse(kWaitDurationInSeconds);
return mCommissionableNodeController.DiscoverCommissioners();
}

void DiscoverCommissionersCommand::Shutdown()
{
int commissionerCount = 0;
for (int i = 0; i < CHIP_DEVICE_CONFIG_MAX_DISCOVERED_NODES; i++)
{
Expand Down Expand Up @@ -86,6 +74,5 @@ CHIP_ERROR DiscoverCommissionersCommand::Run(NodeId localId, NodeId remoteId)
}
}

printf("Total of %d commissioner(s) discovered in %d sec\n", commissionerCount, kWaitDurationInSeconds);
return CHIP_NO_ERROR;
printf("Total of %d commissioner(s) discovered in %" PRIu16 " sec\n", commissionerCount, GetWaitDurationInSeconds());
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class DiscoverCommissionersCommand : public Command
{
public:
DiscoverCommissionersCommand() : Command("discover-commissioners") {}
CHIP_ERROR Run(NodeId localId, NodeId remoteId) override;
CHIP_ERROR Run() override;
uint16_t GetWaitDurationInSeconds() const override { return 3; }
void Shutdown() override;

private:
chip::Controller::CommissionableNodeController mCommissionableNodeController;
Expand Down
Loading