libvhost-user-glib.c (3850B)
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 27G_STATIC_ASSERT((int)G_IO_IN == (int)VU_WATCH_IN); 28G_STATIC_ASSERT((int)G_IO_OUT == (int)VU_WATCH_OUT); 29G_STATIC_ASSERT((int)G_IO_PRI == (int)VU_WATCH_PRI); 30G_STATIC_ASSERT((int)G_IO_ERR == (int)VU_WATCH_ERR); 31G_STATIC_ASSERT((int)G_IO_HUP == (int)VU_WATCH_HUP); 32 33typedef struct VugSrc { 34 GSource parent; 35 VuDev *dev; 36 GPollFD gfd; 37} VugSrc; 38 39static gboolean 40vug_src_prepare(GSource *gsrc, gint *timeout) 41{ 42 g_assert(timeout); 43 44 *timeout = -1; 45 return FALSE; 46} 47 48static gboolean 49vug_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 58static gboolean 59vug_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 70static GSourceFuncs vug_src_funcs = { 71 vug_src_prepare, 72 vug_src_check, 73 vug_src_dispatch, 74 NULL 75}; 76 77GSource * 78vug_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 104static void 105set_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 119static void 120remove_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 132static 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 139void 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 149bool 150vug_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 169void 170vug_deinit(VugDev *dev) 171{ 172 g_assert(dev); 173 174 g_hash_table_unref(dev->fdmap); 175 vug_source_destroy(dev->src); 176}