mirror of https://github.com/yandex/odyssey.git
258 lines
5.3 KiB
C
258 lines
5.3 KiB
C
|
|
/*
|
|
* machinarium.
|
|
*
|
|
* cooperative multitasking engine.
|
|
*/
|
|
|
|
#include <machinarium.h>
|
|
#include <machinarium_private.h>
|
|
|
|
__thread mm_machine_t *mm_self = NULL;
|
|
|
|
static int
|
|
mm_idle_cb(mm_idle_t *handle)
|
|
{
|
|
(void)handle;
|
|
mm_scheduler_run(&mm_self->scheduler, &machinarium.coroutine_cache);
|
|
return mm_scheduler_online(&mm_self->scheduler);
|
|
}
|
|
|
|
static inline void
|
|
machine_free(mm_machine_t *machine)
|
|
{
|
|
/* todo: check active timers and other allocated
|
|
* resources */
|
|
mm_eventmgr_free(&machine->event_mgr, &machine->loop);
|
|
mm_signalmgr_free(&machine->signal_mgr, &machine->loop);
|
|
mm_loop_shutdown(&machine->loop);
|
|
mm_scheduler_free(&machine->scheduler);
|
|
}
|
|
|
|
static void*
|
|
machine_main(void *arg)
|
|
{
|
|
mm_machine_t *machine = arg;
|
|
mm_self = machine;
|
|
|
|
/* set thread name */
|
|
if (machine->name)
|
|
mm_thread_set_name(&machine->thread, machine->name);
|
|
|
|
/* create main coroutine */
|
|
int64_t id;
|
|
id = machine_coroutine_create(machine->main, machine->main_arg);
|
|
(void)id;
|
|
|
|
/* run main loop */
|
|
machine->online = 1;
|
|
for (;;) {
|
|
if (! mm_scheduler_online(&machine->scheduler))
|
|
break;
|
|
mm_loop_step(&machine->loop);
|
|
}
|
|
|
|
machine->online = 0;
|
|
machine_free(machine);
|
|
return NULL;
|
|
}
|
|
|
|
MACHINE_API int64_t
|
|
machine_create(char *name, machine_coroutine_t function, void *arg)
|
|
{
|
|
mm_machine_t *machine;
|
|
machine = malloc(sizeof(*machine));
|
|
if (machine == NULL)
|
|
return -1;
|
|
machine->online = 0;
|
|
machine->id = 0;
|
|
machine->main = function;
|
|
machine->main_arg = arg;
|
|
machine->name = NULL;
|
|
if (name) {
|
|
machine->name = strdup(name);
|
|
if (machine->name == NULL) {
|
|
free(machine);
|
|
return -1;
|
|
}
|
|
}
|
|
mm_list_init(&machine->link);
|
|
mm_scheduler_init(&machine->scheduler);
|
|
int rc;
|
|
rc = mm_loop_init(&machine->loop);
|
|
if (rc < 0) {
|
|
mm_scheduler_free(&machine->scheduler);
|
|
free(machine);
|
|
return -1;
|
|
}
|
|
mm_loop_set_idle(&machine->loop, mm_idle_cb, NULL);
|
|
rc = mm_eventmgr_init(&machine->event_mgr, &machine->loop);
|
|
if (rc == -1) {
|
|
mm_loop_shutdown(&machine->loop);
|
|
mm_scheduler_free(&machine->scheduler);
|
|
free(machine);
|
|
return -1;
|
|
}
|
|
rc = mm_signalmgr_init(&machine->signal_mgr, &machine->loop);
|
|
if (rc == -1) {
|
|
mm_eventmgr_free(&machine->event_mgr, &machine->loop);
|
|
mm_loop_shutdown(&machine->loop);
|
|
mm_scheduler_free(&machine->scheduler);
|
|
free(machine);
|
|
return -1;
|
|
}
|
|
mm_machinemgr_add(&machinarium.machine_mgr, machine);
|
|
rc = mm_thread_create(&machine->thread, PTHREAD_STACK_MIN, machine_main, machine);
|
|
if (rc == -1) {
|
|
mm_machinemgr_delete(&machinarium.machine_mgr, machine);
|
|
mm_eventmgr_free(&machine->event_mgr, &machine->loop);
|
|
mm_loop_shutdown(&machine->loop);
|
|
mm_scheduler_free(&machine->scheduler);
|
|
free(machine);
|
|
return -1;
|
|
}
|
|
return machine->id;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_wait(uint64_t machine_id)
|
|
{
|
|
mm_machine_t *machine;
|
|
machine = mm_machinemgr_delete_by_id(&machinarium.machine_mgr, machine_id);
|
|
if (machine == NULL)
|
|
return -1;
|
|
int rc;
|
|
rc = mm_thread_join(&machine->thread);
|
|
if (machine->name)
|
|
free(machine->name);
|
|
free(machine);
|
|
return rc;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_active(void)
|
|
{
|
|
return mm_self->online;
|
|
}
|
|
|
|
MACHINE_API uint64_t
|
|
machine_self(void)
|
|
{
|
|
return mm_self->id;
|
|
}
|
|
|
|
MACHINE_API void
|
|
machine_stop(void)
|
|
{
|
|
mm_self->online = 0;
|
|
}
|
|
|
|
MACHINE_API int64_t
|
|
machine_coroutine_create(machine_coroutine_t function, void *arg)
|
|
{
|
|
mm_errno_set(0);
|
|
mm_coroutine_t *coroutine;
|
|
coroutine = mm_coroutine_cache_pop(&machinarium.coroutine_cache);
|
|
if (coroutine == NULL) {
|
|
mm_errno_set(ENOMEM);
|
|
return -1;
|
|
}
|
|
mm_scheduler_new(&mm_self->scheduler, coroutine, function, arg);
|
|
return coroutine->id;
|
|
}
|
|
|
|
MACHINE_API void
|
|
machine_sleep(uint32_t time_ms)
|
|
{
|
|
mm_errno_set(0);
|
|
mm_call_t call;
|
|
mm_call(&call, MM_CALL_SLEEP, time_ms);
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_join(uint64_t coroutine_id)
|
|
{
|
|
mm_errno_set(0);
|
|
mm_coroutine_t *coroutine;
|
|
coroutine = mm_scheduler_find(&mm_self->scheduler, coroutine_id);
|
|
if (coroutine == NULL) {
|
|
mm_errno_set(ENOENT);
|
|
return -1;
|
|
}
|
|
mm_coroutine_t *waiter;
|
|
waiter = mm_scheduler_current(&mm_self->scheduler);
|
|
mm_scheduler_join(coroutine, waiter);
|
|
mm_scheduler_yield(&mm_self->scheduler);
|
|
return 0;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_cancel(uint64_t coroutine_id)
|
|
{
|
|
mm_errno_set(0);
|
|
mm_coroutine_t *coroutine;
|
|
coroutine = mm_scheduler_find(&mm_self->scheduler, coroutine_id);
|
|
if (coroutine == NULL) {
|
|
mm_errno_set(ENOENT);
|
|
return -1;
|
|
}
|
|
mm_coroutine_cancel(coroutine);
|
|
return 0;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_condition(uint32_t time_ms)
|
|
{
|
|
mm_errno_set(0);
|
|
mm_call_t call;
|
|
mm_call(&call, MM_CALL_CONDITION, time_ms);
|
|
if (call.status != 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_signal(uint64_t coroutine_id)
|
|
{
|
|
mm_errno_set(0);
|
|
mm_coroutine_t *coroutine;
|
|
coroutine = mm_scheduler_find(&mm_self->scheduler, coroutine_id);
|
|
if (coroutine == NULL) {
|
|
mm_errno_set(ENOENT);
|
|
return -1;
|
|
}
|
|
mm_call_t *call = coroutine->call_ptr;
|
|
if (call == NULL)
|
|
return -1;
|
|
mm_scheduler_wakeup(&mm_self->scheduler, coroutine);
|
|
return 0;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_cancelled(void)
|
|
{
|
|
mm_coroutine_t *coroutine;
|
|
coroutine = mm_scheduler_current(&mm_self->scheduler);
|
|
if (coroutine == NULL)
|
|
return -1;
|
|
return coroutine->cancel > 0;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_timedout(void)
|
|
{
|
|
return mm_errno_get() == ETIMEDOUT;
|
|
}
|
|
|
|
MACHINE_API int
|
|
machine_errno(void)
|
|
{
|
|
return mm_errno_get();
|
|
}
|
|
|
|
MACHINE_API uint64_t
|
|
machine_time(void)
|
|
{
|
|
return mm_self->loop.clock.time_us;
|
|
}
|