odyssey/third_party/machinarium/sources/event_mgr.c

163 lines
3.2 KiB
C

/*
* machinarium.
*
* cooperative multitasking engine.
*/
#include <machinarium.h>
#include <machinarium_private.h>
static void
mm_eventmgr_on_read(mm_fd_t *handle)
{
mm_eventmgr_t *mgr = handle->on_read_arg;
uint64_t id;
int rc;
rc = mm_socket_read(mgr->fd.fd, &id, sizeof(id));
(void)rc;
assert(rc == sizeof(id));
/* wakeup event waiters */
pthread_spin_lock(&mgr->lock);
if (! mgr->count_ready) {
pthread_spin_unlock(&mgr->lock);
return;
}
mm_list_t *i;
mm_list_foreach(&mgr->list_ready, i) {
mm_event_t *event;
event = mm_container_of(i, mm_event_t, link);
assert(event->state == MM_EVENT_READY);
event->state = MM_EVENT_ACTIVE;
mm_scheduler_wakeup(&mm_self->scheduler, event->call.coroutine);
}
mm_list_init(&mgr->list_ready);
mgr->count_ready = 0;
pthread_spin_unlock(&mgr->lock);
}
int mm_eventmgr_init(mm_eventmgr_t *mgr, mm_loop_t *loop)
{
pthread_spin_init(&mgr->lock, PTHREAD_PROCESS_PRIVATE);
mm_list_init(&mgr->list_ready);
mm_list_init(&mgr->list_wait);
mgr->count_ready = 0;
mgr->count_wait = 0;
memset(&mgr->fd, 0, sizeof(mgr->fd));
mgr->fd.fd = eventfd(0, EFD_NONBLOCK);
if (mgr->fd.fd == -1)
return -1;
int rc;
rc = mm_loop_add(loop, &mgr->fd, 0);
if (rc == -1) {
close(mgr->fd.fd);
mgr->fd.fd = -1;
return -1;
}
rc = mm_loop_read(loop, &mgr->fd, mm_eventmgr_on_read, mgr);
if (rc == -1) {
mm_loop_delete(loop, &mgr->fd);
close(mgr->fd.fd);
mgr->fd.fd = -1;
return -1;
}
return 0;
}
void mm_eventmgr_free(mm_eventmgr_t *mgr, mm_loop_t *loop)
{
pthread_spin_destroy(&mgr->lock);
if (mgr->fd.fd == -1)
return;
mm_loop_delete(loop, &mgr->fd);
close(mgr->fd.fd);
mgr->fd.fd = -1;
}
void mm_eventmgr_add(mm_eventmgr_t *mgr, mm_event_t *event)
{
mm_list_init(&event->link);
event->state = MM_EVENT_WAIT;
event->event_mgr = mgr;
/* add event to wait list */
pthread_spin_lock(&mgr->lock);
mm_list_append(&mgr->list_wait, &event->link);
mgr->count_wait++;
pthread_spin_unlock(&mgr->lock);
}
int mm_eventmgr_wait(mm_eventmgr_t *mgr, mm_event_t *event, uint32_t time_ms)
{
/* wait for event */
mm_call(&event->call, MM_CALL_EVENT, time_ms);
/* maybe remove from wait list */
pthread_spin_lock(&mgr->lock);
int complete = 0;
switch (event->state) {
case MM_EVENT_WAIT:
mm_list_unlink(&event->link);
mgr->count_wait--;
break;
case MM_EVENT_READY:
mm_list_unlink(&event->link);
mgr->count_ready--;
break;
case MM_EVENT_ACTIVE:
complete = 1;
break;
case MM_EVENT_NONE:
assert(0);
break;
}
event->state = MM_CALL_NONE;
pthread_spin_unlock(&mgr->lock);
return complete;
}
int mm_eventmgr_signal(mm_event_t *event)
{
mm_eventmgr_t *mgr = event->event_mgr;
pthread_spin_lock(&mgr->lock);
if (event->state == MM_EVENT_ACTIVE) {
pthread_spin_unlock(&mgr->lock);
return 0;
}
int fd = 0;
if (mgr->count_ready == 0)
fd = mgr->fd.fd;
assert(event->state == MM_EVENT_WAIT);
mm_list_unlink(&event->link);
mgr->count_wait--;
event->state = MM_EVENT_READY;
mm_list_append(&mgr->list_ready, &event->link);
mgr->count_ready++;
pthread_spin_unlock(&mgr->lock);
return fd;
}
void mm_eventmgr_wakeup(int fd)
{
uint64_t id = 1;
int rc;
rc = mm_socket_write(fd, &id, sizeof(id));
(void)rc;
assert(rc == sizeof(id));
}