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