Skip to content

Commit

Permalink
Address review comment.
Browse files Browse the repository at this point in the history
  • Loading branch information
bzbarsky-apple committed Jul 7, 2023
1 parent 0d9b285 commit 2b74f96
Showing 1 changed file with 25 additions and 9 deletions.
34 changes: 25 additions & 9 deletions src/protocols/secure_channel/CASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,21 +243,32 @@ class CASESession::WorkHelper
// Execute callback in background thread; data must be OK with this
helper->mStatus = helper->mWorkCallback(helper->mData, cancel);
VerifyOrReturn(!cancel && !helper->IsCancelled());
// Hold strong ptr while work is outstanding
// Hold strong ptr to ourselves while work is outstanding
helper->mStrongPtr.swap(strongPtr);
auto status = DeviceLayer::PlatformMgr().ScheduleWork(AfterWorkHandler, reinterpret_cast<intptr_t>(helper));
if (status != CHIP_NO_ERROR)
{
ChipLogError(SecureChannel, "Failed to Schedule the AfterWorkCallback on foreground thread: %" CHIP_ERROR_FORMAT,
status.Format());

// We failed to schedule after work callback, so setting mScheduleAfterWorkFailed flag to true
// This can be checked from foreground thread and after work callback can be retried
helper->mStatus = status;
ChipLogError(SecureChannel, "Failed to Schedule the AfterWorkCallback on foreground thread");
helper->mScheduleAfterWorkFailed.store(true);

// Release strong ptr since scheduling failed, because nothing guarantees that
// AfterWorkHandler will get called at this point to release the reference, and we
// don't want to leak.
helper->mStrongPtr.reset();
// Release strong ptr to self since scheduling failed, because nothing guarantees
// that AfterWorkHandler will get called at this point to release the reference,
// and we don't want to leak. That said, we want to ensure that "helper" stays
// alive through the end of this function (so we can set mScheduleAfterWorkFailed
// on it), but also want to avoid racing on the single SharedPtr instance in
// helper->mStrongPtr. That means we need to not touch helper->mStrongPtr after
// writing to mScheduleAfterWorkFailed.
//
// The simplest way to do this is to move the reference in helper->mStrongPtr to
// our stack, where it outlives all our accesses to "helper".
strongPtr.swap(helper->mStrongPtr);

// helper and any of its state should not be touched after storing mScheduleAfterWorkFailed.
helper->mScheduleAfterWorkFailed.store(true);
}
}

Expand All @@ -273,8 +284,10 @@ class CASESession::WorkHelper
auto strongPtr(std::move(helper->mStrongPtr));
if (!strongPtr)
{
// This can happen if scheduling AfterWorkHandler failed. Just grab a strong ref to
// handler directly, to fulfill our API contract.
// This can happen if scheduling AfterWorkHandler failed. Just grab a strong ref
// to handler directly, to fulfill our API contract of holding a strong reference
// across the after-work callback. At this point, we are guaranteed that the
// background thread is not touching the helper anymore.
strongPtr = helper->mWeakPtr.lock();
}
if (auto * session = helper->mSession.load())
Expand Down Expand Up @@ -305,6 +318,9 @@ class CASESession::WorkHelper

// If background thread fails to schedule AfterWorkCallback then this flag is set to true
// and CASEServer then can check this one and run the AfterWorkCallback for us.
//
// When this happens, the write to this boolean _must_ be the last code that touches this
// object on the background thread. After that, the Matter thread owns the object.
std::atomic<bool> mScheduleAfterWorkFailed{ false };

public:
Expand Down

0 comments on commit 2b74f96

Please sign in to comment.