Blame src/verto-glib.c

Packit 086201
/*
Packit 086201
 * Copyright 2011 Red Hat, Inc.
Packit 086201
 *
Packit 086201
 * Permission is hereby granted, free of charge, to any person
Packit 086201
 * obtaining a copy of this software and associated documentation files
Packit 086201
 * (the "Software"), to deal in the Software without restriction,
Packit 086201
 * including without limitation the rights to use, copy, modify, merge,
Packit 086201
 * publish, distribute, sublicense, and/or sell copies of the Software,
Packit 086201
 * and to permit persons to whom the Software is furnished to do so,
Packit 086201
 * subject to the following conditions:
Packit 086201
 *
Packit 086201
 * The above copyright notice and this permission notice shall be
Packit 086201
 * included in all copies or substantial portions of the Software.
Packit 086201
 *
Packit 086201
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 086201
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 086201
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 086201
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 086201
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 086201
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 086201
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 086201
 * SOFTWARE.
Packit 086201
 */
Packit 086201
Packit 086201
#include <errno.h>
Packit 086201
Packit 086201
#include <verto-glib.h>
Packit 086201
#define VERTO_MODULE_TYPES
Packit 086201
typedef struct {
Packit 086201
    GMainContext *context;
Packit 086201
    GMainLoop *loop;
Packit 086201
} verto_mod_ctx;
Packit 086201
typedef GSource verto_mod_ev;
Packit 086201
#include <verto-module.h>
Packit 086201
Packit 086201
/* While glib has signal support in >=2.29, it does not support many
Packit 086201
   common signals (like USR*). Therefore, signal support is disabled
Packit 086201
   until they support them (should be soonish) */
Packit 086201
#if GLIB_MAJOR_VERSION >= 999
Packit 086201
#if GLIB_MINOR_VERSION >= 29
Packit 086201
#ifdef G_OS_UNIX /* Not supported on Windows */
Packit 086201
#include <glib-unix.h>
Packit 086201
#define HAS_SIGNAL VERTO_EV_TYPE_SIGNAL
Packit 086201
#endif
Packit 086201
#endif /* GLIB_MINOR_VERSION >= 29 */
Packit 086201
#endif /* GLIB_MAJOR_VERSION >= 2 */
Packit 086201
#ifndef HAS_SIGNAL
Packit 086201
#define HAS_SIGNAL 0
Packit 086201
#endif
Packit 086201
Packit 086201
#define VERTO_GLIB_SUPPORTED_TYPES (VERTO_EV_TYPE_IO \
Packit 086201
                                    | VERTO_EV_TYPE_TIMEOUT \
Packit 086201
                                    | VERTO_EV_TYPE_IDLE \
Packit 086201
                                    | HAS_SIGNAL \
Packit 086201
                                    | VERTO_EV_TYPE_CHILD)
