Swiftgram/submodules/AsyncDisplayKit/Tests/ASRecursiveUnfairLockTests.mm
Peter 9bc996374f Add 'submodules/AsyncDisplayKit/' from commit '02bedc12816e251ad71777f9d2578329b6d2bef6'
git-subtree-dir: submodules/AsyncDisplayKit
git-subtree-mainline: d06f423e0ed3df1fed9bd10d79ee312a9179b632
git-subtree-split: 02bedc12816e251ad71777f9d2578329b6d2bef6
2019-06-11 18:42:43 +01:00

185 lines
4.7 KiB
Plaintext

//
// ASRecursiveUnfairLockTests.mm
// Texture
//
// Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import "ASTestCase.h"
#import <AsyncDisplayKit/ASRecursiveUnfairLock.h>
#import <stdatomic.h>
#import <os/lock.h>
@interface ASRecursiveUnfairLockTests : ASTestCase
@end
@implementation ASRecursiveUnfairLockTests {
ASRecursiveUnfairLock lock;
}
- (void)setUp
{
[super setUp];
lock = AS_RECURSIVE_UNFAIR_LOCK_INIT;
}
- (void)testTheAtomicIsLockFree
{
XCTAssertTrue(atomic_is_lock_free(&lock._thread));
}
- (void)testRelockingFromSameThread
{
ASRecursiveUnfairLockLock(&lock);
ASRecursiveUnfairLockLock(&lock);
ASRecursiveUnfairLockUnlock(&lock);
// Now try locking from another thread.
XCTestExpectation *e1 = [self expectationWithDescription:@"Other thread tried lock."];
[NSThread detachNewThreadWithBlock:^{
XCTAssertFalse(ASRecursiveUnfairLockTryLock(&self->lock));
[e1 fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
ASRecursiveUnfairLockUnlock(&lock);
XCTestExpectation *e2 = [self expectationWithDescription:@"Other thread tried lock again"];
[NSThread detachNewThreadWithBlock:^{
XCTAssertTrue(ASRecursiveUnfairLockTryLock(&self->lock));
ASRecursiveUnfairLockUnlock(&self->lock);
[e2 fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
}
- (void)testThatUnlockingWithoutHoldingMakesAssertion
{
#ifdef NS_BLOCK_ASSERTIONS
#warning Assertions should be on for `testThatUnlockingWithoutHoldingMakesAssertion`
NSLog(@"Passing because assertions are off.");
#else
ASRecursiveUnfairLockLock(&lock);
XCTestExpectation *e1 = [self expectationWithDescription:@"Other thread tried lock."];
[NSThread detachNewThreadWithBlock:^{
XCTAssertThrows(ASRecursiveUnfairLockUnlock(&lock));
[e1 fulfill];
}];
[self waitForExpectationsWithTimeout:10 handler:nil];
ASRecursiveUnfairLockUnlock(&lock);
#endif
}
#define CHAOS_TEST_BODY(contested, prefix, infix, postfix) \
dispatch_group_t g = dispatch_group_create(); \
for (int i = 0; i < (contested ? 16 : 2); i++) {\
dispatch_group_enter(g);\
[NSThread detachNewThreadWithBlock:^{\
for (int i = 0; i < 20000; i++) {\
prefix;\
value += 150;\
infix;\
value -= 150;\
postfix;\
}\
dispatch_group_leave(g);\
}];\
}\
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
#pragma mark - Correctness Tests
- (void)testRecursiveUnfairLockContested
{
__block int value = 0;
[self measureBlock:^{
CHAOS_TEST_BODY(YES, ASRecursiveUnfairLockLock(&lock), {}, ASRecursiveUnfairLockUnlock(&lock));
}];
XCTAssertEqual(value, 0);
}
- (void)testRecursiveUnfairLockUncontested
{
__block int value = 0;
[self measureBlock:^{
CHAOS_TEST_BODY(NO, ASRecursiveUnfairLockLock(&lock), {}, ASRecursiveUnfairLockUnlock(&lock));
}];
XCTAssertEqual(value, 0);
}
#pragma mark - Lock performance tests
#if RUN_LOCK_PERF_TESTS
- (void)testNoLockContested
{
__block int value = 0;
[self measureBlock:^{
CHAOS_TEST_BODY(YES, {}, {}, {});
}];
XCTAssertNotEqual(value, 0);
}
- (void)testPlainUnfairLockContested
{
__block int value = 0;
__block os_unfair_lock unfairLock = OS_UNFAIR_LOCK_INIT;
[self measureBlock:^{
CHAOS_TEST_BODY(YES, os_unfair_lock_lock(&unfairLock), {}, os_unfair_lock_unlock(&unfairLock));
}];
XCTAssertEqual(value, 0);
}
- (void)testRecursiveMutexContested
{
__block int value = 0;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
__block pthread_mutex_t m;
pthread_mutex_init (&m, &attr);
pthread_mutexattr_destroy (&attr);
[self measureBlock:^{
CHAOS_TEST_BODY(YES, pthread_mutex_lock(&m), {}, pthread_mutex_unlock(&m));
}];
pthread_mutex_destroy(&m);
}
- (void)testNoLockUncontested
{
__block int value = 0;
[self measureBlock:^{
CHAOS_TEST_BODY(NO, {}, {}, {});
}];
XCTAssertNotEqual(value, 0);
}
- (void)testPlainUnfairLockUncontested
{
__block int value = 0;
__block os_unfair_lock unfairLock = OS_UNFAIR_LOCK_INIT;
[self measureBlock:^{
CHAOS_TEST_BODY(NO, os_unfair_lock_lock(&unfairLock), {}, os_unfair_lock_unlock(&unfairLock));
}];
XCTAssertEqual(value, 0);
}
- (void)testRecursiveMutexUncontested
{
__block int value = 0;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
__block pthread_mutex_t m;
pthread_mutex_init (&m, &attr);
pthread_mutexattr_destroy (&attr);
[self measureBlock:^{
CHAOS_TEST_BODY(NO, pthread_mutex_lock(&m), {}, pthread_mutex_unlock(&m));
}];
pthread_mutex_destroy(&m);
}
#endif // RUN_LOCK_PERF_TESTS
@end