Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Darwin] Enable taking assertion on MTRDeviceController #35148

Merged
merged 11 commits into from
Aug 23, 2024
56 changes: 56 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ - (instancetype)initForSubclasses
// nothing, as superclass of MTRDeviceController is NSObject
}
_underlyingDeviceMapLock = OS_UNFAIR_LOCK_INIT;

// Setup assertion counters
_keepRunningAssertionCounter = 0;
_shutdownPending = FALSE;
anush-apple marked this conversation as resolved.
Show resolved Hide resolved
return self;
}

Expand Down Expand Up @@ -178,6 +182,11 @@ - (instancetype)initWithFactory:(MTRDeviceControllerFactory *)factory
// Make sure our storage is all set up to work as early as possible,
// before we start doing anything else with the controller.
_uniqueIdentifier = uniqueIdentifier;

// Setup assertion counters
_keepRunningAssertionCounter = 0;
_shutdownPending = FALSE;

if (storageDelegate != nil) {
if (storageDelegateQueue == nil) {
MTR_LOG_ERROR("storageDelegate provided without storageDelegateQueue");
Expand Down Expand Up @@ -311,7 +320,53 @@ - (BOOL)isRunning
return _cppCommissioner != nullptr;
}

- (NSUInteger)shutdownPrecheck
{
__block NSUInteger assertionCount = 0;
dispatch_sync(_chipWorkQueue, ^{
anush-apple marked this conversation as resolved.
Show resolved Hide resolved
self.shutdownPending = TRUE;
assertionCount = self.keepRunningAssertionCounter;
});
return assertionCount;
}

- (void)addRunAssertion
{
dispatch_sync(_chipWorkQueue, ^{
++self.keepRunningAssertionCounter;
MTR_LOG("%@ Adding keep running assertion, total %lu", self, (unsigned long) self.keepRunningAssertionCounter);
});
}

- (void)removeRunAssertion;
{
__block BOOL shouldShutdown = FALSE;
dispatch_sync(_chipWorkQueue, ^{
if (self.keepRunningAssertionCounter > 0) {
--self.keepRunningAssertionCounter;
MTR_LOG("%@ Removing keep running assertion, total %lu", self, (unsigned long) self.keepRunningAssertionCounter);
if (self.keepRunningAssertionCounter == 0 && self.shutdownPending) {
shouldShutdown = TRUE;
}
}
});
if (shouldShutdown) {
MTR_LOG("%@ All assertions removed and shutdown is pending, shutting down", self);
[self finalShutdown];
}
}

- (void)shutdown
{
NSUInteger assertionCount = [self shutdownPrecheck];
anush-apple marked this conversation as resolved.
Show resolved Hide resolved
if (assertionCount != 0) {
MTR_LOG("%@ Pending shutdown since %lu assertions are present", self, (unsigned long) assertionCount);
return;
}
[self finalShutdown];
}

- (void)finalShutdown
{
MTR_LOG("%@ shutdown called", self);
if (_cppCommissioner == nullptr) {
Expand Down Expand Up @@ -374,6 +429,7 @@ - (void)shutDownCppController
_operationalCredentialsDelegate->SetDeviceCommissioner(nullptr);
}
}
self.shutdownPending = FALSE;
}

- (void)deinitFromFactory
Expand Down
10 changes: 10 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,16 @@ - (BOOL)isRunning
}

- (void)shutdown
{
NSUInteger assertionCount = [self shutdownPrecheck];
if (assertionCount != 0) {
MTR_LOG("%@ Pending shutdown since %lu assertions are present", self, (unsigned long) assertionCount);
return;
}
[self finalShutdown];
}

- (void)finalShutdown
{
MTR_LOG("%@ shutdown called", self);
if (_cppCommissioner == nullptr) {
Expand Down
25 changes: 25 additions & 0 deletions src/darwin/Framework/CHIP/MTRDeviceController_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ NS_ASSUME_NONNULL_BEGIN
// (moved here so subclasses can initialize differently)
@property (readwrite, retain) dispatch_queue_t chipWorkQueue;

// Counters to track assertion status
anush-apple marked this conversation as resolved.
Show resolved Hide resolved
@property (nonatomic, readwrite) NSUInteger keepRunningAssertionCounter;
@property (nonatomic, readwrite) BOOL shutdownPending;

- (instancetype)initForSubclasses;

#pragma mark - MTRDeviceControllerFactory methods
Expand Down Expand Up @@ -289,6 +293,27 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)directlyGetSessionForNode:(chip::NodeId)nodeID completion:(MTRInternalDeviceConnectionCallback)completion;

/**
* Takes an assertion to keep the controller running. If `-[MTRDeviceController shutdown]` is called while an assertion
* is held, the shutdown will be honored only after all assertions are released. Invoking this method multiple times increases
* the number of assertions and needs to be matched with equal amount of '-[MTRDeviceController removeRunAssertion]` to release
* the assertion.
*/
- (void)addRunAssertion;

/**
* Removes an assertion to allow the controller to shutdown once all assertions have been released.
* Invoking this method once all assertions have been released in a noop.
*/
- (void)removeRunAssertion;

/**
* This methods marks a request to shutdown.
* Returns the number of run assertions currently being held. If the value returned is not zero, it implies shutdown has to be delayed
* until all assertions have been removed.
*/
- (NSUInteger)shutdownPrecheck;

@end

/**
Expand Down
Loading