diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h index 508092b40fa613..eec013fc26ade8 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h @@ -93,6 +93,13 @@ typedef void (^MTRDeviceControllerDataStoreClusterDataHandler)(NSDictionary *)getStoredDeviceDataForNodeID:(NSNumber *)nodeID; - (void)storeDeviceData:(NSDictionary *)data forNodeID:(NSNumber *)nodeID; +/** + * Mechanism for API client to perform a block after previous async operations (writes) on the storage queue have executed. + * + * If no block is passed in, then the method returns after having synchronously flushed the queue. + */ +- (void)synchronouslyPerformBlock:(void (^_Nullable)(void))block; + @end NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm index 8d57a5b0a1927d..a874e26f44f428 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm @@ -1169,6 +1169,15 @@ - (void)storeDeviceData:(NSDictionary *)data forNodeID:(NSNumber }); } +- (void)synchronouslyPerformBlock:(void (^_Nullable)(void))block +{ + dispatch_sync(_storageDelegateQueue, ^{ + if (block) { + block(); + } + }); +} + @end @implementation MTRCASESessionResumptionInfo diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm index 99398867ccfa68..3ccf5ea2a43634 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm @@ -449,6 +449,13 @@ - (void)cleanupAfterStartup for (MTRDevice * device in devices) { [device invalidate]; } + + // Since MTRDevice invalidate may issue asynchronous writes to storage, perform a + // block synchronously on the storage delegate queue to flush those operations. + [self.controllerDataStore synchronouslyPerformBlock:^{ + MTR_LOG("%@ Finished flushing data store", self); + }]; + [self stopBrowseForCommissionables]; [_factory controllerShuttingDown:self]; diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm index 1d0a113553666a..996e41ff12cf2d 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm @@ -850,6 +850,9 @@ - (void)invalidate os_unfair_lock_lock(&self->_lock); + // Flush unstored attributes if any + [self _persistClusterData]; + _state = MTRDeviceStateUnknown; // Make sure we don't try to resubscribe if we have a pending resubscribe