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 "qemu/osdep.h" 16 17 #include "libvhost-user-glib.h" 18 19 /* glib event loop integration for libvhost-user and misc callbacks */ 20 21 G_STATIC_ASSERT((int)G_IO_IN == (int)VU_WATCH_IN); 22 G_STATIC_ASSERT((int)G_IO_OUT == (int)VU_WATCH_OUT); 23 G_STATIC_ASSERT((int)G_IO_PRI == (int)VU_WATCH_PRI); 24 G_STATIC_ASSERT((int)G_IO_ERR == (int)VU_WATCH_ERR); 25 G_STATIC_ASSERT((int)G_IO_HUP == (int)VU_WATCH_HUP); 26 27 typedef struct VugSrc { 28 GSource parent; 29 VuDev *dev; 30 GPollFD gfd; 31 } VugSrc; 32 33 static gboolean 34 vug_src_prepare(GSource *gsrc, gint *timeout) 35 { 36 g_assert(timeout); 37 38 *timeout = -1; 39 return FALSE; 40 } 41 42 static gboolean 43 vug_src_check(GSource *gsrc) 44 { 45 VugSrc *src = (VugSrc *)gsrc; 46 47 g_assert(src); 48 49 return src->gfd.revents & src->gfd.events; 50 } 51 52 static gboolean 53 vug_src_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data) 54 { 55 VugSrc *src = (VugSrc *)gsrc; 56 57 g_assert(src); 58 59 ((vu_watch_cb)cb)(src->dev, src->gfd.revents, data); 60 61 return G_SOURCE_CONTINUE; 62 } 63 64 static GSourceFuncs vug_src_funcs = { 65 vug_src_prepare, 66 vug_src_check, 67 vug_src_dispatch, 68 NULL 69 }; 70 71 GSource * 72 vug_source_new(VugDev *gdev, int fd, GIOCondition cond, 73 vu_watch_cb vu_cb, gpointer data) 74 { 75 VuDev *dev = &gdev->parent; 76 GSource *gsrc; 77 VugSrc *src; 78 guint id; 79 80 g_assert(gdev); 81 g_assert(fd >= 0); 82 g_assert(vu_cb); 83 84 gsrc = g_source_new(&vug_src_funcs, sizeof(VugSrc)); 85 g_source_set_callback(gsrc, (GSourceFunc)vu_cb, data, NULL); 86 src = (VugSrc *)gsrc; 87 src->dev = dev; 88 src->gfd.fd = fd; 89 src->gfd.events = cond; 90 91 g_source_add_poll(gsrc, &src->gfd); 92 id = g_source_attach(gsrc, NULL); 93 g_assert(id); 94 95 return gsrc; 96 } 97 98 static void 99 set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt) 100 { 101 GSource *src; 102 VugDev *dev; 103 104 g_assert(vu_dev); 105 g_assert(fd >= 0); 106 g_assert(cb); 107 108 dev = container_of(vu_dev, VugDev, parent); 109 src = vug_source_new(dev, fd, vu_evt, cb, pvt); 110 g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src); 111 } 112 113 static void 114 remove_watch(VuDev *vu_dev, int fd) 115 { 116 VugDev *dev; 117 118 g_assert(vu_dev); 119 g_assert(fd >= 0); 120 121 dev = container_of(vu_dev, VugDev, parent); 122 g_hash_table_remove(dev->fdmap, GINT_TO_POINTER(fd)); 123 } 124 125 126 static void vug_watch(VuDev *dev, int condition, void *data) 127 { 128 if (!vu_dispatch(dev) != 0) { 129 dev->panic(dev, "Error processing vhost message"); 130 } 131 } 132 133 void vug_source_destroy(GSource *src) 134 { 135 if (!src) { 136 return; 137 } 138 139 g_source_destroy(src); 140 g_source_unref(src); 141 } 142 143 bool 144 vug_init(VugDev *dev, uint16_t max_queues, int socket, 145 vu_panic_cb panic, const VuDevIface *iface) 146 { 147 g_assert(dev); 148 g_assert(iface); 149 150 if (!vu_init(&dev->parent, max_queues, socket, panic, set_watch, 151 remove_watch, iface)) { 152 return false; 153 } 154 155 dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL, 156 (GDestroyNotify) vug_source_destroy); 157 158 dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL); 159 160 return true; 161 } 162 163 void 164 vug_deinit(VugDev *dev) 165 { 166 g_assert(dev); 167 168 g_hash_table_unref(dev->fdmap); 169 vug_source_destroy(dev->src); 170 } 171