Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017 - Cambridge Greys Ltd * Copyright (C) 2011 - 2014 Cisco Systems Inc * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) */ #include <stdlib.h> #include <errno.h> #include <sys/epoll.h> #include <signal.h> #include <string.h> #include <irq_user.h> #include <os.h> #include <um_malloc.h> /* Epoll support */ static int epollfd = -1; #define MAX_EPOLL_EVENTS 64 static struct epoll_event epoll_events[MAX_EPOLL_EVENTS]; /* Helper to return an Epoll data pointer from an epoll event structure. * We need to keep this one on the userspace side to keep includes separate */ void *os_epoll_get_data_pointer(int index) { return epoll_events[index].data.ptr; } /* Helper to compare events versus the events in the epoll structure. * Same as above - needs to be on the userspace side */ int os_epoll_triggered(int index, int events) { return epoll_events[index].events & events; } /* Helper to set the event mask. * The event mask is opaque to the kernel side, because it does not have * access to the right includes/defines for EPOLL constants. */ int os_event_mask(enum um_irq_type irq_type) { if (irq_type == IRQ_READ) return EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP | EPOLLRDHUP; if (irq_type == IRQ_WRITE) return EPOLLOUT; return 0; } /* * Initial Epoll Setup */ int os_setup_epoll(void) { epollfd = epoll_create(MAX_EPOLL_EVENTS); return epollfd; } /* * Helper to run the actual epoll_wait */ int os_waiting_for_events_epoll(void) { int n, err; n = epoll_wait(epollfd, (struct epoll_event *) &epoll_events, MAX_EPOLL_EVENTS, 0); if (n < 0) { err = -errno; if (errno != EINTR) printk( UM_KERN_ERR "os_waiting_for_events:" " epoll returned %d, error = %s\n", n, strerror(errno) ); return err; } return n; } /* * Helper to add a fd to epoll */ int os_add_epoll_fd(int events, int fd, void *data) { struct epoll_event event; int result; event.data.ptr = data; event.events = events | EPOLLET; result = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event); if ((result) && (errno == EEXIST)) result = os_mod_epoll_fd(events, fd, data); if (result) printk("epollctl add err fd %d, %s\n", fd, strerror(errno)); return result; } /* * Helper to mod the fd event mask and/or data backreference */ int os_mod_epoll_fd(int events, int fd, void *data) { struct epoll_event event; int result; event.data.ptr = data; event.events = events; result = epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event); if (result) printk(UM_KERN_ERR "epollctl mod err fd %d, %s\n", fd, strerror(errno)); return result; } /* * Helper to delete the epoll fd */ int os_del_epoll_fd(int fd) { struct epoll_event event; int result; /* This is quiet as we use this as IO ON/OFF - so it is often * invoked on a non-existent fd */ result = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &event); return result; } void os_set_ioignore(void) { signal(SIGIO, SIG_IGN); } void os_close_epoll_fd(void) { /* Needed so we do not leak an fd when rebooting */ os_close_file(epollfd); } |