qemu/subprojects/libvhost-user/libvhost-user-glib.c
<<
>>
Prefs
   1/*
   2 * Vhost User library
   3 *
   4 * Copyright (c) 2016 Nutanix Inc. All rights reserved.
   5 * Copyright (c) 2017 Red Hat, Inc.
   6 *
   7 * Authors:
   8 *  Marc-André Lureau <mlureau@redhat.com>
   9 *  Felipe Franciosi <felipe@nutanix.com>
  10 *
  11 * This work is licensed under the terms of the GNU GPL, version 2 or
  12 * later.  See the COPYING file in the top-level directory.
  13 */
  14
  15#include "libvhost-user-glib.h"
  16
  17#ifndef container_of
  18#define container_of(ptr, type, member)              \
  19    __extension__({                                  \
  20        void *__mptr = (void *)(ptr);                \
  21        ((type *)(__mptr - offsetof(type, member))); \
  22    })
  23#endif
  24
  25/* glib event loop integration for libvhost-user and misc callbacks */
  26
  27G_STATIC_ASSERT((int)G_IO_IN == (int)VU_WATCH_IN);
  28G_STATIC_ASSERT((int)G_IO_OUT == (int)VU_WATCH_OUT);
  29G_STATIC_ASSERT((int)G_IO_PRI == (int)VU_WATCH_PRI);
  30G_STATIC_ASSERT((int)G_IO_ERR == (int)VU_WATCH_ERR);
  31G_STATIC_ASSERT((int)G_IO_HUP == (int)VU_WATCH_HUP);
  32
  33typedef struct VugSrc {
  34    GSource parent;
  35    VuDev *dev;
  36    GPollFD gfd;
  37} VugSrc;
  38
  39static gboolean
  40vug_src_prepare(GSource *gsrc, gint *timeout)
  41{
  42    g_assert(timeout);
  43
  44    *timeout = -1;
  45    return FALSE;
  46}
  47
  48static gboolean
  49vug_src_check(GSource *gsrc)
  50{
  51    VugSrc *src = (VugSrc *)gsrc;
  52
  53    g_assert(src);
  54
  55    return src->gfd.revents & src->gfd.events;
  56}
  57
  58static gboolean
  59vug_src_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data)
  60{
  61    VugSrc *src = (VugSrc *)gsrc;
  62
  63    g_assert(src);
  64
  65    ((vu_watch_cb)cb)(src->dev, src->gfd.revents, data);
  66
  67    return G_SOURCE_CONTINUE;
  68}
  69
  70static GSourceFuncs vug_src_funcs = {
  71    vug_src_prepare,
  72    vug_src_check,
  73    vug_src_dispatch,
  74    NULL
  75};
  76
  77GSource *
  78vug_source_new(VugDev *gdev, int fd, GIOCondition cond,
  79               vu_watch_cb vu_cb, gpointer data)
  80{
  81    VuDev *dev = &gdev->parent;
  82    GSource *gsrc;
  83    VugSrc *src;
  84    guint id;
  85
  86    g_assert(gdev);
  87    g_assert(fd >= 0);
  88    g_assert(vu_cb);
  89
  90    gsrc = g_source_new(&vug_src_funcs, sizeof(VugSrc));
  91    g_source_set_callback(gsrc, (GSourceFunc)vu_cb, data, NULL);
  92    src = (VugSrc *)gsrc;
  93    src->dev = dev;
  94    src->gfd.fd = fd;
  95    src->gfd.events = cond;
  96
  97    g_source_add_poll(gsrc, &src->gfd);
  98    id = g_source_attach(gsrc, g_main_context_get_thread_default());
  99    g_assert(id);
 100
 101    return gsrc;
 102}
 103
 104static void
 105set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt)
 106{
 107    GSource *src;
 108    VugDev *dev;
 109
 110    g_assert(vu_dev);
 111    g_assert(fd >= 0);
 112    g_assert(cb);
 113
 114    dev = container_of(vu_dev, VugDev, parent);
 115    src = vug_source_new(dev, fd, vu_evt, cb, pvt);
 116    g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src);
 117}
 118
 119static void
 120remove_watch(VuDev *vu_dev, int fd)
 121{
 122    VugDev *dev;
 123
 124    g_assert(vu_dev);
 125    g_assert(fd >= 0);
 126
 127    dev = container_of(vu_dev, VugDev, parent);
 128    g_hash_table_remove(dev->fdmap, GINT_TO_POINTER(fd));
 129}
 130
 131
 132static void vug_watch(VuDev *dev, int condition, void *data)
 133{
 134    if (!vu_dispatch(dev) != 0) {
 135        dev->panic(dev, "Error processing vhost message");
 136    }
 137}
 138
 139void vug_source_destroy(GSource *src)
 140{
 141    if (!src) {
 142        return;
 143    }
 144
 145    g_source_destroy(src);
 146    g_source_unref(src);
 147}
 148
 149bool
 150vug_init(VugDev *dev, uint16_t max_queues, int socket,
 151         vu_panic_cb panic, const VuDevIface *iface)
 152{
 153    g_assert(dev);
 154    g_assert(iface);
 155
 156    if (!vu_init(&dev->parent, max_queues, socket, panic, NULL, set_watch,
 157                 remove_watch, iface)) {
 158        return false;
 159    }
 160
 161    dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL,
 162                                       (GDestroyNotify) vug_source_destroy);
 163
 164    dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL);
 165
 166    return true;
 167}
 168
 169void
 170vug_deinit(VugDev *dev)
 171{
 172    g_assert(dev);
 173
 174    g_hash_table_unref(dev->fdmap);
 175    vug_source_destroy(dev->src);
 176}
 177