int event_notifier_wait_and_clear(EventNotifier *e, long second) { fd_set rfds; int value; struct timeval tv; struct timeval *tvp; if (second != 0) { tv.tv_sec = second; tv.tv_usec = 0; tvp = &tv; } else { tvp = NULL; } FD_ZERO(&rfds); FD_SET(e->rfd, &rfds); value = select(e->rfd + 1, &rfds, NULL, NULL, tvp); switch (value) { case -1: value = -errno; break; case 1: event_notifier_test_and_clear(e); break; case 0: default: value = 0; break; } return value; }
static void qemu_laio_completion_cb(EventNotifier *e) { struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e); if (event_notifier_test_and_clear(&s->e)) { qemu_bh_schedule(s->completion_bh); } }
static void kvm_hv_sint_ack_handler(EventNotifier *notifier) { HvSintRoute *sint_route = container_of(notifier, HvSintRoute, sint_ack_notifier); event_notifier_test_and_clear(notifier); if (sint_route->sint_ack_clb) { sint_route->sint_ack_clb(sint_route); } }
static void v9fs_qemu_process_req_done(EventNotifier *e) { Coroutine *co; event_notifier_test_and_clear(e); while ((co = g_async_queue_try_pop(v9fs_pool.completed)) != NULL) { qemu_coroutine_enter(co, NULL); } }
static void event_ready_cb(EventNotifier *e) { EventNotifierTestData *data = container_of(e, EventNotifierTestData, e); g_assert(event_notifier_test_and_clear(e)); data->n++; if (data->active > 0) { data->active--; } if (data->auto_set && data->active) { event_notifier_set(e); } }
static void win32_aio_completion_cb(EventNotifier *e) { QEMUWin32AIOState *s = container_of(e, QEMUWin32AIOState, e); DWORD count; ULONG_PTR key; OVERLAPPED *ov; event_notifier_test_and_clear(&s->e); while (GetQueuedCompletionStatus(s->hIOCP, &count, &key, &ov, 0)) { QEMUWin32AIOCB *waiocb = container_of(ov, QEMUWin32AIOCB, ov); win32_aio_process_completion(s, waiocb, count); } }
static int pci_testdev_start(IOTest *test) { test->hdr->count = 0; if (!test->hasnotifier) { return 0; } event_notifier_test_and_clear(&test->notifier); memory_region_add_eventfd(test->mr, le32_to_cpu(test->hdr->offset), test->size, test->match_data, test->hdr->data, &test->notifier); return 0; }
static void handle_notify(EventNotifier *e) { VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, host_notifier); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); event_notifier_test_and_clear(&s->host_notifier); blk_io_plug(s->conf->conf.blk); for (;;) { MultiReqBuffer mrb = {}; int ret; /* Disable guest->host notifies to avoid unnecessary vmexits */ vring_disable_notification(s->vdev, &s->vring); for (;;) { VirtIOBlockReq *req = virtio_blk_alloc_request(vblk); ret = vring_pop(s->vdev, &s->vring, &req->elem); if (ret < 0) { virtio_blk_free_request(req); break; /* no more requests */ } trace_virtio_blk_data_plane_process_request(s, req->elem.out_num, req->elem.in_num, req->elem.index); virtio_blk_handle_request(req, &mrb); } if (mrb.num_reqs) { virtio_blk_submit_multireq(s->conf->conf.blk, &mrb); } if (likely(ret == -EAGAIN)) { /* vring emptied */ /* Re-enable guest->host notifies and stop processing the vring. * But if the guest has snuck in more descriptors, keep processing. */ if (vring_enable_notification(s->vdev, &s->vring)) { break; } } else { /* fatal error */ break; } } blk_io_unplug(s->conf->conf.blk); }
static uint64_t pci_testdev_read(void *opaque, hwaddr addr, unsigned size) { PCITestDevState *d = opaque; const char *buf; IOTest *test; if (d->current < 0) { return 0; } test = &d->tests[d->current]; buf = (const char *)test->hdr; if (addr + size >= test->bufsize) { return 0; } if (test->hasnotifier) { event_notifier_test_and_clear(&test->notifier); } return buf[addr]; }
static void ivshmem_vector_notify(void *opaque) { MSIVector *entry = opaque; PCIDevice *pdev = entry->pdev; IVShmemState *s = IVSHMEM(pdev); int vector = entry - s->msi_vectors; EventNotifier *n = &s->peers[s->vm_id].eventfds[vector]; if (!event_notifier_test_and_clear(n)) { return; } IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, vector); if (ivshmem_has_feature(s, IVSHMEM_MSI)) { msix_notify(pdev, vector); } else { ivshmem_IntrStatus_write(s, 1); } }
static void ivshmem_vector_poll(PCIDevice *dev, unsigned int vector_start, unsigned int vector_end) { IVShmemState *s = IVSHMEM_COMMON(dev); unsigned int vector; IVSHMEM_DPRINTF("vector poll %p %d-%d\n", dev, vector_start, vector_end); vector_end = MIN(vector_end, s->vectors); for (vector = vector_start; vector < vector_end; vector++) { EventNotifier *notifier = &s->peers[s->vm_id].eventfds[vector]; if (!msix_is_masked(dev, vector)) { continue; } if (event_notifier_test_and_clear(notifier)) { msix_set_pending(dev, vector); } } }
static void qemu_laio_completion_cb(EventNotifier *e) { struct qemu_laio_state *s = container_of(e, struct qemu_laio_state, e); while (event_notifier_test_and_clear(&s->e)) { struct io_event events[MAX_EVENTS]; struct timespec ts = { 0 }; int nevents, i; do { nevents = io_getevents(s->ctx, MAX_EVENTS, MAX_EVENTS, events, &ts); } while (nevents == -EINTR); for (i = 0; i < nevents; i++) { struct iocb *iocb = events[i].obj; struct qemu_laiocb *laiocb = container_of(iocb, struct qemu_laiocb, iocb); laiocb->ret = io_event_ret(&events[i]); qemu_laio_process_completion(s, laiocb); } } }
static void dummy_notifier_read(EventNotifier *n) { event_notifier_test_and_clear(n); }
static void handle_notify(EventNotifier *e) { VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, host_notifier); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); event_notifier_test_and_clear(&s->host_notifier); blk_io_plug(s->conf->conf.blk); for (;;) { MultiReqBuffer mrb = { .num_writes = 0, }; int ret; /* Disable guest->host notifies to avoid unnecessary vmexits */ vring_disable_notification(s->vdev, &s->vring); for (;;) { VirtIOBlockReq *req = virtio_blk_alloc_request(vblk); ret = vring_pop(s->vdev, &s->vring, &req->elem); if (ret < 0) { virtio_blk_free_request(req); break; /* no more requests */ } trace_virtio_blk_data_plane_process_request(s, req->elem.out_num, req->elem.in_num, req->elem.index); virtio_blk_handle_request(req, &mrb); } virtio_submit_multiwrite(s->conf->conf.blk, &mrb); if (likely(ret == -EAGAIN)) { /* vring emptied */ /* Re-enable guest->host notifies and stop processing the vring. * But if the guest has snuck in more descriptors, keep processing. */ if (vring_enable_notification(s->vdev, &s->vring)) { break; } } else { /* fatal error */ break; } } blk_io_unplug(s->conf->conf.blk); } /* Context: QEMU global mutex held */ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, VirtIOBlockDataPlane **dataplane, Error **errp) { VirtIOBlockDataPlane *s; Error *local_err = NULL; BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); *dataplane = NULL; if (!conf->data_plane && !conf->iothread) { return; } /* Don't try if transport does not support notifiers. */ if (!k->set_guest_notifiers || !k->set_host_notifier) { error_setg(errp, "device is incompatible with x-data-plane " "(transport does not support notifiers)"); return; } /* If dataplane is (re-)enabled while the guest is running there could be * block jobs that can conflict. */ if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, &local_err)) { error_setg(errp, "cannot start dataplane thread: %s", error_get_pretty(local_err)); error_free(local_err); return; } s = g_new0(VirtIOBlockDataPlane, 1); s->vdev = vdev; s->conf = conf; if (conf->iothread) { s->iothread = conf->iothread; object_ref(OBJECT(s->iothread)); } else { /* Create per-device IOThread if none specified. This is for * x-data-plane option compatibility. If x-data-plane is removed we * can drop this. */ object_initialize(&s->internal_iothread_obj, sizeof(s->internal_iothread_obj), TYPE_IOTHREAD); user_creatable_complete(OBJECT(&s->internal_iothread_obj), &error_abort); s->iothread = &s->internal_iothread_obj; } s->ctx = iothread_get_aio_context(s->iothread); s->bh = aio_bh_new(s->ctx, notify_guest_bh, s); error_setg(&s->blocker, "block device is in use by data plane"); blk_op_block_all(conf->conf.blk, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker); *dataplane = s; }