#define IOEVENTFD_MAX_EVENTS 20
static struct epoll_event events[IOEVENTFD_MAX_EVENTS];
-static int epoll_fd;
+static int epoll_fd, epoll_stop_fd;
static LIST_HEAD(used_ioevents);
static bool ioeventfd_avail;
-void ioeventfd__init(struct kvm *kvm)
+static void *ioeventfd__thread(void *param)
{
+ u64 tmp = 1;
+
+ for (;;) {
+ int nfds, i;
+
+ nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1);
+ for (i = 0; i < nfds; i++) {
+ struct ioevent *ioevent;
+
+ if (events[i].data.fd == epoll_stop_fd)
+ goto done;
+
+ ioevent = events[i].data.ptr;
+
+ if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0)
+ die("Failed reading event");
+
+ ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr);
+ }
+ }
+
+done:
+ tmp = 1;
+ tmp = write(epoll_stop_fd, &tmp, sizeof(tmp));
+
+ return NULL;
+}
+
+static int ioeventfd__start(void)
+{
+ pthread_t thread;
+
+ if (!ioeventfd_avail)
+ return -ENOSYS;
+
+ return pthread_create(&thread, NULL, ioeventfd__thread, NULL);
+}
+
+int ioeventfd__init(struct kvm *kvm)
+{
+ struct epoll_event epoll_event = {.events = EPOLLIN};
+ int r;
+
ioeventfd_avail = kvm__supports_extension(kvm, KVM_CAP_IOEVENTFD);
if (!ioeventfd_avail)
- return;
+ return -ENOSYS;
epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS);
if (epoll_fd < 0)
- die("Failed creating epoll fd");
+ return -errno;
+
+ epoll_stop_fd = eventfd(0, 0);
+ epoll_event.data.fd = epoll_stop_fd;
+
+ r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, epoll_stop_fd, &epoll_event);
+ if (r < 0)
+ goto cleanup;
+
+ r = ioeventfd__start();
+ if (r < 0)
+ goto cleanup;
+
+ r = 0;
+
+ return r;
+
+cleanup:
+ close(epoll_stop_fd);
+ close(epoll_fd);
+
+ return r;
}
-void ioeventfd__add_event(struct ioevent *ioevent)
+int ioeventfd__exit(struct kvm *kvm)
+{
+ u64 tmp = 1;
+ int r;
+
+ r = write(epoll_stop_fd, &tmp, sizeof(tmp));
+ if (r < 0)
+ return r;
+
+ r = read(epoll_stop_fd, &tmp, sizeof(tmp));
+ if (r < 0)
+ return r;
+
+ close(epoll_fd);
+ close(epoll_stop_fd);
+
+ return 0;
+}
+
+int ioeventfd__add_event(struct ioevent *ioevent)
{
struct kvm_ioeventfd kvm_ioevent;
struct epoll_event epoll_event;
struct ioevent *new_ioevent;
- int event;
+ int event, r;
if (!ioeventfd_avail)
- return;
+ return -ENOSYS;
new_ioevent = malloc(sizeof(*new_ioevent));
if (new_ioevent == NULL)
- die("Failed allocating memory for new ioevent");
+ return -ENOMEM;
*new_ioevent = *ioevent;
event = new_ioevent->fd;
.flags = KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH,
};
- if (ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent) != 0)
- die("Failed creating new ioeventfd");
+ r = ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent);
+ if (r) {
+ r = -errno;
+ goto cleanup;
+ }
epoll_event = (struct epoll_event) {
.events = EPOLLIN,
.data.ptr = new_ioevent,
};
- if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event) != 0)
- die("Failed assigning new event to the epoll fd");
+ r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event);
+ if (r) {
+ r = -errno;
+ goto cleanup;
+ }
list_add_tail(&new_ioevent->list, &used_ioevents);
+
+ return 0;
+
+cleanup:
+ free(new_ioevent);
+ return r;
}
-void ioeventfd__del_event(u64 addr, u64 datamatch)
+int ioeventfd__del_event(u64 addr, u64 datamatch)
{
struct kvm_ioeventfd kvm_ioevent;
struct ioevent *ioevent;
u8 found = 0;
if (!ioeventfd_avail)
- return;
+ return -ENOSYS;
list_for_each_entry(ioevent, &used_ioevents, list) {
if (ioevent->io_addr == addr) {
}
if (found == 0 || ioevent == NULL)
- return;
+ return -ENOENT;
kvm_ioevent = (struct kvm_ioeventfd) {
.addr = ioevent->io_addr,
close(ioevent->fd);
free(ioevent);
-}
-
-static void *ioeventfd__thread(void *param)
-{
- for (;;) {
- int nfds, i;
-
- nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1);
- for (i = 0; i < nfds; i++) {
- u64 tmp;
- struct ioevent *ioevent;
-
- ioevent = events[i].data.ptr;
-
- if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0)
- die("Failed reading event");
-
- ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr);
- }
- }
-
- return NULL;
-}
-
-void ioeventfd__start(void)
-{
- pthread_t thread;
-
- if (!ioeventfd_avail)
- return;
- if (pthread_create(&thread, NULL, ioeventfd__thread, NULL) != 0)
- die("Failed starting ioeventfd thread");
+ return 0;
}