/* * 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 #include #include struct coio_source { GSource base; }; static gboolean coio_source_prepare(GSource* source, gint* timeout_) { (void)source; uvlong now; int ms = -1; CoioTask* t; if (coio_ready_list.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); } } *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) && t->timeout && now >= t->timeout) { coio_ready(t); } } if (coio_ready_list.head) return TRUE; return FALSE; } static gboolean coio_source_dispatch(GSource* source, GSourceFunc callback, gpointer user_data) { (void)source; CoioTask* last; gboolean result = G_SOURCE_CONTINUE; if (!coio_ready_list.head) return G_SOURCE_CONTINUE; last = coio_ready_list.tail; do { coio_current = coio_ready_list.head; coio_current->ready = 0; coio_del(&coio_ready_list, coio_current); co_switch(coio_current->ctx); /* glib is C, don't let the exception go wild */ try { if (coio_current->eptr) { std::rethrow_exception(coio_current->eptr); } } catch (const std::exception& ex) { std::cerr << "Exception in coroutine " << coio_current->name << ": " << ex.what() << std::endl; } catch (...) { std::cerr << "Unknown exception in coroutine " << coio_current->name << std::endl; } if (coio_current->done) { coio_taskcount--; co_delete(coio_current->ctx); delete coio_current; } } while (coio_current != last); coio_current = NULL; if (callback) { result = callback(user_data); } return result; } static void coio_source_finalize(GSource* source) { (void)source; } GSource* coio_gsource_create() { coio_sched_ctx = co_active(); 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)); }