Skip to content

Commit 1079938

Browse files
bzbarsky-applepull[bot]
authored andcommitted
Fix some threading issues on Darwin. (#20197)
* Fix some threading issues on Darwin. There were two places where we were touching SDK data structures from the wrong event queue. * Address review comments
1 parent 4945016 commit 1079938

File tree

3 files changed

+87
-71
lines changed

3 files changed

+87
-71
lines changed

examples/darwin-framework-tool/commands/tests/TestCommandBridge.h

+3-6
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,11 @@ class TestCommandBridge : public CHIPCommandBridge,
117117

118118
SetIdentity(identity);
119119

120-
// Disconnect our existing device; otherwise getConnectedDevice will
121-
// just hand it right back to us without establishing a new CASE
120+
// Invalidate our existing CASE session; otherwise getConnectedDevice
121+
// will just hand it right back to us without establishing a new CASE
122122
// session.
123123
if (GetDevice(identity) != nil) {
124-
auto device = [GetDevice(identity) internalDevice];
125-
if (device != nullptr) {
126-
device->Disconnect();
127-
}
124+
[GetDevice(identity) invalidateCASESession];
128125
mConnectedDevices[identity] = nil;
129126
}
130127

src/darwin/Framework/CHIP/CHIPDevice.mm

+77-65
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,16 @@ - (instancetype)initWithDevice:(chip::DeviceProxy *)device
244244
return _cppDevice;
245245
}
246246

