libvhost-user-glib.c 3.8 KB

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