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 | g_source_unref(gsrc); |
95 | |
96 | return gsrc; |
97 | } |
98 | |
99 | static void |
100 | set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt) |
101 | { |
102 | GSource *src; |
103 | VugDev *dev; |
104 | |
105 | g_assert(vu_dev); |
106 | g_assert(fd >= 0); |
107 | g_assert(cb); |
108 | |
109 | dev = container_of(vu_dev, VugDev, parent); |
110 | src = vug_source_new(dev, fd, vu_evt, cb, pvt); |
111 | g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src); |
112 | } |
113 | |
114 | static void |
115 | remove_watch(VuDev *vu_dev, int fd) |
116 | { |
117 | VugDev *dev; |
118 | |
119 | g_assert(vu_dev); |
120 | g_assert(fd >= 0); |
121 | |
122 | dev = container_of(vu_dev, VugDev, parent); |
123 | g_hash_table_remove(dev->fdmap, GINT_TO_POINTER(fd)); |
124 | } |
125 | |
126 | |
127 | static void vug_watch(VuDev *dev, int condition, void *data) |
128 | { |
129 | if (!vu_dispatch(dev) != 0) { |
130 | dev->panic(dev, "Error processing vhost message" ); |
131 | } |
132 | } |
133 | |
134 | bool |
135 | vug_init(VugDev *dev, uint16_t max_queues, int socket, |
136 | vu_panic_cb panic, const VuDevIface *iface) |
137 | { |
138 | g_assert(dev); |
139 | g_assert(iface); |
140 | |
141 | if (!vu_init(&dev->parent, max_queues, socket, panic, set_watch, |
142 | remove_watch, iface)) { |
143 | return false; |
144 | } |
145 | |
146 | dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL, |
147 | (GDestroyNotify) g_source_destroy); |
148 | |
149 | dev->src = vug_source_new(dev, socket, G_IO_IN, vug_watch, NULL); |
150 | |
151 | return true; |
152 | } |
153 | |
154 | void |
155 | vug_deinit(VugDev *dev) |
156 | { |
157 | g_assert(dev); |
158 | |
159 | g_hash_table_unref(dev->fdmap); |
160 | g_source_unref(dev->src); |
161 | } |
162 | |