801 lines
19 KiB
C
801 lines
19 KiB
C
/*
|
|
Credits
|
|
|
|
Originally based on Edgar Toernig's Minimalistic cooperative multitasking
|
|
http://www.goron.de/~froese/
|
|
reorg by Steve Dekorte and Chis Double
|
|
Symbian and Cygwin support by Chis Double
|
|
Linux/PCC, Linux/Opteron, Irix and FreeBSD/Alpha, ucontext support by Austin Kurahone
|
|
FreeBSD/Intel support by Faried Nawaz
|
|
Mingw support by Pit Capitain
|
|
Visual C support by Daniel Vollmer
|
|
Solaris support by Manpreet Singh
|
|
Fibers support by Jonas Eschenburg
|
|
Ucontext arg support by Olivier Ansaldi
|
|
Ucontext x86-64 support by James Burgess and Jonathan Wright
|
|
Russ Cox for the newer portable ucontext implementions.
|
|
|
|
Notes
|
|
|
|
This is the system dependent coro code.
|
|
Setup a jmp_buf so when we longjmp, it will invoke 'func' using 'stack'.
|
|
Important: 'func' must not return!
|
|
|
|
Usually done by setting the program counter and stack pointer of a new, empty stack.
|
|
If you're adding a new platform, look in the setjmp.h for PC and SP members
|
|
of the stack structure
|
|
|
|
If you don't see those members, Kentaro suggests writting a simple
|
|
test app that calls setjmp and dumps out the contents of the jmp_buf.
|
|
(The PC and SP should be in jmp_buf->__jmpbuf).
|
|
|
|
Using something like GDB to be able to peek into register contents right
|
|
before the setjmp occurs would be helpful also.
|
|
*/
|
|
|
|
#include "Common.h"
|
|
#include "flow/Platform.h"
|
|
#include "Base.h"
|
|
#include "Coro.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stddef.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#ifndef WIN32
|
|
#include "taskimpl.h"
|
|
#endif
|
|
|
|
#ifdef USE_VALGRIND
|
|
#include <valgrind.h>
|
|
#define STACK_REGISTER(coro) \
|
|
{ \
|
|
Coro *c = (coro); \
|
|
c->valgrindStackId = VALGRIND_STACK_REGISTER( \
|
|
c->stack, \
|
|
c->stack + c->requestedStackSize); \
|
|
}
|
|
|
|
#define STACK_DEREGISTER(coro) \
|
|
VALGRIND_STACK_DEREGISTER((coro)->valgrindStackId)
|
|
|
|
#else
|
|
#define STACK_REGISTER(coro)
|
|
#define STACK_DEREGISTER(coro)
|
|
#endif
|
|
|
|
// Define outside
|
|
extern intptr_t g_stackYieldLimit;
|
|
|
|
typedef struct CallbackBlock
|
|
{
|
|
void *context;
|
|
CoroStartCallback *func;
|
|
} CallbackBlock;
|
|
|
|
static CallbackBlock globalCallbackBlock;
|
|
|
|
Coro *Coro_new(void)
|
|
{
|
|
Coro *self = (Coro *)io_calloc(1, sizeof(Coro));
|
|
if (self == NULL)
|
|
{
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
|
|
self->requestedStackSize = CORO_DEFAULT_STACK_SIZE;
|
|
self->allocatedStackSize = 0;
|
|
|
|
#ifdef USE_FIBERS
|
|
self->fiber = NULL;
|
|
#else
|
|
self->stack = NULL;
|
|
#endif
|
|
return self;
|
|
}
|
|
|
|
int Coro_allocStackIfNeeded(Coro *self)
|
|
{
|
|
if (self->stack && self->requestedStackSize < self->allocatedStackSize)
|
|
{
|
|
io_free(self->stack);
|
|
self->stack = NULL;
|
|
self->requestedStackSize = 0;
|
|
}
|
|
|
|
if (!self->stack)
|
|
{
|
|
self->stack = (void *)io_calloc(1, self->requestedStackSize + 16);
|
|
if (self->stack == NULL)
|
|
{
|
|
errno = ENOMEM;
|
|
return ENOMEM;
|
|
}
|
|
|
|
self->allocatedStackSize = self->requestedStackSize;
|
|
//printf("Coro_%p allocating stack size %i\n", (void *)self, self->requestedStackSize);
|
|
STACK_REGISTER(self);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Coro_free(Coro *self)
|
|
{
|
|
#ifdef USE_FIBERS
|
|
// If this coro has a fiber, delete it.
|
|
// Don't delete the main fiber. We don't want to commit suicide.
|
|
if (self->fiber && !self->isMain)
|
|
{
|
|
DeleteFiber(self->fiber);
|
|
}
|
|
#else
|
|
STACK_DEREGISTER(self);
|
|
#endif
|
|
if (self->stack)
|
|
{
|
|
io_free(self->stack);
|
|
}
|
|
|
|
//printf("Coro_%p io_free\n", (void *)self);
|
|
|
|
io_free(self);
|
|
}
|
|
|
|
// stack
|
|
|
|
void *Coro_stack(Coro *self)
|
|
{
|
|
return self->stack;
|
|
}
|
|
|
|
size_t Coro_stackSize(Coro *self)
|
|
{
|
|
return self->requestedStackSize;
|
|
}
|
|
|
|
void Coro_setStackSize_(Coro *self, size_t sizeInBytes)
|
|
{
|
|
self->requestedStackSize = sizeInBytes;
|
|
//self->stack = (void *)io_realloc(self->stack, sizeInBytes);
|
|
//printf("Coro_%p io_reallocating stack size %i\n", (void *)self, sizeInBytes);
|
|
}
|
|
|
|
#if __GNUC__ == 4
|
|
uint8_t *Coro_CurrentStackPointer(void) __attribute__ ((noinline));
|
|
#endif
|
|
|
|
uint8_t *Coro_CurrentStackPointer(void)
|
|
{
|
|
uint8_t a;
|
|
uint8_t *b = &a; // to avoid compiler warning about unused variables
|
|
return b;
|
|
}
|
|
|
|
size_t Coro_bytesLeftOnStack(Coro *self)
|
|
{
|
|
unsigned char 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->requestedStackSize;
|
|
|
|
if (/*stackMovesUp*/ 0)
|
|
{
|
|
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;
|
|
|
|
// So that Coro_bytesLeftOnStack etc will do something on the main thread, guess that there is 800KB of stack
|
|
// "left" when this function is called.
|
|
|
|
// FIXME: The commented code below could be adapted to find the actual stack size using pthreads
|
|
self->requestedStackSize = 800 << 10;
|
|
self->stack = (char*)&self - self->requestedStackSize;
|
|
self->allocatedStackSize = 0;
|
|
g_stackYieldLimit = (intptr_t) self->stack + 65536;
|
|
/* // Get the pthread attributes
|
|
pthread_attr_t Attributes;
|
|
void *StackAddress;
|
|
size_t StackSize;
|
|
memset (&Attributes, 0, sizeof (Attributes));
|
|
pthread_getattr_np (pthread_self(), &Attributes);
|
|
|
|
// From the attributes, get the stack info
|
|
pthread_attr_getstack (&Attributes, &StackAddress, &StackSize);
|
|
|
|
// Done with the attributes
|
|
pthread_attr_destroy (&Attributes);
|
|
|
|
printf ("Stack top: %p\n", StackAddress);
|
|
printf ("Stack size: %u bytes\n", StackSize);
|
|
printf ("Stack bottom: %p\n", (uint8_t*)StackAddress + StackSize);*/
|
|
|
|
|
|
#ifdef USE_FIBERS
|
|
// We must convert the current thread into a fiber if it hasn't already been done.
|
|
if ((LPVOID) 0x1e00 == GetCurrentFiber()) // value returned when not a fiber
|
|
{
|
|
// Make this thread a fiber and set its data field to the main coro's address
|
|
ConvertThreadToFiber(self);
|
|
}
|
|
// Make the main coro represent the current fiber
|
|
self->fiber = GetCurrentFiber();
|
|
#endif
|
|
}
|
|
|
|
int Coro_startCoro_(Coro *self, Coro *other, void *context, CoroStartCallback *callback)
|
|
{
|
|
CallbackBlock sblock;
|
|
int result;
|
|
|
|
CallbackBlock *block = &sblock;
|
|
//CallbackBlock *block = malloc(sizeof(CallbackBlock)); // memory leak
|
|
block->context = context;
|
|
block->func = callback;
|
|
|
|
result = Coro_allocStackIfNeeded(other);
|
|
if (result)
|
|
return result;
|
|
|
|
Coro_setup(other, block);
|
|
Coro_switchTo_(self, other);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
int Coro_startCoro_(Coro *self, Coro *other, void *context, CoroStartCallback *callback)
|
|
{
|
|
int result;
|
|
globalCallbackBlock.context = context;
|
|
globalCallbackBlock.func = callback;
|
|
result = Coro_allocStackIfNeeded(other);
|
|
if (result)
|
|
return result;
|
|
|
|
Coro_setup(other, &globalCallbackBlock);
|
|
Coro_switchTo_(self, other);
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
#if defined(USE_UCONTEXT) && defined(__x86_64__)
|
|
void Coro_StartWithArg(unsigned int hiArg, unsigned int loArg)
|
|
{
|
|
setProfilingEnabled(1);
|
|
CallbackBlock *block = (CallbackBlock*)(((long long)hiArg << 32) | (long long)loArg);
|
|
(block->func)(block->context);
|
|
criticalError(FDB_EXIT_ABORT, "SchedulerError", "returned from coro start function");
|
|
}
|
|
|
|
/*
|
|
void Coro_Start(void)
|
|
{
|
|
CallbackBlock block = globalCallbackBlock;
|
|
unsigned int hiArg = (unsigned int)(((long long)&block) >> 32);
|
|
unsigned int loArg = (unsigned int)(((long long)&block) & 0xFFFFFFFF);
|
|
Coro_StartWithArg(hiArg, loArg);
|
|
}
|
|
*/
|
|
#else
|
|
void Coro_StartWithArg(CallbackBlock *block)
|
|
{
|
|
setProfilingEnabled(1);
|
|
(block->func)(block->context);
|
|
criticalError(FDB_EXIT_ABORT, "SchedulerError", "returned from coro start function");
|
|
}
|
|
|
|
void Coro_Start(void)
|
|
{
|
|
CallbackBlock block = globalCallbackBlock;
|
|
Coro_StartWithArg(&block);
|
|
}
|
|
|
|
#endif
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
void Coro_switchTo_(Coro *self, Coro *next)
|
|
{
|
|
g_stackYieldLimit = (intptr_t) next->stack + 65536;
|
|
#if defined(__SYMBIAN32__)
|
|
ProcessUIEvent();
|
|
#elif defined(USE_FIBERS)
|
|
SwitchToFiber(next->fiber);
|
|
#elif defined(USE_UCONTEXT)
|
|
setProfilingEnabled(0);
|
|
swapcontext(&self->env, &next->env);
|
|
setProfilingEnabled(1);
|
|
#elif defined(USE_SETJMP)
|
|
if (setjmp(self->env) == 0)
|
|
{
|
|
longjmp(next->env, 1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ---- setup ------------------------------------------
|
|
|
|
#if defined(USE_SETJMP) && defined(__x86_64__)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
/* since ucontext seems to be broken on amg64 */
|
|
|
|
setjmp(self->env);
|
|
/* This is probably not nice in that it deals directly with
|
|
* something with __ in front of it.
|
|
*
|
|
* Anyhow, Coro.h makes the member env of a struct Coro a
|
|
* jmp_buf. A jmp_buf, as defined in the amd64 setjmp.h
|
|
* is an array of one struct that wraps the actual __jmp_buf type
|
|
* which is the array of longs (on a 64 bit machine) that
|
|
* the programmer below expected. This struct begins with
|
|
* the __jmp_buf array of longs, so I think it was supposed
|
|
* to work like he originally had it, but for some reason
|
|
* it didn't. I don't know why.
|
|
* - Bryce Schroeder, 16 December 2006
|
|
*
|
|
* Explaination of `magic' numbers: 6 is the stack pointer
|
|
* (RSP, the 64 bit equivalent of ESP), 7 is the program counter.
|
|
* This information came from this file on my Gentoo linux
|
|
* amd64 computer:
|
|
* /usr/include/gento-multilib/amd64/bits/setjmp.h
|
|
* Which was ultimatly included from setjmp.h in /usr/include. */
|
|
self->env[0].__jmpbuf[6] = ((unsigned long)(Coro_stack(self)));
|
|
self->env[0].__jmpbuf[7] = ((long)Coro_Start);
|
|
}
|
|
|
|
#elif defined(HAS_UCONTEXT_ON_PRE_SOLARIS_10)
|
|
|
|
typedef void (*makecontext_func)(void);
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
ucontext_t *ucp = (ucontext_t *) &self->env;
|
|
|
|
getcontext(ucp);
|
|
|
|
ucp->uc_stack.ss_sp = Coro_stack(self) + Coro_stackSize(self) - 8;
|
|
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); }
|
|
|
|
|
|
#elif defined(USE_UCONTEXT)
|
|
|
|
typedef void (*makecontext_func)(void);
|
|
|
|
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);
|
|
#if !defined(__APPLE__)
|
|
ucp->uc_stack.ss_flags = 0;
|
|
ucp->uc_link = NULL;
|
|
#endif
|
|
|
|
#if defined(__x86_64__)
|
|
unsigned int hiArg = (unsigned int)((long long)arg >> 32);
|
|
unsigned int loArg = (unsigned int)((long long)arg & 0xFFFFFFFF);
|
|
makecontext(ucp, (makecontext_func)Coro_StartWithArg, 2, hiArg, loArg);
|
|
#else
|
|
makecontext(ucp, (makecontext_func)Coro_StartWithArg, 1, arg);
|
|
#endif
|
|
}
|
|
|
|
#elif defined(USE_FIBERS)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
// If this coro was recycled and already has a fiber, delete it.
|
|
// Don't delete the main fiber. We don't want to commit suicide.
|
|
|
|
if (self->fiber && !self->isMain)
|
|
{
|
|
DeleteFiber(self->fiber);
|
|
}
|
|
|
|
self->fiber = CreateFiber(Coro_stackSize(self),
|
|
(LPFIBER_START_ROUTINE)Coro_StartWithArg,
|
|
(LPVOID)arg);
|
|
if (!self->fiber)
|
|
criticalError(FDB_EXIT_ABORT, "SchedulerError", "unable to create fiber");
|
|
}
|
|
|
|
#elif defined(__CYGWIN__)
|
|
|
|
#define buf (self->env)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
setjmp(buf);
|
|
buf[7] = (long)(Coro_stack(self) + Coro_stackSize(self) - 16);
|
|
buf[8] = (long)Coro_Start;
|
|
globalCallbackBlock.context=((CallbackBlock*)arg)->context;
|
|
globalCallbackBlock.func=((CallbackBlock*)arg)->func;
|
|
}
|
|
|
|
#elif defined(__SYMBIAN32__)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
/*
|
|
setjmp/longjmp is flakey under Symbian.
|
|
If the setjmp is done inside the call then a crash occurs.
|
|
Inlining it here solves the problem
|
|
*/
|
|
|
|
setjmp(self->env);
|
|
self->env[0] = 0;
|
|
self->env[1] = 0;
|
|
self->env[2] = 0;
|
|
self->env[3] = (unsigned long)(Coro_stack(self))
|
|
+ Coro_stackSize(self) - 64;
|
|
self->env[9] = (long)Coro_Start;
|
|
self->env[8] = self->env[3] + 32;
|
|
}
|
|
|
|
#elif defined(_BSD_PPC_SETJMP_H_)
|
|
|
|
#define buf (self->env)
|
|
#define setjmp _setjmp
|
|
#define longjmp _longjmp
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
size_t *sp = (size_t *)(((intptr_t)Coro_stack(self)
|
|
+ Coro_stackSize(self) - 64 + 15) & ~15);
|
|
|
|
setjmp(buf);
|
|
|
|
//printf("self = %p\n", self);
|
|
//printf("sp = %p\n", sp);
|
|
buf[0] = (long)sp;
|
|
buf[21] = (long)Coro_Start;
|
|
globalCallbackBlock.context=((CallbackBlock*)arg)->context;
|
|
globalCallbackBlock.func=((CallbackBlock*)arg)->func;
|
|
//sp[-4] = (size_t)self; // for G5 10.3
|
|
//sp[-6] = (size_t)self; // for G4 10.4
|
|
|
|
//printf("self = %p\n", (void *)self);
|
|
//printf("sp = %p\n", sp);
|
|
}
|
|
|
|
/*
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
size_t *sp = (size_t *)(((intptr_t)Coro_stack(self)
|
|
+ Coro_stackSize(self) - 64 + 15) & ~15);
|
|
|
|
setjmp(buf);
|
|
|
|
//printf("self = %p\n", self);
|
|
//printf("sp = %p\n", sp);
|
|
buf[0] = (long)sp;
|
|
buf[21] = (long)Coro_Start;
|
|
//sp[-4] = (size_t)self; // for G5 10.3
|
|
//sp[-6] = (size_t)self; // for G4 10.4
|
|
|
|
//printf("self = %p\n", (void *)self);
|
|
//printf("sp = %p\n", sp);
|
|
}
|
|
*/
|
|
|
|
#elif defined(__DragonFly__)
|
|
|
|
#define buf (self->env)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
void *stack = Coro_stack(self);
|
|
size_t stacksize = Coro_stackSize(self);
|
|
void *func = (void *)Coro_Start;
|
|
|
|
setjmp(buf);
|
|
|
|
buf->_jb[2] = (long)(stack + stacksize);
|
|
buf->_jb[0] = (long)func;
|
|
return;
|
|
}
|
|
|
|
#elif defined(__arm__)
|
|
// contributed by Peter van Hardenberg
|
|
|
|
#define buf (self->env)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
setjmp(buf);
|
|
buf[8] = (int)Coro_stack(self) + (int)Coro_stackSize(self) - 16;
|
|
buf[9] = (int)Coro_Start;
|
|
}
|
|
|
|
#else
|
|
|
|
#error "Coro.c Error: Coro_setup() function needs to be defined for this platform."
|
|
|
|
#endif
|
|
|
|
|
|
// old code
|
|
|
|
/*
|
|
// APPLE coros are handled by PortableUContext now
|
|
#elif defined(_BSD_PPC_SETJMP_H_)
|
|
|
|
#define buf (self->env)
|
|
#define setjmp _setjmp
|
|
#define longjmp _longjmp
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
size_t *sp = (size_t *)(((intptr_t)Coro_stack(self) + Coro_stackSize(self) - 64 + 15) & ~15);
|
|
|
|
setjmp(buf);
|
|
|
|
//printf("self = %p\n", self);
|
|
//printf("sp = %p\n", sp);
|
|
buf[0] = (int)sp;
|
|
buf[21] = (int)Coro_Start;
|
|
//sp[-4] = (size_t)self; // for G5 10.3
|
|
//sp[-6] = (size_t)self; // for G4 10.4
|
|
|
|
//printf("self = %p\n", (void *)self);
|
|
//printf("sp = %p\n", sp);
|
|
}
|
|
|
|
#elif defined(_BSD_I386_SETJMP_H)
|
|
|
|
#define buf (self->env)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
size_t *sp = (size_t *)((intptr_t)Coro_stack(self) + Coro_stackSize(self));
|
|
|
|
setjmp(buf);
|
|
|
|
buf[9] = (int)(sp); // esp
|
|
buf[12] = (int)Coro_Start; // eip
|
|
//buf[8] = 0; // ebp
|
|
}
|
|
*/
|
|
|
|
/* Solaris supports ucontext - so we don't need this stuff anymore
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
// this bit goes before the setjmp call
|
|
// Solaris 9 Sparc with GCC
|
|
#if defined(__SVR4) && defined (__sun)
|
|
#if defined(_JBLEN) && (_JBLEN == 12) && defined(__sparc)
|
|
#if defined(_LP64) || defined(_I32LPx)
|
|
#define JBTYPE long
|
|
JBTYPE x;
|
|
#else
|
|
#define JBTYPE int
|
|
JBTYPE x;
|
|
asm("ta 3"); // flush register window
|
|
#endif
|
|
|
|
#define SUN_STACK_END_INDEX 1
|
|
#define SUN_PROGRAM_COUNTER 2
|
|
#define SUN_STACK_START_INDEX 3
|
|
|
|
// Solaris 9 i386 with GCC
|
|
#elif defined(_JBLEN) && (_JBLEN == 10) && defined(__i386)
|
|
#if defined(_LP64) || defined(_I32LPx)
|
|
#define JBTYPE long
|
|
JBTYPE x;
|
|
#else
|
|
#define JBTYPE int
|
|
JBTYPE x;
|
|
#endif
|
|
#define SUN_PROGRAM_COUNTER 5
|
|
#define SUN_STACK_START_INDEX 3
|
|
#define SUN_STACK_END_INDEX 4
|
|
#endif
|
|
#endif
|
|
*/
|
|
|
|
/* Irix supports ucontext - so we don't need this stuff anymore
|
|
|
|
#elif defined(sgi) && defined(_IRIX4_SIGJBLEN) // Irix/SGI
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
setjmp(buf);
|
|
buf[JB_SP] = (__uint64_t)((char *)stack + stacksize - 8);
|
|
buf[JB_PC] = (__uint64_t)Coro_Start;
|
|
}
|
|
*/
|
|
|
|
/* Linux supports ucontext - so we don't need this stuff anymore
|
|
|
|
#elif defined(linux)
|
|
// Various flavors of Linux.
|
|
#if defined(JB_GPR1)
|
|
// Linux/PPC
|
|
buf->__jmpbuf[JB_GPR1] = ((int) stack + stacksize - 64 + 15) & ~15;
|
|
buf->__jmpbuf[JB_LR] = (int) Coro_Start;
|
|
return;
|
|
|
|
#elif defined(JB_RBX)
|
|
// Linux/Opteron
|
|
buf->__jmpbuf[JB_RSP] = (long int )stack + stacksize;
|
|
buf->__jmpbuf[JB_PC] = Coro_Start;
|
|
return;
|
|
|
|
#elif defined(JB_SP)
|
|
|
|
// Linux/x86 with glibc2
|
|
buf->__jmpbuf[JB_SP] = (int)stack + stacksize;
|
|
buf->__jmpbuf[JB_PC] = (int)Coro_StartWithArg;
|
|
// Push the argument on the stack (stack grows downwards)
|
|
// note: stack is stacksize + 16 bytes long
|
|
((int *)stack)[stacksize/sizeof(int) + 1] = (int)self;
|
|
return;
|
|
|
|
#elif defined(_I386_JMP_BUF_H)
|
|
// x86-linux with libc5
|
|
buf->__sp = (int)stack + stacksize;
|
|
buf->__pc = Coro_Start;
|
|
return;
|
|
|
|
#elif defined(__JMP_BUF_SP)
|
|
// arm-linux on the sharp zauras
|
|
buf->__jmpbuf[__JMP_BUF_SP] = (int)stack + stacksize;
|
|
buf->__jmpbuf[__JMP_BUF_SP+1] = (int)Coro_Start;
|
|
return;
|
|
|
|
#else
|
|
|
|
*/
|
|
|
|
|
|
/* Windows supports fibers - so we don't need this stuff anymore
|
|
|
|
#elif defined(__MINGW32__)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
setjmp(buf);
|
|
buf[4] = (int)((unsigned char *)stack + stacksize - 16); // esp
|
|
buf[5] = (int)Coro_Start; // eip
|
|
}
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
setjmp(buf);
|
|
// win32 visual c
|
|
// should this be the same as __MINGW32__?
|
|
buf[4] = (int)((unsigned char *)stack + stacksize - 16); // esp
|
|
buf[5] = (int)Coro_Start; // eip
|
|
}
|
|
*/
|
|
|
|
|
|
/* FreeBSD supports ucontext - so we don't need this stuff anymore
|
|
|
|
#elif defined(__FreeBSD__)
|
|
// FreeBSD.
|
|
#if defined(_JBLEN) && (_JBLEN == 81)
|
|
// FreeBSD/Alpha
|
|
buf->_jb[2] = (long)Coro_Start; // sc_pc
|
|
buf->_jb[26+4] = (long)Coro_Start; // sc_regs[R_RA]
|
|
buf->_jb[27+4] = (long)Coro_Start; // sc_regs[R_T12]
|
|
buf->_jb[30+4] = (long)(stack + stacksize); // sc_regs[R_SP]
|
|
return;
|
|
|
|
#elif defined(_JBLEN)
|
|
// FreeBSD on IA32
|
|
buf->_jb[2] = (long)(stack + stacksize);
|
|
buf->_jb[0] = (long)Coro_Start;
|
|
return;
|
|
|
|
#else
|
|
#error Unsupported platform
|
|
#endif
|
|
*/
|
|
|
|
/* NetBSD supports ucontext - so we don't need this stuff anymore
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
setjmp(buf);
|
|
#if defined(_JB_ATTRIBUTES)
|
|
// NetBSD i386
|
|
buf[2] = (long)(stack + stacksize);
|
|
buf[0] = (long)Coro_Start;
|
|
#else
|
|
#error Unsupported platform
|
|
#endif
|
|
}
|
|
*/
|
|
|
|
/* Sun supports ucontext - so we don't need this stuff anymore
|
|
|
|
// Solaris supports ucontext - so we don't need this stuff anymore
|
|
|
|
void Coro_setup(Coro *self, void *arg)
|
|
{
|
|
// this bit goes before the setjmp call
|
|
// Solaris 9 Sparc with GCC
|
|
#if defined(__SVR4) && defined (__sun)
|
|
#if defined(_JBLEN) && (_JBLEN == 12) && defined(__sparc)
|
|
#if defined(_LP64) || defined(_I32LPx)
|
|
#define JBTYPE long
|
|
JBTYPE x;
|
|
#else
|
|
#define JBTYPE int
|
|
JBTYPE x;
|
|
asm("ta 3"); // flush register window
|
|
#endif
|
|
|
|
#define SUN_STACK_END_INDEX 1
|
|
#define SUN_PROGRAM_COUNTER 2
|
|
#define SUN_STACK_START_INDEX 3
|
|
|
|
// Solaris 9 i386 with GCC
|
|
#elif defined(_JBLEN) && (_JBLEN == 10) && defined(__i386)
|
|
#if defined(_LP64) || defined(_I32LPx)
|
|
#define JBTYPE long
|
|
JBTYPE x;
|
|
#else
|
|
#define JBTYPE int
|
|
JBTYPE x;
|
|
#endif
|
|
#define SUN_PROGRAM_COUNTER 5
|
|
#define SUN_STACK_START_INDEX 3
|
|
#define SUN_STACK_END_INDEX 4
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#elif defined(__SVR4) && defined(__sun)
|
|
// Solaris
|
|
#if defined(SUN_PROGRAM_COUNTER)
|
|
// SunOS 9
|
|
buf[SUN_PROGRAM_COUNTER] = (JBTYPE)Coro_Start;
|
|
|
|
x = (JBTYPE)stack;
|
|
while ((x % 8) != 0) x --; // align on an even boundary
|
|
buf[SUN_STACK_START_INDEX] = (JBTYPE)x;
|
|
x = (JBTYPE)((JBTYPE)stack-stacksize / 2 + 15);
|
|
while ((x % 8) != 0) x ++; // align on an even boundary
|
|
buf[SUN_STACK_END_INDEX] = (JBTYPE)x;
|
|
|
|
*/
|
|
|
|
|
|
|