diff --git a/Makefile b/Makefile index 0e957d5..7322466 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,15 @@ LIB = libcoio.a OBJS = \ coro.o \ - coio.o + coio.o \ + coio_glib.o all: $(LIB) $(OBJS): coio.h coro.h .c.o: - $(CC) $(CFLAGS) -W -Wall -Wextra -Werror -c $*.c + $(CC) $(shell pkg-config --cflags glib-2.0) $(CFLAGS) -W -Wall -Wextra -Werror -c $*.c $(LIB): $(OBJS) $(AR) rvc $(LIB) $? diff --git a/coio.c b/coio.c index d936e0c..b5db6f2 100644 --- a/coio.c +++ b/coio.c @@ -13,8 +13,11 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _POSIX_C_SOURCE 200809L + #include #include +#include #include "coioimpl.h" #include "coro.h" @@ -24,12 +27,26 @@ #include #endif -static coro_context _sched_ctx; -static unsigned long _taskcount = 0; - CoioTaskList coio_ready = {0, 0}; CoioTaskList coio_sleeping = {0, 0}; +coro_context coio_sched_ctx; CoioTask *coio_current; +unsigned long coio_taskcount = 0; + +static int msleep(uvlong ms) +{ + struct timespec req, rem; + + if(ms > 999) { + req.tv_sec = (int)(ms / 1000); + req.tv_nsec = (ms - ((long)req.tv_sec * 1000)) * 1000000; + } else { + req.tv_sec = 0; + req.tv_nsec = ms * 1000000; + } + + return nanosleep(&req , &rem); +} static void _process_events() @@ -47,7 +64,7 @@ _process_events() } } /* TODO:do I/O polling instead of usleep */ - usleep(ms * 1000); + msleep(ms); /* handle CLOCK_MONOTONIC bugs (VirtualBox anyone?) */ while (!coio_ready.head) { @@ -63,7 +80,7 @@ int coio_main() { /* initialize empty ctx for scheduler */ - coro_create(&_sched_ctx, NULL, NULL, NULL, 0); + coro_create(&coio_sched_ctx, NULL, NULL, NULL, 0); /* scheduler mainloop */ for (;;) { @@ -75,17 +92,17 @@ coio_main() coio_current = coio_ready.head; coio_del(&coio_ready, coio_current); - coro_transfer(&_sched_ctx, &coio_current->ctx); + coro_transfer(&coio_sched_ctx, &coio_current->ctx); if (coio_current->done) { - _taskcount--; + coio_taskcount--; coro_stack_free(&coio_current->stk); free(coio_current); } coio_current = NULL; } - if (_taskcount) { + if (coio_taskcount) { return -1; } return 0; @@ -99,7 +116,7 @@ _coio_entry(void *arg) task->func(task->arg); task->done = 1; - coro_transfer(&coio_current->ctx, &_sched_ctx); + coro_transfer(&coio_current->ctx, &coio_sched_ctx); } int @@ -121,7 +138,7 @@ coio_create(coio_func f, void *arg, unsigned int stacksize) coro_create(&task->ctx, _coio_entry, task, task->stk.sptr, task->stk.ssze); coio_add(&coio_ready, task); - _taskcount++; + coio_taskcount++; return 0; } @@ -196,13 +213,13 @@ coio_del(CoioTaskList * lst, CoioTask * task) { if (task->prev) { task->prev->next = task->next; - } else { + } else if (lst->head == task) { lst->head = task->next; } if (task->next) { task->next->prev = task->prev; - } else { + } else if (lst->tail == task) { lst->tail = task->prev; } } @@ -218,7 +235,7 @@ coio_rdy(CoioTask * task) void coio_transfer() { - coro_transfer(&coio_current->ctx, &_sched_ctx); + coro_transfer(&coio_current->ctx, &coio_sched_ctx); } uvlong diff --git a/coio_glib.c b/coio_glib.c new file mode 100644 index 0000000..0c7626c --- /dev/null +++ b/coio_glib.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 Moritz Bitsch + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "coio_glib.h" +#include "coio.h" +#include "coioimpl.h" + +#include + +struct coio_source +{ + GSource base; +}; + +static gboolean coio_source_prepare(GSource* source, gint* timeout_) +{ + (void)source; + uvlong now; + int ms = 5; + CoioTask* t; + + if (coio_ready.head) { + *timeout_ = 0; + + /* if we return true here our check functions do not get called */ + if (coio_sleeping.head) { + return FALSE; + } + + return TRUE; + } + + if ((t = coio_sleeping.head) != NULL && t->timeout != 0) { + now = coio_now(); + if (now >= t->timeout) { + ms = 0; + } else { + ms = (t->timeout - now) / 1000000; + } + } + + *timeout_ = ms; + return FALSE; +} + +static gboolean coio_source_check(GSource* source) +{ + (void)source; + CoioTask* t; + + if (coio_sleeping.head) { + /* wake up timed out tasks */ + uvlong now = coio_now(); + while ((t = coio_sleeping.head) && now >= t->timeout) { + coio_rdy(t); + } + } + + return TRUE; +} + +static gboolean coio_source_dispatch(GSource* source, GSourceFunc callback, gpointer user_data) +{ + (void)source; + CoioTask* last; + gboolean result = G_SOURCE_CONTINUE; + + /* error condition */ + if (!coio_ready.head && !coio_sleeping.head) + return G_SOURCE_REMOVE; + + if (!coio_ready.head) + return G_SOURCE_CONTINUE; + + last = coio_ready.tail; + + do { + coio_current = coio_ready.head; + coio_del(&coio_ready, coio_current); + coro_transfer(&coio_sched_ctx, &coio_current->ctx); + + if (coio_current->done) { + coio_taskcount--; + coro_stack_free(&coio_current->stk); + free(coio_current); + } + } while (coio_current != last); + + if (callback) { + result = callback(user_data); + } + + return result; +} + +static void coio_source_finalize(GSource* source) +{ + (void)source; +} + +GSource* coio_gsource_create() +{ + coro_create(&coio_sched_ctx, NULL, NULL, NULL, 0); + + static GSourceFuncs funcs = + { + coio_source_prepare, + coio_source_check, + coio_source_dispatch, + coio_source_finalize, + NULL, + NULL + }; + + return g_source_new(&funcs, sizeof(struct coio_source)); +} diff --git a/coio_glib.h b/coio_glib.h new file mode 100644 index 0000000..758ec47 --- /dev/null +++ b/coio_glib.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 Moritz Bitsch + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef COIO_GLIB_H +#define COIO_GLIB_H + +#include + +GSource* coio_gsource_create(); + +#endif diff --git a/coioimpl.h b/coioimpl.h index 0acd967..ec03442 100644 --- a/coioimpl.h +++ b/coioimpl.h @@ -44,6 +44,8 @@ struct CoioTaskList { extern CoioTaskList coio_ready; extern CoioTaskList coio_sleeping; extern CoioTask *coio_current; +extern coro_context coio_sched_ctx; +extern unsigned long coio_taskcount; void coio_add (CoioTaskList * lst, CoioTask * task); void coio_del (CoioTaskList * lst, CoioTask * task);