Skip to content

Commit

Permalink
Merge pull request ReactiveCocoa#26 from Lightricks/feature/tests-tsa…
Browse files Browse the repository at this point in the history
…n-fix

ReactiveObjCTests: fix TSan issues.
  • Loading branch information
barakwei authored Nov 5, 2018
2 parents e1da278 + 9d538c9 commit 1809484
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 42 deletions.
32 changes: 17 additions & 15 deletions ReactiveObjCTests/RACSchedulerSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
@import Nimble;

#import "RACScheduler.h"

#import <ReactiveObjC/EXTScope.h>
#import <stdatomic.h>

#import "RACScheduler+Private.h"
#import "RACQueueScheduler+Subclass.h"
#import "RACDisposable.h"
#import <ReactiveObjC/EXTScope.h>
#import "RACTestExampleScheduler.h"
#import <libkern/OSAtomic.h>

// This shouldn't be used directly. Use the `expectCurrentSchedulers` block
// below instead.
Expand Down Expand Up @@ -143,8 +145,8 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should cancel scheduled blocks when disposed", ^{
__block BOOL firstBlockRan = NO;
__block BOOL secondBlockRan = NO;
__block atomic_bool firstBlockRan = NO;
__block atomic_bool secondBlockRan = NO;

// Start off on the scheduler so the enqueued blocks won't run until we
// return.
Expand All @@ -167,7 +169,7 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should schedule future blocks", ^{
__block BOOL done = NO;
__block atomic_bool done = NO;

