Lines Matching +full:closed +full:- +full:loop
2 * Sharing QEMU devices via vhost-user protocol
8 * later. See the COPYING file in the top-level directory.
11 #include "qemu/error-report.h"
12 #include "qemu/main-loop.h"
13 #include "qemu/vhost-user-server.h"
14 #include "block/aio-wait.h"
20 * vhost_user_server_stop() from the main loop thread. Starting the server
21 * opens a vhost-user UNIX domain socket and listens for incoming connections.
25 * VuServer->ctx AioContext. The coroutine consists of a vu_dispatch() loop
26 * where libvhost-user calls vu_message_read() to receive the next vhost-user
29 * When virtqueues are set up libvhost-user calls set_watch() to monitor kick
30 * fds. These fds are also handled in the VuServer->ctx AioContext.
36 * libvhost-user before terminating the coroutine. vu_deinit() calls
41 * loop thread to accept the next client connection.
43 * When libvhost-user detects an error it calls panic_cb() and sets the
44 * dev->broken flag. Both vu_client_trip() and kick fd processing stop when
45 * the dev->broken flag is set.
52 * possible by QIOChannel's support for spurious coroutine re-entry in
53 * qio_channel_yield(). The coroutine will restart I/O when re-entered from the
60 for (i = 0; i < vmsg->fd_num; i++) { in vmsg_close_fds()
61 close(vmsg->fds[i]); in vmsg_close_fds()
73 * non-blocking fails with errno = ENOTTY) in vmsg_unblock_fds()
75 if (vmsg->request == VHOST_USER_ADD_MEM_REG || in vmsg_unblock_fds()
76 vmsg->request == VHOST_USER_SET_MEM_TABLE) { in vmsg_unblock_fds()
80 for (i = 0; i < vmsg->fd_num; i++) { in vmsg_unblock_fds()
81 qemu_socket_set_nonblock(vmsg->fds[i]); in vmsg_unblock_fds()
92 assert(!server->wait_idle); in vhost_user_server_inc_in_flight()
93 qatomic_inc(&server->in_flight); in vhost_user_server_inc_in_flight()
98 if (qatomic_fetch_dec(&server->in_flight) == 1) { in vhost_user_server_dec_in_flight()
99 if (server->wait_idle) { in vhost_user_server_dec_in_flight()
100 aio_co_wake(server->co_trip); in vhost_user_server_dec_in_flight()
107 return qatomic_load_acquire(&server->in_flight) > 0; in vhost_user_server_has_in_flight()
119 const size_t max_fds = G_N_ELEMENTS(vmsg->fds); in vu_message_read()
121 QIOChannel *ioc = server->ioc; in vu_message_read()
123 vmsg->fd_num = 0; in vu_message_read()
142 if (server->ctx) { in vu_message_read()
143 server->in_qio_channel_yield = true; in vu_message_read()
145 server->in_qio_channel_yield = false; in vu_message_read()
157 if (vmsg->fd_num + nfds > max_fds) { in vu_message_read()
160 max_fds, vmsg->fd_num + nfds); in vu_message_read()
164 memcpy(vmsg->fds + vmsg->fd_num, fds, nfds * sizeof(vmsg->fds[0])); in vu_message_read()
165 vmsg->fd_num += nfds; in vu_message_read()
169 if (rc == 0) { /* socket closed */ in vu_message_read()
174 iov.iov_len -= rc; in vu_message_read()
180 if (vmsg->size > sizeof(vmsg->payload)) { in vu_message_read()
182 "size: vmsg->size: %u, " in vu_message_read()
183 "while sizeof(vmsg->payload) = %zu", in vu_message_read()
184 vmsg->request, vmsg->size, sizeof(vmsg->payload)); in vu_message_read()
189 .iov_base = (char *)&vmsg->payload, in vu_message_read()
190 .iov_len = vmsg->size, in vu_message_read()
192 if (vmsg->size) { in vu_message_read()
213 VuDev *vu_dev = &server->vu_dev; in vu_client_trip()
215 while (!vu_dev->broken) { in vu_client_trip()
216 if (server->quiescing) { in vu_client_trip()
217 server->co_trip = NULL; in vu_client_trip()
221 /* vu_dispatch() returns false if server->ctx went away */ in vu_client_trip()
222 if (!vu_dispatch(vu_dev) && server->ctx) { in vu_client_trip()
229 server->wait_idle = true; in vu_client_trip()
231 server->wait_idle = false; in vu_client_trip()
238 assert(QTAILQ_EMPTY(&server->vu_fd_watches)); in vu_client_trip()
240 object_unref(OBJECT(server->sioc)); in vu_client_trip()
241 server->sioc = NULL; in vu_client_trip()
243 object_unref(OBJECT(server->ioc)); in vu_client_trip()
244 server->ioc = NULL; in vu_client_trip()
246 server->co_trip = NULL; in vu_client_trip()
247 if (server->restart_listener_bh) { in vu_client_trip()
248 qemu_bh_schedule(server->restart_listener_bh); in vu_client_trip()
263 VuDev *vu_dev = vu_fd_watch->vu_dev; in kick_handler()
265 vu_fd_watch->cb(vu_dev, 0, vu_fd_watch->pvt); in kick_handler()
267 /* Stop vu_client_trip() if an error occurred in vu_fd_watch->cb() */ in kick_handler()
268 if (vu_dev->broken) { in kick_handler()
271 qio_channel_shutdown(server->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); in kick_handler()
279 QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) { in find_vu_fd_watch()
280 if (vu_fd_watch->fd == fd) { in find_vu_fd_watch()
302 QTAILQ_INSERT_TAIL(&server->vu_fd_watches, vu_fd_watch, next); in set_watch()
304 vu_fd_watch->fd = fd; in set_watch()
305 vu_fd_watch->cb = cb; in set_watch()
307 aio_set_fd_handler(server->ctx, fd, kick_handler, in set_watch()
309 vu_fd_watch->vu_dev = vu_dev; in set_watch()
310 vu_fd_watch->pvt = pvt; in set_watch()
328 aio_set_fd_handler(server->ctx, fd, NULL, NULL, NULL, NULL, NULL); in remove_watch()
330 QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next); in remove_watch()
340 if (server->sioc) { in vu_accept()
341 warn_report("Only one vhost-user client is allowed to " in vu_accept()
346 if (!vu_init(&server->vu_dev, server->max_queues, sioc->fd, panic_cb, in vu_accept()
347 vu_message_read, set_watch, remove_watch, server->vu_iface)) { in vu_accept()
348 error_report("Failed to initialize libvhost-user"); in vu_accept()
354 * vhost-user client keeping waiting until this client disconnects in vu_accept()
356 qio_net_listener_set_client_func(server->listener, in vu_accept()
360 server->sioc = sioc; in vu_accept()
365 object_ref(OBJECT(server->sioc)); in vu_accept()
366 qio_channel_set_name(QIO_CHANNEL(sioc), "vhost-user client"); in vu_accept()
367 server->ioc = QIO_CHANNEL(sioc); in vu_accept()
368 object_ref(OBJECT(server->ioc)); in vu_accept()
370 /* TODO vu_message_write() spins if non-blocking! */ in vu_accept()
371 qio_channel_set_blocking(server->ioc, false, NULL); in vu_accept()
373 qio_channel_set_follow_coroutine_ctx(server->ioc, true); in vu_accept()
375 vhost_user_server_attach_aio_context(server, server->ctx); in vu_accept()
378 /* server->ctx acquired by caller */
381 qemu_bh_delete(server->restart_listener_bh); in vhost_user_server_stop()
382 server->restart_listener_bh = NULL; in vhost_user_server_stop()
384 if (server->sioc) { in vhost_user_server_stop()
387 QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) { in vhost_user_server_stop()
388 aio_set_fd_handler(server->ctx, vu_fd_watch->fd, in vhost_user_server_stop()
392 qio_channel_shutdown(server->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); in vhost_user_server_stop()
394 AIO_WAIT_WHILE(server->ctx, server->co_trip); in vhost_user_server_stop()
397 if (server->listener) { in vhost_user_server_stop()
398 qio_net_listener_disconnect(server->listener); in vhost_user_server_stop()
399 object_unref(OBJECT(server->listener)); in vhost_user_server_stop()
405 * loop.
411 qio_net_listener_set_client_func(server->listener, vu_accept, server, in restart_listener_bh()
420 server->ctx = ctx; in vhost_user_server_attach_aio_context()
422 if (!server->sioc) { in vhost_user_server_attach_aio_context()
426 QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) { in vhost_user_server_attach_aio_context()
427 aio_set_fd_handler(ctx, vu_fd_watch->fd, kick_handler, NULL, in vhost_user_server_attach_aio_context()
431 if (server->co_trip) { in vhost_user_server_attach_aio_context()
434 * non-polling drains like in bdrv_graph_wrlock()). This is okay as long in vhost_user_server_attach_aio_context()
441 AioContext *co_ctx = qemu_coroutine_get_aio_context(server->co_trip); in vhost_user_server_attach_aio_context()
443 assert(!server->quiescing); in vhost_user_server_attach_aio_context()
446 server->co_trip = qemu_coroutine_create(vu_client_trip, server); in vhost_user_server_attach_aio_context()
447 assert(!server->in_qio_channel_yield); in vhost_user_server_attach_aio_context()
448 aio_co_schedule(ctx, server->co_trip); in vhost_user_server_attach_aio_context()
452 /* Called with server->ctx acquired */
455 if (server->sioc) { in vhost_user_server_detach_aio_context()
458 QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) { in vhost_user_server_detach_aio_context()
459 aio_set_fd_handler(server->ctx, vu_fd_watch->fd, in vhost_user_server_detach_aio_context()
464 server->ctx = NULL; in vhost_user_server_detach_aio_context()
466 if (server->ioc) { in vhost_user_server_detach_aio_context()
467 if (server->in_qio_channel_yield) { in vhost_user_server_detach_aio_context()
468 /* Stop receiving the next vhost-user message */ in vhost_user_server_detach_aio_context()
469 qio_channel_wake_read(server->ioc); in vhost_user_server_detach_aio_context()
484 if (socket_addr->type != SOCKET_ADDRESS_TYPE_UNIX && in vhost_user_server_start()
485 socket_addr->type != SOCKET_ADDRESS_TYPE_FD) { in vhost_user_server_start()
508 qio_net_listener_set_name(server->listener, "vhost-user-backend-listener"); in vhost_user_server_start()
510 qio_net_listener_set_client_func(server->listener, in vhost_user_server_start()
515 QTAILQ_INIT(&server->vu_fd_watches); in vhost_user_server_start()