|
Lines 98-111
__attribute__((packed))
Link Here
|
| 98 |
#define LINUX_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) |
98 |
#define LINUX_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) |
| 99 |
|
99 |
|
| 100 |
static void epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata); |
100 |
static void epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata); |
| 101 |
static int epoll_to_kevent(struct thread *td, struct file *epfp, |
101 |
static int epoll_to_kevent(struct thread *td, int fd, |
| 102 |
int fd, struct epoll_event *l_event, int *kev_flags, |
102 |
struct epoll_event *l_event, struct kevent *kevent, |
| 103 |
struct kevent *kevent, int *nkevents); |
103 |
int *nkevents); |
| 104 |
static void kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event); |
104 |
static void kevent_to_epoll(struct kevent *kevent, struct epoll_event *l_event); |
| 105 |
static int epoll_kev_copyout(void *arg, struct kevent *kevp, int count); |
105 |
static int epoll_kev_copyout(void *arg, struct kevent *kevp, int count); |
| 106 |
static int epoll_kev_copyin(void *arg, struct kevent *kevp, int count); |
106 |
static int epoll_kev_copyin(void *arg, struct kevent *kevp, int count); |
| 107 |
static int epoll_delete_event(struct thread *td, struct file *epfp, |
107 |
static int epoll_register_kevent(struct thread *td, struct file *epfp, |
| 108 |
int fd, int filter); |
108 |
int fd, int filter, unsigned int flags); |
|
|
109 |
static int epoll_fd_registered(struct thread *td, struct file *epfp, |
| 110 |
int fd); |
| 109 |
static int epoll_delete_all_events(struct thread *td, struct file *epfp, |
111 |
static int epoll_delete_all_events(struct thread *td, struct file *epfp, |
| 110 |
int fd); |
112 |
int fd); |
| 111 |
|
113 |
|
|
Lines 296-326
linux_epoll_create1(struct thread *td, struct linux_epoll_create1_args *args)
Link Here
|
| 296 |
|
298 |
|
| 297 |
/* Structure converting function from epoll to kevent. */ |
299 |
/* Structure converting function from epoll to kevent. */ |
| 298 |
static int |
300 |
static int |
| 299 |
epoll_to_kevent(struct thread *td, struct file *epfp, |
301 |
epoll_to_kevent(struct thread *td, int fd, struct epoll_event *l_event, |
| 300 |
int fd, struct epoll_event *l_event, int *kev_flags, |
|
|
| 301 |
struct kevent *kevent, int *nkevents) |
302 |
struct kevent *kevent, int *nkevents) |
| 302 |
{ |
303 |
{ |
| 303 |
uint32_t levents = l_event->events; |
304 |
uint32_t levents = l_event->events; |
| 304 |
struct linux_pemuldata *pem; |
305 |
struct linux_pemuldata *pem; |
| 305 |
struct proc *p; |
306 |
struct proc *p; |
|
|
307 |
unsigned short kev_flags = EV_ADD | EV_ENABLE; |
| 306 |
|
308 |
|
| 307 |
/* flags related to how event is registered */ |
309 |
/* flags related to how event is registered */ |
| 308 |
if ((levents & LINUX_EPOLLONESHOT) != 0) |
310 |
if ((levents & LINUX_EPOLLONESHOT) != 0) |
| 309 |
*kev_flags |= EV_DISPATCH; |
311 |
kev_flags |= EV_DISPATCH; |
| 310 |
if ((levents & LINUX_EPOLLET) != 0) |
312 |
if ((levents & LINUX_EPOLLET) != 0) |
| 311 |
*kev_flags |= EV_CLEAR; |
313 |
kev_flags |= EV_CLEAR; |
| 312 |
if ((levents & LINUX_EPOLLERR) != 0) |
314 |
if ((levents & LINUX_EPOLLERR) != 0) |
| 313 |
*kev_flags |= EV_ERROR; |
315 |
kev_flags |= EV_ERROR; |
| 314 |
if ((levents & LINUX_EPOLLRDHUP) != 0) |
316 |
if ((levents & LINUX_EPOLLRDHUP) != 0) |
| 315 |
*kev_flags |= EV_EOF; |
317 |
kev_flags |= EV_EOF; |
| 316 |
|
318 |
|
| 317 |
/* flags related to what event is registered */ |
319 |
/* flags related to what event is registered */ |
| 318 |
if ((levents & LINUX_EPOLL_EVRD) != 0) { |
320 |
if ((levents & LINUX_EPOLL_EVRD) != 0) { |
| 319 |
EV_SET(kevent++, fd, EVFILT_READ, *kev_flags, 0, 0, 0); |
321 |
EV_SET(kevent++, fd, EVFILT_READ, kev_flags, 0, 0, 0); |
| 320 |
++(*nkevents); |
322 |
++(*nkevents); |
| 321 |
} |
323 |
} |
| 322 |
if ((levents & LINUX_EPOLL_EVWR) != 0) { |
324 |
if ((levents & LINUX_EPOLL_EVWR) != 0) { |
| 323 |
EV_SET(kevent++, fd, EVFILT_WRITE, *kev_flags, 0, 0, 0); |
325 |
EV_SET(kevent++, fd, EVFILT_WRITE, kev_flags, 0, 0, 0); |
|
|
326 |
++(*nkevents); |
| 327 |
} |
| 328 |
/* zero event mask is legal */ |
| 329 |
if ((levents & (LINUX_EPOLL_EVRD | LINUX_EPOLL_EVWR)) == 0) { |
| 330 |
EV_SET(kevent++, fd, EVFILT_READ, EV_ADD|EV_DISABLE, 0, 0, 0); |
| 324 |
++(*nkevents); |
331 |
++(*nkevents); |
| 325 |
} |
332 |
} |
| 326 |
|
333 |
|
|
Lines 451-457
linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args)
Link Here
|
| 451 |
epoll_kev_copyin}; |
458 |
epoll_kev_copyin}; |
| 452 |
struct epoll_event le; |
459 |
struct epoll_event le; |
| 453 |
cap_rights_t rights; |
460 |
cap_rights_t rights; |
| 454 |
int kev_flags; |
|
|
| 455 |
int nchanges = 0; |
461 |
int nchanges = 0; |
| 456 |
int error; |
462 |
int error; |
| 457 |
|
463 |
|
|
Lines 484-492
linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args)
Link Here
|
| 484 |
ciargs.changelist = kev; |
490 |
ciargs.changelist = kev; |
| 485 |
|
491 |
|
| 486 |
if (args->op != LINUX_EPOLL_CTL_DEL) { |
492 |
if (args->op != LINUX_EPOLL_CTL_DEL) { |
| 487 |
kev_flags = EV_ADD | EV_ENABLE; |
493 |
error = epoll_to_kevent(td, args->fd, &le, kev, &nchanges); |
| 488 |
error = epoll_to_kevent(td, epfp, args->fd, &le, |
|
|
| 489 |
&kev_flags, kev, &nchanges); |
| 490 |
if (error != 0) |
494 |
if (error != 0) |
| 491 |
goto leave0; |
495 |
goto leave0; |
| 492 |
} |
496 |
} |
|
Lines 499-517
linux_epoll_ctl(struct thread *td, struct linux_epoll_ctl_args *args)
Link Here
|
| 499 |
break; |
503 |
break; |
| 500 |
|
504 |
|
| 501 |
case LINUX_EPOLL_CTL_ADD: |
505 |
case LINUX_EPOLL_CTL_ADD: |
| 502 |
/* |
506 |
if (epoll_fd_registered(td, epfp, args->fd)) { |
| 503 |
* kqueue_register() return ENOENT if event does not exists |
|
|
| 504 |
* and the EV_ADD flag is not set. Reset EV_ENABLE flag to |
| 505 |
* avoid accidental activation of fired oneshot events. |
| 506 |
*/ |
| 507 |
kev[0].flags &= ~(EV_ADD | EV_ENABLE); |
| 508 |
error = kqfd_register(args->epfd, &kev[0], td, M_WAITOK); |
| 509 |
if (error != ENOENT) { |
| 510 |
error = EEXIST; |
507 |
error = EEXIST; |
| 511 |
goto leave0; |
508 |
goto leave0; |
| 512 |
} |
509 |
} |
| 513 |
error = 0; |
|
|
| 514 |
kev[0].flags |= (EV_ADD | EV_ENABLE); |
| 515 |
break; |
510 |
break; |
| 516 |
|
511 |
|
| 517 |
case LINUX_EPOLL_CTL_DEL: |
512 |
case LINUX_EPOLL_CTL_DEL: |
|
Lines 651-657
linux_epoll_pwait(struct thread *td, struct linux_epoll_pwait_args *args)
Link Here
|
| 651 |
} |
646 |
} |
| 652 |
|
647 |
|
| 653 |
static int |
648 |
static int |
| 654 |
epoll_delete_event(struct thread *td, struct file *epfp, int fd, int filter) |
649 |
epoll_register_kevent(struct thread *td, struct file *epfp, int fd, int filter, |
|
|
650 |
unsigned int flags) |
| 655 |
{ |
651 |
{ |
| 656 |
struct epoll_copyin_args ciargs; |
652 |
struct epoll_copyin_args ciargs; |
| 657 |
struct kevent kev; |
653 |
struct kevent kev; |
|
Lines 660-677
epoll_delete_event(struct thread *td, struct file *epfp, int fd, int filter)
Link Here
|
| 660 |
epoll_kev_copyin}; |
656 |
epoll_kev_copyin}; |
| 661 |
|
657 |
|
| 662 |
ciargs.changelist = &kev; |
658 |
ciargs.changelist = &kev; |
| 663 |
EV_SET(&kev, fd, filter, EV_DELETE | EV_DISABLE, 0, 0, 0); |
659 |
EV_SET(&kev, fd, filter, flags, 0, 0, 0); |
| 664 |
|
660 |
|
| 665 |
return (kern_kevent_fp(td, epfp, 1, 0, &k_ops, NULL)); |
661 |
return (kern_kevent_fp(td, epfp, 1, 0, &k_ops, NULL)); |
| 666 |
} |
662 |
} |
| 667 |
|
663 |
|
|
|
664 |
static int |
| 665 |
epoll_fd_registered(struct thread *td, struct file *epfp, int fd) |
| 666 |
{ |
| 667 |
/* |
| 668 |
* Set empty filter flags to avoid accidental modification of already |
| 669 |
* registered events. In the case of re-registration: |
| 670 |
* 1. If event does not exists kevent() does nothing and returns ENOENT |
| 671 |
* 2. If event does exists, it's enabled/disabled state is preserved |
| 672 |
* but fflags, data and udata fields are overwritten. |
| 673 |
* p.2 means that we can not store user's context pointer in udata. |
| 674 |
*/ |
| 675 |
if (epoll_register_kevent(td, epfp, fd, EVFILT_READ, 0) != ENOENT || |
| 676 |
epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, 0) != ENOENT) |
| 677 |
return (1); |
| 678 |
|
| 679 |
return (0); |
| 680 |
} |
| 681 |
|
| 668 |
static int |
682 |
static int |
| 669 |
epoll_delete_all_events(struct thread *td, struct file *epfp, int fd) |
683 |
epoll_delete_all_events(struct thread *td, struct file *epfp, int fd) |
| 670 |
{ |
684 |
{ |
| 671 |
int error1, error2; |
685 |
int error1, error2; |
| 672 |
|
686 |
|
| 673 |
error1 = epoll_delete_event(td, epfp, fd, EVFILT_READ); |
687 |
error1 = epoll_register_kevent(td, epfp, fd, EVFILT_READ, EV_DELETE); |
| 674 |
error2 = epoll_delete_event(td, epfp, fd, EVFILT_WRITE); |
688 |
error2 = epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, EV_DELETE); |
| 675 |
|
689 |
|
| 676 |
/* return 0 if at least one result positive */ |
690 |
/* return 0 if at least one result positive */ |
| 677 |
return (error1 == 0 ? 0 : error2); |
691 |
return (error1 == 0 ? 0 : error2); |