247+
- (void)invalidateCASESession
248+
{
249+
dispatch_sync(DeviceLayer::PlatformMgrImpl().GetWorkQueue(), ^{
250+
DeviceProxy * device = [self internalDevice];
251+
if (device != nullptr) {
252+
device->Disconnect();
253+
}
254+
});
255+
}
256+
247257
typedef void (^ReportCallback)(NSArray * _Nullable value, NSError * _Nullable error);
248258
typedef void (^DataReportCallback)(NSArray * value);
249259
typedef void (^ErrorCallback)(NSError * error);
@@ -371,76 +381,78 @@ - (void)subscribeWithQueue:(dispatch_queue_t)queue
371381
errorHandler:(void (^)(NSError * error))errorHandler
372382
subscriptionEstablished:(nullable void (^)(void))subscriptionEstablishedHandler
373383
{
374-
DeviceProxy * device = [self internalDevice];
375-
if (!device) {
376-
dispatch_async(queue, ^{
377-
errorHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]);
378-
});
379-
return;
380-
}
381-
382-
// Wildcard endpoint, cluster, attribute, event.
383-
auto attributePath = std::make_unique<AttributePathParams>();
384-
auto eventPath = std::make_unique<EventPathParams>();
385-
ReadPrepareParams readParams(device->GetSecureSession().Value());
386-
readParams.mMinIntervalFloorSeconds = minInterval;
387-
readParams.mMaxIntervalCeilingSeconds = maxInterval;
388-
readParams.mpAttributePathParamsList = attributePath.get();
389-
readParams.mAttributePathParamsListSize = 1;
390-
readParams.mpEventPathParamsList = eventPath.get();
391-
readParams.mEventPathParamsListSize = 1;
392-
readParams.mKeepSubscriptions
393-
= (params != nil) && (params.keepPreviousSubscriptions != nil) && [params.keepPreviousSubscriptions boolValue];
394-
395-
std::unique_ptr<SubscriptionCallback> callback;
396-
std::unique_ptr<ReadClient> readClient;
397-
std::unique_ptr<ClusterStateCache> attributeCache;
398-
if (attributeCacheContainer) {
399-
__weak CHIPAttributeCacheContainer * weakPtr = attributeCacheContainer;
400-
callback = std::make_unique<SubscriptionCallback>(
401-
queue, attributeReportHandler, eventReportHandler, errorHandler, subscriptionEstablishedHandler, ^{
402-
CHIPAttributeCacheContainer * container = weakPtr;
403-
if (container) {
404-
container.cppAttributeCache = nullptr;
405-
}
384+
dispatch_async(DeviceLayer::PlatformMgrImpl().GetWorkQueue(), ^{
385+
DeviceProxy * device = [self internalDevice];
386+
if (!device) {
387+
dispatch_async(queue, ^{
388+
errorHandler([CHIPError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]);
406389
});
407-
attributeCache = std::make_unique<ClusterStateCache>(*callback.get());
408-
readClient = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
409-
attributeCache->GetBufferedCallback(), ReadClient::InteractionType::Subscribe);
410-
} else {
411-
callback = std::make_unique<SubscriptionCallback>(
412-
queue, attributeReportHandler, eventReportHandler, errorHandler, subscriptionEstablishedHandler);
413-
readClient = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
414-
callback->GetBufferedCallback(), ReadClient::InteractionType::Subscribe);
415-
}
390+
return;
391+
}
416392

417-
CHIP_ERROR err;
418-
if (params != nil && params.autoResubscribe != nil && ![params.autoResubscribe boolValue]) {
419-
err = readClient->SendRequest(readParams);
420-
} else {
421-
// SendAutoResubscribeRequest cleans up the params, even on failure.
422-
attributePath.release();
423-
eventPath.release();
424-
err = readClient->SendAutoResubscribeRequest(std::move(readParams));
425-
}
393+
// Wildcard endpoint, cluster, attribute, event.
394+
auto attributePath = std::make_unique<AttributePathParams>();
395+
auto eventPath = std::make_unique<EventPathParams>();
396+
ReadPrepareParams readParams(device->GetSecureSession().Value());
397+
readParams.mMinIntervalFloorSeconds = minInterval;
398+
readParams.mMaxIntervalCeilingSeconds = maxInterval;
399+
readParams.mpAttributePathParamsList = attributePath.get();
400+
readParams.mAttributePathParamsListSize = 1;
401+
readParams.mpEventPathParamsList = eventPath.get();
402+
readParams.mEventPathParamsListSize = 1;
403+
readParams.mKeepSubscriptions
404+
= (params != nil) && (params.keepPreviousSubscriptions != nil) && [params.keepPreviousSubscriptions boolValue];
405+
406+
std::unique_ptr<SubscriptionCallback> callback;
407+
std::unique_ptr<ReadClient> readClient;
408+
std::unique_ptr<ClusterStateCache> attributeCache;
409+
if (attributeCacheContainer) {
410+
__weak CHIPAttributeCacheContainer * weakPtr = attributeCacheContainer;
411+
callback = std::make_unique<SubscriptionCallback>(
412+
queue, attributeReportHandler, eventReportHandler, errorHandler, subscriptionEstablishedHandler, ^{
413+
CHIPAttributeCacheContainer * container = weakPtr;
414+
if (container) {
415+
container.cppAttributeCache = nullptr;
416+
}
417+
});
418+
attributeCache = std::make_unique<ClusterStateCache>(*callback.get());
419+
readClient = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
420+
attributeCache->GetBufferedCallback(), ReadClient::InteractionType::Subscribe);
421+
} else {
422+
callback = std::make_unique<SubscriptionCallback>(
423+
queue, attributeReportHandler, eventReportHandler, errorHandler, subscriptionEstablishedHandler);
424+
readClient = std::make_unique<ReadClient>(InteractionModelEngine::GetInstance(), device->GetExchangeManager(),
425+
callback->GetBufferedCallback(), ReadClient::InteractionType::Subscribe);
426+
}
426427

427-
if (err != CHIP_NO_ERROR) {
428-
dispatch_async(queue, ^{
429-
errorHandler([CHIPError errorForCHIPErrorCode:err]);
430-
});
428+
CHIP_ERROR err;
429+
if (params != nil && params.autoResubscribe != nil && ![params.autoResubscribe boolValue]) {
430+
err = readClient->SendRequest(readParams);
431+
} else {
432+
// SendAutoResubscribeRequest cleans up the params, even on failure.
433+
attributePath.release();
434+
eventPath.release();
435+
err = readClient->SendAutoResubscribeRequest(std::move(readParams));
436+
}
431437

432-
return;
433-
}
438+
if (err != CHIP_NO_ERROR) {
439+
dispatch_async(queue, ^{
440+
errorHandler([CHIPError errorForCHIPErrorCode:err]);
441+
});
434442

435-
if (attributeCacheContainer) {
436-
attributeCacheContainer.cppAttributeCache = attributeCache.get();
437-
// ClusterStateCache will be deleted when OnDone is called or an error is encountered as well.
438-
callback->AdoptAttributeCache(std::move(attributeCache));
439-
}
440-
// Callback and ReadClient will be deleted when OnDone is called or an error is
441-
// encountered.
442-
callback->AdoptReadClient(std::move(readClient));
443-
callback.release();
443+
return;
444+
}
445+
446+
if (attributeCacheContainer) {
447+
attributeCacheContainer.cppAttributeCache = attributeCache.get();
448+
// ClusterStateCache will be deleted when OnDone is called or an error is encountered as well.
449+
callback->AdoptAttributeCache(std::move(attributeCache));
450+
}
451+
// Callback and ReadClient will be deleted when OnDone is called or an error is
452+
// encountered.
453+
callback->AdoptReadClient(std::move(readClient));
454+
callback.release();
455+
});
444456
}
445457

446458
// Convert TLV data into NSObject

src/darwin/Framework/CHIP/CHIPDevice_Internal.h

+7
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ NS_ASSUME_NONNULL_BEGIN
3232
- (instancetype)initWithDevice:(chip::DeviceProxy *)device;
3333
- (chip::DeviceProxy *)internalDevice;
3434

35+
/**
36+
* Invalidate the CASE session, so an attempt to getConnectedDevice for this
37+
* device id will have to create a new CASE session. Ideally this API will go
38+
* away.
39+
*/
40+
- (void)invalidateCASESession;
41+
3542
@end
3643

3744
@interface CHIPAttributePath ()

0 commit comments

Comments
 (0)