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); 92a00fdc9cSJohannes Berg id = g_source_attach(gsrc, g_main_context_get_thread_default()); 938bb7ddb7SMarc-André Lureau g_assert(id); 948bb7ddb7SMarc-André Lureau 958bb7ddb7SMarc-André Lureau return gsrc; 968bb7ddb7SMarc-André Lureau } 978bb7ddb7SMarc-André Lureau 988bb7ddb7SMarc-André Lureau static void 998bb7ddb7SMarc-André Lureau set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt) 1008bb7ddb7SMarc-André Lureau { 1018bb7ddb7SMarc-André Lureau GSource *src; 1028bb7ddb7SMarc-André Lureau VugDev *dev; 1038bb7ddb7SMarc-André Lureau 1048bb7ddb7SMarc-André Lureau g_assert(vu_dev); 1058bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 1068bb7ddb7SMarc-André Lureau g_assert(cb); 1078bb7ddb7SMarc-André Lureau 1088bb7ddb7SMarc-André Lureau dev = container_of(vu_dev, VugDev, parent); 109922ef483SMarc-André Lureau src = vug_source_new(dev, fd, vu_evt, cb, pvt); 1108bb7ddb7SMarc-André Lureau g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src); 1118bb7ddb7SMarc-André Lureau } 1128bb7ddb7SMarc-André Lureau 1138bb7ddb7SMarc-André Lureau static void 1148bb7ddb7SMarc-André Lureau remove_watch(VuDev *vu_dev, int fd) 1158bb7ddb7SMarc-André Lureau { 1168bb7ddb7SMarc-André Lureau VugDev *dev; 1178bb7ddb7SMarc-André Lureau 1188bb7ddb7SMarc-André Lureau g_assert(vu_dev); 1198bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 1208bb7ddb7SMarc-André Lureau 1218bb7ddb7SMarc-André Lureau dev = container_of(vu_dev, VugDev, parent); 1228bb7ddb7SMarc-André Lureau g_hash_table_remove(dev->fdmap, GINT_TO_POINTER(fd)); 1238bb7ddb7SMarc-André Lureau } 1248bb7ddb7SMarc-André Lureau 1258bb7ddb7SMarc-André Lureau 1268bb7ddb7SMarc-André Lureau static void vug_watch(VuDev *dev, int condition, void *data) 1278bb7ddb7SMarc-André Lureau { 1288bb7ddb7SMarc-André Lureau if (!vu_dispatch(dev) != 0) { 1298bb7ddb7SMarc-André Lureau dev->panic(dev, "Error processing vhost message"); 1308bb7ddb7SMarc-André Lureau } 1318bb7ddb7SMarc-André Lureau } 1328bb7ddb7SMarc-André Lureau 133a7290a79SJohannes Berg void vug_source_destroy(GSource *src) 134a7290a79SJohannes Berg { 135a7290a79SJohannes Berg if (!src) { 136a7290a79SJohannes Berg return; 137a7290a79SJohannes Berg } 138a7290a79SJohannes Berg 139a7290a79SJohannes Berg g_source_destroy(src); 140a7290a79SJohannes Berg g_source_unref(src); 141a7290a79SJohannes Berg } 142a7290a79SJohannes Berg 1436f5fd837SStefan Hajnoczi bool 1446f5fd837SStefan Hajnoczi vug_init(VugDev *dev, uint16_t max_queues, int socket, 1458bb7ddb7SMarc-André Lureau vu_panic_cb panic, const VuDevIface *iface) 1468bb7ddb7SMarc-André Lureau { 1478bb7ddb7SMarc-André Lureau g_assert(dev); 1488bb7ddb7SMarc-André Lureau g_assert(iface); 1498bb7ddb7SMarc-André Lureau 150*049f5550SCoiby Xu if (!vu_init(&dev->parent, max_queues, socket, panic, NULL, set_watch, 1516f5fd837SStefan Hajnoczi remove_watch, iface)) { 1526f5fd837SStefan Hajnoczi return false; 1536f5fd837SStefan Hajnoczi } 1546f5fd837SStefan Hajnoczi 1558bb7ddb7SMarc-André Lureau dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL, 156a7290a79SJohannes Berg (GDestroyNotify) vug_source_destroy); 1578bb7ddb7SMarc-André Lureau 158922ef483SMarc-André Lureau dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL); 1596f5fd837SStefan Hajnoczi 1606f5fd837SStefan Hajnoczi return true; 1618bb7ddb7SMarc-André Lureau } 1628bb7ddb7SMarc-André Lureau 1638bb7ddb7SMarc-André Lureau void 1648bb7ddb7SMarc-André Lureau vug_deinit(VugDev *dev) 1658bb7ddb7SMarc-André Lureau { 1668bb7ddb7SMarc-André Lureau g_assert(dev); 1678bb7ddb7SMarc-André Lureau 1688bb7ddb7SMarc-André Lureau g_hash_table_unref(dev->fdmap); 169a7290a79SJohannes Berg vug_source_destroy(dev->src); 1708bb7ddb7SMarc-André Lureau } 171