2017-05-17 11:49:52 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* machinarium.
|
|
|
|
*
|
|
|
|
* cooperative multitasking engine.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <machinarium.h>
|
2017-05-17 14:20:04 +00:00
|
|
|
#include <machinarium_private.h>
|
|
|
|
|
|
|
|
__thread mm_machine_t *mm_self = NULL;
|
2017-05-17 11:49:52 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
mm_idle_cb(mm_idle_t *handle)
|
|
|
|
{
|
2017-05-18 12:07:16 +00:00
|
|
|
(void)handle;
|
|
|
|
mm_scheduler_run(&mm_self->scheduler);
|
2017-05-22 14:20:44 +00:00
|
|
|
|
|
|
|
if (mm_scheduler_online(&mm_self->scheduler))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* machine shutdown */
|
|
|
|
mm_queuerdpool_free(&mm_self->queuerd_pool);
|
|
|
|
|
|
|
|
/* todo: check active timers and other allocated
|
|
|
|
* resources */
|
2017-05-17 11:49:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-17 14:20:04 +00:00
|
|
|
static inline void
|
|
|
|
machine_free(mm_machine_t *machine)
|
|
|
|
{
|
|
|
|
mm_loop_shutdown(&machine->loop);
|
|
|
|
mm_scheduler_free(&machine->scheduler);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
machine_main(void *arg)
|
|
|
|
{
|
|
|
|
mm_machine_t *machine = arg;
|
|
|
|
mm_self = machine;
|
|
|
|
|
2017-05-17 14:35:55 +00:00
|
|
|
/* set thread name */
|
|
|
|
if (machine->name)
|
|
|
|
mm_thread_set_name(&machine->thread, machine->name);
|
|
|
|
|
|
|
|
/* create main fiber */
|
2017-05-17 14:20:04 +00:00
|
|
|
int64_t id;
|
2017-05-18 10:18:25 +00:00
|
|
|
id = machine_fiber_create(machine->main, machine->main_arg);
|
2017-05-17 14:20:04 +00:00
|
|
|
(void)id;
|
|
|
|
|
2017-05-17 14:35:55 +00:00
|
|
|
/* run main loop */
|
|
|
|
machine->online = 1;
|
2017-05-17 14:20:04 +00:00
|
|
|
for (;;) {
|
|
|
|
if (! mm_scheduler_online(&machine->scheduler))
|
|
|
|
break;
|
|
|
|
mm_loop_step(&machine->loop);
|
|
|
|
}
|
|
|
|
|
2017-05-17 14:35:55 +00:00
|
|
|
machine->online = 0;
|
2017-05-17 14:20:04 +00:00
|
|
|
machine_free(machine);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int
|
2017-05-17 14:35:55 +00:00
|
|
|
machine_create(char *name, machine_function_t function, void *arg)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
|
|
|
mm_machine_t *machine;
|
|
|
|
machine = malloc(sizeof(*machine));
|
|
|
|
if (machine == NULL)
|
2017-05-17 14:20:04 +00:00
|
|
|
return -1;
|
2017-05-17 11:49:52 +00:00
|
|
|
machine->online = 0;
|
2017-05-17 14:20:04 +00:00
|
|
|
machine->id = 0;
|
|
|
|
machine->main = function;
|
|
|
|
machine->main_arg = arg;
|
2017-05-17 14:35:55 +00:00
|
|
|
machine->name = NULL;
|
|
|
|
if (name) {
|
|
|
|
machine->name = strdup(name);
|
|
|
|
if (machine->name == NULL) {
|
|
|
|
free(machine);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_list_init(&machine->link);
|
2017-05-18 10:27:10 +00:00
|
|
|
mm_scheduler_init(&machine->scheduler, 2048 /* 16K */);
|
2017-05-22 14:20:44 +00:00
|
|
|
mm_queuerdpool_init(&machine->queuerd_pool);
|
2017-05-17 11:49:52 +00:00
|
|
|
int rc;
|
|
|
|
rc = mm_loop_init(&machine->loop);
|
2017-05-17 14:20:04 +00:00
|
|
|
if (rc < 0) {
|
2017-05-22 14:20:44 +00:00
|
|
|
mm_queuerdpool_free(&machine->queuerd_pool);
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_scheduler_free(&machine->scheduler);
|
|
|
|
free(machine);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-05-18 12:07:16 +00:00
|
|
|
mm_loop_set_idle(&machine->loop, mm_idle_cb, NULL);
|
2017-05-18 09:50:28 +00:00
|
|
|
mm_machinemgr_add(&machinarium.machine_mgr, machine);
|
2017-05-17 14:20:04 +00:00
|
|
|
rc = mm_thread_create(&machine->thread, machine_main, machine);
|
|
|
|
if (rc == -1) {
|
2017-05-18 09:50:28 +00:00
|
|
|
mm_machinemgr_delete(&machinarium.machine_mgr, machine);
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_loop_shutdown(&machine->loop);
|
2017-05-22 14:20:44 +00:00
|
|
|
mm_queuerdpool_free(&machine->queuerd_pool);
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_scheduler_free(&machine->scheduler);
|
|
|
|
free(machine);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return machine->id;
|
2017-05-17 11:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int
|
2017-05-18 10:18:25 +00:00
|
|
|
machine_wait(int id)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_machine_t *machine;
|
2017-05-18 09:50:28 +00:00
|
|
|
machine = mm_machinemgr_delete_by_id(&machinarium.machine_mgr, id);
|
|
|
|
if (machine == NULL)
|
2017-05-17 11:49:52 +00:00
|
|
|
return -1;
|
2017-05-18 09:50:28 +00:00
|
|
|
int rc;
|
2017-05-17 14:20:04 +00:00
|
|
|
rc = mm_thread_join(&machine->thread);
|
2017-05-17 14:35:55 +00:00
|
|
|
if (machine->name)
|
|
|
|
free(machine->name);
|
2017-05-17 14:20:04 +00:00
|
|
|
free(machine);
|
|
|
|
return rc;
|
2017-05-17 11:49:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-17 14:20:04 +00:00
|
|
|
MACHINE_API int
|
|
|
|
machine_active(void)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
return mm_self->online;
|
2017-05-17 11:49:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-17 14:20:04 +00:00
|
|
|
MACHINE_API machine_t
|
|
|
|
machine_self(void)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
return mm_self;
|
2017-05-17 11:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API void
|
2017-05-17 14:20:04 +00:00
|
|
|
machine_stop(void)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_self->online = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int64_t
|
2017-05-18 10:18:25 +00:00
|
|
|
machine_fiber_create(machine_function_t function, void *arg)
|
2017-05-17 14:20:04 +00:00
|
|
|
{
|
|
|
|
mm_fiber_t *fiber;
|
|
|
|
fiber = mm_scheduler_new(&mm_self->scheduler, function, arg);
|
|
|
|
if (fiber == NULL)
|
|
|
|
return -1;
|
|
|
|
return fiber->id;
|
2017-05-17 11:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API void
|
2017-05-17 14:20:04 +00:00
|
|
|
machine_sleep(uint64_t time_ms)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
|
|
|
mm_fiber_t *fiber;
|
2017-05-17 14:20:04 +00:00
|
|
|
fiber = mm_scheduler_current(&mm_self->scheduler);
|
2017-05-17 11:49:52 +00:00
|
|
|
if (mm_fiber_is_cancelled(fiber))
|
|
|
|
return;
|
|
|
|
mm_call_t call;
|
2017-05-18 10:43:43 +00:00
|
|
|
mm_call(&call, time_ms);
|
2017-05-17 11:49:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int
|
2017-05-18 10:18:25 +00:00
|
|
|
machine_join(uint64_t id)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_fiber_t *fiber;
|
|
|
|
fiber = mm_scheduler_find(&mm_self->scheduler, id);
|
2017-05-17 11:49:52 +00:00
|
|
|
if (fiber == NULL)
|
|
|
|
return -1;
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_fiber_t *waiter = mm_scheduler_current(&mm_self->scheduler);
|
2017-05-18 12:07:16 +00:00
|
|
|
mm_scheduler_join(fiber, waiter);
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_scheduler_yield(&mm_self->scheduler);
|
2017-05-17 11:49:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int
|
2017-05-17 14:20:04 +00:00
|
|
|
machine_cancel(uint64_t id)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_fiber_t *fiber;
|
|
|
|
fiber = mm_scheduler_find(&mm_self->scheduler, id);
|
2017-05-17 11:49:52 +00:00
|
|
|
if (fiber == NULL)
|
|
|
|
return -1;
|
|
|
|
mm_fiber_cancel(fiber);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int
|
2017-05-17 14:20:04 +00:00
|
|
|
machine_condition(uint64_t time_ms)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_fiber_t *fiber;
|
|
|
|
fiber = mm_scheduler_current(&mm_self->scheduler);
|
2017-05-17 11:49:52 +00:00
|
|
|
if (mm_fiber_is_cancelled(fiber))
|
|
|
|
return -1;
|
|
|
|
mm_call_t call;
|
2017-05-18 10:43:43 +00:00
|
|
|
mm_call(&call, time_ms);
|
2017-05-17 11:49:52 +00:00
|
|
|
if (call.status != 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int
|
2017-05-17 14:20:04 +00:00
|
|
|
machine_signal(uint64_t id)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
2017-05-17 14:20:04 +00:00
|
|
|
mm_fiber_t *fiber;
|
|
|
|
fiber = mm_scheduler_find(&mm_self->scheduler, id);
|
2017-05-17 11:49:52 +00:00
|
|
|
if (fiber == NULL)
|
|
|
|
return -1;
|
|
|
|
mm_call_t *call = fiber->call_ptr;
|
|
|
|
if (call == NULL)
|
|
|
|
return -1;
|
2017-05-18 12:07:16 +00:00
|
|
|
mm_scheduler_wakeup(&mm_self->scheduler, fiber);
|
2017-05-17 11:49:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MACHINE_API int
|
2017-05-17 14:20:04 +00:00
|
|
|
machine_cancelled(void)
|
2017-05-17 11:49:52 +00:00
|
|
|
{
|
|
|
|
mm_fiber_t *fiber;
|
2017-05-17 14:20:04 +00:00
|
|
|
fiber = mm_scheduler_current(&mm_self->scheduler);
|
2017-05-17 11:49:52 +00:00
|
|
|
if (fiber == NULL)
|
|
|
|
return -1;
|
|
|
|
return fiber->cancel > 0;
|
|
|
|
}
|