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 "libvhost-user-glib.h" 168bb7ddb7SMarc-André Lureau 17*3d22bd27SMarc-André Lureau #ifndef container_of 18*3d22bd27SMarc-André Lureau #define container_of(ptr, type, member) \ 19*3d22bd27SMarc-André Lureau __extension__({ \ 20*3d22bd27SMarc-André Lureau void *__mptr = (void *)(ptr); \ 21*3d22bd27SMarc-André Lureau ((type *)(__mptr - offsetof(type, member))); \ 22*3d22bd27SMarc-André Lureau }) 23*3d22bd27SMarc-André Lureau #endif 24*3d22bd27SMarc-André Lureau 258bb7ddb7SMarc-André Lureau /* glib event loop integration for libvhost-user and misc callbacks */ 268bb7ddb7SMarc-André Lureau 278bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_IN == (int)VU_WATCH_IN); 288bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_OUT == (int)VU_WATCH_OUT); 298bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_PRI == (int)VU_WATCH_PRI); 308bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_ERR == (int)VU_WATCH_ERR); 318bb7ddb7SMarc-André Lureau G_STATIC_ASSERT((int)G_IO_HUP == (int)VU_WATCH_HUP); 328bb7ddb7SMarc-André Lureau 338bb7ddb7SMarc-André Lureau typedef struct VugSrc { 348bb7ddb7SMarc-André Lureau GSource parent; 358bb7ddb7SMarc-André Lureau VuDev *dev; 368bb7ddb7SMarc-André Lureau GPollFD gfd; 378bb7ddb7SMarc-André Lureau } VugSrc; 388bb7ddb7SMarc-André Lureau 398bb7ddb7SMarc-André Lureau static gboolean 408bb7ddb7SMarc-André Lureau vug_src_prepare(GSource *gsrc, gint *timeout) 418bb7ddb7SMarc-André Lureau { 428bb7ddb7SMarc-André Lureau g_assert(timeout); 438bb7ddb7SMarc-André Lureau 448bb7ddb7SMarc-André Lureau *timeout = -1; 458bb7ddb7SMarc-André Lureau return FALSE; 468bb7ddb7SMarc-André Lureau } 478bb7ddb7SMarc-André Lureau 488bb7ddb7SMarc-André Lureau static gboolean 498bb7ddb7SMarc-André Lureau vug_src_check(GSource *gsrc) 508bb7ddb7SMarc-André Lureau { 518bb7ddb7SMarc-André Lureau VugSrc *src = (VugSrc *)gsrc; 528bb7ddb7SMarc-André Lureau 538bb7ddb7SMarc-André Lureau g_assert(src); 548bb7ddb7SMarc-André Lureau 558bb7ddb7SMarc-André Lureau return src->gfd.revents & src->gfd.events; 568bb7ddb7SMarc-André Lureau } 578bb7ddb7SMarc-André Lureau 588bb7ddb7SMarc-André Lureau static gboolean 598bb7ddb7SMarc-André Lureau vug_src_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data) 608bb7ddb7SMarc-André Lureau { 618bb7ddb7SMarc-André Lureau VugSrc *src = (VugSrc *)gsrc; 628bb7ddb7SMarc-André Lureau 638bb7ddb7SMarc-André Lureau g_assert(src); 648bb7ddb7SMarc-André Lureau 658bb7ddb7SMarc-André Lureau ((vu_watch_cb)cb)(src->dev, src->gfd.revents, data); 668bb7ddb7SMarc-André Lureau 678bb7ddb7SMarc-André Lureau return G_SOURCE_CONTINUE; 688bb7ddb7SMarc-André Lureau } 698bb7ddb7SMarc-André Lureau 708bb7ddb7SMarc-André Lureau static GSourceFuncs vug_src_funcs = { 718bb7ddb7SMarc-André Lureau vug_src_prepare, 728bb7ddb7SMarc-André Lureau vug_src_check, 738bb7ddb7SMarc-André Lureau vug_src_dispatch, 748bb7ddb7SMarc-André Lureau NULL 758bb7ddb7SMarc-André Lureau }; 768bb7ddb7SMarc-André Lureau 77922ef483SMarc-André Lureau GSource * 78922ef483SMarc-André Lureau vug_source_new(VugDev *gdev, int fd, GIOCondition cond, 798bb7ddb7SMarc-André Lureau vu_watch_cb vu_cb, gpointer data) 808bb7ddb7SMarc-André Lureau { 81922ef483SMarc-André Lureau VuDev *dev = &gdev->parent; 828bb7ddb7SMarc-André Lureau GSource *gsrc; 838bb7ddb7SMarc-André Lureau VugSrc *src; 848bb7ddb7SMarc-André Lureau guint id; 858bb7ddb7SMarc-André Lureau 86922ef483SMarc-André Lureau g_assert(gdev); 878bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 888bb7ddb7SMarc-André Lureau g_assert(vu_cb); 898bb7ddb7SMarc-André Lureau 908bb7ddb7SMarc-André Lureau gsrc = g_source_new(&vug_src_funcs, sizeof(VugSrc)); 918bb7ddb7SMarc-André Lureau g_source_set_callback(gsrc, (GSourceFunc)vu_cb, data, NULL); 928bb7ddb7SMarc-André Lureau src = (VugSrc *)gsrc; 938bb7ddb7SMarc-André Lureau src->dev = dev; 948bb7ddb7SMarc-André Lureau src->gfd.fd = fd; 958bb7ddb7SMarc-André Lureau src->gfd.events = cond; 968bb7ddb7SMarc-André Lureau 978bb7ddb7SMarc-André Lureau g_source_add_poll(gsrc, &src->gfd); 98a00fdc9cSJohannes Berg id = g_source_attach(gsrc, g_main_context_get_thread_default()); 998bb7ddb7SMarc-André Lureau g_assert(id); 1008bb7ddb7SMarc-André Lureau 1018bb7ddb7SMarc-André Lureau return gsrc; 1028bb7ddb7SMarc-André Lureau } 1038bb7ddb7SMarc-André Lureau 1048bb7ddb7SMarc-André Lureau static void 1058bb7ddb7SMarc-André Lureau set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt) 1068bb7ddb7SMarc-André Lureau { 1078bb7ddb7SMarc-André Lureau GSource *src; 1088bb7ddb7SMarc-André Lureau VugDev *dev; 1098bb7ddb7SMarc-André Lureau 1108bb7ddb7SMarc-André Lureau g_assert(vu_dev); 1118bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 1128bb7ddb7SMarc-André Lureau g_assert(cb); 1138bb7ddb7SMarc-André Lureau 1148bb7ddb7SMarc-André Lureau dev = container_of(vu_dev, VugDev, parent); 115922ef483SMarc-André Lureau src = vug_source_new(dev, fd, vu_evt, cb, pvt); 1168bb7ddb7SMarc-André Lureau g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src); 1178bb7ddb7SMarc-André Lureau } 1188bb7ddb7SMarc-André Lureau 1198bb7ddb7SMarc-André Lureau static void 1208bb7ddb7SMarc-André Lureau remove_watch(VuDev *vu_dev, int fd) 1218bb7ddb7SMarc-André Lureau { 1228bb7ddb7SMarc-André Lureau VugDev *dev; 1238bb7ddb7SMarc-André Lureau 1248bb7ddb7SMarc-André Lureau g_assert(vu_dev); 1258bb7ddb7SMarc-André Lureau g_assert(fd >= 0); 1268bb7ddb7SMarc-André Lureau 1278bb7ddb7SMarc-André Lureau dev = container_of(vu_dev, VugDev, parent); 1288bb7ddb7SMarc-André Lureau g_hash_table_remove(dev->fdmap, GINT_TO_POINTER(fd)); 1298bb7ddb7SMarc-André Lureau } 1308bb7ddb7SMarc-André Lureau 1318bb7ddb7SMarc-André Lureau 1328bb7ddb7SMarc-André Lureau static void vug_watch(VuDev *dev, int condition, void *data) 1338bb7ddb7SMarc-André Lureau { 1348bb7ddb7SMarc-André Lureau if (!vu_dispatch(dev) != 0) { 1358bb7ddb7SMarc-André Lureau dev->panic(dev, "Error processing vhost message"); 1368bb7ddb7SMarc-André Lureau } 1378bb7ddb7SMarc-André Lureau } 1388bb7ddb7SMarc-André Lureau 139a7290a79SJohannes Berg void vug_source_destroy(GSource *src) 140a7290a79SJohannes Berg { 141a7290a79SJohannes Berg if (!src) { 142a7290a79SJohannes Berg return; 143a7290a79SJohannes Berg } 144a7290a79SJohannes Berg 145a7290a79SJohannes Berg g_source_destroy(src); 146a7290a79SJohannes Berg g_source_unref(src); 147a7290a79SJohannes Berg } 148a7290a79SJohannes Berg 1496f5fd837SStefan Hajnoczi bool 1506f5fd837SStefan Hajnoczi vug_init(VugDev *dev, uint16_t max_queues, int socket, 1518bb7ddb7SMarc-André Lureau vu_panic_cb panic, const VuDevIface *iface) 1528bb7ddb7SMarc-André Lureau { 1538bb7ddb7SMarc-André Lureau g_assert(dev); 1548bb7ddb7SMarc-André Lureau g_assert(iface); 1558bb7ddb7SMarc-André Lureau 156049f5550SCoiby Xu if (!vu_init(&dev->parent, max_queues, socket, panic, NULL, set_watch, 1576f5fd837SStefan Hajnoczi remove_watch, iface)) { 1586f5fd837SStefan Hajnoczi return false; 1596f5fd837SStefan Hajnoczi } 1606f5fd837SStefan Hajnoczi 1618bb7ddb7SMarc-André Lureau dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL, 162a7290a79SJohannes Berg (GDestroyNotify) vug_source_destroy); 1638bb7ddb7SMarc-André Lureau 164922ef483SMarc-André Lureau dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL); 1656f5fd837SStefan Hajnoczi 1666f5fd837SStefan Hajnoczi return true; 1678bb7ddb7SMarc-André Lureau } 1688bb7ddb7SMarc-André Lureau 1698bb7ddb7SMarc-André Lureau void 1708bb7ddb7SMarc-André Lureau vug_deinit(VugDev *dev) 1718bb7ddb7SMarc-André Lureau { 1728bb7ddb7SMarc-André Lureau g_assert(dev); 1738bb7ddb7SMarc-André Lureau 1748bb7ddb7SMarc-André Lureau g_hash_table_unref(dev->fdmap); 175a7290a79SJohannes Berg vug_source_destroy(dev->src); 1768bb7ddb7SMarc-André Lureau } 177