# HG changeset patch # User Jens Alfke # Date 1209513932 25200 # Node ID deb0ee0c5b21fae3b2451277ea5965f0cb8ae54e First checkin diff -r 000000000000 -r deb0ee0c5b21 Actors.xcodeproj/project.pbxproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Actors.xcodeproj/project.pbxproj Tue Apr 29 17:05:32 2008 -0700 @@ -0,0 +1,235 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 2703CFE40DC796DC00DD026B /* MYCoroutine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2703CFE30DC796DC00DD026B /* MYCoroutine.m */; }; + 2703D1BE0DC7DAD100DD026B /* CoroX.c in Sources */ = {isa = PBXBuildFile; fileRef = 2703D1BD0DC7DAD100DD026B /* CoroX.c */; }; + 2703D28B0DC7EC5A00DD026B /* MYCoroutineTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2703D28A0DC7EC5A00DD026B /* MYCoroutineTest.m */; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 2703CFE20DC796DC00DD026B /* MYCoroutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCoroutine.h; sourceTree = ""; }; + 2703CFE30DC796DC00DD026B /* MYCoroutine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCoroutine.m; sourceTree = ""; }; + 2703D1BC0DC7DAD100DD026B /* CoroX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoroX.h; sourceTree = ""; }; + 2703D1BD0DC7DAD100DD026B /* CoroX.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CoroX.c; sourceTree = ""; }; + 2703D28A0DC7EC5A00DD026B /* MYCoroutineTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCoroutineTest.m; sourceTree = ""; }; + 8DD76FA10486AA7600D96B5E /* Coroutines */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Coroutines; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* Coroutines */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = Coroutines; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 2703D2A30DC7EE7100DD026B /* Coroutines */, + ); + name = Source; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* Coroutines */, + ); + name = Products; + sourceTree = ""; + }; + 2703D2A30DC7EE7100DD026B /* Coroutines */ = { + isa = PBXGroup; + children = ( + 2703CFE20DC796DC00DD026B /* MYCoroutine.h */, + 2703CFE30DC796DC00DD026B /* MYCoroutine.m */, + 2703D28A0DC7EC5A00DD026B /* MYCoroutineTest.m */, + 2703D1BC0DC7DAD100DD026B /* CoroX.h */, + 2703D1BD0DC7DAD100DD026B /* CoroX.c */, + ); + path = Coroutines; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* Coroutines */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "Coroutines" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + 8DD76F9E0486AA7600D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Coroutines; + productInstallPath = "$(HOME)/bin"; + productName = Coroutines; + productReference = 8DD76FA10486AA7600D96B5E /* Coroutines */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "Actors" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* Coroutines */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* Coroutines */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2703CFE40DC796DC00DD026B /* MYCoroutine.m in Sources */, + 2703D1BE0DC7DAD100DD026B /* CoroX.c in Sources */, + 2703D28B0DC7EC5A00DD026B /* MYCoroutineTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = ""; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = Coroutines; + WARNING_CFLAGS = "-Wall"; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = ""; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = Coroutines; + WARNING_CFLAGS = "-Wall"; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.5; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "Coroutines" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "Actors" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff -r 000000000000 -r deb0ee0c5b21 Coroutines/CoroX.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coroutines/CoroX.c Tue Apr 29 17:05:32 2008 -0700 @@ -0,0 +1,188 @@ +/* + * CoroX.c + * Coroutines for Mac OS X + * + * Created by Jens Alfke on 4/29/08. + * Adapted from Steve Dekorte's libCoroutine: + * + * by putting it on a piece of wood and banging a few nails through it. + * No, actually I removed all the stuff for cross-platform support, leaving only the simple + * code that works on Mac OS X 10.5, and then cleaned things up a bit. + * + * Copyright 2008 Jens Alfke. All rights reserved. + * Copyright (c) 2002, 2003 Steve Dekorte. All rights reserved. + * License is at the bottom of this file. + * + */ + +#include "CoroX.h" +#include +#include +#include +#include + + +#define CORO_DEFAULT_STACK_SIZE (65536*4) +#define CORO_STACK_SIZE_MIN 8192 + + +struct Coro +{ + size_t stackSize; + void *stack; + ucontext_t env; + // The following field works around bug(?) in sys/_structs.h. This field should be part of ucontext_t: + _STRUCT_MCONTEXT env_registers; + unsigned char isMain; +}; + + +typedef struct CallbackBlock +{ + void *context; + CoroStartCallback *func; +} CallbackBlock; + + +Coro *Coro_new(void) +{ + Coro *self = (Coro *)calloc(1, sizeof(Coro)); + self->stackSize = CORO_DEFAULT_STACK_SIZE; + self->stack = NULL; + return self; +} + +void Coro_free(Coro *self) +{ + if (self->stack) + free(self->stack); + free(self); +} + + +void *Coro_stack(Coro *self) +{ + return self->stack; +} + +size_t Coro_stackSize(Coro *self) +{ + return self->stackSize; +} + +void Coro_setStackSize_(Coro *self, size_t sizeInBytes) +{ + self->stackSize = sizeInBytes; +} + +uint8_t *Coro_CurrentStackPointer(void) __attribute__ ((noinline)); + +uint8_t *Coro_CurrentStackPointer(void) +{ + uint8_t a; + uint8_t *b = &a; + return b; +} + +size_t Coro_bytesLeftOnStack(Coro *self) +{ + uint8_t dummy; + ptrdiff_t p1 = (ptrdiff_t)(&dummy); + ptrdiff_t p2 = (ptrdiff_t)Coro_CurrentStackPointer(); + int stackMovesUp = p2 > p1; + ptrdiff_t start = ((ptrdiff_t)self->stack); + ptrdiff_t end = start + self->stackSize; + + if (stackMovesUp) + { + return end - p1; + } + else + { + return p1 - start; + } +} + +int Coro_stackSpaceAlmostGone(Coro *self) +{ + return Coro_bytesLeftOnStack(self) < CORO_STACK_SIZE_MIN; +} + + +void Coro_initializeMainCoro(Coro *self) +{ + self->isMain = 1; +} + + +static void Coro_StartWithArg(CallbackBlock *block) +{ + (block->func)(block->context); + fprintf(stderr,"CoroX error: returned from coro start function\n"); + abort(); +} + +typedef void (*makecontext_func)(void); + +static void Coro_setup(Coro *self, void *arg) +{ + ucontext_t *ucp = (ucontext_t *) &self->env; + getcontext(ucp); + + ucp->uc_stack.ss_sp = Coro_stack(self); + ucp->uc_stack.ss_size = Coro_stackSize(self); + ucp->uc_stack.ss_flags = 0; + ucp->uc_link = NULL; + + makecontext(ucp, (makecontext_func)Coro_StartWithArg, 1, arg); +} + + +void Coro_startCoro_(Coro *self, Coro *other, void *context, CoroStartCallback *callback) +{ + assert(other->stack==NULL); + other->stack = calloc(1, other->stackSize + 16); + + CallbackBlock callbackBlock = {context,callback}; + Coro_setup(other, &callbackBlock); + + Coro_switchTo_(self, other); +} + +void Coro_switchTo_(Coro *self, Coro *next) +{ + swapcontext(&self->env, &next->env); +} + + + + +/* + (This is a BSD License) + + Copyright (c) 2002, 2003 Steve Dekorte + Copyright (c) 2008 Jens Alfke + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are + permitted provided that the following conditions are met: + + • Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + • Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + • Neither the name of the author nor the names of other contributors may be used to + endorse or promote products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff -r 000000000000 -r deb0ee0c5b21 Coroutines/CoroX.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coroutines/CoroX.h Tue Apr 29 17:05:32 2008 -0700 @@ -0,0 +1,58 @@ +/* + * CoroX.c + * Coroutines for Mac OS X + * + * Created by Jens Alfke on 4/29/08. + * Adapted from Steve Dekorte's libCoroutine: + * + * by putting it on a piece of wood and banging a few nails through it. + * No, actually I removed all the stuff for cross-platform support, leaving only the simple + * code that works on Mac OS X 10.5, and then cleaned things up a bit. + * + * Copyright 2008 Jens Alfke. All rights reserved. + * Copyright (c) 2002, 2003 Steve Dekorte. All rights reserved. + * License is at the bottom of CoroX.c. + * + */ + +#pragma once +#include +#include + +/** C coroutine implementation for Mac OS X. + Based on, and API-compatible with, Steve Dekorte's libCoroutine. + His docs are at http://www.dekorte.com/projects/opensource/libCoroutine/docs/ +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct Coro Coro; + + Coro *Coro_new(void); + void Coro_free(Coro *self); + + // stack + + void *Coro_stack(Coro *self); + size_t Coro_stackSize(Coro *self); + void Coro_setStackSize_(Coro *self, size_t sizeInBytes); + size_t Coro_bytesLeftOnStack(Coro *self); + int Coro_stackSpaceAlmostGone(Coro *self); + + // initialization + + void Coro_initializeMainCoro(Coro *self); + + typedef void (CoroStartCallback)(void *); + + void Coro_startCoro_(Coro *self, Coro *other, void *context, CoroStartCallback *callback); + + // context-switch + + void Coro_switchTo_(Coro *self, Coro *next); + +#ifdef __cplusplus +} +#endif diff -r 000000000000 -r deb0ee0c5b21 Coroutines/MYCoroutine.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coroutines/MYCoroutine.h Tue Apr 29 17:05:32 2008 -0700 @@ -0,0 +1,74 @@ +// +// MYCoroutine.h +// Coroutines for Mac OS X +// +// Created by Jens Alfke on 4/29/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// + +#import + + +/** Objective-C coroutine class. + See: http://en.wikipedia.org/wiki/Coroutine +*/ +@interface MYCoroutine : NSObject +{ + @private + struct Coro *_coro; + NSString *_name; +} + +/** The "main" coroutine: the one corresponding to the execution context before the + first coroutine is started. */ ++ (MYCoroutine*) mainCoroutine; + +/** The currently active coroutine. */ ++ (MYCoroutine*) currentCoroutine; + +/** Creates a new coroutine and starts it, performing the given invocation on it. + That method must not return! */ ++ (MYCoroutine*) startWithInvocation: (NSInvocation*)invocation; + +/** Creates but does not start a coroutine. */ +- (id) init; + +/** Starts a new coroutine, and performs the given invocation on it. + The current coroutine will block (i.e. this call won't return) + until some other coroutine tells it to resume. */ +- (void) startWithInvocation: (NSInvocation*)invocation; + +/** Starts a new coroutine, invoking its -main method as its body. + Since the default implementation of -main is empty, this only makes sense to call + on an instance of a subclass of MYCoroutine that's overridden -main. + The current coroutine will block (i.e. this call won't return) + until some other coroutine tells it to resume. */ +- (void) start; + +/** The "main" method that will be called if the coroutine is started with -start. + The default implementation is empty, so a subclass using -start must override this. */ +- (void) main; + +/** Returns control to an already-started (but blocked) coroutine. + The most recent -resume call made from within that coroutine will return. + The current coroutine will block (i.e. this call won't return) + until some other coroutine tells it to resume. */ +- (void) resume; + + +/** The coroutine's name. You can put anything you want here, as a debugging aid. */ +@property (copy) NSString* name; + +/** Returns YES if this is the currently executing coroutine. */ +@property (readonly) BOOL isCurrent; + +/** The stack size of the coroutine. You can only change this before calling -start! */ +@property size_t stackSize; + +/** The number of bytes of stack space left on this coroutine. */ +@property (readonly) size_t bytesLeftOnStack; + +/** Returns YES if this coroutine is almost out of stack space (less than 8k left) */ +@property (readonly) BOOL stackSpaceAlmostGone; + +@end diff -r 000000000000 -r deb0ee0c5b21 Coroutines/MYCoroutine.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coroutines/MYCoroutine.m Tue Apr 29 17:05:32 2008 -0700 @@ -0,0 +1,173 @@ +// +// MYCoroutine.m +// Coroutines +// +// Created by Jens Alfke on 4/29/08. +// Copyright 2008 Jens Alfke. All rights reserved. +// License is at the bottom of this file. +// + +#import "MYCoroutine.h" +#import "CoroX.h" + + +#ifndef LogTo +#define kEnableLog 0 /* 1 enables logging, 0 disables it */ +#define LogTo(DOMAIN,MSG,...) do{ if(kEnableLog) NSLog(@""#DOMAIN ": " MSG,__VA_ARGS__); }while(0) +#endif + +#ifndef Warn +#define Warn(MSG,...) NSLog(@"WARNING: " #MSG,__VA_ARGS__) +#endif + + +@implementation MYCoroutine + + +static MYCoroutine *sMain, *sCurrent; + + ++ (void) initialize +{ + if( self == [MYCoroutine class] ) { + sMain = [[self alloc] init]; + Coro_initializeMainCoro(sMain->_coro); + sMain.name = @"MAIN"; + sCurrent = sMain; + } +} + + +- (id) init +{ + self = [super init]; + if (self != nil) { + _coro = Coro_new(); + LogTo(Coroutine,@"INIT %@ : _coro=%p",self,_coro); + } + return self; +} + + +- (void) dealloc +{ + LogTo(Coroutine,@"DEALLOC %@",self); + Coro_free(_coro); + [super dealloc]; +} + + +- (NSString*) description +{ + if( _name ) + return [NSString stringWithFormat: @"%@[%@]", [self class],_name]; + else + return [NSString stringWithFormat: @"%@[%p]", [self class],self]; +} + + +@synthesize name=_name; + + ++ (MYCoroutine*) mainCoroutine {return sMain;} ++ (MYCoroutine*) currentCoroutine {return sCurrent;} + +- (BOOL) isCurrent {return self==sCurrent;} + +- (const void*) stack {return Coro_stack(_coro);} +- (size_t) stackSize {return Coro_stackSize(_coro);} +- (void) setStackSize: (size_t)size {Coro_setStackSize_(_coro,size);} + +- (size_t) bytesLeftOnStack {return Coro_bytesLeftOnStack(_coro);} +- (BOOL) stackSpaceAlmostGone {return Coro_stackSpaceAlmostGone(_coro);} + + +static void startWithInvocation( void *context ) +{ + [(NSInvocation*)context invoke]; +} + +static void startWithMain( void *context ) +{ + [(MYCoroutine*)context main]; +} + +- (void) startWithInvocation: (NSInvocation*)invocation +{ + LogTo(Coroutine,@"Starting %@ (currently in %@)",self,sCurrent); + MYCoroutine *current = sCurrent; + sCurrent = self; + + if( invocation ) + Coro_startCoro_(current->_coro, _coro, invocation, &startWithInvocation); + else + Coro_startCoro_(current->_coro, _coro, self, &startWithMain); + + sCurrent = current; + LogTo(Coroutine,@"...resumed %@ after starting %@",sCurrent,self); +} + +- (void) start +{ + [self startWithInvocation: nil]; +} + + ++ (MYCoroutine*) startWithInvocation: (NSInvocation*)invocation +{ + MYCoroutine *cr = [[self alloc] init]; + [cr startWithInvocation: invocation]; + return cr; +} + + +- (void) resume +{ + LogTo(Coroutine,@"Resuming %@ (currently in %@)",self,sCurrent); + MYCoroutine *current = sCurrent; + sCurrent = self; + Coro_switchTo_(current->_coro,_coro); + sCurrent = current; + LogTo(Coroutine,@"...resumed %@",sCurrent); +} + + +- (void) main +{ + // subclasses should override this. +} + + +@end + + + + +/* + (This is a BSD License) + + Copyright (c) 2008 Jens Alfke + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are + permitted provided that the following conditions are met: + + • Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + • Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + • Neither the name of the author nor the names of other contributors may be used to + endorse or promote products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff -r 000000000000 -r deb0ee0c5b21 Coroutines/MYCoroutineTest.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coroutines/MYCoroutineTest.m Tue Apr 29 17:05:32 2008 -0700 @@ -0,0 +1,88 @@ +// +// MYCoroutineTest.m +// Coroutines +// +// Created by Jens Alfke on 4/29/08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import "MYCoroutine.h" + + +@interface CoroTest1 : MYCoroutine +{ + int value; +} +@property int value; +@end + +@interface CoroTest2 : CoroTest1 +@end + + +CoroTest1 *firstCoro, *secondCoro; + + +@implementation CoroTest2 + +- (void) main +{ + int num = 0; + + NSLog(@"secondTask created with value %d", self.value); + + while (1) + { + NSLog(@"secondTask: %d %d", self.bytesLeftOnStack, num++); + [firstCoro resume]; + } +} + +@end + + +@implementation CoroTest1 + +@synthesize value; + +- (void) main +{ + int num = 0; + + NSLog(@"firstTask created with value %d", self.value); + secondCoro = [[CoroTest2 alloc] init]; + secondCoro.name = @"second"; + secondCoro.value = 2; + [secondCoro start]; + + while ( num < 100 ) + { + NSLog(@"firstTask: %d %d", self.bytesLeftOnStack, num++); + [secondCoro resume]; + } + + [secondCoro release]; + + [[MYCoroutine mainCoroutine] resume]; +} + +@end + + +int main() +{ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + + NSLog(@"Starting test..."); + //[[[NSThread alloc] init] start]; + firstCoro = [[CoroTest1 alloc] init]; + firstCoro.name = @"first"; + firstCoro.value = 1; + [firstCoro start]; + + NSLog(@"Returned from coroutines; exiting"); + + [firstCoro release]; + + [pool drain]; +}