Replace pthread specifics with C11 thread-local variables (#811)

* Replace pthread specifics with C11 thread-local variables for speed and safety

* Increment changelog
This commit is contained in:
Adlai Holler 2018-02-28 12:42:30 -08:00 committed by GitHub
parent 6b57b1cf1a
commit a1055254f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 17 additions and 54 deletions

View File

@ -30,6 +30,7 @@
- Fix ASTextNode2 is accessing backgroundColor off main while sizing / layout is happening. [Michael Schneider](https://github.com/maicki) [#794](https://github.com/TextureGroup/Texture/pull/778/) - Fix ASTextNode2 is accessing backgroundColor off main while sizing / layout is happening. [Michael Schneider](https://github.com/maicki) [#794](https://github.com/TextureGroup/Texture/pull/778/)
- Pass scrollViewWillEndDragging delegation through in ASIGListAdapterDataSource for IGListKit integration. [#796](https://github.com/TextureGroup/Texture/pull/796) - Pass scrollViewWillEndDragging delegation through in ASIGListAdapterDataSource for IGListKit integration. [#796](https://github.com/TextureGroup/Texture/pull/796)
- Fix UIResponder handling with view backing ASDisplayNode. [Michael Schneider](https://github.com/maicki) [#789] (https://github.com/TextureGroup/Texture/pull/789/) - Fix UIResponder handling with view backing ASDisplayNode. [Michael Schneider](https://github.com/maicki) [#789] (https://github.com/TextureGroup/Texture/pull/789/)
- Optimized thread-local storage by replacing pthread_specific with C11 thread-local variables. [Adlai Holler](https://github.com/Adlai-Holler) [#811] (https://github.com/TextureGroup/Texture/pull/811/)
## 2.6 ## 2.6
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon) - [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)

View File

@ -15,8 +15,6 @@
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
// //
#import <pthread.h>
#import <AsyncDisplayKit/ASBlockTypes.h> #import <AsyncDisplayKit/ASBlockTypes.h>
#import <AsyncDisplayKit/ASDisplayNode.h> #import <AsyncDisplayKit/ASDisplayNode.h>

View File

@ -1046,15 +1046,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
restrictedToSize:(ASLayoutElementSize)size restrictedToSize:(ASLayoutElementSize)size
relativeToParentSize:(CGSize)parentSize relativeToParentSize:(CGSize)parentSize
{ {
// Use a pthread specific to mark when this method is called re-entrant on same thread.
// We only want one calculateLayout signpost interval per thread. // We only want one calculateLayout signpost interval per thread.
// This is fast enough to do it unconditionally. static _Thread_local NSInteger tls_callDepth;
auto key = ASPthreadStaticKey(NULL);
BOOL isRootCall = (pthread_getspecific(key) == NULL);
as_activity_scope_verbose(as_activity_create("Calculate node layout", AS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT)); as_activity_scope_verbose(as_activity_create("Calculate node layout", AS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT));
as_log_verbose(ASLayoutLog(), "Calculating layout for %@ sizeRange %@", self, NSStringFromASSizeRange(constrainedSize)); as_log_verbose(ASLayoutLog(), "Calculating layout for %@ sizeRange %@", self, NSStringFromASSizeRange(constrainedSize));
if (isRootCall) { if (tls_callDepth++ == 0) {
pthread_setspecific(key, kCFBooleanTrue);
ASSignpostStart(ASSignpostCalculateLayout); ASSignpostStart(ASSignpostCalculateLayout);
} }
@ -1063,8 +1059,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASLayout *result = [self calculateLayoutThatFits:resolvedRange]; ASLayout *result = [self calculateLayoutThatFits:resolvedRange];
as_log_verbose(ASLayoutLog(), "Calculated layout %@", result); as_log_verbose(ASLayoutLog(), "Calculated layout %@", result);
if (isRootCall) { if (--tls_callDepth == 0) {
pthread_setspecific(key, NULL);
ASSignpostEnd(ASSignpostCalculateLayout); ASSignpostEnd(ASSignpostCalculateLayout);
} }
return result; return result;

View File

@ -11,29 +11,18 @@
// //
#import <AsyncDisplayKit/ASAssert.h> #import <AsyncDisplayKit/ASAssert.h>
#import <Foundation/Foundation.h>
static pthread_key_t ASMainThreadAssertionsDisabledKey() static _Thread_local int tls_mainThreadAssertionsDisabledCount;
{
return ASPthreadStaticKey(NULL);
}
BOOL ASMainThreadAssertionsAreDisabled() { BOOL ASMainThreadAssertionsAreDisabled() {
return (size_t)pthread_getspecific(ASMainThreadAssertionsDisabledKey()) > 0; return tls_mainThreadAssertionsDisabledCount > 0;
} }
void ASPushMainThreadAssertionsDisabled() { void ASPushMainThreadAssertionsDisabled() {
pthread_key_t key = ASMainThreadAssertionsDisabledKey(); tls_mainThreadAssertionsDisabledCount += 1;
size_t oldValue = (size_t)pthread_getspecific(key);
pthread_setspecific(key, (void *)(oldValue + 1));
} }
void ASPopMainThreadAssertionsDisabled() { void ASPopMainThreadAssertionsDisabled() {
pthread_key_t key = ASMainThreadAssertionsDisabledKey(); tls_mainThreadAssertionsDisabledCount -= 1;
size_t oldValue = (size_t)pthread_getspecific(key); ASDisplayNodeCAssert(tls_mainThreadAssertionsDisabledCount >= 0, @"Attempt to pop thread assertion-disabling without corresponding push.");
if (oldValue > 0) {
pthread_setspecific(key, (void *)(oldValue - 1));
} else {
ASDisplayNodeCFailAssert(@"Attempt to pop thread assertion-disabling without corresponding push.");
}
} }

View File

@ -211,15 +211,6 @@
#define AS_SUBCLASSING_RESTRICTED #define AS_SUBCLASSING_RESTRICTED
#endif #endif
#define ASPthreadStaticKey(dtor) ({ \
static dispatch_once_t onceToken; \
static pthread_key_t key; \
dispatch_once(&onceToken, ^{ \
pthread_key_create(&key, dtor); \
}); \
key; \
})
#define ASCreateOnce(expr) ({ \ #define ASCreateOnce(expr) ({ \
static dispatch_once_t onceToken; \ static dispatch_once_t onceToken; \
static __typeof__(expr) staticVar; \ static __typeof__(expr) staticVar; \

View File

@ -50,38 +50,27 @@ CGSize const ASLayoutElementParentSizeUndefined = {ASLayoutElementParentDimensio
int32_t const ASLayoutElementContextInvalidTransitionID = 0; int32_t const ASLayoutElementContextInvalidTransitionID = 0;
int32_t const ASLayoutElementContextDefaultTransitionID = ASLayoutElementContextInvalidTransitionID + 1; int32_t const ASLayoutElementContextDefaultTransitionID = ASLayoutElementContextInvalidTransitionID + 1;
static void ASLayoutElementDestructor(void *p) { static _Thread_local __unsafe_unretained ASLayoutElementContext *tls_context;
if (p != NULL) {
ASDisplayNodeCFailAssert(@"Thread exited without clearing layout element context!");
CFBridgingRelease(p);
}
};
pthread_key_t ASLayoutElementContextKey()
{
return ASPthreadStaticKey(ASLayoutElementDestructor);
}
void ASLayoutElementPushContext(ASLayoutElementContext *context) void ASLayoutElementPushContext(ASLayoutElementContext *context)
{ {
// NOTE: It would be easy to support nested contexts just use an NSMutableArray here. // NOTE: It would be easy to support nested contexts just use an NSMutableArray here.
ASDisplayNodeCAssertNil(ASLayoutElementGetCurrentContext(), @"Nested ASLayoutElementContexts aren't supported."); ASDisplayNodeCAssertNil(tls_context, @"Nested ASLayoutElementContexts aren't supported.");
pthread_setspecific(ASLayoutElementContextKey(), CFBridgingRetain(context));
tls_context = (__bridge ASLayoutElementContext *)(__bridge_retained CFTypeRef)context;
} }
ASLayoutElementContext *ASLayoutElementGetCurrentContext() ASLayoutElementContext *ASLayoutElementGetCurrentContext()
{ {
// Don't retain here. Caller will retain if it wants to! // Don't retain here. Caller will retain if it wants to!
return (__bridge __unsafe_unretained ASLayoutElementContext *)pthread_getspecific(ASLayoutElementContextKey()); return tls_context;
} }
void ASLayoutElementPopContext() void ASLayoutElementPopContext()
{ {
ASLayoutElementContextKey(); ASDisplayNodeCAssertNotNil(tls_context, @"Attempt to pop context when there wasn't a context!");
ASDisplayNodeCAssertNotNil(ASLayoutElementGetCurrentContext(), @"Attempt to pop context when there wasn't a context!"); CFRelease((__bridge CFTypeRef)tls_context);
auto key = ASLayoutElementContextKey(); tls_context = nil;
CFBridgingRelease(pthread_getspecific(key));
pthread_setspecific(key, NULL);
} }
#pragma mark - ASLayoutElementStyle #pragma mark - ASLayoutElementStyle