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