First checkin
authorJens Alfke <jens@mooseyard.com>
Tue Apr 29 17:05:32 2008 -0700 (2008-04-29)
changeset 0deb0ee0c5b21
child 1 2475f871c218
First checkin
Actors.xcodeproj/project.pbxproj
Coroutines/CoroX.c
Coroutines/CoroX.h
Coroutines/MYCoroutine.h
Coroutines/MYCoroutine.m
Coroutines/MYCoroutineTest.m
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Actors.xcodeproj/project.pbxproj	Tue Apr 29 17:05:32 2008 -0700
     1.3 @@ -0,0 +1,235 @@
     1.4 +// !$*UTF8*$!
     1.5 +{
     1.6 +	archiveVersion = 1;
     1.7 +	classes = {
     1.8 +	};
     1.9 +	objectVersion = 45;
    1.10 +	objects = {
    1.11 +
    1.12 +/* Begin PBXBuildFile section */
    1.13 +		2703CFE40DC796DC00DD026B /* MYCoroutine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2703CFE30DC796DC00DD026B /* MYCoroutine.m */; };
    1.14 +		2703D1BE0DC7DAD100DD026B /* CoroX.c in Sources */ = {isa = PBXBuildFile; fileRef = 2703D1BD0DC7DAD100DD026B /* CoroX.c */; };
    1.15 +		2703D28B0DC7EC5A00DD026B /* MYCoroutineTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2703D28A0DC7EC5A00DD026B /* MYCoroutineTest.m */; };
    1.16 +		8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
    1.17 +/* End PBXBuildFile section */
    1.18 +
    1.19 +/* Begin PBXCopyFilesBuildPhase section */
    1.20 +		8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
    1.21 +			isa = PBXCopyFilesBuildPhase;
    1.22 +			buildActionMask = 8;
    1.23 +			dstPath = /usr/share/man/man1/;
    1.24 +			dstSubfolderSpec = 0;
    1.25 +			files = (
    1.26 +			);
    1.27 +			runOnlyForDeploymentPostprocessing = 1;
    1.28 +		};
    1.29 +/* End PBXCopyFilesBuildPhase section */
    1.30 +
    1.31 +/* Begin PBXFileReference section */
    1.32 +		08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
    1.33 +		2703CFE20DC796DC00DD026B /* MYCoroutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCoroutine.h; sourceTree = "<group>"; };
    1.34 +		2703CFE30DC796DC00DD026B /* MYCoroutine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCoroutine.m; sourceTree = "<group>"; };
    1.35 +		2703D1BC0DC7DAD100DD026B /* CoroX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoroX.h; sourceTree = "<group>"; };
    1.36 +		2703D1BD0DC7DAD100DD026B /* CoroX.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CoroX.c; sourceTree = "<group>"; };
    1.37 +		2703D28A0DC7EC5A00DD026B /* MYCoroutineTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCoroutineTest.m; sourceTree = "<group>"; };
    1.38 +		8DD76FA10486AA7600D96B5E /* Coroutines */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Coroutines; sourceTree = BUILT_PRODUCTS_DIR; };
    1.39 +/* End PBXFileReference section */
    1.40 +
    1.41 +/* Begin PBXFrameworksBuildPhase section */
    1.42 +		8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
    1.43 +			isa = PBXFrameworksBuildPhase;
    1.44 +			buildActionMask = 2147483647;
    1.45 +			files = (
    1.46 +				8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
    1.47 +			);
    1.48 +			runOnlyForDeploymentPostprocessing = 0;
    1.49 +		};
    1.50 +/* End PBXFrameworksBuildPhase section */
    1.51 +
    1.52 +/* Begin PBXGroup section */
    1.53 +		08FB7794FE84155DC02AAC07 /* Coroutines */ = {
    1.54 +			isa = PBXGroup;
    1.55 +			children = (
    1.56 +				08FB7795FE84155DC02AAC07 /* Source */,
    1.57 +				08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
    1.58 +				1AB674ADFE9D54B511CA2CBB /* Products */,
    1.59 +			);
    1.60 +			name = Coroutines;
    1.61 +			sourceTree = "<group>";
    1.62 +		};
    1.63 +		08FB7795FE84155DC02AAC07 /* Source */ = {
    1.64 +			isa = PBXGroup;
    1.65 +			children = (
    1.66 +				2703D2A30DC7EE7100DD026B /* Coroutines */,
    1.67 +			);
    1.68 +			name = Source;
    1.69 +			sourceTree = "<group>";
    1.70 +		};
    1.71 +		08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
    1.72 +			isa = PBXGroup;
    1.73 +			children = (
    1.74 +				08FB779EFE84155DC02AAC07 /* Foundation.framework */,
    1.75 +			);
    1.76 +			name = "External Frameworks and Libraries";
    1.77 +			sourceTree = "<group>";
    1.78 +		};
    1.79 +		1AB674ADFE9D54B511CA2CBB /* Products */ = {
    1.80 +			isa = PBXGroup;
    1.81 +			children = (
    1.82 +				8DD76FA10486AA7600D96B5E /* Coroutines */,
    1.83 +			);
    1.84 +			name = Products;
    1.85 +			sourceTree = "<group>";
    1.86 +		};
    1.87 +		2703D2A30DC7EE7100DD026B /* Coroutines */ = {
    1.88 +			isa = PBXGroup;
    1.89 +			children = (
    1.90 +				2703CFE20DC796DC00DD026B /* MYCoroutine.h */,
    1.91 +				2703CFE30DC796DC00DD026B /* MYCoroutine.m */,
    1.92 +				2703D28A0DC7EC5A00DD026B /* MYCoroutineTest.m */,
    1.93 +				2703D1BC0DC7DAD100DD026B /* CoroX.h */,
    1.94 +				2703D1BD0DC7DAD100DD026B /* CoroX.c */,
    1.95 +			);
    1.96 +			path = Coroutines;
    1.97 +			sourceTree = "<group>";
    1.98 +		};
    1.99 +/* End PBXGroup section */
   1.100 +
   1.101 +/* Begin PBXNativeTarget section */
   1.102 +		8DD76F960486AA7600D96B5E /* Coroutines */ = {
   1.103 +			isa = PBXNativeTarget;
   1.104 +			buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "Coroutines" */;
   1.105 +			buildPhases = (
   1.106 +				8DD76F990486AA7600D96B5E /* Sources */,
   1.107 +				8DD76F9B0486AA7600D96B5E /* Frameworks */,
   1.108 +				8DD76F9E0486AA7600D96B5E /* CopyFiles */,
   1.109 +			);
   1.110 +			buildRules = (
   1.111 +			);
   1.112 +			dependencies = (
   1.113 +			);
   1.114 +			name = Coroutines;
   1.115 +			productInstallPath = "$(HOME)/bin";
   1.116 +			productName = Coroutines;
   1.117 +			productReference = 8DD76FA10486AA7600D96B5E /* Coroutines */;
   1.118 +			productType = "com.apple.product-type.tool";
   1.119 +		};
   1.120 +/* End PBXNativeTarget section */
   1.121 +
   1.122 +/* Begin PBXProject section */
   1.123 +		08FB7793FE84155DC02AAC07 /* Project object */ = {
   1.124 +			isa = PBXProject;
   1.125 +			buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "Actors" */;
   1.126 +			compatibilityVersion = "Xcode 3.1";
   1.127 +			hasScannedForEncodings = 1;
   1.128 +			mainGroup = 08FB7794FE84155DC02AAC07 /* Coroutines */;
   1.129 +			projectDirPath = "";
   1.130 +			projectRoot = "";
   1.131 +			targets = (
   1.132 +				8DD76F960486AA7600D96B5E /* Coroutines */,
   1.133 +			);
   1.134 +		};
   1.135 +/* End PBXProject section */
   1.136 +
   1.137 +/* Begin PBXSourcesBuildPhase section */
   1.138 +		8DD76F990486AA7600D96B5E /* Sources */ = {
   1.139 +			isa = PBXSourcesBuildPhase;
   1.140 +			buildActionMask = 2147483647;
   1.141 +			files = (
   1.142 +				2703CFE40DC796DC00DD026B /* MYCoroutine.m in Sources */,
   1.143 +				2703D1BE0DC7DAD100DD026B /* CoroX.c in Sources */,
   1.144 +				2703D28B0DC7EC5A00DD026B /* MYCoroutineTest.m in Sources */,
   1.145 +			);
   1.146 +			runOnlyForDeploymentPostprocessing = 0;
   1.147 +		};
   1.148 +/* End PBXSourcesBuildPhase section */
   1.149 +
   1.150 +/* Begin XCBuildConfiguration section */
   1.151 +		1DEB927508733DD40010E9CD /* Debug */ = {
   1.152 +			isa = XCBuildConfiguration;
   1.153 +			buildSettings = {
   1.154 +				ALWAYS_SEARCH_USER_PATHS = NO;
   1.155 +				COPY_PHASE_STRIP = NO;
   1.156 +				GCC_C_LANGUAGE_STANDARD = gnu99;
   1.157 +				GCC_DYNAMIC_NO_PIC = NO;
   1.158 +				GCC_ENABLE_FIX_AND_CONTINUE = YES;
   1.159 +				GCC_MODEL_TUNING = G5;
   1.160 +				GCC_OPTIMIZATION_LEVEL = 0;
   1.161 +				GCC_PRECOMPILE_PREFIX_HEADER = YES;
   1.162 +				GCC_PREFIX_HEADER = "";
   1.163 +				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
   1.164 +				INSTALL_PATH = /usr/local/bin;
   1.165 +				PRODUCT_NAME = Coroutines;
   1.166 +				WARNING_CFLAGS = "-Wall";
   1.167 +			};
   1.168 +			name = Debug;
   1.169 +		};
   1.170 +		1DEB927608733DD40010E9CD /* Release */ = {
   1.171 +			isa = XCBuildConfiguration;
   1.172 +			buildSettings = {
   1.173 +				ALWAYS_SEARCH_USER_PATHS = NO;
   1.174 +				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
   1.175 +				GCC_C_LANGUAGE_STANDARD = gnu99;
   1.176 +				GCC_MODEL_TUNING = G5;
   1.177 +				GCC_PRECOMPILE_PREFIX_HEADER = YES;
   1.178 +				GCC_PREFIX_HEADER = "";
   1.179 +				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
   1.180 +				INSTALL_PATH = /usr/local/bin;
   1.181 +				PRODUCT_NAME = Coroutines;
   1.182 +				WARNING_CFLAGS = "-Wall";
   1.183 +			};
   1.184 +			name = Release;
   1.185 +		};
   1.186 +		1DEB927908733DD40010E9CD /* Debug */ = {
   1.187 +			isa = XCBuildConfiguration;
   1.188 +			buildSettings = {
   1.189 +				ALWAYS_SEARCH_USER_PATHS = NO;
   1.190 +				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
   1.191 +				GCC_C_LANGUAGE_STANDARD = c99;
   1.192 +				GCC_OPTIMIZATION_LEVEL = 0;
   1.193 +				GCC_WARN_ABOUT_RETURN_TYPE = YES;
   1.194 +				GCC_WARN_UNUSED_VARIABLE = YES;
   1.195 +				ONLY_ACTIVE_ARCH = YES;
   1.196 +				PREBINDING = NO;
   1.197 +				SDKROOT = macosx10.5;
   1.198 +			};
   1.199 +			name = Debug;
   1.200 +		};
   1.201 +		1DEB927A08733DD40010E9CD /* Release */ = {
   1.202 +			isa = XCBuildConfiguration;
   1.203 +			buildSettings = {
   1.204 +				ALWAYS_SEARCH_USER_PATHS = NO;
   1.205 +				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
   1.206 +				GCC_C_LANGUAGE_STANDARD = c99;
   1.207 +				GCC_WARN_ABOUT_RETURN_TYPE = YES;
   1.208 +				GCC_WARN_UNUSED_VARIABLE = YES;
   1.209 +				PREBINDING = NO;
   1.210 +				SDKROOT = macosx10.5;
   1.211 +			};
   1.212 +			name = Release;
   1.213 +		};
   1.214 +/* End XCBuildConfiguration section */
   1.215 +
   1.216 +/* Begin XCConfigurationList section */
   1.217 +		1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "Coroutines" */ = {
   1.218 +			isa = XCConfigurationList;
   1.219 +			buildConfigurations = (
   1.220 +				1DEB927508733DD40010E9CD /* Debug */,
   1.221 +				1DEB927608733DD40010E9CD /* Release */,
   1.222 +			);
   1.223 +			defaultConfigurationIsVisible = 0;
   1.224 +			defaultConfigurationName = Release;
   1.225 +		};
   1.226 +		1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "Actors" */ = {
   1.227 +			isa = XCConfigurationList;
   1.228 +			buildConfigurations = (
   1.229 +				1DEB927908733DD40010E9CD /* Debug */,
   1.230 +				1DEB927A08733DD40010E9CD /* Release */,
   1.231 +			);
   1.232 +			defaultConfigurationIsVisible = 0;
   1.233 +			defaultConfigurationName = Release;
   1.234 +		};
   1.235 +/* End XCConfigurationList section */
   1.236 +	};
   1.237 +	rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
   1.238 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Coroutines/CoroX.c	Tue Apr 29 17:05:32 2008 -0700
     2.3 @@ -0,0 +1,188 @@
     2.4 +/*
     2.5 + *  CoroX.c
     2.6 + *  Coroutines for Mac OS X
     2.7 + *
     2.8 + *  Created by Jens Alfke on 4/29/08.
     2.9 + *  Adapted from Steve Dekorte's libCoroutine:
    2.10 + *  <http://www.dekorte.com/projects/opensource/libCoroutine/>
    2.11 + *  by putting it on a piece of wood and banging a few nails through it.
    2.12 + *  No, actually I removed all the stuff for cross-platform support, leaving only the simple
    2.13 + *  code that works on Mac OS X 10.5, and then cleaned things up a bit.
    2.14 + *
    2.15 + *  Copyright 2008 Jens Alfke. All rights reserved.
    2.16 + *  Copyright (c) 2002, 2003 Steve Dekorte. All rights reserved.
    2.17 + *  License is at the bottom of this file.
    2.18 + *
    2.19 + */
    2.20 +
    2.21 +#include "CoroX.h"
    2.22 +#include <ucontext.h>
    2.23 +#include <stddef.h>
    2.24 +#include <stdio.h>
    2.25 +#include <assert.h>
    2.26 +
    2.27 +
    2.28 +#define CORO_DEFAULT_STACK_SIZE (65536*4)
    2.29 +#define CORO_STACK_SIZE_MIN     8192
    2.30 +
    2.31 +
    2.32 +struct Coro
    2.33 +{        
    2.34 +    size_t stackSize;
    2.35 +    void *stack;
    2.36 +    ucontext_t env;
    2.37 +    // The following field works around bug(?) in sys/_structs.h. This field should be part of ucontext_t:
    2.38 +    _STRUCT_MCONTEXT	env_registers; 
    2.39 +    unsigned char isMain;
    2.40 +};
    2.41 +
    2.42 +
    2.43 +typedef struct CallbackBlock
    2.44 +{
    2.45 +    void *context;
    2.46 +    CoroStartCallback *func;
    2.47 +} CallbackBlock;
    2.48 +
    2.49 +
    2.50 +Coro *Coro_new(void)
    2.51 +{
    2.52 +    Coro *self = (Coro *)calloc(1, sizeof(Coro));
    2.53 +    self->stackSize = CORO_DEFAULT_STACK_SIZE;
    2.54 +    self->stack = NULL;
    2.55 +    return self;
    2.56 +}
    2.57 +
    2.58 +void Coro_free(Coro *self)
    2.59 +{
    2.60 +    if (self->stack)
    2.61 +        free(self->stack);
    2.62 +    free(self);
    2.63 +}
    2.64 +
    2.65 +
    2.66 +void *Coro_stack(Coro *self)
    2.67 +{
    2.68 +    return self->stack;
    2.69 +}
    2.70 +
    2.71 +size_t Coro_stackSize(Coro *self)
    2.72 +{
    2.73 +    return self->stackSize;
    2.74 +}
    2.75 +
    2.76 +void Coro_setStackSize_(Coro *self, size_t sizeInBytes)
    2.77 +{
    2.78 +    self->stackSize = sizeInBytes;
    2.79 +}
    2.80 +
    2.81 +uint8_t *Coro_CurrentStackPointer(void) __attribute__ ((noinline));
    2.82 +
    2.83 +uint8_t *Coro_CurrentStackPointer(void)
    2.84 +{
    2.85 +    uint8_t a;
    2.86 +    uint8_t *b = &a;
    2.87 +    return b;
    2.88 +}
    2.89 +
    2.90 +size_t Coro_bytesLeftOnStack(Coro *self)
    2.91 +{
    2.92 +    uint8_t dummy;
    2.93 +    ptrdiff_t p1 = (ptrdiff_t)(&dummy);
    2.94 +    ptrdiff_t p2 = (ptrdiff_t)Coro_CurrentStackPointer();
    2.95 +    int stackMovesUp = p2 > p1;
    2.96 +    ptrdiff_t start = ((ptrdiff_t)self->stack);
    2.97 +    ptrdiff_t end = start + self->stackSize;
    2.98 +    
    2.99 +    if (stackMovesUp)
   2.100 +    {
   2.101 +        return end - p1;
   2.102 +    }
   2.103 +    else
   2.104 +    {
   2.105 +        return p1 - start;
   2.106 +    }
   2.107 +}
   2.108 +
   2.109 +int Coro_stackSpaceAlmostGone(Coro *self)
   2.110 +{
   2.111 +    return Coro_bytesLeftOnStack(self) < CORO_STACK_SIZE_MIN;
   2.112 +}
   2.113 +
   2.114 +
   2.115 +void Coro_initializeMainCoro(Coro *self)
   2.116 +{
   2.117 +    self->isMain = 1;
   2.118 +}
   2.119 +
   2.120 +
   2.121 +static void Coro_StartWithArg(CallbackBlock *block)
   2.122 +{
   2.123 +    (block->func)(block->context);
   2.124 +    fprintf(stderr,"CoroX error: returned from coro start function\n");
   2.125 +    abort();
   2.126 +}
   2.127 +
   2.128 +typedef void (*makecontext_func)(void);
   2.129 +
   2.130 +static void Coro_setup(Coro *self, void *arg)
   2.131 +{
   2.132 +    ucontext_t *ucp = (ucontext_t *) &self->env;
   2.133 +    getcontext(ucp);
   2.134 +    
   2.135 +    ucp->uc_stack.ss_sp = Coro_stack(self);
   2.136 +    ucp->uc_stack.ss_size = Coro_stackSize(self);
   2.137 +    ucp->uc_stack.ss_flags = 0;
   2.138 +    ucp->uc_link = NULL;
   2.139 +    
   2.140 +    makecontext(ucp, (makecontext_func)Coro_StartWithArg, 1, arg);
   2.141 +}
   2.142 +
   2.143 +
   2.144 +void Coro_startCoro_(Coro *self, Coro *other, void *context, CoroStartCallback *callback)
   2.145 +{
   2.146 +    assert(other->stack==NULL);
   2.147 +    other->stack = calloc(1, other->stackSize + 16);
   2.148 +
   2.149 +    CallbackBlock callbackBlock = {context,callback};
   2.150 +    Coro_setup(other, &callbackBlock);
   2.151 +    
   2.152 +    Coro_switchTo_(self, other);
   2.153 +}
   2.154 +
   2.155 +void Coro_switchTo_(Coro *self, Coro *next)
   2.156 +{
   2.157 +    swapcontext(&self->env, &next->env);
   2.158 +}
   2.159 +
   2.160 +
   2.161 +
   2.162 +
   2.163 +/*
   2.164 + (This is a BSD License)
   2.165 + 
   2.166 + Copyright (c) 2002, 2003 Steve Dekorte
   2.167 + Copyright (c) 2008 Jens Alfke
   2.168 + All rights reserved.
   2.169 + 
   2.170 + Redistribution and use in source and binary forms, with or without modification, are
   2.171 + permitted provided that the following conditions are met:
   2.172 + 
   2.173 + • Redistributions of source code must retain the above copyright notice, this list of
   2.174 + conditions and the following disclaimer.
   2.175 + • Redistributions in binary form must reproduce the above copyright notice, this list
   2.176 + of conditions and the following disclaimer in the documentation and/or other materials
   2.177 + provided with the distribution.
   2.178 + • Neither the name of the author nor the names of other contributors may be used to
   2.179 + endorse or promote products derived from this software without specific prior written
   2.180 + permission.
   2.181 + 
   2.182 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
   2.183 + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   2.184 + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   2.185 + THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   2.186 + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   2.187 + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   2.188 + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
   2.189 + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   2.190 + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   2.191 +*/
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/Coroutines/CoroX.h	Tue Apr 29 17:05:32 2008 -0700
     3.3 @@ -0,0 +1,58 @@
     3.4 +/*
     3.5 + *  CoroX.c
     3.6 + *  Coroutines for Mac OS X
     3.7 + *
     3.8 + *  Created by Jens Alfke on 4/29/08.
     3.9 + *  Adapted from Steve Dekorte's libCoroutine:
    3.10 + *  <http://www.dekorte.com/projects/opensource/libCoroutine/>
    3.11 + *  by putting it on a piece of wood and banging a few nails through it.
    3.12 + *  No, actually I removed all the stuff for cross-platform support, leaving only the simple
    3.13 + *  code that works on Mac OS X 10.5, and then cleaned things up a bit.
    3.14 + *
    3.15 + *  Copyright 2008 Jens Alfke. All rights reserved.
    3.16 + *  Copyright (c) 2002, 2003 Steve Dekorte. All rights reserved.
    3.17 + *  License is at the bottom of CoroX.c.
    3.18 + *
    3.19 + */
    3.20 +
    3.21 +#pragma once
    3.22 +#include <stdlib.h>
    3.23 +#include <stdint.h>
    3.24 +
    3.25 +/** C coroutine implementation for Mac OS X.
    3.26 +    Based on, and API-compatible with, Steve Dekorte's libCoroutine.
    3.27 +    His docs are at http://www.dekorte.com/projects/opensource/libCoroutine/docs/
    3.28 +*/
    3.29 +
    3.30 +#ifdef __cplusplus
    3.31 +extern "C" {
    3.32 +#endif
    3.33 +    
    3.34 +    typedef struct Coro Coro;
    3.35 +    
    3.36 +    Coro *Coro_new(void);
    3.37 +    void Coro_free(Coro *self);
    3.38 +    
    3.39 +    // stack
    3.40 +    
    3.41 +    void *Coro_stack(Coro *self);
    3.42 +    size_t Coro_stackSize(Coro *self);
    3.43 +    void Coro_setStackSize_(Coro *self, size_t sizeInBytes);
    3.44 +    size_t Coro_bytesLeftOnStack(Coro *self);
    3.45 +    int Coro_stackSpaceAlmostGone(Coro *self);
    3.46 +    
    3.47 +    // initialization
    3.48 +    
    3.49 +    void Coro_initializeMainCoro(Coro *self);
    3.50 +    
    3.51 +    typedef void (CoroStartCallback)(void *);
    3.52 +    
    3.53 +    void Coro_startCoro_(Coro *self, Coro *other, void *context, CoroStartCallback *callback);
    3.54 +    
    3.55 +    // context-switch
    3.56 +    
    3.57 +    void Coro_switchTo_(Coro *self, Coro *next);
    3.58 +    
    3.59 +#ifdef __cplusplus
    3.60 +}
    3.61 +#endif
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/Coroutines/MYCoroutine.h	Tue Apr 29 17:05:32 2008 -0700
     4.3 @@ -0,0 +1,74 @@
     4.4 +//
     4.5 +//  MYCoroutine.h
     4.6 +//  Coroutines for Mac OS X
     4.7 +//
     4.8 +//  Created by Jens Alfke on 4/29/08.
     4.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    4.10 +//
    4.11 +
    4.12 +#import <Foundation/Foundation.h>
    4.13 +
    4.14 +
    4.15 +/** Objective-C coroutine class.
    4.16 +    See: http://en.wikipedia.org/wiki/Coroutine 
    4.17 +*/
    4.18 +@interface MYCoroutine : NSObject
    4.19 +{
    4.20 +    @private
    4.21 +    struct Coro *_coro;
    4.22 +    NSString *_name;
    4.23 +}
    4.24 +
    4.25 +/** The "main" coroutine: the one corresponding to the execution context before the
    4.26 +    first coroutine is started. */
    4.27 ++ (MYCoroutine*) mainCoroutine;
    4.28 +
    4.29 +/** The currently active coroutine. */
    4.30 ++ (MYCoroutine*) currentCoroutine;
    4.31 +
    4.32 +/** Creates a new coroutine and starts it, performing the given invocation on it.
    4.33 +    That method must not return! */
    4.34 ++ (MYCoroutine*) startWithInvocation: (NSInvocation*)invocation;
    4.35 +
    4.36 +/** Creates but does not start a coroutine. */
    4.37 +- (id) init;
    4.38 +
    4.39 +/** Starts a new coroutine, and performs the given invocation on it.
    4.40 +    The current coroutine will block (i.e. this call won't return)
    4.41 +    until some other coroutine tells it to resume. */
    4.42 +- (void) startWithInvocation: (NSInvocation*)invocation;
    4.43 +
    4.44 +/** Starts a new coroutine, invoking its -main method as its body.
    4.45 +    Since the default implementation of -main is empty, this only makes sense to call
    4.46 +    on an instance of a subclass of MYCoroutine that's overridden -main.
    4.47 +    The current coroutine will block (i.e. this call won't return)
    4.48 +    until some other coroutine tells it to resume. */
    4.49 +- (void) start;
    4.50 +
    4.51 +/** The "main" method that will be called if the coroutine is started with -start.
    4.52 +    The default implementation is empty, so a subclass using -start must override this. */
    4.53 +- (void) main;
    4.54 +
    4.55 +/** Returns control to an already-started (but blocked) coroutine.
    4.56 +    The most recent -resume call made from within that coroutine will return.
    4.57 +    The current coroutine will block (i.e. this call won't return)
    4.58 +    until some other coroutine tells it to resume. */
    4.59 +- (void) resume;
    4.60 +
    4.61 +
    4.62 +/** The coroutine's name. You can put anything you want here, as a debugging aid. */
    4.63 +@property (copy) NSString* name;
    4.64 +
    4.65 +/** Returns YES if this is the currently executing coroutine. */
    4.66 +@property (readonly) BOOL isCurrent;
    4.67 +
    4.68 +/** The stack size of the coroutine. You can only change this before calling -start! */
    4.69 +@property size_t stackSize;
    4.70 +
    4.71 +/** The number of bytes of stack space left on this coroutine. */
    4.72 +@property (readonly) size_t bytesLeftOnStack;
    4.73 +
    4.74 +/** Returns YES if this coroutine is almost out of stack space (less than 8k left) */
    4.75 +@property (readonly) BOOL stackSpaceAlmostGone;
    4.76 +
    4.77 +@end
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/Coroutines/MYCoroutine.m	Tue Apr 29 17:05:32 2008 -0700
     5.3 @@ -0,0 +1,173 @@
     5.4 +//
     5.5 +//  MYCoroutine.m
     5.6 +//  Coroutines
     5.7 +//
     5.8 +//  Created by Jens Alfke on 4/29/08.
     5.9 +//  Copyright 2008 Jens Alfke. All rights reserved.
    5.10 +//  License is at the bottom of this file.
    5.11 +//
    5.12 +
    5.13 +#import "MYCoroutine.h"
    5.14 +#import "CoroX.h"
    5.15 +
    5.16 +
    5.17 +#ifndef LogTo
    5.18 +#define kEnableLog 0    /* 1 enables logging, 0 disables it */
    5.19 +#define LogTo(DOMAIN,MSG,...) do{ if(kEnableLog) NSLog(@""#DOMAIN ": " MSG,__VA_ARGS__); }while(0)
    5.20 +#endif
    5.21 +
    5.22 +#ifndef Warn
    5.23 +#define Warn(MSG,...) NSLog(@"WARNING: " #MSG,__VA_ARGS__)
    5.24 +#endif
    5.25 +
    5.26 +
    5.27 +@implementation MYCoroutine
    5.28 +
    5.29 +
    5.30 +static MYCoroutine *sMain, *sCurrent;
    5.31 +
    5.32 +
    5.33 ++ (void) initialize
    5.34 +{
    5.35 +    if( self == [MYCoroutine class] ) {
    5.36 +        sMain = [[self alloc] init];
    5.37 +        Coro_initializeMainCoro(sMain->_coro);
    5.38 +        sMain.name = @"MAIN";
    5.39 +        sCurrent = sMain;
    5.40 +    }
    5.41 +}
    5.42 +
    5.43 +
    5.44 +- (id) init
    5.45 +{
    5.46 +    self = [super init];
    5.47 +    if (self != nil) {
    5.48 +        _coro = Coro_new();
    5.49 +        LogTo(Coroutine,@"INIT %@ : _coro=%p",self,_coro);
    5.50 +    }
    5.51 +    return self;
    5.52 +}
    5.53 +
    5.54 +
    5.55 +- (void) dealloc
    5.56 +{
    5.57 +    LogTo(Coroutine,@"DEALLOC %@",self);
    5.58 +    Coro_free(_coro);
    5.59 +    [super dealloc];
    5.60 +}
    5.61 +
    5.62 +
    5.63 +- (NSString*) description
    5.64 +{
    5.65 +    if( _name )
    5.66 +        return [NSString stringWithFormat: @"%@[%@]", [self class],_name];
    5.67 +    else
    5.68 +        return [NSString stringWithFormat: @"%@[%p]", [self class],self];
    5.69 +}
    5.70 +
    5.71 +
    5.72 +@synthesize name=_name;
    5.73 +
    5.74 +
    5.75 ++ (MYCoroutine*) mainCoroutine          {return sMain;}
    5.76 ++ (MYCoroutine*) currentCoroutine       {return sCurrent;}
    5.77 +
    5.78 +- (BOOL) isCurrent                      {return self==sCurrent;}
    5.79 +
    5.80 +- (const void*) stack                   {return Coro_stack(_coro);}
    5.81 +- (size_t) stackSize                    {return Coro_stackSize(_coro);}
    5.82 +- (void) setStackSize: (size_t)size     {Coro_setStackSize_(_coro,size);}
    5.83 +
    5.84 +- (size_t) bytesLeftOnStack             {return Coro_bytesLeftOnStack(_coro);}
    5.85 +- (BOOL) stackSpaceAlmostGone           {return Coro_stackSpaceAlmostGone(_coro);}
    5.86 +
    5.87 +
    5.88 +static void startWithInvocation( void *context )
    5.89 +{
    5.90 +    [(NSInvocation*)context invoke];
    5.91 +}
    5.92 +
    5.93 +static void startWithMain( void *context )
    5.94 +{
    5.95 +    [(MYCoroutine*)context main];
    5.96 +}
    5.97 +
    5.98 +- (void) startWithInvocation: (NSInvocation*)invocation
    5.99 +{
   5.100 +    LogTo(Coroutine,@"Starting %@ (currently in %@)",self,sCurrent);
   5.101 +    MYCoroutine *current = sCurrent;
   5.102 +    sCurrent = self;
   5.103 +    
   5.104 +    if( invocation )
   5.105 +        Coro_startCoro_(current->_coro, _coro, invocation, &startWithInvocation);
   5.106 +    else
   5.107 +        Coro_startCoro_(current->_coro, _coro, self, &startWithMain);
   5.108 +    
   5.109 +    sCurrent = current;
   5.110 +    LogTo(Coroutine,@"...resumed %@ after starting %@",sCurrent,self);
   5.111 +}
   5.112 +
   5.113 +- (void) start
   5.114 +{
   5.115 +    [self startWithInvocation: nil];
   5.116 +}
   5.117 +
   5.118 +
   5.119 ++ (MYCoroutine*) startWithInvocation: (NSInvocation*)invocation
   5.120 +{
   5.121 +    MYCoroutine *cr = [[self alloc] init];
   5.122 +    [cr startWithInvocation: invocation];
   5.123 +    return cr;
   5.124 +}
   5.125 +
   5.126 +
   5.127 +- (void) resume
   5.128 +{
   5.129 +    LogTo(Coroutine,@"Resuming %@ (currently in %@)",self,sCurrent);
   5.130 +    MYCoroutine *current = sCurrent;
   5.131 +    sCurrent = self;
   5.132 +    Coro_switchTo_(current->_coro,_coro);
   5.133 +    sCurrent = current;
   5.134 +    LogTo(Coroutine,@"...resumed %@",sCurrent);
   5.135 +}
   5.136 +
   5.137 +
   5.138 +- (void) main
   5.139 +{
   5.140 +    // subclasses should override this.
   5.141 +}
   5.142 +
   5.143 +
   5.144 +@end
   5.145 +
   5.146 +
   5.147 +
   5.148 +
   5.149 +/*
   5.150 + (This is a BSD License)
   5.151 + 
   5.152 + Copyright (c) 2008 Jens Alfke
   5.153 + All rights reserved.
   5.154 + 
   5.155 + Redistribution and use in source and binary forms, with or without modification, are
   5.156 + permitted provided that the following conditions are met:
   5.157 + 
   5.158 + • Redistributions of source code must retain the above copyright notice, this list of
   5.159 + conditions and the following disclaimer.
   5.160 + • Redistributions in binary form must reproduce the above copyright notice, this list
   5.161 + of conditions and the following disclaimer in the documentation and/or other materials
   5.162 + provided with the distribution.
   5.163 + • Neither the name of the author nor the names of other contributors may be used to
   5.164 + endorse or promote products derived from this software without specific prior written
   5.165 + permission.
   5.166 + 
   5.167 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
   5.168 + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   5.169 + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   5.170 + THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   5.171 + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   5.172 + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   5.173 + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
   5.174 + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   5.175 + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   5.176 +*/
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/Coroutines/MYCoroutineTest.m	Tue Apr 29 17:05:32 2008 -0700
     6.3 @@ -0,0 +1,88 @@
     6.4 +//
     6.5 +//  MYCoroutineTest.m
     6.6 +//  Coroutines
     6.7 +//
     6.8 +//  Created by Jens Alfke on 4/29/08.
     6.9 +//  Copyright 2008 __MyCompanyName__. All rights reserved.
    6.10 +//
    6.11 +
    6.12 +#import "MYCoroutine.h"
    6.13 +
    6.14 +
    6.15 +@interface CoroTest1 : MYCoroutine
    6.16 +{
    6.17 +    int value;
    6.18 +}
    6.19 +@property int value;
    6.20 +@end
    6.21 +
    6.22 +@interface CoroTest2 : CoroTest1
    6.23 +@end
    6.24 +
    6.25 +
    6.26 +CoroTest1 *firstCoro, *secondCoro;
    6.27 +
    6.28 +
    6.29 +@implementation CoroTest2
    6.30 +
    6.31 +- (void) main
    6.32 +{
    6.33 +    int num = 0;
    6.34 +    
    6.35 +	NSLog(@"secondTask created with value %d", self.value);
    6.36 +	
    6.37 +	while (1) 
    6.38 +	{
    6.39 +		NSLog(@"secondTask: %d %d", self.bytesLeftOnStack, num++);
    6.40 +		[firstCoro resume];
    6.41 +	}
    6.42 +}
    6.43 +
    6.44 +@end
    6.45 +
    6.46 +
    6.47 +@implementation CoroTest1
    6.48 +
    6.49 +@synthesize value;
    6.50 +
    6.51 +- (void) main
    6.52 +{
    6.53 +	int num = 0;
    6.54 +	
    6.55 +	NSLog(@"firstTask created with value %d", self.value);
    6.56 +	secondCoro = [[CoroTest2 alloc] init];
    6.57 +    secondCoro.name = @"second";
    6.58 +    secondCoro.value = 2;
    6.59 +	[secondCoro start];
    6.60 +	
    6.61 +	while ( num < 100 ) 
    6.62 +	{
    6.63 +		NSLog(@"firstTask:  %d %d", self.bytesLeftOnStack, num++);
    6.64 +        [secondCoro resume];
    6.65 +	}
    6.66 +    
    6.67 +    [secondCoro release];
    6.68 +    
    6.69 +    [[MYCoroutine mainCoroutine] resume];
    6.70 +}
    6.71 +
    6.72 +@end
    6.73 +
    6.74 +
    6.75 +int main()
    6.76 +{
    6.77 +    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    6.78 +    
    6.79 +    NSLog(@"Starting test...");
    6.80 +    //[[[NSThread alloc] init] start];
    6.81 +	firstCoro = [[CoroTest1 alloc] init];
    6.82 +    firstCoro.name = @"first";
    6.83 +    firstCoro.value = 1;
    6.84 +    [firstCoro start];
    6.85 +    
    6.86 +    NSLog(@"Returned from coroutines; exiting");
    6.87 +    
    6.88 +    [firstCoro release];
    6.89 +    
    6.90 +    [pool drain];
    6.91 +}