Changeset View
Standalone View
sys/compat/linux/linux_event.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2007 Roman Divacky | * Copyright (c) 2007 Roman Divacky | ||||
* Copyright (c) 2014 Dmitry Chagin | * Copyright (c) 2014 Dmitry Chagin | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
Show All 37 Lines | |||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <sys/event.h> | #include <sys/event.h> | ||||
#include <sys/poll.h> | #include <sys/poll.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/selinfo.h> | #include <sys/selinfo.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/syscallsubr.h> | #include <sys/syscallsubr.h> | ||||
#include <sys/timespec.h> | #include <sys/timespec.h> | ||||
#include <sys/eventfd.h> | |||||
#ifdef COMPAT_LINUX32 | #ifdef COMPAT_LINUX32 | ||||
#include <machine/../linux32/linux.h> | #include <machine/../linux32/linux.h> | ||||
#include <machine/../linux32/linux32_proto.h> | #include <machine/../linux32/linux32_proto.h> | ||||
#else | #else | ||||
#include <machine/../linux/linux.h> | #include <machine/../linux/linux.h> | ||||
#include <machine/../linux/linux_proto.h> | #include <machine/../linux/linux_proto.h> | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
struct epoll_copyout_args { | struct epoll_copyout_args { | ||||
struct epoll_event *leventlist; | struct epoll_event *leventlist; | ||||
struct proc *p; | struct proc *p; | ||||
uint32_t count; | uint32_t count; | ||||
int error; | int error; | ||||
}; | }; | ||||
/* eventfd */ | |||||
typedef uint64_t eventfd_t; | |||||
static fo_rdwr_t eventfd_read; | |||||
static fo_rdwr_t eventfd_write; | |||||
static fo_ioctl_t eventfd_ioctl; | |||||
static fo_poll_t eventfd_poll; | |||||
static fo_kqfilter_t eventfd_kqfilter; | |||||
static fo_stat_t eventfd_stat; | |||||
static fo_close_t eventfd_close; | |||||
static fo_fill_kinfo_t eventfd_fill_kinfo; | |||||
static struct fileops eventfdops = { | |||||
.fo_read = eventfd_read, | |||||
.fo_write = eventfd_write, | |||||
.fo_truncate = invfo_truncate, | |||||
.fo_ioctl = eventfd_ioctl, | |||||
.fo_poll = eventfd_poll, | |||||
.fo_kqfilter = eventfd_kqfilter, | |||||
.fo_stat = eventfd_stat, | |||||
.fo_close = eventfd_close, | |||||
.fo_chmod = invfo_chmod, | |||||
.fo_chown = invfo_chown, | |||||
.fo_sendfile = invfo_sendfile, | |||||
.fo_fill_kinfo = eventfd_fill_kinfo, | |||||
.fo_flags = DFLAG_PASSABLE | |||||
}; | |||||
static void filt_eventfddetach(struct knote *kn); | |||||
static int filt_eventfdread(struct knote *kn, long hint); | |||||
static int filt_eventfdwrite(struct knote *kn, long hint); | |||||
static struct filterops eventfd_rfiltops = { | |||||
.f_isfd = 1, | |||||
.f_detach = filt_eventfddetach, | |||||
.f_event = filt_eventfdread | |||||
}; | |||||
static struct filterops eventfd_wfiltops = { | |||||
.f_isfd = 1, | |||||
.f_detach = filt_eventfddetach, | |||||
.f_event = filt_eventfdwrite | |||||
}; | |||||
/* timerfd */ | /* timerfd */ | ||||
typedef uint64_t timerfd_t; | typedef uint64_t timerfd_t; | ||||
static fo_rdwr_t timerfd_read; | static fo_rdwr_t timerfd_read; | ||||
static fo_ioctl_t timerfd_ioctl; | |||||
static fo_poll_t timerfd_poll; | static fo_poll_t timerfd_poll; | ||||
static fo_kqfilter_t timerfd_kqfilter; | static fo_kqfilter_t timerfd_kqfilter; | ||||
static fo_stat_t timerfd_stat; | static fo_stat_t timerfd_stat; | ||||
static fo_close_t timerfd_close; | static fo_close_t timerfd_close; | ||||
static fo_fill_kinfo_t timerfd_fill_kinfo; | static fo_fill_kinfo_t timerfd_fill_kinfo; | ||||
static struct fileops timerfdops = { | static struct fileops timerfdops = { | ||||
.fo_read = timerfd_read, | .fo_read = timerfd_read, | ||||
.fo_write = invfo_rdwr, | .fo_write = invfo_rdwr, | ||||
.fo_truncate = invfo_truncate, | .fo_truncate = invfo_truncate, | ||||
.fo_ioctl = eventfd_ioctl, | .fo_ioctl = timerfd_ioctl, | ||||
.fo_poll = timerfd_poll, | .fo_poll = timerfd_poll, | ||||
.fo_kqfilter = timerfd_kqfilter, | .fo_kqfilter = timerfd_kqfilter, | ||||
.fo_stat = timerfd_stat, | .fo_stat = timerfd_stat, | ||||
.fo_close = timerfd_close, | .fo_close = timerfd_close, | ||||
.fo_chmod = invfo_chmod, | .fo_chmod = invfo_chmod, | ||||
.fo_chown = invfo_chown, | .fo_chown = invfo_chown, | ||||
.fo_sendfile = invfo_sendfile, | .fo_sendfile = invfo_sendfile, | ||||
.fo_fill_kinfo = timerfd_fill_kinfo, | .fo_fill_kinfo = timerfd_fill_kinfo, | ||||
.fo_flags = DFLAG_PASSABLE | .fo_flags = DFLAG_PASSABLE | ||||
}; | }; | ||||
static void filt_timerfddetach(struct knote *kn); | static void filt_timerfddetach(struct knote *kn); | ||||
static int filt_timerfdread(struct knote *kn, long hint); | static int filt_timerfdread(struct knote *kn, long hint); | ||||
static struct filterops timerfd_rfiltops = { | static struct filterops timerfd_rfiltops = { | ||||
.f_isfd = 1, | .f_isfd = 1, | ||||
.f_detach = filt_timerfddetach, | .f_detach = filt_timerfddetach, | ||||
.f_event = filt_timerfdread | .f_event = filt_timerfdread | ||||
}; | }; | ||||
struct eventfd { | |||||
eventfd_t efd_count; | |||||
uint32_t efd_flags; | |||||
struct selinfo efd_sel; | |||||
struct mtx efd_lock; | |||||
}; | |||||
struct timerfd { | struct timerfd { | ||||
clockid_t tfd_clockid; | clockid_t tfd_clockid; | ||||
struct itimerspec tfd_time; | struct itimerspec tfd_time; | ||||
struct callout tfd_callout; | struct callout tfd_callout; | ||||
timerfd_t tfd_count; | timerfd_t tfd_count; | ||||
bool tfd_canceled; | bool tfd_canceled; | ||||
struct selinfo tfd_sel; | struct selinfo tfd_sel; | ||||
struct mtx tfd_lock; | struct mtx tfd_lock; | ||||
}; | }; | ||||
static int eventfd_create(struct thread *td, uint32_t initval, int flags); | |||||
static void linux_timerfd_expire(void *); | static void linux_timerfd_expire(void *); | ||||
static void linux_timerfd_curval(struct timerfd *, struct itimerspec *); | static void linux_timerfd_curval(struct timerfd *, struct itimerspec *); | ||||
static void | static void | ||||
epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata) | epoll_fd_install(struct thread *td, int fd, epoll_udata_t udata) | ||||
{ | { | ||||
struct linux_pemuldata *pem; | struct linux_pemuldata *pem; | ||||
struct epoll_emuldata *emd; | struct epoll_emuldata *emd; | ||||
▲ Show 20 Lines • Show All 461 Lines • ▼ Show 20 Lines | epoll_delete_all_events(struct thread *td, struct file *epfp, int fd) | ||||
error1 = epoll_register_kevent(td, epfp, fd, EVFILT_READ, EV_DELETE); | error1 = epoll_register_kevent(td, epfp, fd, EVFILT_READ, EV_DELETE); | ||||
error2 = epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, EV_DELETE); | error2 = epoll_register_kevent(td, epfp, fd, EVFILT_WRITE, EV_DELETE); | ||||
/* return 0 if at least one result positive */ | /* return 0 if at least one result positive */ | ||||
return (error1 == 0 ? 0 : error2); | return (error1 == 0 ? 0 : error2); | ||||
} | } | ||||
static int | |||||
eventfd_create(struct thread *td, uint32_t initval, int flags) | |||||
{ | |||||
struct filedesc *fdp; | |||||
struct eventfd *efd; | |||||
struct file *fp; | |||||
int fflags, fd, error; | |||||
fflags = 0; | |||||
if ((flags & LINUX_O_CLOEXEC) != 0) | |||||
fflags |= O_CLOEXEC; | |||||
fdp = td->td_proc->p_fd; | |||||
error = falloc(td, &fp, &fd, fflags); | |||||
if (error != 0) | |||||
return (error); | |||||
efd = malloc(sizeof(*efd), M_EPOLL, M_WAITOK | M_ZERO); | |||||
efd->efd_flags = flags; | |||||
efd->efd_count = initval; | |||||
mtx_init(&efd->efd_lock, "eventfd", NULL, MTX_DEF); | |||||
knlist_init_mtx(&efd->efd_sel.si_note, &efd->efd_lock); | |||||
fflags = FREAD | FWRITE; | |||||
if ((flags & LINUX_O_NONBLOCK) != 0) | |||||
fflags |= FNONBLOCK; | |||||
finit(fp, fflags, DTYPE_LINUXEFD, efd, &eventfdops); | |||||
fdrop(fp, td); | |||||
td->td_retval[0] = fd; | |||||
return (error); | |||||
} | |||||
#ifdef LINUX_LEGACY_SYSCALLS | #ifdef LINUX_LEGACY_SYSCALLS | ||||
int | int | ||||
linux_eventfd(struct thread *td, struct linux_eventfd_args *args) | linux_eventfd(struct thread *td, struct linux_eventfd_args *args) | ||||
{ | { | ||||
return (eventfd_create(td, args->initval, 0)); | return (eventfd_create(td, args->initval, 0)); | ||||
} | } | ||||
#endif | #endif | ||||
int | int | ||||
linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args) | linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args) | ||||
{ | { | ||||
int flags = 0; | |||||
if ((args->flags & ~(LINUX_O_CLOEXEC|LINUX_O_NONBLOCK|LINUX_EFD_SEMAPHORE)) != 0) | if ((args->flags & ~(LINUX_O_CLOEXEC|LINUX_O_NONBLOCK|EFD_SEMAPHORE)) != 0) | ||||
kib: spaces should be put around both sides of binary op:
`LINUX_O_CLOEXEC | LINUX_O_NONBLOCK |… | |||||
val_packett.coolUnsubmitted Done Inline ActionsIt was like this.. maybe to keep the line under 80 characters :) but this file already has slightly longer lines so I guess that doesn't matter that much val_packett.cool: It was like this.. maybe to keep the line under 80 characters :) but this file already has… | |||||
return (EINVAL); | return (EINVAL); | ||||
return (eventfd_create(td, args->initval, args->flags)); | if ((args->flags & LINUX_O_CLOEXEC) != 0) | ||||
} | flags |= EFD_CLOEXEC; | ||||
if ((args->flags & LINUX_O_NONBLOCK) != 0) | |||||
flags |= EFD_NONBLOCK; | |||||
Done Inline ActionsIt seems better to translate to the aliases, i.e., flags |= EFD_CLOEXEC or EFD_NONBLOCK. markj: It seems better to translate to the aliases, i.e., `flags |= EFD_CLOEXEC` or `EFD_NONBLOCK`. | |||||
if ((args->flags & EFD_SEMAPHORE) != 0) | |||||
kibAuthorUnsubmitted Done Inline ActionsShould this be LINUX_EFD_SEMAPHORE ? kib: Should this be LINUX_EFD_SEMAPHORE ? | |||||
flags |= EFD_SEMAPHORE; | |||||
static int | return (eventfd_create(td, args->initval, flags)); | ||||
eventfd_close(struct file *fp, struct thread *td) | |||||
{ | |||||
struct eventfd *efd; | |||||
efd = fp->f_data; | |||||
if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) | |||||
return (EINVAL); | |||||
seldrain(&efd->efd_sel); | |||||
knlist_destroy(&efd->efd_sel.si_note); | |||||
fp->f_ops = &badfileops; | |||||
mtx_destroy(&efd->efd_lock); | |||||
free(efd, M_EPOLL); | |||||
return (0); | |||||
} | } | ||||
static int | |||||
eventfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred, | |||||
int flags, struct thread *td) | |||||
{ | |||||
struct eventfd *efd; | |||||
eventfd_t count; | |||||
int error; | |||||
efd = fp->f_data; | |||||
if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) | |||||
return (EINVAL); | |||||
if (uio->uio_resid < sizeof(eventfd_t)) | |||||
return (EINVAL); | |||||
error = 0; | |||||
mtx_lock(&efd->efd_lock); | |||||
retry: | |||||
if (efd->efd_count == 0) { | |||||
if ((fp->f_flag & FNONBLOCK) != 0) { | |||||
mtx_unlock(&efd->efd_lock); | |||||
return (EAGAIN); | |||||
} | |||||
error = mtx_sleep(&efd->efd_count, &efd->efd_lock, PCATCH, "lefdrd", 0); | |||||
if (error == 0) | |||||
goto retry; | |||||
} | |||||
if (error == 0) { | |||||
if ((efd->efd_flags & LINUX_EFD_SEMAPHORE) != 0) { | |||||
count = 1; | |||||
--efd->efd_count; | |||||
} else { | |||||
count = efd->efd_count; | |||||
efd->efd_count = 0; | |||||
} | |||||
KNOTE_LOCKED(&efd->efd_sel.si_note, 0); | |||||
selwakeup(&efd->efd_sel); | |||||
wakeup(&efd->efd_count); | |||||
mtx_unlock(&efd->efd_lock); | |||||
error = uiomove(&count, sizeof(eventfd_t), uio); | |||||
} else | |||||
mtx_unlock(&efd->efd_lock); | |||||
return (error); | |||||
} | |||||
static int | |||||
eventfd_write(struct file *fp, struct uio *uio, struct ucred *active_cred, | |||||
int flags, struct thread *td) | |||||
{ | |||||
struct eventfd *efd; | |||||
eventfd_t count; | |||||
int error; | |||||
efd = fp->f_data; | |||||
if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) | |||||
return (EINVAL); | |||||
if (uio->uio_resid < sizeof(eventfd_t)) | |||||
return (EINVAL); | |||||
error = uiomove(&count, sizeof(eventfd_t), uio); | |||||
if (error != 0) | |||||
return (error); | |||||
if (count == UINT64_MAX) | |||||
return (EINVAL); | |||||
mtx_lock(&efd->efd_lock); | |||||
retry: | |||||
if (UINT64_MAX - efd->efd_count <= count) { | |||||
if ((fp->f_flag & FNONBLOCK) != 0) { | |||||
mtx_unlock(&efd->efd_lock); | |||||
/* Do not not return the number of bytes written */ | |||||
uio->uio_resid += sizeof(eventfd_t); | |||||
return (EAGAIN); | |||||
} | |||||
error = mtx_sleep(&efd->efd_count, &efd->efd_lock, | |||||
PCATCH, "lefdwr", 0); | |||||
if (error == 0) | |||||
goto retry; | |||||
} | |||||
if (error == 0) { | |||||
efd->efd_count += count; | |||||
KNOTE_LOCKED(&efd->efd_sel.si_note, 0); | |||||
selwakeup(&efd->efd_sel); | |||||
wakeup(&efd->efd_count); | |||||
} | |||||
mtx_unlock(&efd->efd_lock); | |||||
return (error); | |||||
} | |||||
static int | |||||
eventfd_poll(struct file *fp, int events, struct ucred *active_cred, | |||||
struct thread *td) | |||||
{ | |||||
struct eventfd *efd; | |||||
int revents = 0; | |||||
efd = fp->f_data; | |||||
if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) | |||||
return (POLLERR); | |||||
mtx_lock(&efd->efd_lock); | |||||
if ((events & (POLLIN|POLLRDNORM)) && efd->efd_count > 0) | |||||
revents |= events & (POLLIN|POLLRDNORM); | |||||
if ((events & (POLLOUT|POLLWRNORM)) && UINT64_MAX - 1 > efd->efd_count) | |||||
revents |= events & (POLLOUT|POLLWRNORM); | |||||
if (revents == 0) | |||||
selrecord(td, &efd->efd_sel); | |||||
mtx_unlock(&efd->efd_lock); | |||||
return (revents); | |||||
} | |||||
/*ARGSUSED*/ | |||||
static int | |||||
eventfd_kqfilter(struct file *fp, struct knote *kn) | |||||
{ | |||||
struct eventfd *efd; | |||||
efd = fp->f_data; | |||||
if (fp->f_type != DTYPE_LINUXEFD || efd == NULL) | |||||
return (EINVAL); | |||||
mtx_lock(&efd->efd_lock); | |||||
switch (kn->kn_filter) { | |||||
case EVFILT_READ: | |||||
kn->kn_fop = &eventfd_rfiltops; | |||||
break; | |||||
case EVFILT_WRITE: | |||||
kn->kn_fop = &eventfd_wfiltops; | |||||
break; | |||||
default: | |||||
mtx_unlock(&efd->efd_lock); | |||||
return (EINVAL); | |||||
} | |||||
kn->kn_hook = efd; | |||||
knlist_add(&efd->efd_sel.si_note, kn, 1); | |||||
mtx_unlock(&efd->efd_lock); | |||||
return (0); | |||||
} | |||||
static void | |||||
filt_eventfddetach(struct knote *kn) | |||||
{ | |||||
struct eventfd *efd = kn->kn_hook; | |||||
mtx_lock(&efd->efd_lock); | |||||
knlist_remove(&efd->efd_sel.si_note, kn, 1); | |||||
mtx_unlock(&efd->efd_lock); | |||||
} | |||||
/*ARGSUSED*/ | |||||
static int | |||||
filt_eventfdread(struct knote *kn, long hint) | |||||
{ | |||||
struct eventfd *efd = kn->kn_hook; | |||||
int ret; | |||||
mtx_assert(&efd->efd_lock, MA_OWNED); | |||||
ret = (efd->efd_count > 0); | |||||
return (ret); | |||||
} | |||||
/*ARGSUSED*/ | |||||
static int | |||||
filt_eventfdwrite(struct knote *kn, long hint) | |||||
{ | |||||
struct eventfd *efd = kn->kn_hook; | |||||
int ret; | |||||
mtx_assert(&efd->efd_lock, MA_OWNED); | |||||
ret = (UINT64_MAX - 1 > efd->efd_count); | |||||
return (ret); | |||||
} | |||||
/*ARGSUSED*/ | |||||
static int | |||||
eventfd_ioctl(struct file *fp, u_long cmd, void *data, | |||||
struct ucred *active_cred, struct thread *td) | |||||
{ | |||||
if (fp->f_data == NULL || (fp->f_type != DTYPE_LINUXEFD && | |||||
fp->f_type != DTYPE_LINUXTFD)) | |||||
return (EINVAL); | |||||
switch (cmd) | |||||
{ | |||||
case FIONBIO: | |||||
if ((*(int *)data)) | |||||
atomic_set_int(&fp->f_flag, FNONBLOCK); | |||||
else | |||||
atomic_clear_int(&fp->f_flag, FNONBLOCK); | |||||
case FIOASYNC: | |||||
return (0); | |||||
default: | |||||
return (ENXIO); | |||||
} | |||||
} | |||||
/*ARGSUSED*/ | |||||
static int | |||||
eventfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred, | |||||
struct thread *td) | |||||
{ | |||||
return (ENXIO); | |||||
} | |||||
/*ARGSUSED*/ | |||||
static int | |||||
eventfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) | |||||
{ | |||||
kif->kf_type = KF_TYPE_UNKNOWN; | |||||
return (0); | |||||
} | |||||
int | int | ||||
linux_timerfd_create(struct thread *td, struct linux_timerfd_create_args *args) | linux_timerfd_create(struct thread *td, struct linux_timerfd_create_args *args) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct timerfd *tfd; | struct timerfd *tfd; | ||||
struct file *fp; | struct file *fp; | ||||
clockid_t clockid; | clockid_t clockid; | ||||
int fflags, fd, error; | int fflags, fd, error; | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | if ((events & (POLLIN|POLLRDNORM)) && tfd->tfd_count > 0) | ||||
revents |= events & (POLLIN|POLLRDNORM); | revents |= events & (POLLIN|POLLRDNORM); | ||||
if (revents == 0) | if (revents == 0) | ||||
selrecord(td, &tfd->tfd_sel); | selrecord(td, &tfd->tfd_sel); | ||||
mtx_unlock(&tfd->tfd_lock); | mtx_unlock(&tfd->tfd_lock); | ||||
return (revents); | return (revents); | ||||
} | } | ||||
/*ARGSUSED*/ | |||||
static int | static int | ||||
timerfd_kqfilter(struct file *fp, struct knote *kn) | timerfd_kqfilter(struct file *fp, struct knote *kn) | ||||
{ | { | ||||
struct timerfd *tfd; | struct timerfd *tfd; | ||||
tfd = fp->f_data; | tfd = fp->f_data; | ||||
if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL) | if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
Show All 14 Lines | |||||
{ | { | ||||
struct timerfd *tfd = kn->kn_hook; | struct timerfd *tfd = kn->kn_hook; | ||||
mtx_lock(&tfd->tfd_lock); | mtx_lock(&tfd->tfd_lock); | ||||
knlist_remove(&tfd->tfd_sel.si_note, kn, 1); | knlist_remove(&tfd->tfd_sel.si_note, kn, 1); | ||||
mtx_unlock(&tfd->tfd_lock); | mtx_unlock(&tfd->tfd_lock); | ||||
} | } | ||||
/*ARGSUSED*/ | |||||
static int | static int | ||||
filt_timerfdread(struct knote *kn, long hint) | filt_timerfdread(struct knote *kn, long hint) | ||||
{ | { | ||||
struct timerfd *tfd = kn->kn_hook; | struct timerfd *tfd = kn->kn_hook; | ||||
return (tfd->tfd_count > 0); | return (tfd->tfd_count > 0); | ||||
} | } | ||||
/*ARGSUSED*/ | |||||
static int | static int | ||||
Done Inline ActionsDo not add dead annotations. kib: Do not add dead annotations. | |||||
Done Inline ActionsThis (and most other things) are just moved from linux_event.c, I didn't think changing them was appropriate.. okay, will do val_packett.cool: This (and most other things) are just moved from linux_event.c, I didn't think changing them… | |||||
timerfd_ioctl(struct file *fp, u_long cmd, void *data, | |||||
struct ucred *active_cred, struct thread *td) | |||||
{ | |||||
if (fp->f_data == NULL || fp->f_type != DTYPE_LINUXTFD) | |||||
return (EINVAL); | |||||
switch (cmd) { | |||||
case FIONBIO: | |||||
case FIOASYNC: | |||||
return (0); | |||||
Done Inline ActionsThis is already handled by kern_ioctl(). kib: This is already handled by kern_ioctl(). | |||||
Done Inline ActionsI guess the intention of the original code was to make FIOASYNC do nothing, but it seems fine to leave kern_ioctl to set it in f_flag, we just don't do anything with that bit anywhere. val_packett.cool: I guess the intention of the original code was to make `FIOASYNC` do nothing, but it seems fine… | |||||
Done Inline Actions(disregard that comment, I thought .fo_ioctl overrides kern_ioctl but no, it's called from there) val_packett.cool: (disregard that comment, I thought `.fo_ioctl` overrides `kern_ioctl` but no, it's called from… | |||||
} | |||||
return (ENOTTY); | |||||
} | |||||
static int | |||||
timerfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred, | timerfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred, | ||||
struct thread *td) | struct thread *td) | ||||
{ | { | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/*ARGSUSED*/ | |||||
static int | static int | ||||
timerfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) | timerfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) | ||||
{ | { | ||||
kif->kf_type = KF_TYPE_UNKNOWN; | kif->kf_type = KF_TYPE_UNKNOWN; | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 161 Lines • Show Last 20 Lines |
spaces should be put around both sides of binary op:
LINUX_O_CLOEXEC | LINUX_O_NONBLOCK | EFD_SEMAPHORE