Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_event.c
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/socketvar.h> | #include <sys/socketvar.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/sysproto.h> | #include <sys/sysproto.h> | ||||
#include <sys/syscallsubr.h> | #include <sys/syscallsubr.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <sys/umtx.h> | |||||
#include <sys/user.h> | #include <sys/user.h> | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
#include <sys/ktrace.h> | #include <sys/ktrace.h> | ||||
#endif | #endif | ||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | static struct filterops timer_filtops = { | ||||
.f_touch = filt_timertouch, | .f_touch = filt_timertouch, | ||||
}; | }; | ||||
static struct filterops user_filtops = { | static struct filterops user_filtops = { | ||||
.f_attach = filt_userattach, | .f_attach = filt_userattach, | ||||
.f_detach = filt_userdetach, | .f_detach = filt_userdetach, | ||||
.f_event = filt_user, | .f_event = filt_user, | ||||
.f_touch = filt_usertouch, | .f_touch = filt_usertouch, | ||||
}; | }; | ||||
static struct filterops usermem_filtops = { | |||||
.f_attach = filt_usermemattach, | |||||
.f_detach = filt_usermemdetach, | |||||
.f_event = filt_usermem, | |||||
.f_touch = filt_usermemtouch, | |||||
.f_anon = filt_usermemanon, | |||||
}; | |||||
static uma_zone_t knote_zone; | static uma_zone_t knote_zone; | ||||
static unsigned int __exclusive_cache_line kq_ncallouts; | static unsigned int __exclusive_cache_line kq_ncallouts; | ||||
static unsigned int kq_calloutmax = 4 * 1024; | static unsigned int kq_calloutmax = 4 * 1024; | ||||
SYSCTL_UINT(_kern, OID_AUTO, kq_calloutmax, CTLFLAG_RW, | SYSCTL_UINT(_kern, OID_AUTO, kq_calloutmax, CTLFLAG_RW, | ||||
&kq_calloutmax, 0, "Maximum number of callouts allocated for kqueue"); | &kq_calloutmax, 0, "Maximum number of callouts allocated for kqueue"); | ||||
/* XXX - ensure not influx ? */ | /* XXX - ensure not influx ? */ | ||||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | static struct { | ||||
{ &sig_filtops, 1 }, /* EVFILT_SIGNAL */ | { &sig_filtops, 1 }, /* EVFILT_SIGNAL */ | ||||
{ &timer_filtops, 1 }, /* EVFILT_TIMER */ | { &timer_filtops, 1 }, /* EVFILT_TIMER */ | ||||
{ &file_filtops, 1 }, /* EVFILT_PROCDESC */ | { &file_filtops, 1 }, /* EVFILT_PROCDESC */ | ||||
{ &fs_filtops, 1 }, /* EVFILT_FS */ | { &fs_filtops, 1 }, /* EVFILT_FS */ | ||||
{ &null_filtops }, /* EVFILT_LIO */ | { &null_filtops }, /* EVFILT_LIO */ | ||||
{ &user_filtops, 1 }, /* EVFILT_USER */ | { &user_filtops, 1 }, /* EVFILT_USER */ | ||||
{ &null_filtops }, /* EVFILT_SENDFILE */ | { &null_filtops }, /* EVFILT_SENDFILE */ | ||||
{ &file_filtops, 1 }, /* EVFILT_EMPTY */ | { &file_filtops, 1 }, /* EVFILT_EMPTY */ | ||||
{ &usermem_filtops, 1 }, /* EVFILT_USERMEM */ | |||||
}; | }; | ||||
/* | /* | ||||
* Simple redirection for all cdevsw style objects to call their fo_kqfilter | * Simple redirection for all cdevsw style objects to call their fo_kqfilter | ||||
* method. | * method. | ||||
*/ | */ | ||||
static int | static int | ||||
filt_fileattach(struct knote *kn) | filt_fileattach(struct knote *kn) | ||||
▲ Show 20 Lines • Show All 916 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
kern_kevent(struct thread *td, int fd, int nchanges, int nevents, | kern_kevent(struct thread *td, int fd, int nchanges, int nevents, | ||||
struct kevent_copyops *k_ops, const struct timespec *timeout) | struct kevent_copyops *k_ops, const struct timespec *timeout) | ||||
{ | { | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
struct file *fp; | struct file *fp; | ||||
int error; | int error; | ||||
if (fd == KQUEUE_FD_ANON) { | |||||
error = kern_kevent_anonymous(td, nchanges, nevents, k_ops, timeout); | |||||
return (error); | |||||
} | |||||
cap_rights_init_zero(&rights); | cap_rights_init_zero(&rights); | ||||
if (nchanges > 0) | if (nchanges > 0) | ||||
cap_rights_set_one(&rights, CAP_KQUEUE_CHANGE); | cap_rights_set_one(&rights, CAP_KQUEUE_CHANGE); | ||||
if (nevents > 0) | if (nevents > 0) | ||||
cap_rights_set_one(&rights, CAP_KQUEUE_EVENT); | cap_rights_set_one(&rights, CAP_KQUEUE_EVENT); | ||||
error = fget(td, fd, &rights, &fp); | error = fget(td, fd, &rights, &fp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | kern_kevent_fp(struct thread *td, struct file *fp, int nchanges, int nevents, | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Performs a kevent() call on a temporarily created kqueue. This can be | * Performs a kevent() call on a temporarily created kqueue. This can be | ||||
* used to perform one-shot polling, similar to poll() and select(). | * used to perform one-shot polling, similar to poll() and select(). | ||||
*/ | */ | ||||
int | int | ||||
kern_kevent_anonymous(struct thread *td, int nevents, | kern_kevent_anonymous(struct thread *td, int nchanges, int nevents, | ||||
struct kevent_copyops *k_ops) | struct kevent_copyops *k_ops, const struct timespec *timeout) | ||||
{ | { | ||||
struct kqueue kq = {}; | struct kqueue kq = {}; | ||||
int error; | int error; | ||||
kqueue_init(&kq); | kqueue_init(&kq); | ||||
kq.kq_refcnt = 1; | kq.kq_refcnt = 1; | ||||
error = kqueue_kevent(&kq, td, nevents, nevents, k_ops, NULL); | error = kqueue_kevent(&kq, td, nchanges, nevents, k_ops, timeout); | ||||
kqueue_drain(&kq, td); | kqueue_drain(&kq, td); | ||||
kqueue_destroy(&kq); | kqueue_destroy(&kq); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
kqueue_add_filteropts(int filt, struct filterops *filtops) | kqueue_add_filteropts(int filt, struct filterops *filtops) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, | ||||
error = 0; | error = 0; | ||||
haskqglobal = 0; | haskqglobal = 0; | ||||
filedesc_unlock = 0; | filedesc_unlock = 0; | ||||
filt = kev->filter; | filt = kev->filter; | ||||
fops = kqueue_fo_find(filt); | fops = kqueue_fo_find(filt); | ||||
if (fops == NULL) | if (fops == NULL) | ||||
return EINVAL; | return EINVAL; | ||||
/* Anonymous actions have no kqueue or knote */ | |||||
if (kev->flags & EV_ANON) { | |||||
tkn = NULL; | |||||
if (fops->f_anon == NULL) { | |||||
error = EINVAL; | |||||
goto done; | |||||
} | |||||
error = fops->f_anon(kev); | |||||
goto done; | |||||
} | |||||
if (kev->flags & EV_ADD) { | if (kev->flags & EV_ADD) { | ||||
/* Reject an invalid flag pair early */ | /* Reject an invalid flag pair early */ | ||||
if (kev->flags & EV_KEEPUDATA) { | if (kev->flags & EV_KEEPUDATA) { | ||||
tkn = NULL; | tkn = NULL; | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done; | goto done; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,311 Lines • Show Last 20 Lines |