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