@@ -120,7 +120,6 @@ @implementation MTRDeviceController {
120
120
MTROperationalCredentialsDelegate * _operationalCredentialsDelegate;
121
121
MTRDeviceAttestationDelegateBridge * _deviceAttestationDelegateBridge;
122
122
MTRDeviceControllerFactory * _factory;
123
- NSMapTable * _nodeIDToDeviceMap;
124
123
os_unfair_lock _underlyingDeviceMapLock;
125
124
MTRCommissionableBrowser * _commissionableBrowser;
126
125
MTRAttestationTrustStoreBridge * _attestationTrustStoreBridge;
@@ -135,6 +134,7 @@ @implementation MTRDeviceController {
135
134
MTRP256KeypairBridge _operationalKeypairBridge;
136
135
137
136
BOOL _suspended;
137
+ os_unfair_lock _suspensionLock;
138
138
139
139
// Counters to track assertion status and access controlled by the _assertionLock
140
140
NSUInteger _keepRunningAssertionCounter;
@@ -160,6 +160,12 @@ - (instancetype)initForSubclasses:(BOOL)startSuspended
160
160
_assertionLock = OS_UNFAIR_LOCK_INIT;
161
161
162
162
_suspended = startSuspended;
163
+ // All synchronous suspend/resume activity has to be protected by
164
+ // _suspensionLock, so that parts of suspend/resume can't interleave with
165
+ // each other.
166
+ _suspensionLock = OS_UNFAIR_LOCK_INIT;
167
+
168
+ _nodeIDToDeviceMap = [NSMapTable strongToWeakObjectsMapTable ];
163
169
164
170
return self;
165
171
}
@@ -204,6 +210,7 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
204
210
_assertionLock = OS_UNFAIR_LOCK_INIT;
205
211
206
212
_suspended = startSuspended;
213
+ _suspensionLock = OS_UNFAIR_LOCK_INIT;
207
214
208
215
if (storageDelegate != nil ) {
209
216
if (storageDelegateQueue == nil ) {
@@ -350,9 +357,26 @@ - (BOOL)isSuspended
350
357
351
358
- (void )suspend
352
359
{
360
+ MTR_LOG (" %@ suspending" , self);
361
+
362
+ std::lock_guard lock (_suspensionLock);
363
+
353
364
_suspended = YES ;
354
365
355
- // TODO: In the concrete class (which is unused so far!), iterate our
366
+ NSEnumerator * devices;
367
+ {
368
+ std::lock_guard lock (*self.deviceMapLock );
369
+ devices = [self .nodeIDToDeviceMap objectEnumerator ];
370
+ }
371
+
372
+ for (MTRDevice * device in devices) {
373
+ [device controllerSuspended ];
374
+ }
375
+
376
+ // TODO: In the concrete class, consider what should happen with:
377
+ //
378
+ // * Active commissioning sessions (presumably close them?)
379
+ // * CASE sessions in general.
356
380
// MTRDevices, tell them to tear down subscriptions. Possibly close all
357
381
// CASE sessions for our identity. Possibly try to see whether we can
358
382
// change our fabric entry to not advertise and restart advertising.
@@ -363,10 +387,21 @@ - (void)suspend
363
387
364
388
- (void )resume
365
389
{
390
+ MTR_LOG (" %@ resuming" , self);
391
+
392
+ std::lock_guard lock (_suspensionLock);
393
+
366
394
_suspended = NO ;
367
395
368
- // TODO: In the concrete class (which is unused so far!), iterate our
369
- // MTRDevices, tell them to restart subscriptions.
396
+ NSEnumerator * devices;
397
+ {
398
+ std::lock_guard lock (*self.deviceMapLock );
399
+ devices = [self .nodeIDToDeviceMap objectEnumerator ];
400
+ }
401
+
402
+ for (MTRDevice * device in devices) {
403
+ [device controllerResumed ];
404
+ }
370
405
}
371
406
372
407
- (BOOL )matchesPendingShutdownControllerWithOperationalCertificate : (nullable MTRCertificateDERBytes)operationalCertificate andRootCertificate : (nullable MTRCertificateDERBytes)rootCertificate
0 commit comments