[scheduler after:futureDate() schedule:^{
done = YES;
Expand All @@ -178,8 +180,8 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should cancel future blocks when disposed", ^{
__block BOOL firstBlockRan = NO;
__block BOOL secondBlockRan = NO;
__block atomic_bool firstBlockRan = NO;
__block atomic_bool secondBlockRan = NO;

NSDate *date = futureDate();
RACDisposable *disposable = [scheduler after:date schedule:^{
Expand All @@ -199,7 +201,7 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should schedule recurring blocks", ^{
__block NSUInteger count = 0;
__block atomic_uint count = 0;

RACDisposable *disposable = [scheduler after:[NSDate date] repeatingEvery:0.05 withLeeway:0 schedule:^{
count++;
Expand Down Expand Up @@ -259,8 +261,8 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should execute scheduled blocks immediately if it's in a scheduler already", ^{
__block BOOL done = NO;
__block BOOL executedImmediately = NO;
__block atomic_bool done = NO;
__block atomic_bool executedImmediately = NO;

[[RACScheduler scheduler] schedule:^{
[RACScheduler.subscriptionScheduler schedule:^{
Expand Down Expand Up @@ -366,12 +368,12 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should reschedule when invoked asynchronously", ^{
__block NSUInteger count = 0;
__block atomic_uint count = 0;

RACScheduler *asynchronousScheduler = [RACScheduler scheduler];
[RACScheduler.mainThreadScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) {
[asynchronousScheduler after:[NSDate dateWithTimeIntervalSinceNow:0.01] schedule:^{
NSUInteger thisCount = ++count;
atomic_uint thisCount = ++count;
if (thisCount < 3) {
recurse();

Expand All @@ -386,7 +388,7 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"shouldn't reschedule itself when disposed", ^{
__block NSUInteger count = 0;
__block atomic_uint count = 0;
__block RACDisposable *disposable = [RACScheduler.mainThreadScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) {
++count;

Expand All @@ -409,7 +411,7 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should invoke blocks scheduled with -schedule:", ^{
__block BOOL invoked = NO;
__block atomic_bool invoked = NO;
[scheduler schedule:^{
invoked = YES;
}];
Expand All @@ -418,7 +420,7 @@ static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *cu
});

qck_it(@"should invoke blocks scheduled with -after:schedule:", ^{
__block BOOL invoked = NO;
__block atomic_bool invoked = NO;
[scheduler after:[NSDate dateWithTimeIntervalSinceNow:0.01] schedule:^{
invoked = YES;
}];
Expand Down
6 changes: 4 additions & 2 deletions ReactiveObjCTests/RACSequenceExamples.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#import "RACSequenceExamples.h"

#import <stdatomic.h>

#import "RACScheduler.h"
#import "RACSequence.h"
#import "RACSignal+Operations.h"
Expand Down Expand Up @@ -59,8 +61,8 @@ + (void)configure:(Configuration *)configuration {
RACScheduler* scheduler = [RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh];
RACSignal *signal = [sequence signalWithScheduler:scheduler];

__block BOOL flag = YES;
__block BOOL completed = NO;
__block atomic_bool flag = YES;
__block atomic_bool completed = NO;
[signal subscribeNext:^(id x) {
expect(@(flag)).to(beTruthy());
flag = NO;
Expand Down
4 changes: 3 additions & 1 deletion ReactiveObjCTests/RACSequenceSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#import "RACSequenceExamples.h"
#import "RACStreamExamples.h"

#import <stdatomic.h>

#import "NSArray+RACSequenceAdditions.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACPropertySubscribing.h"
Expand Down Expand Up @@ -305,7 +307,7 @@
[values addObject:@(i)];
}

__block BOOL finished = NO;
__block atomic_bool finished = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@autoreleasepool {
(void)[[values.rac_sequence map:^(id value) {
Expand Down
6 changes: 4 additions & 2 deletions ReactiveObjCTests/RACSerialDisposableSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#import "RACSerialDisposable.h"

#import <stdatomic.h>

QuickSpecBegin(RACSerialDisposableSpec)

qck_it(@"should initialize with -init", ^{
Expand Down Expand Up @@ -138,12 +140,12 @@
});

qck_it(@"should not crash when racing between swapInDisposable and disposable", ^{
__block BOOL stop = NO;
__block atomic_bool stop = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (long long)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
stop = YES;
});

RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init];
RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
while (!stop) {
[serialDisposable swapInDisposable:[RACDisposable disposableWithBlock:^{}]];
Expand Down
24 changes: 12 additions & 12 deletions ReactiveObjCTests/RACSignalSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#import "RACTestObject.h"

#import <ReactiveObjC/EXTKeyPathCoding.h>
#import <stdatomic.h>

#import "NSObject+RACDeallocating.h"
#import "NSObject+RACPropertySubscribing.h"
#import "RACBehaviorSubject.h"
Expand All @@ -33,7 +35,6 @@
#import "RACTestScheduler.h"
#import "RACTuple.h"
#import "RACUnit.h"
#import <libkern/OSAtomic.h>

// Set in a beforeAll below.
static NSError *RACSignalTestError;
Expand Down Expand Up @@ -111,7 +112,7 @@ + (void)configure:(Configuration *)configuration {
};

RACSignal *infiniteSignal = [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
__block volatile int32_t done = 0;
__block atomic_int done = 0;

[RACScheduler.mainThreadScheduler schedule:^{
while (!done) {
Expand All @@ -120,7 +121,7 @@ + (void)configure:(Configuration *)configuration {
}];

return [RACDisposable disposableWithBlock:^{
OSAtomicIncrement32Barrier(&done);
++done;
}];
}];

Expand Down Expand Up @@ -345,21 +346,21 @@ + (void)configure:(Configuration *)configuration {
});

qck_it(@"should have a current scheduler in didSubscribe block", ^{
__block RACScheduler *currentScheduler;
__block atomic_bool hasCurrentScheduler = NO;
RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
currentScheduler = RACScheduler.currentScheduler;
hasCurrentScheduler = RACScheduler.currentScheduler != nil;
[subscriber sendCompleted];
return nil;
}];

[signal subscribeNext:^(id x) {}];
expect(currentScheduler).notTo(beNil());
expect(hasCurrentScheduler).to(beTruthy());

currentScheduler = nil;
hasCurrentScheduler = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[signal subscribeNext:^(id x) {}];
});
expect(currentScheduler).toEventuallyNot(beNil());
expect(hasCurrentScheduler).toEventually(beTruthy());
});

qck_it(@"should automatically dispose of other subscriptions from +createSignal:", ^{
Expand Down Expand Up @@ -860,12 +861,11 @@ + (void)configure:(Configuration *)configuration {
}];
}];

__block NSUInteger nextCount = 0;
__block BOOL gotCompleted = NO;
__block atomic_uint nextCount = 0;
__block atomic_bool gotCompleted = NO;
[[signal repeat] subscribeNext:^(id x) {
nextCount++;
} error:^(NSError *error) {

} completed:^{
gotCompleted = YES;
}];
Expand Down Expand Up @@ -2304,7 +2304,7 @@ + (void)configure:(Configuration *)configuration {

qck_beforeEach(^{
testTimer = [^(RACSignal *timer, NSNumber *minInterval, NSNumber *leeway) {
__block NSUInteger nextsReceived = 0;
__block atomic_uint nextsReceived = 0;

NSTimeInterval startTime = NSDate.timeIntervalSinceReferenceDate;
[[timer take:3] subscribeNext:^(NSDate *date) {
Expand Down
21 changes: 11 additions & 10 deletions ReactiveObjCTests/RACSubjectSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@

#import "RACSubscriberExamples.h"

#import <libkern/OSAtomic.h>
#import <ReactiveObjC/EXTScope.h>
#import <stdatomic.h>

#import "RACBehaviorSubject.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
Expand Down Expand Up @@ -240,10 +241,10 @@ - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable {

// Just leak it, ain't no thang.
__unsafe_unretained volatile id *values = (__unsafe_unretained id *)calloc(count, sizeof(*values));
__block volatile int32_t nextIndex = 0;
__block atomic_int nextIndex = 0;

[subject subscribeNext:^(NSNumber *value) {
int32_t indexPlusOne = OSAtomicIncrement32(&nextIndex);
int32_t indexPlusOne = ++nextIndex;
values[indexPlusOne - 1] = value;
}];

Expand All @@ -261,7 +262,7 @@ - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable {
[subject sendCompleted];
});

OSMemoryBarrier();
atomic_thread_fence(memory_order_seq_cst);

NSArray *liveValues = [NSArray arrayWithObjects:(id *)values count:(NSUInteger)nextIndex];
expect(liveValues).to(haveCount(@(count)));
Expand All @@ -280,21 +281,21 @@ - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable {
qck_it(@"should have a current scheduler when replaying", ^{
[subject sendNext:RACUnit.defaultUnit];

__block RACScheduler *currentScheduler;
__block atomic_bool hasCurrentScheduler = NO;
[subject subscribeNext:^(id x) {
currentScheduler = RACScheduler.currentScheduler;
hasCurrentScheduler = RACScheduler.currentScheduler != nil;
}];

expect(currentScheduler).notTo(beNil());
expect(hasCurrentScheduler).notTo(beNil());

currentScheduler = nil;
hasCurrentScheduler = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[subject subscribeNext:^(id x) {
currentScheduler = RACScheduler.currentScheduler;
hasCurrentScheduler = RACScheduler.currentScheduler != nil;
}];
});

expect(currentScheduler).toEventuallyNot(beNil());
expect(hasCurrentScheduler).toEventually(beTruthy());
});

qck_it(@"should stop replaying when the subscription is disposed", ^{
Expand Down

0 comments on commit 1809484

Please sign in to comment.