Add a Flag to Disable Main Thread Assertions #trivial (#348)

* Add a thread-flag for disabling main thread assertions

* Fix the license header
This commit is contained in:
Adlai Holler
2017-06-11 18:53:20 -05:00
committed by GitHub
parent 69e69873cc
commit 8af1538a5b
5 changed files with 92 additions and 3 deletions

View File

@@ -369,6 +369,7 @@
CCA282CD1E9EB73E0037E8B7 /* ASTipNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA282CB1E9EB73E0037E8B7 /* ASTipNode.m */; }; CCA282CD1E9EB73E0037E8B7 /* ASTipNode.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA282CB1E9EB73E0037E8B7 /* ASTipNode.m */; };
CCA282D01E9EBF6C0037E8B7 /* ASTipsWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = CCA282CE1E9EBF6C0037E8B7 /* ASTipsWindow.h */; }; CCA282D01E9EBF6C0037E8B7 /* ASTipsWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = CCA282CE1E9EBF6C0037E8B7 /* ASTipsWindow.h */; };
CCA282D11E9EBF6C0037E8B7 /* ASTipsWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA282CF1E9EBF6C0037E8B7 /* ASTipsWindow.m */; }; CCA282D11E9EBF6C0037E8B7 /* ASTipsWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA282CF1E9EBF6C0037E8B7 /* ASTipsWindow.m */; };
CCA5F62E1EECC2A80060C137 /* ASAssert.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA5F62D1EECC2A80060C137 /* ASAssert.m */; };
CCA5F62C1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA5F62B1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.m */; }; CCA5F62C1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = CCA5F62B1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.m */; };
CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */; }; CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */; };
CCBBBF5D1EB161760069AA91 /* ASRangeManagingNode.h in Headers */ = {isa = PBXBuildFile; fileRef = CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; CCBBBF5D1EB161760069AA91 /* ASRangeManagingNode.h in Headers */ = {isa = PBXBuildFile; fileRef = CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -826,6 +827,7 @@
CCA282CB1E9EB73E0037E8B7 /* ASTipNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTipNode.m; sourceTree = "<group>"; }; CCA282CB1E9EB73E0037E8B7 /* ASTipNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTipNode.m; sourceTree = "<group>"; };
CCA282CE1E9EBF6C0037E8B7 /* ASTipsWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTipsWindow.h; sourceTree = "<group>"; }; CCA282CE1E9EBF6C0037E8B7 /* ASTipsWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTipsWindow.h; sourceTree = "<group>"; };
CCA282CF1E9EBF6C0037E8B7 /* ASTipsWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTipsWindow.m; sourceTree = "<group>"; }; CCA282CF1E9EBF6C0037E8B7 /* ASTipsWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTipsWindow.m; sourceTree = "<group>"; };
CCA5F62D1EECC2A80060C137 /* ASAssert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASAssert.m; sourceTree = "<group>"; };
CCA5F62A1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+ASTestHelpers.h"; sourceTree = "<group>"; }; CCA5F62A1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+ASTestHelpers.h"; sourceTree = "<group>"; };
CCA5F62B1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+ASTestHelpers.m"; sourceTree = "<group>"; }; CCA5F62B1EEC9E9B0060C137 /* NSInvocation+ASTestHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+ASTestHelpers.m"; sourceTree = "<group>"; };
CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeSnapshotTests.m; sourceTree = "<group>"; }; CCB2F34C1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayNodeSnapshotTests.m; sourceTree = "<group>"; };
@@ -1368,6 +1370,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
058D0A43195D058D00B7D73C /* ASAssert.h */, 058D0A43195D058D00B7D73C /* ASAssert.h */,
CCA5F62D1EECC2A80060C137 /* ASAssert.m */,
0516FA3A1A15563400B4EBED /* ASAvailability.h */, 0516FA3A1A15563400B4EBED /* ASAvailability.h */,
058D0A44195D058D00B7D73C /* ASBaseDefines.h */, 058D0A44195D058D00B7D73C /* ASBaseDefines.h */,
1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */, 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */,
@@ -2088,6 +2091,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
DEB8ED7C1DD003D300DBDE55 /* ASLayoutTransition.mm in Sources */, DEB8ED7C1DD003D300DBDE55 /* ASLayoutTransition.mm in Sources */,
CCA5F62E1EECC2A80060C137 /* ASAssert.m in Sources */,
9F98C0261DBE29E000476D92 /* ASControlTargetAction.m in Sources */, 9F98C0261DBE29E000476D92 /* ASControlTargetAction.m in Sources */,
9C70F2091CDABA36007D6C76 /* ASViewController.mm in Sources */, 9C70F2091CDABA36007D6C76 /* ASViewController.mm in Sources */,
3917EBD51E9C2FC400D04A01 /* _ASCollectionReusableView.m in Sources */, 3917EBD51E9C2FC400D04A01 /* _ASCollectionReusableView.m in Sources */,

View File

@@ -3224,7 +3224,10 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
- (NSString *)debugDescription - (NSString *)debugDescription
{ {
return ASObjectDescriptionMake(self, [self propertiesForDebugDescription]); ASPushMainThreadAssertionsDisabled();
auto result = ASObjectDescriptionMake(self, [self propertiesForDebugDescription]);
ASPopMainThreadAssertionsDisabled();
return result;
} }
// This should only be called for debugging. It's not thread safe and it doesn't assert. // This should only be called for debugging. It's not thread safe and it doesn't assert.

View File

@@ -19,6 +19,7 @@
#import <Foundation/NSException.h> #import <Foundation/NSException.h>
#import <pthread.h> #import <pthread.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#define ASDISPLAYNODE_ASSERTIONS_ENABLED (!defined(NS_BLOCK_ASSERTIONS)) #define ASDISPLAYNODE_ASSERTIONS_ENABLED (!defined(NS_BLOCK_ASSERTIONS))
@@ -42,8 +43,8 @@
#define ASDisplayNodeAssertNotInstantiable() ASDisplayNodeAssert(NO, nil, @"This class is not instantiable."); #define ASDisplayNodeAssertNotInstantiable() ASDisplayNodeAssert(NO, nil, @"This class is not instantiable.");
#define ASDisplayNodeAssertNotSupported() ASDisplayNodeAssert(NO, nil, @"This method is not supported by class %@", [self class]); #define ASDisplayNodeAssertNotSupported() ASDisplayNodeAssert(NO, nil, @"This method is not supported by class %@", [self class]);
#define ASDisplayNodeAssertMainThread() ASDisplayNodeAssert(0 != pthread_main_np(), @"This method must be called on the main thread") #define ASDisplayNodeAssertMainThread() ASDisplayNodeAssert(ASMainThreadAssertionsAreDisabled() || 0 != pthread_main_np(), @"This method must be called on the main thread")
#define ASDisplayNodeCAssertMainThread() ASDisplayNodeCAssert(0 != pthread_main_np(), @"This function must be called on the main thread") #define ASDisplayNodeCAssertMainThread() ASDisplayNodeCAssert(ASMainThreadAssertionsAreDisabled() || 0 != pthread_main_np(), @"This function must be called on the main thread")
#define ASDisplayNodeAssertNotMainThread() ASDisplayNodeAssert(0 == pthread_main_np(), @"This method must be called off the main thread") #define ASDisplayNodeAssertNotMainThread() ASDisplayNodeAssert(0 == pthread_main_np(), @"This method must be called off the main thread")
#define ASDisplayNodeCAssertNotMainThread() ASDisplayNodeCAssert(0 == pthread_main_np(), @"This function must be called off the main thread") #define ASDisplayNodeCAssertNotMainThread() ASDisplayNodeCAssert(0 == pthread_main_np(), @"This function must be called off the main thread")
@@ -69,6 +70,23 @@
#define ASDisplayNodeErrorDomain @"ASDisplayNodeErrorDomain" #define ASDisplayNodeErrorDomain @"ASDisplayNodeErrorDomain"
#define ASDisplayNodeNonFatalErrorCode 1 #define ASDisplayNodeNonFatalErrorCode 1
/**
* In debug methods, it can be useful to disable main thread assertions to get valuable information,
* even if it means violating threading requirements. These functions are used in -debugDescription and let
* threads decide to suppress/re-enable main thread assertions.
*/
#pragma mark - Main Thread Assertions Disabling
ASDISPLAYNODE_EXTERN_C_BEGIN
BOOL ASMainThreadAssertionsAreDisabled();
void ASPushMainThreadAssertionsDisabled();
void ASPopMainThreadAssertionsDisabled();
ASDISPLAYNODE_EXTERN_C_END
#pragma mark - Non-Fatal Assertions
/// Returns YES if assertion passed, NO otherwise. /// Returns YES if assertion passed, NO otherwise.
#define ASDisplayNodeAssertNonFatal(condition, desc, ...) ({ \ #define ASDisplayNodeAssertNonFatal(condition, desc, ...) ({ \
BOOL __evaluated = condition; \ BOOL __evaluated = condition; \

45
Source/Base/ASAssert.m Normal file
View File

@@ -0,0 +1,45 @@
//
// ASAssert.m
// Texture
//
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
#import <AsyncDisplayKit/ASAssert.h>
#import <Foundation/Foundation.h>
// pthread_key_create must be called before the key can be used. This function does that.
static pthread_key_t ASMainThreadAssertionsDisabledKey()
{
static pthread_key_t ASMainThreadAssertionsDisabledKey;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
pthread_key_create(&ASMainThreadAssertionsDisabledKey, NULL);
});
return ASMainThreadAssertionsDisabledKey;
}
BOOL ASMainThreadAssertionsAreDisabled() {
return (size_t)pthread_getspecific(ASMainThreadAssertionsDisabledKey()) > 0;
}
void ASPushMainThreadAssertionsDisabled() {
pthread_key_t key = ASMainThreadAssertionsDisabledKey();
size_t oldValue = (size_t)pthread_getspecific(key);
pthread_setspecific(key, (void *)(oldValue + 1));
}
void ASPopMainThreadAssertionsDisabled() {
pthread_key_t key = ASMainThreadAssertionsDisabledKey();
size_t oldValue = (size_t)pthread_getspecific(key);
if (oldValue > 0) {
pthread_setspecific(key, (void *)(oldValue - 1));
} else {
ASDisplayNodeCFailAssert(@"Attempt to pop thread assertion-disabling without corresponding push.");
}
}

View File

@@ -2260,4 +2260,23 @@ static bool stringContainsPointer(NSString *description, id p) {
ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin); ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin);
} }
- (void)testThatItIsAllowedToRetrieveDebugDescriptionIncludingVCOffMainThread
{
ASDisplayNode *node = [[ASDisplayNode alloc] init];
UIViewController *vc = [[UIViewController alloc] init];
[vc.view addSubnode:node];
dispatch_group_t g = dispatch_group_create();
dispatch_group_enter(g);
__block NSString *debugDescription;
[NSThread detachNewThreadWithBlock:^{
debugDescription = [node debugDescription];
dispatch_group_leave(g);
}];
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
// Ensure the debug description contains the VC string.
// Have to split into two lines because XCTAssert macro can't handle the stringWithFormat:.
BOOL hasVC = [debugDescription containsString:[NSString stringWithFormat:@"%p", vc]];
XCTAssert(hasVC);
}
@end @end