mirror of https://github.com/yandex/odyssey.git
110 lines
2.0 KiB
C
110 lines
2.0 KiB
C
|
|
/*
|
|
* machinarium.
|
|
*
|
|
* cooperative multitasking engine.
|
|
*/
|
|
|
|
#include <machinarium.h>
|
|
#include <machinarium_private.h>
|
|
|
|
typedef struct {
|
|
mm_context_t *context_runner;
|
|
mm_context_t *context;
|
|
mm_context_function_t function;
|
|
void *arg;
|
|
} mm_runner_t;
|
|
|
|
static __thread mm_runner_t runner;
|
|
|
|
static void
|
|
mm_context_runner(void)
|
|
{
|
|
/* save argument */
|
|
volatile mm_runner_t runner_arg = runner;
|
|
|
|
/* return to mm_context_create() */
|
|
mm_context_swap(runner_arg.context, runner_arg.context_runner);
|
|
|
|
runner_arg.function(runner_arg.arg);
|
|
abort();
|
|
}
|
|
|
|
static inline void**
|
|
mm_context_prepare(mm_contextstack_t *stack)
|
|
{
|
|
void **sp;
|
|
sp = (void**)(stack->pointer + stack->size);
|
|
*--sp = NULL;
|
|
*--sp = (void*)mm_context_runner;
|
|
#if __amd64
|
|
sp -= 6;
|
|
memset(sp, 0, sizeof(void*) * 6);
|
|
#else
|
|
sp -= 4;
|
|
memset(sp, 0, sizeof(void*) * 4);
|
|
#endif
|
|
return sp;
|
|
}
|
|
|
|
void
|
|
mm_context_create(mm_context_t *context, mm_contextstack_t *stack,
|
|
void (*function)(void*),
|
|
void *arg)
|
|
{
|
|
/* must be first */
|
|
mm_context_t context_runner;
|
|
|
|
/* prepare context runner */
|
|
runner.context_runner = &context_runner,
|
|
runner.context = context,
|
|
runner.function = function,
|
|
runner.arg = arg;
|
|
|
|
/* prepare context */
|
|
context->sp = mm_context_prepare(stack);
|
|
|
|
/* execute runner: pass function and argument */
|
|
mm_context_swap(&context_runner, context);
|
|
}
|
|
|
|
#if !defined(__amd64) && !defined(__i386)
|
|
# error unsupported architecture
|
|
#endif
|
|
|
|
asm (
|
|
"\t.text\n"
|
|
"\t.globl mm_context_swap\n"
|
|
"\t.type x,@function\n"
|
|
"mm_context_swap:\n"
|
|
#if __amd64
|
|
"\tpushq %rbp\n"
|
|
"\tpushq %rbx\n"
|
|
"\tpushq %r12\n"
|
|
"\tpushq %r13\n"
|
|
"\tpushq %r14\n"
|
|
"\tpushq %r15\n"
|
|
"\tmovq %rsp, (%rdi)\n"
|
|
"\tmovq (%rsi), %rsp\n"
|
|
"\tpopq %r15\n"
|
|
"\tpopq %r14\n"
|
|
"\tpopq %r13\n"
|
|
"\tpopq %r12\n"
|
|
"\tpopq %rbx\n"
|
|
"\tpopq %rbp\n"
|
|
"\tret\n"
|
|
#elif __i386
|
|
"\tpushl %ebp\n"
|
|
"\tpushl %ebx\n"
|
|
"\tpushl %esi\n"
|
|
"\tpushl %edi\n"
|
|
"\tmovl %esp, (%eax)\n"
|
|
"\tmovl (%edx), %esp\n"
|
|
"\tpopl %edi\n"
|
|
"\tpopl %esi\n"
|
|
"\tpopl %ebx\n"
|
|
"\tpopl %ebp\n"
|
|
"\tret\n"
|
|
#endif
|
|
);
|