Packit 086201
Packit 086201
typedef gboolean
Packit 086201
(*GIOCallback)(gpointer data, GIOCondition condition);
Packit 086201
Packit 086201
typedef struct GIOSource {
Packit 086201
    GSource  source;
Packit 086201
    GPollFD  fd;
Packit 086201
    gboolean autoclose;
Packit 086201
} GIOSource;
Packit 086201
Packit 086201
static gboolean
Packit 086201
prepare(GSource *source, gint *timeout)
Packit 086201
{
Packit 086201
    (void) source;
Packit 086201
Packit 086201
    *timeout = -1;
Packit 086201
    return FALSE;
Packit 086201
}
Packit 086201
Packit 086201
static gboolean
Packit 086201
check(GSource *source)
Packit 086201
{
Packit 086201
    GIOSource *src = (GIOSource*) source;
Packit 086201
    return src->fd.revents & src->fd.events;
Packit 086201
}
Packit 086201
Packit 086201
static gboolean
Packit 086201
dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
Packit 086201
{
Packit 086201
    GIOSource *src = (GIOSource*) source;
Packit 086201
    return ((GIOCallback) callback)(user_data, src->fd.revents);
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
finalize(GSource *source)
Packit 086201
{
Packit 086201
    GIOSource *src = (GIOSource*) source;
Packit 086201
    if (src->autoclose)
Packit 086201
        close(src->fd.fd);
Packit 086201
}
Packit 086201
Packit 086201
static GSourceFuncs funcs = { prepare, check, dispatch, finalize, NULL, NULL };
Packit 086201
Packit 086201
static void *
Packit 086201
glib_convert_(GMainContext *mc, GMainLoop *ml)
Packit 086201
{
Packit 086201
    verto_mod_ctx *l = NULL;
Packit 086201
Packit 086201
    l = g_new0(verto_mod_ctx, 1);
Packit 086201
    if (l) {
Packit 086201
        if (mc) {
Packit 086201
            /* Steal references */
Packit 086201
            l->context = mc;
Packit 086201
            l->loop = ml ? ml : g_main_loop_new(l->context, FALSE);
Packit 086201
Packit 086201
            if (g_main_context_default() == mc)
Packit 086201
                g_main_context_ref(mc);
Packit 086201
        } else {
Packit 086201
            l->context = g_main_context_ref(g_main_context_default());
Packit 086201
            l->loop = g_main_loop_new(l->context, FALSE);
Packit 086201
        }
Packit 086201
    } else {
Packit 086201
        g_main_loop_unref(ml);
Packit 086201
        g_main_context_unref(mc);
Packit 086201
    }
Packit 086201
Packit 086201
    return l;
Packit 086201
}
Packit 086201
Packit 086201
static verto_mod_ctx *
Packit 086201
glib_ctx_new(void) {
Packit 086201
    return glib_convert_(g_main_context_new(), NULL);
Packit 086201
}
Packit 086201
Packit 086201
static verto_mod_ctx *
Packit 086201
glib_ctx_default(void) {
Packit 086201
    return glib_convert_(g_main_context_default(), NULL);
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
glib_ctx_free(verto_mod_ctx *ctx)
Packit 086201
{
Packit 086201
    g_main_loop_unref(ctx->loop);
Packit 086201
    g_main_context_unref(ctx->context);
Packit 086201
    g_free(ctx);
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
glib_ctx_run(verto_mod_ctx *ctx)
Packit 086201
{
Packit 086201
    g_main_loop_run(ctx->loop);
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
glib_ctx_run_once(verto_mod_ctx *ctx)
Packit 086201
{
Packit 086201
    g_main_context_iteration(ctx->context, TRUE);
Packit 086201
}
Packit 086201
Packit 086201
static gboolean
Packit 086201
break_callback(gpointer loop)
Packit 086201
{
Packit 086201
    g_main_loop_quit(loop);
Packit 086201
    return FALSE;
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
glib_ctx_break(verto_mod_ctx *ctx)
Packit 086201
{
Packit 086201
    GSource *src = g_timeout_source_new(0);
Packit 086201
    g_assert(src);
Packit 086201
    g_source_set_callback(src, break_callback, ctx->loop, NULL);
Packit 086201
    g_source_set_priority(src, G_PRIORITY_HIGH);
Packit 086201
    g_assert(g_source_attach(src, ctx->context) != 0);
Packit 086201
    g_source_unref(src);
Packit 086201
}
Packit 086201
Packit 086201
static gboolean
Packit 086201
glib_callback(gpointer data)
Packit 086201
{
Packit 086201
    gboolean persists = verto_get_flags(data) & VERTO_EV_FLAG_PERSIST;
Packit 086201
    verto_fire(data);
Packit 086201
    return persists;
Packit 086201
}
Packit 086201
Packit 086201
static gboolean
Packit 086201
glib_callback_io(gpointer data, GIOCondition condition)
Packit 086201
{
Packit 086201
    verto_ev_flag state = VERTO_EV_FLAG_NONE;
Packit 086201
Packit 086201
    if (condition & (G_IO_IN | G_IO_PRI))
Packit 086201
        state |= VERTO_EV_FLAG_IO_READ;
Packit 086201
    if (condition & G_IO_OUT)
Packit 086201
        state |= VERTO_EV_FLAG_IO_WRITE;
Packit 086201
    if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
Packit 086201
        state |= VERTO_EV_FLAG_IO_ERROR;
Packit 086201
Packit 086201
    verto_set_fd_state(data, state);
Packit 086201
    return glib_callback(data);
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
glib_callback_child(GPid pid, gint status, gpointer data)
Packit 086201
{
Packit 086201
    (void) pid;
Packit 086201
Packit 086201
    verto_set_proc_status(data, status);
Packit 086201
    verto_fire(data);
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
glib_ctx_set_flags(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv)
Packit 086201
{
Packit 086201
    (void) ctx;
Packit 086201
Packit 086201
    if (verto_get_flags(ev) & VERTO_EV_FLAG_PRIORITY_HIGH)
Packit 086201
        g_source_set_priority(evpriv, G_PRIORITY_HIGH);
Packit 086201
    else if (verto_get_flags(ev) & VERTO_EV_FLAG_PRIORITY_MEDIUM)
Packit 086201
        g_source_set_priority(evpriv, G_PRIORITY_DEFAULT_IDLE);
Packit 086201
    else if (verto_get_flags(ev) & VERTO_EV_FLAG_PRIORITY_LOW)
Packit 086201
        g_source_set_priority(evpriv, G_PRIORITY_LOW);
Packit 086201
Packit 086201
    if (verto_get_type(ev) == VERTO_EV_TYPE_IO) {
Packit 086201
        ((GIOSource*) evpriv)->fd.events = 0;
Packit 086201
Packit 086201
        if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ)
Packit 086201
            ((GIOSource*) evpriv)->fd.events |= G_IO_IN  | G_IO_PRI | G_IO_ERR |
Packit 086201
                                                G_IO_HUP | G_IO_NVAL;
Packit 086201
        if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE)
Packit 086201
            ((GIOSource*) evpriv)->fd.events |= G_IO_OUT | G_IO_ERR |
Packit 086201
                                                G_IO_HUP | G_IO_NVAL;
Packit 086201
    }
Packit 086201
}
Packit 086201
Packit 086201
static verto_mod_ev *
Packit 086201
glib_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags)
Packit 086201
{
Packit 086201
    verto_mod_ev *evpriv = NULL;
Packit 086201
    verto_ev_type type = verto_get_type(ev);
Packit 086201
Packit 086201
    *flags |= verto_get_flags(ev) & VERTO_EV_FLAG_PERSIST;
Packit 086201
    *flags |= verto_get_flags(ev) & VERTO_EV_FLAG_IO_CLOSE_FD;
Packit 086201
Packit 086201
    switch (type) {
Packit 086201
        case VERTO_EV_TYPE_IO:
Packit 086201
            evpriv = g_source_new(&funcs, sizeof(GIOSource));
Packit 086201
            if (evpriv) {
Packit 086201
                ((GIOSource*) evpriv)->fd.fd = verto_get_fd(ev);
Packit 086201
                ((GIOSource*) evpriv)->autoclose =
Packit 086201
                        *flags & VERTO_EV_FLAG_IO_CLOSE_FD;
Packit 086201
                g_source_add_poll(evpriv, &((GIOSource*) evpriv)->fd);
Packit 086201
            }
Packit 086201
            break;
Packit 086201
        case VERTO_EV_TYPE_TIMEOUT:
Packit 086201
            evpriv = g_timeout_source_new(verto_get_interval(ev));
Packit 086201
            break;
Packit 086201
        case VERTO_EV_TYPE_IDLE:
Packit 086201
            evpriv = g_idle_source_new();
Packit 086201
            break;
Packit 086201
        case VERTO_EV_TYPE_CHILD:
Packit 086201
            evpriv = g_child_watch_source_new(verto_get_proc(ev));
Packit 086201
            break;
Packit 086201
        case VERTO_EV_TYPE_SIGNAL:
Packit 086201
/* While glib has signal support in >=2.29, it does not support many
Packit 086201
   common signals (like USR*). Therefore, signal support is disabled
Packit 086201
   until they support them (should be soonish) */
Packit 086201
#if GLIB_MAJOR_VERSION >= 999
Packit 086201
#if GLIB_MINOR_VERSION >= 29
Packit 086201
#ifdef G_OS_UNIX /* Not supported on Windows */
Packit 086201
            evpriv = g_unix_signal_source_new(verto_get_signal(ev));
Packit 086201
            break;
Packit 086201
#endif
Packit 086201
#endif /* GLIB_MINOR_VERSION >= 29 */
Packit 086201
#endif /* GLIB_MAJOR_VERSION >= 2 */
Packit 086201
        default:
Packit 086201
            return NULL; /* Not supported */
Packit 086201
    }
Packit 086201
Packit 086201
    if (!evpriv)
Packit 086201
        goto error;
Packit 086201
Packit 086201
    if (type == VERTO_EV_TYPE_IO)
Packit 086201
        g_source_set_callback(evpriv, (GSourceFunc) glib_callback_io,
Packit 086201
                              (void *) ev, NULL);
Packit 086201
    else if (type == VERTO_EV_TYPE_CHILD)
Packit 086201
        g_source_set_callback(evpriv, (GSourceFunc) glib_callback_child,
Packit 086201
                              (void *) ev, NULL);
Packit 086201
    else
Packit 086201
        g_source_set_callback(evpriv, glib_callback, (void *) ev, NULL);
Packit 086201
Packit 086201
    glib_ctx_set_flags(ctx, ev, evpriv);
Packit 086201
Packit 086201
    g_source_set_can_recurse(evpriv, FALSE);
Packit 086201
    if (g_source_attach(evpriv, ctx->context) == 0)
Packit 086201
        goto error;
Packit 086201
Packit 086201
    return evpriv;
Packit 086201
Packit 086201
    error:
Packit 086201
        if (evpriv) {
Packit 086201
            g_source_destroy(evpriv);
Packit 086201
            g_source_unref(evpriv);
Packit 086201
        }
Packit 086201
        return NULL;
Packit 086201
}
Packit 086201
Packit 086201
static void
Packit 086201
glib_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv)
Packit 086201
{
Packit 086201
    (void) ctx;
Packit 086201
Packit 086201
    if (!ev)
Packit 086201
        return;
Packit 086201
Packit 086201
    g_source_destroy(evpriv);
Packit 086201
    g_source_unref(evpriv);
Packit 086201
}
Packit 086201
Packit 086201
#define glib_ctx_reinitialize NULL
Packit 086201
VERTO_MODULE(glib, g_main_context_default, VERTO_GLIB_SUPPORTED_TYPES);
Packit 086201
Packit 086201
verto_ctx *
Packit 086201
verto_convert_glib(GMainContext *mc, GMainLoop *ml)
Packit 086201
{
Packit 086201
    return verto_convert(glib, 0, glib_convert_(mc, ml));
Packit 086201
}