diff -r deb0ee0c5b21 -r 2475f871c218 Coroutines/CoroX.c
--- a/Coroutines/CoroX.c Tue Apr 29 17:05:32 2008 -0700
+++ b/Coroutines/CoroX.c Wed Apr 30 14:18:49 2008 -0700
@@ -5,9 +5,6 @@
* 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.
@@ -15,142 +12,142 @@
*
*/
+#define _XOPEN_SOURCE /* decl of ucontext_t in is wrong unless this is defined */
+
#include "CoroX.h"
+#include
+#include
+#include
#include
-#include
-#include
-#include
+// Experimentally, the coroutine bus-errors when its stack space drops below about 10k,
+// implying that the kernel unmaps the very end of it. So allow extra room:
+#define STACK_OVERHEAD (12*1024)
-#define CORO_DEFAULT_STACK_SIZE (65536*4)
-#define CORO_STACK_SIZE_MIN 8192
+// Even with that overhead, stack sizes less than this cause an immediate crash:
+const size_t kCoroX_minStackSize = 20*1024;
-struct Coro
+struct CoroX
{
size_t stackSize;
void *stack;
+ CoroEntryPoint entryPoint;
+ void *userData;
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
+CoroX *CoroX_new(CoroEntryPoint entryPoint, void *userData)
{
- 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;
+ CoroX *self = (CoroX *)calloc(1, sizeof(CoroX));
+ self->stackSize = CoroX_getDefaultStackSize();
+ self->entryPoint = entryPoint;
+ self->userData = userData;
return self;
}
-void Coro_free(Coro *self)
+void CoroX_free(CoroX *self)
{
- if (self->stack)
- free(self->stack);
- free(self);
+ if( self ) {
+ if (self->stack)
+ free(self->stack);
+ free(self);
+ }
}
+void* CoroX_userData(CoroX *self) {return self->userData;}
+bool CoroX_isMain(CoroX *self) {return self->entryPoint==NULL;}
-void *Coro_stack(Coro *self)
+
+#pragma mark STACK:
+
+
+void* CoroX_stack(CoroX *self) {return self->stack;}
+size_t CoroX_stackSize(CoroX *self) {return self->stackSize;}
+
+void CoroX_setStackSize_(CoroX *self, size_t sizeInBytes)
{
- return self->stack;
-}
-
-size_t Coro_stackSize(Coro *self)
-{
- return self->stackSize;
-}
-
-void Coro_setStackSize_(Coro *self, size_t sizeInBytes)
-{
+ if( sizeInBytes < kCoroX_minStackSize )
+ sizeInBytes = kCoroX_minStackSize;
self->stackSize = sizeInBytes;
}
-uint8_t *Coro_CurrentStackPointer(void) __attribute__ ((noinline));
-uint8_t *Coro_CurrentStackPointer(void)
+static size_t sDefaultStackSize;
+
+size_t CoroX_getDefaultStackSize(void)
+{
+ if( sDefaultStackSize == 0 ) {
+ pthread_attr_t pthreadAttrs; // Find out default pthread stack size
+ int err = pthread_attr_init(&pthreadAttrs);
+ if( ! err )
+ err = pthread_attr_getstacksize(&pthreadAttrs, &sDefaultStackSize);
+ if (err)
+ sDefaultStackSize = 512*1024;
+ }
+ return sDefaultStackSize;
+}
+
+void CoroX_setDefaultStackSize( size_t size )
+{
+ sDefaultStackSize = size;
+}
+
+
+ __attribute__ ((noinline))
+static uint8_t *CoroX_CurrentStackPointer(void)
{
uint8_t a;
uint8_t *b = &a;
return b;
}
-size_t Coro_bytesLeftOnStack(Coro *self)
+size_t CoroX_bytesLeftOnStack(CoroX *self)
{
uint8_t dummy;
ptrdiff_t p1 = (ptrdiff_t)(&dummy);
- ptrdiff_t p2 = (ptrdiff_t)Coro_CurrentStackPointer();
+ ptrdiff_t p2 = (ptrdiff_t)CoroX_CurrentStackPointer();
int stackMovesUp = p2 > p1;
- ptrdiff_t start = ((ptrdiff_t)self->stack);
+ ptrdiff_t start = ((ptrdiff_t)self->stack) ;
ptrdiff_t end = start + self->stackSize;
if (stackMovesUp)
- {
- return end - p1;
- }
+ return end - p1 - STACK_OVERHEAD;
else
- {
- return p1 - start;
- }
+ return p1 - start - STACK_OVERHEAD;
}
-int Coro_stackSpaceAlmostGone(Coro *self)
+int CoroX_stackSpaceAlmostGone(CoroX *self)
{
- return Coro_bytesLeftOnStack(self) < CORO_STACK_SIZE_MIN;
+ return CoroX_bytesLeftOnStack(self) < 2048;
}
-void Coro_initializeMainCoro(Coro *self)
-{
- self->isMain = 1;
-}
+#pragma mark SETUP & SWITCH:
-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)
+static void CoroX_setup_(CoroX *self)
{
- ucontext_t *ucp = (ucontext_t *) &self->env;
- getcontext(ucp);
+ size_t stackSize = self->stackSize + STACK_OVERHEAD;
+ self->stack = valloc(stackSize);
+ assert(self->stack);
- 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);
+ getcontext(&self->env);
+ self->env.uc_stack.ss_sp = self->stack;
+ self->env.uc_stack.ss_size = stackSize;
+ self->env.uc_stack.ss_flags = 0;
+ self->env.uc_link = NULL;
+ makecontext(&self->env, (makecontext_func)self->entryPoint, 1, self);
}
-void Coro_startCoro_(Coro *self, Coro *other, void *context, CoroStartCallback *callback)
+void CoroX_switchTo_(CoroX *self, CoroX *next)
{
- 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)
-{
+ if( ! next->stack && next->entryPoint )
+ CoroX_setup_(next);
swapcontext(&self->env, &next->env);
}