@@ -757,11 +757,16 @@ - (void)_ensureSubscriptionForExistingDelegates:(NSString *)reason
757
757
if ([self _deviceUsesThread]) {
758
758
MTR_LOG(" => %@ - device is a thread device, scheduling in pool", self);
759
759
[self _scheduleSubscriptionPoolWork:^{
760
- std::lock_guard lock(self->_lock);
761
- [self _setupSubscriptionWithReason:[NSString stringWithFormat:@"%@ and scheduled subscription is happening", reason]];
760
+ [self->_deviceController asyncDispatchToMatterQueue:^{
761
+ std::lock_guard lock(self->_lock);
762
+ [self _setupSubscriptionWithReason:[NSString stringWithFormat:@"%@ and scheduled subscription is happening", reason]];
763
+ } errorHandler:nil];
762
764
} inNanoseconds:0 description:@"MTRDevice setDelegate first subscription"];
763
765
} else {
764
- [self _setupSubscriptionWithReason:[NSString stringWithFormat:@"%@ and subscription is needed", reason]];
766
+ [_deviceController asyncDispatchToMatterQueue:^{
767
+ std::lock_guard lock(self->_lock);
768
+ [self _setupSubscriptionWithReason:[NSString stringWithFormat:@"%@ and subscription is needed", reason]];
769
+ } errorHandler:nil];
765
770
}
766
771
}
767
772
@@ -946,6 +951,15 @@ - (void)_callDelegateDeviceCachePrimed
946
951
// assume lock is held
947
952
- (void)_changeState:(MTRDeviceState)state
948
953
{
954
+ // We want to avoid situations where something changes our state and then an
955
+ // async block that was queued earlier in response to something changes it
956
+ // again, to a value that no longer makes sense. To avoid that:
957
+ //
958
+ // 1) All state changes happen on the Matter queue.
959
+ // 2) All state changes happen synchronously with the event that actually
960
+ // triggers the state change.
961
+ assertChipStackLockedByCurrentThread();
962
+
949
963
os_unfair_lock_assert_owner(&self->_lock);
950
964
MTRDeviceState lastState = _state;
951
965
_state = state;
@@ -970,6 +984,15 @@ - (void)_changeState:(MTRDeviceState)state
970
984
971
985
- (void)_changeInternalState:(MTRInternalDeviceState)state
972
986
{
987
+ // We want to avoid situations where something changes our state and then an
988
+ // async block that was queued earlier in response to something changes it
989
+ // again, to a value that no longer makes sense. To avoid that:
990
+ //
991
+ // 1) All state changes happen on the Matter queue.
992
+ // 2) All state changes happen synchronously with the event that actually
993
+ // triggers the state change.
994
+ assertChipStackLockedByCurrentThread();
995
+
973
996
os_unfair_lock_assert_owner(&self->_lock);
974
997
MTRInternalDeviceState lastState = _internalDeviceState;
975
998
_internalDeviceState = state;
@@ -1053,12 +1076,16 @@ - (void)_handleSubscriptionEstablished
1053
1076
1054
1077
- (void)_handleSubscriptionError:(NSError *)error
1055
1078
{
1079
+ assertChipStackLockedByCurrentThread();
1080
+
1056
1081
std::lock_guard lock(_lock);
1057
1082
[self _doHandleSubscriptionError:error];
1058
1083
}
1059
1084
1060
1085
- (void)_doHandleSubscriptionError:(NSError *)error
1061
1086
{
1087
+ assertChipStackLockedByCurrentThread();
1088
+
1062
1089
os_unfair_lock_assert_owner(&_lock);
1063
1090
1064
1091
[self _changeInternalState:MTRInternalDeviceStateUnsubscribed];
@@ -1174,13 +1201,23 @@ - (void)_scheduleSubscriptionPoolWork:(dispatch_block_t)workBlock inNanoseconds:
1174
1201
1175
1202
- (void)_handleResubscriptionNeededWithDelay:(NSNumber *)resubscriptionDelayMs
1176
1203
{
1177
- BOOL deviceUsesThread ;
1204
+ assertChipStackLockedByCurrentThread() ;
1178
1205
1179
- os_unfair_lock_lock(&self-> _lock);
1206
+ std::lock_guard lock( _lock);
1180
1207
1208
+ // Change our state before going async.
1181
1209
[self _changeState:MTRDeviceStateUnknown];
1182
1210
[self _changeInternalState:MTRInternalDeviceStateResubscribing];
1183
1211
1212
+ dispatch_async(self.queue, ^{
1213
+ [self _handleResubscriptionNeededWithDelayOnDeviceQueue:resubscriptionDelayMs];
1214
+ });
1215
+ }
1216
+
1217
+ - (void)_handleResubscriptionNeededWithDelayOnDeviceQueue:(NSNumber *)resubscriptionDelayMs
1218
+ {
1219
+ os_unfair_lock_lock(&self->_lock);
1220
+
1184
1221
// If we are here, then the ReadClient either just detected a subscription
1185
1222
// drop or just tried again and failed. Either way, count it as "tried and
1186
1223
// failed to subscribe": in the latter case it's actually true, and in the
@@ -1192,7 +1229,7 @@ - (void)_handleResubscriptionNeededWithDelay:(NSNumber *)resubscriptionDelayMs
1192
1229
_lastSubscriptionFailureTimeForDescription = _lastSubscriptionFailureTime;
1193
1230
}
1194
1231
[self _notifyDelegateOfPrivateInternalPropertiesChanges];
1195
- deviceUsesThread = [self _deviceUsesThread];
1232
+ BOOL deviceUsesThread = [self _deviceUsesThread];
1196
1233
1197
1234
// If a previous resubscription failed, remove the item from the subscription pool.
1198
1235
[self _clearSubscriptionPoolWork];
@@ -1228,6 +1265,8 @@ - (void)_handleResubscriptionNeededWithDelay:(NSNumber *)resubscriptionDelayMs
1228
1265
1229
1266
- (void)_handleSubscriptionReset:(NSNumber * _Nullable)retryDelay
1230
1267
{
1268
+ assertChipStackLockedByCurrentThread();
1269
+
1231
1270
std::lock_guard lock(_lock);
1232
1271
[self _doHandleSubscriptionReset:retryDelay];
1233
1272
}
@@ -1247,6 +1286,8 @@ - (void)_setLastSubscriptionAttemptWait:(uint32_t)lastSubscriptionAttemptWait
1247
1286
1248
1287
- (void)_doHandleSubscriptionReset:(NSNumber * _Nullable)retryDelay
1249
1288
{
1289
+ assertChipStackLockedByCurrentThread();
1290
+
1250
1291
os_unfair_lock_assert_owner(&_lock);
1251
1292
1252
1293
if (_deviceController.isSuspended) {
@@ -1309,8 +1350,11 @@ - (void)_doHandleSubscriptionReset:(NSNumber * _Nullable)retryDelay
1309
1350
// Call _reattemptSubscriptionNowIfNeededWithReason when timer fires - if subscription is
1310
1351
// in a better state at that time this will be a no-op.
1311
1352
auto resubscriptionBlock = ^{
1312
- std::lock_guard lock(self->_lock);
1313
- [self _reattemptSubscriptionNowIfNeededWithReason:@"got subscription reset"];
1353
+ [self->_deviceController asyncDispatchToMatterQueue:^{
1354
+ std::lock_guard lock(self->_lock);
1355
+ [self _reattemptSubscriptionNowIfNeededWithReason:@"got subscription reset"];
1356
+ }
1357
+ errorHandler:nil];
1314
1358
};
1315
1359
1316
1360
int64_t resubscriptionDelayNs = static_cast<int64_t>(secondsToWait * NSEC_PER_SEC);
@@ -1326,6 +1370,8 @@ - (void)_doHandleSubscriptionReset:(NSNumber * _Nullable)retryDelay
1326
1370
1327
1371
- (void)_reattemptSubscriptionNowIfNeededWithReason:(NSString *)reason
1328
1372
{
1373
+ assertChipStackLockedByCurrentThread();
1374
+
1329
1375
os_unfair_lock_assert_owner(&self->_lock);
1330
1376
if (!self.reattemptingSubscription) {
1331
1377
return;
@@ -1338,6 +1384,8 @@ - (void)_reattemptSubscriptionNowIfNeededWithReason:(NSString *)reason
1338
1384
1339
1385
- (void)_handleUnsolicitedMessageFromPublisher
1340
1386
{
1387
+ assertChipStackLockedByCurrentThread();
1388
+
1341
1389
std::lock_guard lock(_lock);
1342
1390
1343
1391
[self _changeState:MTRDeviceStateReachable];
@@ -1358,18 +1406,23 @@ - (void)_handleUnsolicitedMessageFromPublisher
1358
1406
1359
1407
- (void)_markDeviceAsUnreachableIfNeverSubscribed
1360
1408
{
1361
- os_unfair_lock_assert_owner(&self->_lock);
1409
+ [_deviceController asyncDispatchToMatterQueue:^{
1410
+ std::lock_guard lock(self->_lock);
1362
1411
1363
- if (HadSubscriptionEstablishedOnce(_internalDeviceState)) {
1364
- return;
1365
- }
1412
+ if (HadSubscriptionEstablishedOnce(self-> _internalDeviceState)) {
1413
+ return;
1414
+ }
1366
1415
1367
- MTR_LOG("%@ still not subscribed, marking the device as unreachable", self);
1368
- [self _changeState:MTRDeviceStateUnreachable];
1416
+ MTR_LOG("%@ still not subscribed, marking the device as unreachable", self);
1417
+ [self _changeState:MTRDeviceStateUnreachable];
1418
+ }
1419
+ errorHandler:nil];
1369
1420
}
1370
1421
1371
1422
- (void)_handleReportBegin
1372
1423
{
1424
+ assertChipStackLockedByCurrentThread();
1425
+
1373
1426
std::lock_guard lock(_lock);
1374
1427
1375
1428
_receivingReport = YES;
@@ -1807,11 +1860,14 @@ - (void)unitTestInjectEventReport:(NSArray<NSDictionary<NSString *, id> *> *)eve
1807
1860
1808
1861
- (void)unitTestInjectAttributeReport:(NSArray<NSDictionary<NSString *, id> *> *)attributeReport fromSubscription:(BOOL)isFromSubscription
1809
1862
{
1810
- dispatch_async(self.queue, ^{
1863
+ [_deviceController asyncDispatchToMatterQueue: ^{
1811
1864
[self _handleReportBegin];
1812
- [self _handleAttributeReport:attributeReport fromSubscription:isFromSubscription];
1813
- [self _handleReportEnd];
1814
- });
1865
+ dispatch_async(self.queue, ^{
1866
+ [self _handleAttributeReport:attributeReport fromSubscription:isFromSubscription];
1867
+ [self _handleReportEnd];
1868
+ });
1869
+ }
1870
+ errorHandler:nil];
1815
1871
}
1816
1872
#endif
1817
1873
@@ -2242,6 +2298,8 @@ - (void)unitTestResetSubscription
2242
2298
// assume lock is held
2243
2299
- (void)_setupSubscriptionWithReason:(NSString *)reason
2244
2300
{
2301
+ assertChipStackLockedByCurrentThread();
2302
+
2245
2303
os_unfair_lock_assert_owner(&self->_lock);
2246
2304
2247
2305
if (![self _subscriptionsAllowed]) {
@@ -2287,7 +2345,6 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2287
2345
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, static_cast<int64_t>(kSecondsToWaitBeforeMarkingUnreachableAfterSettingUpSubscription) * static_cast<int64_t>(NSEC_PER_SEC)), self.queue, ^{
2288
2346
mtr_strongify(self);
2289
2347
if (self != nil) {
2290
- std::lock_guard lock(self->_lock);
2291
2348
[self _markDeviceAsUnreachableIfNeverSubscribed];
2292
2349
}
2293
2350
});
@@ -2305,10 +2362,8 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2305
2362
NSNumber * _Nullable retryDelay) {
2306
2363
if (error != nil) {
2307
2364
MTR_LOG_ERROR("%@ getSessionForNode error %@", self, error);
2308
- dispatch_async(self.queue, ^{
2309
- [self _handleSubscriptionError:error];
2310
- [self _handleSubscriptionReset:retryDelay];
2311
- });
2365
+ [self _handleSubscriptionError:error];
2366
+ [self _handleSubscriptionReset:retryDelay];
2312
2367
return;
2313
2368
}
2314
2369
@@ -2332,17 +2387,13 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2332
2387
},
2333
2388
^(NSError * error) {
2334
2389
MTR_LOG_ERROR("%@ got subscription error %@", self, error);
2335
- dispatch_async(self.queue, ^{
2336
- // OnError
2337
- [self _handleSubscriptionError:error];
2338
- });
2390
+ // OnError
2391
+ [self _handleSubscriptionError:error];
2339
2392
},
2340
2393
^(NSError * error, NSNumber * resubscriptionDelayMs) {
2341
2394
MTR_LOG_ERROR("%@ got resubscription error %@ delay %@", self, error, resubscriptionDelayMs);
2342
- dispatch_async(self.queue, ^{
2343
- // OnResubscriptionNeeded
2344
- [self _handleResubscriptionNeededWithDelay:resubscriptionDelayMs];
2345
- });
2395
+ // OnResubscriptionNeeded
2396
+ [self _handleResubscriptionNeededWithDelay:resubscriptionDelayMs];
2346
2397
},
2347
2398
^(void) {
2348
2399
MTR_LOG("%@ got subscription established", self);
@@ -2373,23 +2424,17 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2373
2424
self->_currentReadClient = nullptr;
2374
2425
self->_currentSubscriptionCallback = nullptr;
2375
2426
2376
- dispatch_async(self.queue, ^{
2377
- // OnDone
2378
- [self _handleSubscriptionReset:nil];
2379
- });
2427
+ // OnDone
2428
+ [self _doHandleSubscriptionReset:nil];
2380
2429
},
2381
2430
^(void) {
2382
2431
MTR_LOG("%@ got unsolicited message from publisher", self);
2383
- dispatch_async(self.queue, ^{
2384
- // OnUnsolicitedMessageFromPublisher
2385
- [self _handleUnsolicitedMessageFromPublisher];
2386
- });
2432
+ // OnUnsolicitedMessageFromPublisher
2433
+ [self _handleUnsolicitedMessageFromPublisher];
2387
2434
},
2388
2435
^(void) {
2389
2436
MTR_LOG("%@ got report begin", self);
2390
- dispatch_async(self.queue, ^{
2391
- [self _handleReportBegin];
2392
- });
2437
+ [self _handleReportBegin];
2393
2438
},
2394
2439
^(void) {
2395
2440
MTR_LOG("%@ got report end", self);
@@ -2459,10 +2504,8 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2459
2504
if (err != CHIP_NO_ERROR) {
2460
2505
NSError * error = [MTRError errorForCHIPErrorCode:err logContext:self];
2461
2506
MTR_LOG_ERROR("%@ SendAutoResubscribeRequest error %@", self, error);
2462
- dispatch_async(self.queue, ^{
2463
- [self _handleSubscriptionError:error];
2464
- [self _handleSubscriptionReset:nil];
2465
- });
2507
+ [self _handleSubscriptionError:error];
2508
+ [self _handleSubscriptionReset:nil];
2466
2509
2467
2510
return;
2468
2511
}
0 commit comments