Skip to content

Commit

Permalink
fix(CODispatch): fix crash when co_launch in backgroundThread
Browse files Browse the repository at this point in the history
fix crash when co_launch in backgroundThread

fix alibaba#60
  • Loading branch information
pengyutang125 committed Mar 28, 2019
1 parent b15bcc4 commit 80b2a3d
Show file tree
Hide file tree
Showing 9 changed files with 555 additions and 41 deletions.
316 changes: 311 additions & 5 deletions Examples/coobjcBaseExample/coobjcBaseExampleTests/coobjcPromiseTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,36 @@
#import <OCMock/OCMock.h>
#import <coobjc/coobjc.h>


@interface TestThreadObject1 : NSObject

+ (instancetype)sharedInstance;

- (void)runBlock:(dispatch_block_t)block;

@end

@implementation TestThreadObject1

+ (instancetype)sharedInstance{
static TestThreadObject1 *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[TestThreadObject1 alloc] init];
});
return instance;
}

- (void)_handle:(dispatch_block_t)block{
block();
}

- (void)runBlock:(dispatch_block_t)block{
[self performSelectorInBackground:@selector(_handle:) withObject:block];
}

@end

static dispatch_queue_t test_queue(){
static dispatch_queue_t q = nil;
static dispatch_once_t onceToken;
Expand Down Expand Up @@ -125,14 +155,18 @@ static id testPromise3() {
COPromise *promise = [COPromise new];


NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5 target:[Test123 instanceWithBlock:^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[promise fulfill:@13];
}] selector:@selector(fire) userInfo:nil repeats:NO];
});

// NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5 target:[Test123 instanceWithBlock:^{
// [promise fulfill:@13];
// }] selector:@selector(fire) userInfo:nil repeats:NO];

[promise onCancel:^(COPromise * _Nonnull promise) {
[timer invalidate];
}];

// [promise onCancel:^(COPromise * _Nonnull promise) {
// [timer invalidate];
// }];

return promise;
}
Expand Down Expand Up @@ -429,4 +463,276 @@ static id testPromise3() {
});

});


describe(@"background Thread Proimse tests", ^{
it(@"fulfill will return the result normally.", ^{
__block NSInteger val = 0;

[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{

id result = await(testPromise1());
val = [result integerValue];
expect(val).to.equal(11);
});
}];


waitUntil(^(DoneCallback done) {
dispatch_async(dispatch_get_main_queue(), ^{
expect(val).to.equal(11);
done();
});
});
});

it(@"reject should return nil, and error.", ^{
__block NSInteger val = 0;
[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{

id result = await(testPromise2());
if (!result) {
NSError *error = co_getError();
expect(error).to.equal([NSError errorWithDomain:@"hehe" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"hehe1"}]);
val = 12;
} else {
val = 11;
}
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
expect(val).to.equal(12);
done();
});
});
});

it(@"after cancel, the coroutine should not execute the rest codes.", ^{
__block NSInteger val = 44;
__block COCoroutine *co = nil;
[[TestThreadObject1 sharedInstance] runBlock:^{
co = co_launch(^{

id result = await(testPromise3());
if (!result) {
NSError *error = co_getError();
expect([COPromise isPromiseCancelled:error]).to.beTruthy();
expect(co_isActive()).to.equal(NO);
expect(co_isCancelled()).to.equal(YES);
val = 12;
} else {
val = 11;
}
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[co cancel];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
expect(val).to.equal(12);
done();
});
});
});
});

it(@"cancel a routine which is finished will do nothing.", ^{
__block NSInteger val = 44;
__block COCoroutine *co = nil;
[[TestThreadObject1 sharedInstance] runBlock:^{
co = co_launch(^{

id result = await(testPromise3());
if (!result) {
NSError *error = co_getError();
val = 12;
} else {
val = 11;
}
});
}];
waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[co cancel];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
expect(val).to.equal(11);
done();
});
});
});
});

it(@"batch await test", ^{
__block NSInteger val = 0;
[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{

NSArray *results = batch_await(@[
testPromise11(),
testPromise12(),
testPromise13(),
]);
val = 1;
expect(results[0]).to.equal(@"1");
expect(results[1]).to.equal(@"2");
expect(results[2]).to.equal([NSError errorWithDomain:@"aa" code:3 userInfo:@{}]);

});
}];


waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
expect(val).to.equal(1);
done();
});
});
});

it(@"https://github.com/alibaba/coobjc/issues/26", ^{

[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{
id dd = await(downloadImageWithError());
expect(co_getError()).notTo.equal(nil);
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
done();
});
});
});

it(@"test progress promise", ^{
[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{
int progressCount = 0;
COProgressPromise *promise = progressDownloadFileFromUrl(@"http://img17.3lian.com/d/file/201701/17/9a0d018ba683b9cbdcc5a7267b90891c.jpg");
for(id p in promise){
double v = [p doubleValue];
NSLog(@"current progress: %f", (float)v);
progressCount++;
}
expect(progressCount > 0).beTruthy();
NSData *data = await(promise);
expect(data.length > 0).beTruthy();
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
done();
});
});
});

it(@"test progress promise 50%", ^{

[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{
int progressCount = 0;
COProgressPromise *promise = progressDownloadFileFromUrl(@"http://img17.3lian.com/d/file/201701/17/9a0d018ba683b9cbdcc5a7267b90891c.jpg");
for(id p in promise){
double v = [p doubleValue];
if(v >= 0.5){
break;
}
NSLog(@"current progress: %f", (float)v);
progressCount++;
}
expect(progressCount > 0).beTruthy();
NSData *data = await(promise);
expect(data.length > 0).beTruthy();
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
done();
});
});
});

it(@"test progress promise direct", ^{
[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{
int progressCount = 0;
COProgressPromise *promise = progressDownloadFileFromUrl(@"http://img17.3lian.com/d/file/201701/17/9a0d018ba683b9cbdcc5a7267b90891c.jpg");
NSData *data = await(promise);
expect(data.length > 0).beTruthy();
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
done();
});
});
});

it(@"test progress promise error", ^{
[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{
int progressCount = 0;
COProgressPromise *promise = progressDownloadFileFromUrl(@"http://img17.3lianghhjghj.com/d/file/201701/17/9a0d018ba683b9cbdcc5a7267b90891c.jpg1111");
for(id p in promise){
double v = [p doubleValue];
if(v >= 0.5){
break;
}
NSLog(@"current progress: %f", (float)v);
progressCount++;
}
expect(progressCount).to.equal(1);
NSData *data = await(promise);
expect(data == nil).beTruthy();
expect(co_getError() != nil).beTruthy();
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
done();
});
});
});

it(@"test concurrent await promise", ^{
__block int val = 0;
[[TestThreadObject1 sharedInstance] runBlock:^{
co_launch(^{

NSTimeInterval begin = CACurrentMediaTime();
id p1 = testPromise21();
id p2 = testPromise22();

NSString *r1 = await(p1);
expect(r1).to.equal(@"1");
NSString *r2 = await(p2);
expect(r2).to.equal(@"2");

NSTimeInterval duration = CACurrentMediaTime() - begin;
expect(duration < 5.5).beTruthy();
val = 1;
});
}];

waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
expect(val).to.equal(1);
done();
});
});
});

});
SpecEnd
42 changes: 42 additions & 0 deletions cocore/CODispatch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// CODispatch.h
// cocore
//
// Created by 彭 玉堂 on 2019/3/28.
// Copyright © 2019 Alibaba lnc. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface CODispatchTimer : NSObject

@property (nonatomic, strong) dispatch_block_t block;

- (void)invalidate;

@end




NS_ASSUME_NONNULL_BEGIN

@interface CODispatch : NSObject

+ (instancetype)currentDispatch;

- (BOOL)isCurrentDispatch;

- (void)dispatch_block:(dispatch_block_t)block;

- (void)dispatch_async_block:(dispatch_block_t)block;


- (CODispatchTimer*)dispatch_timer:(dispatch_block_t)block
interval:(NSTimeInterval)interval;

- (BOOL)isEqualToDipatch:(CODispatch*)dispatch;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 80b2a3d

Please sign in to comment.