18bb7ddb7SMarc-André Lureau /* 28bb7ddb7SMarc-André Lureau * Vhost User library 38bb7ddb7SMarc-André Lureau * 48bb7ddb7SMarc-André Lureau * Copyright (c) 2016 Nutanix Inc. All rights reserved. 58bb7ddb7SMarc-André Lureau * Copyright (c) 2017 Red Hat, Inc. 68bb7ddb7SMarc-André Lureau * 78bb7ddb7SMarc-André Lureau * Authors: 88bb7ddb7SMarc-André Lureau * Marc-André Lureau <mlureau@redhat.com> 98bb7ddb7SMarc-André Lureau * Felipe Franciosi <felipe@nutanix.com> 108bb7ddb7SMarc-André Lureau * 118bb7ddb7SMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or 128bb7ddb7SMarc-André Lureau * later. See the COPYING file in the top-level directory. 138bb7ddb7SMarc-André Lureau */ 148bb7ddb7SMarc-André Lureau 158bb7ddb7SMarc-André Lureau #include "qemu/osdep.h" 168bb7ddb7SMarc-André Lureau 178bb7ddb7SMarc-André Lureau #include "libvhost-user-glib.h" 188bb7ddb7SMarc-André Lureau 198bb7ddb7SMarc-André Lureau /* glib event loop integration for libvhost-user and misc callbacks */ 208bb7ddb7SMarc-André Lureau 218bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_IN == (int)VU_WATCH_IN); 228bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_OUT == (int)VU_WATCH_OUT); 238bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_PRI == (int)VU_WATCH_PRI); 248bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_ERR == (int)VU_WATCH_ERR); 258bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_HUP == (int)VU_WATCH_HUP); 268bb7ddb7SMarc-André Lureau 278bb7ddb7SMarc-André Lureau typedef struct VugSrc { 288bb7ddb7SMarc-André Lureau GSource parent; 298bb7ddb7SMarc-André Lureau VuDev *dev; 308bb7ddb7SMarc-André Lureau GPollFD gfd; 318bb7ddb7SMarc-André Lureau } VugSrc; 328bb7ddb7SMarc-André Lureau 338bb7ddb7SMarc-André Lureau static gboolean 348bb7ddb7SMarc-André Lureau vug_src_prepare(GSource *gsrc, gint *timeout) 358bb7ddb7SMarc-André Lureau { 368bb7ddb7SMarc-André Lureau g_assert(timeout); 378bb7ddb7SMarc-André Lureau 388bb7ddb7SMarc-André Lureau *timeout = -1; 398bb7ddb7SMarc-André Lureau return FALSE; 408bb7ddb7SMarc-André Lureau } 418bb7ddb7SMarc-André Lureau 428bb7ddb7SMarc-André Lureau static gboolean 438bb7ddb7SMarc-André Lureau vug_src_check(GSource *gsrc) 448bb7ddb7SMarc-André Lureau { 458bb7ddb7SMarc-André Lureau VugSrc *src = (VugSrc *)gsrc; 468bb7ddb7SMarc-André Lureau 478bb7ddb7SMarc-André Lureau g_assert(src); 488bb7ddb7SMarc-André Lureau 498bb7ddb7SMarc-André Lureau return src->gfd.revents & src->gfd.events; 508bb7ddb7SMarc-André Lureau } 518bb7ddb7SMarc-André Lureau 528bb7ddb7SMarc-André Lureau static gboolean 538bb7ddb7SMarc-André Lureau vug_src_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data) 548bb7ddb7SMarc-André Lureau { 558bb7ddb7SMarc-André Lureau VugSrc *src = (VugSrc *)gsrc; 568bb7ddb7SMarc-André Lureau 578bb7ddb7SMarc-André Lureau g_assert(src); 588bb7ddb7SMarc-André Lureau 598bb7ddb7SMarc-André Lureau ((vu_watch_cb)cb)(src->dev, src->gfd.revents, data); 608bb7ddb7SMarc-André Lureau 618bb7ddb7SMarc-André Lureau return G_SOURCE_CONTINUE; 628bb7ddb7SMarc-André Lureau } 638bb7ddb7SMarc-André Lureau 648bb7ddb7SMarc-André Lureau static GSourceFuncs vug_src_funcs = { 658bb7ddb7SMarc-André Lureau vug_src_prepare, 668bb7ddb7SMarc-André Lureau vug_src_check, 678bb7ddb7SMarc-André Lureau vug_src_dispatch, 688bb7ddb7SMarc-André Lureau NULL 698bb7ddb7SMarc-André Lureau }; 708bb7ddb7SMarc-André Lureau 71922ef483SMarc-André Lureau GSource * 72922ef483SMarc-André Lureau vug_source_new(VugDev *gdev, int fd, GIOCondition cond, 738bb7ddb7SMarc-André Lureau vu_watch_cb vu_cb, gpointer data) 748bb7ddb7SMarc-André Lureau { 75922ef483SMarc-André Lureau VuDev *dev = &gdev->parent; 768bb7ddb7SMarc-André Lureau GSource *gsrc; 778bb7ddb7SMarc-André Lureau VugSrc *src; 788bb7ddb7SMarc-André Lureau guint id; 798bb7ddb7SMarc-André Lureau 80922ef483SMarc-André Lureau g_assert(gdev); 818bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 828bb7ddb7SMarc-André Lureau g_assert(vu_cb); 838bb7ddb7SMarc-André Lureau 848bb7ddb7SMarc-André Lureau gsrc = g_source_new(&vug_src_funcs, sizeof(VugSrc)); 858bb7ddb7SMarc-André Lureau g_source_set_callback(gsrc, (GSourceFunc)vu_cb, data, NULL); 868bb7ddb7SMarc-André Lureau src = (VugSrc *)gsrc; 878bb7ddb7SMarc-André Lureau src->dev = dev; 888bb7ddb7SMarc-André Lureau src->gfd.fd = fd; 898bb7ddb7SMarc-André Lureau src->gfd.events = cond; 908bb7ddb7SMarc-André Lureau 918bb7ddb7SMarc-André Lureau g_source_add_poll(gsrc, &src->gfd); 928bb7ddb7SMarc-André Lureau id = g_source_attach(gsrc, NULL); 938bb7ddb7SMarc-André Lureau g_assert(id); 948bb7ddb7SMarc-André Lureau g_source_unref(gsrc); 958bb7ddb7SMarc-André Lureau 968bb7ddb7SMarc-André Lureau return gsrc; 978bb7ddb7SMarc-André Lureau } 988bb7ddb7SMarc-André Lureau 998bb7ddb7SMarc-André Lureau static void 1008bb7ddb7SMarc-André Lureau set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt) 1018bb7ddb7SMarc-André Lureau { 1028bb7ddb7SMarc-André Lureau GSource *src; 1038bb7ddb7SMarc-André Lureau VugDev *dev; 1048bb7ddb7SMarc-André Lureau 1058bb7ddb7SMarc-André Lureau g_assert(vu_dev); 1068bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 1078bb7ddb7SMarc-André Lureau g_assert(cb); 1088bb7ddb7SMarc-André Lureau 1098bb7ddb7SMarc-André Lureau dev = container_of(vu_dev, VugDev, parent); 110922ef483SMarc-André Lureau src = vug_source_new(dev, fd, vu_evt, cb, pvt); 1118bb7ddb7SMarc-André Lureau g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src); 1128bb7ddb7SMarc-André Lureau } 1138bb7ddb7SMarc-André Lureau 1148bb7ddb7SMarc-André Lureau static void 1158bb7ddb7SMarc-André Lureau remove_watch(VuDev *vu_dev, int fd) 1168bb7ddb7SMarc-André Lureau { 1178bb7ddb7SMarc-André Lureau VugDev *dev; 1188bb7ddb7SMarc-André Lureau 1198bb7ddb7SMarc-André Lureau g_assert(vu_dev); 1208bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 1218bb7ddb7SMarc-André Lureau 1228bb7ddb7SMarc-André Lureau dev = container_of(vu_dev, VugDev, parent); 1238bb7ddb7SMarc-André Lureau g_hash_table_remove(dev->fdmap, GINT_TO_POINTER(fd)); 1248bb7ddb7SMarc-André Lureau } 1258bb7ddb7SMarc-André Lureau 1268bb7ddb7SMarc-André Lureau 1278bb7ddb7SMarc-André Lureau static void vug_watch(VuDev *dev, int condition, void *data) 1288bb7ddb7SMarc-André Lureau { 1298bb7ddb7SMarc-André Lureau if (!vu_dispatch(dev) != 0) { 1308bb7ddb7SMarc-André Lureau dev->panic(dev, "Error processing vhost message"); 1318bb7ddb7SMarc-André Lureau } 1328bb7ddb7SMarc-André Lureau } 1338bb7ddb7SMarc-André Lureau 134*6f5fd837SStefan Hajnoczi bool 135*6f5fd837SStefan Hajnoczi vug_init(VugDev *dev, uint16_t max_queues, int socket, 1368bb7ddb7SMarc-André Lureau vu_panic_cb panic, const VuDevIface *iface) 1378bb7ddb7SMarc-André Lureau { 1388bb7ddb7SMarc-André Lureau g_assert(dev); 1398bb7ddb7SMarc-André Lureau g_assert(iface); 1408bb7ddb7SMarc-André Lureau 141*6f5fd837SStefan Hajnoczi if (!vu_init(&dev->parent, max_queues, socket, panic, set_watch, 142*6f5fd837SStefan Hajnoczi remove_watch, iface)) { 143*6f5fd837SStefan Hajnoczi return false; 144*6f5fd837SStefan Hajnoczi } 145*6f5fd837SStefan Hajnoczi 1468bb7ddb7SMarc-André Lureau dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL, 1478bb7ddb7SMarc-André Lureau (GDestroyNotify) g_source_destroy); 1488bb7ddb7SMarc-André Lureau 149922ef483SMarc-André Lureau dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL); 150*6f5fd837SStefan Hajnoczi 151*6f5fd837SStefan Hajnoczi return true; 1528bb7ddb7SMarc-André Lureau } 1538bb7ddb7SMarc-André Lureau 1548bb7ddb7SMarc-André Lureau void 1558bb7ddb7SMarc-André Lureau vug_deinit(VugDev *dev) 1568bb7ddb7SMarc-André Lureau { 1578bb7ddb7SMarc-André Lureau g_assert(dev); 1588bb7ddb7SMarc-André Lureau 1598bb7ddb7SMarc-André Lureau g_hash_table_unref(dev->fdmap); 1608bb7ddb7SMarc-André Lureau g_source_unref(dev->src); 1618bb7ddb7SMarc-André Lureau } 162