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/)
- 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/)
- 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
- [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
//
#import <pthread.h>
#import <AsyncDisplayKit/ASBlockTypes.h>
#import <AsyncDisplayKit/ASDisplayNode.h>

View File

@ -1046,15 +1046,11 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
restrictedToSize:(ASLayoutElementSize)size
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.
// This is fast enough to do it unconditionally.
auto key = ASPthreadStaticKey(NULL);
BOOL isRootCall = (pthread_getspecific(key) == NULL);
static _Thread_local NSInteger tls_callDepth;
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));
if (isRootCall) {
pthread_setspecific(key, kCFBooleanTrue);
if (tls_callDepth++ == 0) {
ASSignpostStart(ASSignpostCalculateLayout);
}
@ -1063,8 +1059,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASLayout *result = [self calculateLayoutThatFits:resolvedRange];
as_log_verbose(ASLayoutLog(), "Calculated layout %@", result);
if (isRootCall) {
pthread_setspecific(key, NULL);
if (--tls_callDepth == 0) {
ASSignpostEnd(ASSignpostCalculateLayout);
}
return result;

View File

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

View File

@ -211,15 +211,6 @@
#define AS_SUBCLASSING_RESTRICTED
#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) ({ \
static dispatch_once_t onceToken; \
static __typeof__(expr) staticVar; \

View File

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