CocoaDev

Edit AllPages

This is a small test for CSCoroutine. It simply runs two interleaved loops that count up and down.


Update on September 12, 2007: Added a second test for thread-switching.

Update on September 20, 2007: Changed code to use NSConditionLock.

Update on October 10, 2007: Added an exception-throwing test, and comments.


#import “CSCoroutine.h”

@interface TestObject:NSObject { NSConditionLock *lock; } -(void)test; -(void)test1:(int)val; -(void)test1b:(int)val; -(void)test2; -(void)test2b; -(void)test3; -(void)test3b:(CSCoroutine *)coro; -(void)test3c; @end

@implementation TestObject

-(void)test { // Run each test [self test1:10]; [self test2]; [self test3]; }

-(void)test1:(int)val { printf(“Test 1: Interleaved loops\n”);

// Create and start coroutine which will return immediately.
CSCoroutine *coro=[self newCoroutine];
[(id)coro test1b:val];

// Print five numbers, invoking the coroutine after each.
for(int i=0;i<=5;i++)
{
	printf("a: %d\n",val+i);
	[coro switchTo];
} 

[coro release]; }

-(void)test1b:(int)val { // Return immediately to let main function run. [CSCoroutine returnFromCurrent];

// Print five numbers, returning after each one
for(int i=0;i<=5;i++)
{
	printf("b: %d\n",val-i);
	[CSCoroutine returnFromCurrent];
} }

-(void)test2 { printf(“Test 2: Exceptions\n”);

// Save the current coroutine pointer before calling potentially
// exception-throwing coroutine.
CSCoroutine *savedcoro=[CSCoroutine currentCoroutine];

@try
{
	// Create and start coroutine which will throw an exception.
	CSCoroutine *coro=[self newCoroutine];
	[(id)coro test2b];
}
@catch(id e)
{
	// Clean up after the exception by explicitly restoring
	// the current coroutine pointer. This is important!
	[CSCoroutine setCurrentCoroutine:savedcoro];
	printf("Exception caught!\n");
} }

-(void)test2b { printf(“In coroutine, throwing exception.\n”); [NSException raise:@”TestException” format:@”Test”]; }

-(void)test3 { printf(“Test 3: Jumping threads\n”);

// Create and start a coroutine on the main thread.
CSCoroutine *coro=[self newCoroutine];
[(id)coro test3c];

// Detach a secondary thread, which will also invoke the same coroutine.
lock=[[NSConditionLock alloc] initWithCondition:0];
[NSThread detachNewThreadSelector:@selector(test3b:) toTarget:self withObject:coro];

// Wait until thread finishes.
[lock lockWhenCondition:1];
[lock unlock];
[lock release]; }

-(void)test3b:(CSCoroutine *)coro { printf(“Separate thread started\n”);

// Invoke the coroutine created earlier, then clean up and exit.
[coro switchTo];
[coro release];
[lock lockWhenCondition:0];
[lock unlockWithCondition:1]; }

-(void)test3c { printf(“First invocation in main thread.\n”); [CSCoroutine returnFromCurrent]; printf(“Second invocation in separate thread.\n”); }

@end

int main(int argc,char **argv) { NSAutoreleasePool *pool=[NSAutoreleasePool new];

TestObject *test=[TestObject new];
[test test];
[test release];

[pool release]; }

The correct output should look something like this:

Test 1: Interleaved loops a: 10 b: 10 a: 11 b: 9 a: 12 b: 8 a: 13 b: 7 a: 14 b: 6 a: 15 b: 5 Test 2: Exceptions In coroutine, throwing exception. Exception caught! Test 3: Jumping threads First invocation in main thread. Separate thread started Second invocation in separate thread.