2 * Copyright (c) 2007 Roman Divacky
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include "opt_compat.h"
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kern_syscall.h>
32 #include <sys/event.h>
34 #include <sys/mplock2.h>
35 #include <sys/malloc.h>
36 #include <sys/ptrace.h>
38 #include <sys/signalvar.h>
39 #include <sys/sysent.h>
40 #include <sys/sysproto.h>
43 #include <vm/vm_param.h>
44 #include <vm/vm_page.h>
45 #include <vm/vm_extern.h>
47 #include <sys/kernel.h>
48 #include <sys/module.h>
49 #include <machine/cpu.h>
51 #include "i386/linux.h"
52 #include "i386/linux_proto.h"
53 #include "linux_signal.h"
54 #include "linux_util.h"
55 #include "linux_epoll.h"
58 /* Create a new epoll file descriptor. */
60 sys_linux_epoll_create(struct linux_epoll_create_args
*args
)
62 struct kqueue_args k_args
;
66 /* args->size is unused. Linux ignores it as well. */
68 return (sys_kqueue(&k_args
));
71 /* Structure converting function from epoll to kevent. */
73 linux_epoll_to_kevent(int fd
, struct linux_epoll_event
*event
, struct kevent
*kevent
)
76 int flags
= kevent
->flags
;
78 if (event
->events
& LINUX_EPOLLIN
)
79 filter
|= EVFILT_READ
;
80 if (event
->events
& LINUX_EPOLLOUT
)
81 filter
|= EVFILT_WRITE
;
82 if (event
->events
& LINUX_EPOLLPRI
)
83 filter
|= EVFILT_READ
;
84 if (event
->events
& LINUX_EPOLLET
)
86 if (event
->events
& LINUX_EPOLLONESHOT
)
89 EV_SET(kevent
, fd
, filter
, flags
, 0, 0, NULL
);
93 * Structure converting function from kevent to epoll. In a case
94 * this is called on error in registration we store the error in
95 * event->data and pick it up later in linux_epoll_ctl().
98 linux_kevent_to_epoll(struct kevent
*kevent
, struct linux_epoll_event
*event
)
100 if (kevent
->flags
& EV_ERROR
) {
101 event
->data
= kevent
->data
;
104 switch (kevent
->filter
) {
106 if (kevent
->data
> 0)
107 event
->events
= LINUX_EPOLLIN
;
108 event
->data
= kevent
->ident
;
111 if (kevent
->data
> 0)
112 event
->events
= LINUX_EPOLLOUT
;
113 event
->data
= kevent
->ident
;
119 * Copyout callback used by kevent. This converts kevent
120 * events to epoll events and copies them back to the
121 * userspace. This is also called on error on registering
125 linux_kev_copyout(void *arg
, struct kevent
*kevp
, int count
)
127 struct kevent_args
*uap
;
128 struct linux_epoll_event
*eep
;
131 uap
= (struct kevent_args
*) arg
;
133 eep
= kmalloc(sizeof(*eep
) * count
, M_TEMP
, M_WAITOK
| M_ZERO
);
135 for (i
= 0; i
< count
; i
++) {
136 linux_kevent_to_epoll(&kevp
[i
], &eep
[i
]);
139 error
= copyout(eep
, uap
->eventlist
, count
* sizeof(*eep
));
141 uap
->eventlist
= (struct kevent
*)((char *)uap
->eventlist
+ count
* sizeof(*eep
));
148 * Copyin callback used by kevent. This copies already
149 * converted filters to the kevent internal memory.
152 linux_kev_copyin(void *arg
, struct kevent
*kevp
, int count
)
154 struct kevent_args
*uap
;
156 uap
= (struct kevent_args
*) arg
;
158 memcpy(kevp
, uap
->changelist
, count
* sizeof(*kevp
));
160 uap
->changelist
+= count
;
166 * Load epoll filter, convert it to kevent filter
167 * and load it into kevent subsystem.
170 sys_linux_epoll_ctl(struct linux_epoll_ctl_args
*args
)
172 struct kevent_args k_args
;
174 struct linux_epoll_event le
;
177 error
= copyin(args
->event
, &le
, sizeof(le
));
181 if (ldebug(epoll_ctl
))
182 kprintf(ARGS(epoll_ctl
,"%i, %i, %i, %u"), args
->epfd
, args
->op
,
183 args
->fd
, le
.events
);
185 k_args
.fd
= args
->epfd
;
186 k_args
.changelist
= &kev
;
187 /* The epoll can register only 1 filter at once. */
189 k_args
.eventlist
= NULL
;
191 k_args
.timeout
= NULL
;
194 case LINUX_EPOLL_CTL_ADD
:
195 kev
.flags
= EV_ADD
| EV_ENABLE
;
197 case LINUX_EPOLL_CTL_MOD
:
198 /* TODO: DELETE && ADD maybe? */
201 case LINUX_EPOLL_CTL_DEL
:
202 kev
.flags
= EV_DELETE
| EV_DISABLE
;
205 linux_epoll_to_kevent(args
->fd
, &le
, &kev
);
207 error
= kern_kevent(args
->epfd
, 1, 0, &k_args
, linux_kev_copyin
,
208 linux_kev_copyout
, NULL
);
209 /* Check if there was an error during registration. */
210 if (error
== 0 && k_args
.sysmsg_result
!= 0) {
211 /* The copyout callback stored the error there. */
219 * Wait for a filter to be triggered on the epoll file descriptor. */
221 sys_linux_epoll_wait(struct linux_epoll_wait_args
*args
)
224 struct kevent_args k_args
;
227 /* Convert from miliseconds to timespec. */
228 ts
.tv_sec
= args
->timeout
/ 1000000;
229 ts
.tv_nsec
= (args
->timeout
% 1000000) * 1000;
231 k_args
.fd
= args
->epfd
;
232 k_args
.changelist
= NULL
;
235 * We don't mind the bogus type-cast because
236 * our copyout function knows about this and
237 * handles it correctly.
239 k_args
.eventlist
= (struct kevent
*)args
->events
;
240 k_args
.nevents
= args
->maxevents
;
241 k_args
.timeout
= &ts
;
243 error
= kern_kevent(args
->epfd
, 0, args
->maxevents
, &k_args
,
244 linux_kev_copyin
, linux_kev_copyout
, &ts
);