Rewrote CoroX. Simplified APIs. Improved stack size checks.
3 * Coroutines for Mac OS X
5 * Created by Jens Alfke on 4/29/08.
6 * Adapted from Steve Dekorte's libCoroutine:
7 * <http://www.dekorte.com/projects/opensource/libCoroutine/>
9 * Copyright 2008 Jens Alfke. All rights reserved.
10 * Copyright (c) 2002, 2003 Steve Dekorte. All rights reserved.
11 * License is at the bottom of this file.
15 #define _XOPEN_SOURCE /* decl of ucontext_t in <sys/_structs.h> is wrong unless this is defined */
23 // Experimentally, the coroutine bus-errors when its stack space drops below about 10k,
24 // implying that the kernel unmaps the very end of it. So allow extra room:
25 #define STACK_OVERHEAD (12*1024)
27 // Even with that overhead, stack sizes less than this cause an immediate crash:
28 const size_t kCoroX_minStackSize = 20*1024;
35 CoroEntryPoint entryPoint;
41 CoroX *CoroX_new(CoroEntryPoint entryPoint, void *userData)
43 CoroX *self = (CoroX *)calloc(1, sizeof(CoroX));
44 self->stackSize = CoroX_getDefaultStackSize();
45 self->entryPoint = entryPoint;
46 self->userData = userData;
50 void CoroX_free(CoroX *self)
59 void* CoroX_userData(CoroX *self) {return self->userData;}
60 bool CoroX_isMain(CoroX *self) {return self->entryPoint==NULL;}
66 void* CoroX_stack(CoroX *self) {return self->stack;}
67 size_t CoroX_stackSize(CoroX *self) {return self->stackSize;}
69 void CoroX_setStackSize_(CoroX *self, size_t sizeInBytes)
71 if( sizeInBytes < kCoroX_minStackSize )
72 sizeInBytes = kCoroX_minStackSize;
73 self->stackSize = sizeInBytes;
77 static size_t sDefaultStackSize;
79 size_t CoroX_getDefaultStackSize(void)
81 if( sDefaultStackSize == 0 ) {
82 pthread_attr_t pthreadAttrs; // Find out default pthread stack size
83 int err = pthread_attr_init(&pthreadAttrs);
85 err = pthread_attr_getstacksize(&pthreadAttrs, &sDefaultStackSize);
87 sDefaultStackSize = 512*1024;
89 return sDefaultStackSize;
92 void CoroX_setDefaultStackSize( size_t size )
94 sDefaultStackSize = size;
98 __attribute__ ((noinline))
99 static uint8_t *CoroX_CurrentStackPointer(void)
106 size_t CoroX_bytesLeftOnStack(CoroX *self)
109 ptrdiff_t p1 = (ptrdiff_t)(&dummy);
110 ptrdiff_t p2 = (ptrdiff_t)CoroX_CurrentStackPointer();
111 int stackMovesUp = p2 > p1;
112 ptrdiff_t start = ((ptrdiff_t)self->stack) ;
113 ptrdiff_t end = start + self->stackSize;
116 return end - p1 - STACK_OVERHEAD;
118 return p1 - start - STACK_OVERHEAD;
121 int CoroX_stackSpaceAlmostGone(CoroX *self)
123 return CoroX_bytesLeftOnStack(self) < 2048;
127 #pragma mark SETUP & SWITCH:
130 typedef void (*makecontext_func)(void);
132 static void CoroX_setup_(CoroX *self)
134 size_t stackSize = self->stackSize + STACK_OVERHEAD;
135 self->stack = valloc(stackSize);
138 getcontext(&self->env);
139 self->env.uc_stack.ss_sp = self->stack;
140 self->env.uc_stack.ss_size = stackSize;
141 self->env.uc_stack.ss_flags = 0;
142 self->env.uc_link = NULL;
143 makecontext(&self->env, (makecontext_func)self->entryPoint, 1, self);
147 void CoroX_switchTo_(CoroX *self, CoroX *next)
149 if( ! next->stack && next->entryPoint )
151 swapcontext(&self->env, &next->env);
158 (This is a BSD License)
160 Copyright (c) 2002, 2003 Steve Dekorte
161 Copyright (c) 2008 Jens Alfke
164 Redistribution and use in source and binary forms, with or without modification, are
165 permitted provided that the following conditions are met:
167 • Redistributions of source code must retain the above copyright notice, this list of
168 conditions and the following disclaimer.
169 • Redistributions in binary form must reproduce the above copyright notice, this list
170 of conditions and the following disclaimer in the documentation and/or other materials
171 provided with the distribution.
172 • Neither the name of the author nor the names of other contributors may be used to
173 endorse or promote products derived from this software without specific prior written
176 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
177 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
178 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
179 THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
180 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
181 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
182 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
183 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
184 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.