Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (C) 2017 - Cambridge Greys Ltd
4 : * Copyright (C) 2011 - 2014 Cisco Systems Inc
5 : * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
6 : */
7 :
8 : #include <stdlib.h>
9 : #include <errno.h>
10 : #include <sys/epoll.h>
11 : #include <signal.h>
12 : #include <string.h>
13 : #include <irq_user.h>
14 : #include <os.h>
15 : #include <um_malloc.h>
16 :
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 0 : void *os_epoll_get_data_pointer(int index)
30 : {
31 0 : 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 0 : int os_epoll_triggered(int index, int events)
40 : {
41 0 : 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 1 : int os_event_mask(enum um_irq_type irq_type)
49 : {
50 1 : if (irq_type == IRQ_READ)
51 : return EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP | EPOLLRDHUP;
52 0 : if (irq_type == IRQ_WRITE)
53 : return EPOLLOUT;
54 0 : return 0;
55 : }
56 :
57 : /*
58 : * Initial Epoll Setup
59 : */
60 1 : int os_setup_epoll(void)
61 : {
62 1 : epollfd = epoll_create(MAX_EPOLL_EVENTS);
63 1 : return epollfd;
64 : }
65 :
66 : /*
67 : * Helper to run the actual epoll_wait
68 : */
69 0 : int os_waiting_for_events_epoll(void)
70 : {
71 : int n, err;
72 :
73 0 : n = epoll_wait(epollfd,
74 : (struct epoll_event *) &epoll_events, MAX_EPOLL_EVENTS, 0);
75 0 : if (n < 0) {
76 0 : err = -errno;
77 0 : if (errno != EINTR)
78 0 : printk(
79 : UM_KERN_ERR "os_waiting_for_events:"
80 : " epoll returned %d, error = %s\n", n,
81 : strerror(errno)
82 : );
83 : return err;
84 : }
85 : return n;
86 : }
87 :
88 :
89 : /*
90 : * Helper to add a fd to epoll
91 : */
92 1 : int os_add_epoll_fd(int events, int fd, void *data)
93 : {
94 : struct epoll_event event;
95 : int result;
96 :
97 1 : event.data.ptr = data;
98 1 : event.events = events | EPOLLET;
99 1 : result = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
100 1 : if ((result) && (errno == EEXIST))
101 0 : result = os_mod_epoll_fd(events, fd, data);
102 1 : if (result)
103 0 : printk("epollctl add err fd %d, %s\n", fd, strerror(errno));
104 1 : return result;
105 : }
106 :
107 : /*
108 : * Helper to mod the fd event mask and/or data backreference
109 : */
110 0 : int os_mod_epoll_fd(int events, int fd, void *data)
111 : {
112 : struct epoll_event event;
113 : int result;
114 :
115 0 : event.data.ptr = data;
116 0 : event.events = events;
117 0 : result = epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
118 0 : if (result)
119 0 : printk(UM_KERN_ERR
120 : "epollctl mod err fd %d, %s\n", fd, strerror(errno));
121 0 : return result;
122 : }
123 :
124 : /*
125 : * Helper to delete the epoll fd
126 : */
127 1 : int os_del_epoll_fd(int fd)
128 : {
129 : struct epoll_event event;
130 : /* This is quiet as we use this as IO ON/OFF - so it is often
131 : * invoked on a non-existent fd
132 : */
133 1 : return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &event);
134 : }
135 :
136 1 : void os_set_ioignore(void)
137 : {
138 1 : signal(SIGIO, SIG_IGN);
139 1 : }
140 :
141 1 : void os_close_epoll_fd(void)
142 : {
143 : /* Needed so we do not leak an fd when rebooting */
144 1 : os_close_file(epollfd);
145 1 : }
|