kern_event.c revision 101983
159290Sjlemon/*- 272969Sjlemon * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org> 359290Sjlemon * All rights reserved. 459290Sjlemon * 559290Sjlemon * Redistribution and use in source and binary forms, with or without 659290Sjlemon * modification, are permitted provided that the following conditions 759290Sjlemon * are met: 859290Sjlemon * 1. Redistributions of source code must retain the above copyright 959290Sjlemon * notice, this list of conditions and the following disclaimer. 1059290Sjlemon * 2. Redistributions in binary form must reproduce the above copyright 1159290Sjlemon * notice, this list of conditions and the following disclaimer in the 1259290Sjlemon * documentation and/or other materials provided with the distribution. 1359290Sjlemon * 1459290Sjlemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559290Sjlemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659290Sjlemon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759290Sjlemon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859290Sjlemon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959290Sjlemon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059290Sjlemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159290Sjlemon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259290Sjlemon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359290Sjlemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459290Sjlemon * SUCH DAMAGE. 2559290Sjlemon * 2663452Sjlemon * $FreeBSD: head/sys/kern/kern_event.c 101983 2002-08-16 12:52:03Z rwatson $ 2759290Sjlemon */ 2859290Sjlemon 2959290Sjlemon#include <sys/param.h> 3059290Sjlemon#include <sys/systm.h> 3159290Sjlemon#include <sys/kernel.h> 3276166Smarkm#include <sys/lock.h> 3376166Smarkm#include <sys/mutex.h> 3459290Sjlemon#include <sys/proc.h> 3559290Sjlemon#include <sys/malloc.h> 3659290Sjlemon#include <sys/unistd.h> 3759290Sjlemon#include <sys/file.h> 3859290Sjlemon#include <sys/fcntl.h> 3970834Swollman#include <sys/selinfo.h> 4059290Sjlemon#include <sys/queue.h> 4159290Sjlemon#include <sys/event.h> 4259290Sjlemon#include <sys/eventvar.h> 4359290Sjlemon#include <sys/poll.h> 4459290Sjlemon#include <sys/protosw.h> 4559290Sjlemon#include <sys/socket.h> 4659290Sjlemon#include <sys/socketvar.h> 4759290Sjlemon#include <sys/stat.h> 4884138Sjlemon#include <sys/sysctl.h> 4959290Sjlemon#include <sys/sysproto.h> 5059290Sjlemon#include <sys/uio.h> 5159290Sjlemon 5292751Sjeff#include <vm/uma.h> 5359290Sjlemon 5484138SjlemonMALLOC_DEFINE(M_KQUEUE, "kqueue", "memory for kqueue system"); 5584138Sjlemon 5659290Sjlemonstatic int kqueue_scan(struct file *fp, int maxevents, 5763977Speter struct kevent *ulistp, const struct timespec *timeout, 5883366Sjulian struct thread *td); 5959290Sjlemonstatic int kqueue_read(struct file *fp, struct uio *uio, 60101941Srwatson struct ucred *active_cred, int flags, struct thread *td); 6159290Sjlemonstatic int kqueue_write(struct file *fp, struct uio *uio, 62101941Srwatson struct ucred *active_cred, int flags, struct thread *td); 6399009Salfredstatic int kqueue_ioctl(struct file *fp, u_long com, void *data, 6483366Sjulian struct thread *td); 65101983Srwatsonstatic int kqueue_poll(struct file *fp, int events, 66101983Srwatson struct ucred *active_cred, struct thread *td); 6772521Sjlemonstatic int kqueue_kqfilter(struct file *fp, struct knote *kn); 68101983Srwatsonstatic int kqueue_stat(struct file *fp, struct stat *st, 69101983Srwatson struct ucred *active_cred, struct thread *td); 7083366Sjulianstatic int kqueue_close(struct file *fp, struct thread *td); 7159290Sjlemonstatic void kqueue_wakeup(struct kqueue *kq); 7259290Sjlemon 7372521Sjlemonstatic struct fileops kqueueops = { 7472521Sjlemon kqueue_read, 7572521Sjlemon kqueue_write, 7672521Sjlemon kqueue_ioctl, 7772521Sjlemon kqueue_poll, 7872521Sjlemon kqueue_kqfilter, 7972521Sjlemon kqueue_stat, 8072521Sjlemon kqueue_close 8172521Sjlemon}; 8272521Sjlemon 8359290Sjlemonstatic void knote_attach(struct knote *kn, struct filedesc *fdp); 8483366Sjulianstatic void knote_drop(struct knote *kn, struct thread *td); 8559290Sjlemonstatic void knote_enqueue(struct knote *kn); 8659290Sjlemonstatic void knote_dequeue(struct knote *kn); 8759290Sjlemonstatic void knote_init(void); 8859290Sjlemonstatic struct knote *knote_alloc(void); 8959290Sjlemonstatic void knote_free(struct knote *kn); 9059290Sjlemon 9172521Sjlemonstatic void filt_kqdetach(struct knote *kn); 9272521Sjlemonstatic int filt_kqueue(struct knote *kn, long hint); 9372521Sjlemonstatic int filt_procattach(struct knote *kn); 9472521Sjlemonstatic void filt_procdetach(struct knote *kn); 9572521Sjlemonstatic int filt_proc(struct knote *kn, long hint); 9672521Sjlemonstatic int filt_fileattach(struct knote *kn); 9779989Sjlemonstatic void filt_timerexpire(void *knx); 9879989Sjlemonstatic int filt_timerattach(struct knote *kn); 9979989Sjlemonstatic void filt_timerdetach(struct knote *kn); 10079989Sjlemonstatic int filt_timer(struct knote *kn, long hint); 10172521Sjlemon 10279989Sjlemonstatic struct filterops file_filtops = 10379989Sjlemon { 1, filt_fileattach, NULL, NULL }; 10472521Sjlemonstatic struct filterops kqread_filtops = 10572521Sjlemon { 1, NULL, filt_kqdetach, filt_kqueue }; 10672521Sjlemonstatic struct filterops proc_filtops = 10772521Sjlemon { 0, filt_procattach, filt_procdetach, filt_proc }; 10879989Sjlemonstatic struct filterops timer_filtops = 10979989Sjlemon { 0, filt_timerattach, filt_timerdetach, filt_timer }; 11072521Sjlemon 11192751Sjeffstatic uma_zone_t knote_zone; 11284138Sjlemonstatic int kq_ncallouts = 0; 11384138Sjlemonstatic int kq_calloutmax = (4 * 1024); 11484138SjlemonSYSCTL_INT(_kern, OID_AUTO, kq_calloutmax, CTLFLAG_RW, 11584138Sjlemon &kq_calloutmax, 0, "Maximum number of callouts allocated for kqueue"); 11659290Sjlemon 11759290Sjlemon#define KNOTE_ACTIVATE(kn) do { \ 11859290Sjlemon kn->kn_status |= KN_ACTIVE; \ 11959290Sjlemon if ((kn->kn_status & (KN_QUEUED | KN_DISABLED)) == 0) \ 12059290Sjlemon knote_enqueue(kn); \ 12159290Sjlemon} while(0) 12259290Sjlemon 12359290Sjlemon#define KN_HASHSIZE 64 /* XXX should be tunable */ 12459290Sjlemon#define KN_HASH(val, mask) (((val) ^ (val >> 8)) & (mask)) 12559290Sjlemon 12688633Salfredstatic int 12788633Salfredfilt_nullattach(struct knote *kn) 12888633Salfred{ 12988633Salfred 13088633Salfred return (ENXIO); 13188633Salfred}; 13288633Salfred 13388633Salfredstruct filterops null_filtops = 13488633Salfred { 0, filt_nullattach, NULL, NULL }; 13588633Salfred 13659290Sjlemonextern struct filterops sig_filtops; 13759290Sjlemon 13859290Sjlemon/* 13972521Sjlemon * Table for for all system-defined filters. 14059290Sjlemon */ 14159290Sjlemonstatic struct filterops *sysfilt_ops[] = { 14272521Sjlemon &file_filtops, /* EVFILT_READ */ 14372521Sjlemon &file_filtops, /* EVFILT_WRITE */ 14488633Salfred &null_filtops, /* EVFILT_AIO */ 14572521Sjlemon &file_filtops, /* EVFILT_VNODE */ 14659290Sjlemon &proc_filtops, /* EVFILT_PROC */ 14759290Sjlemon &sig_filtops, /* EVFILT_SIGNAL */ 14879989Sjlemon &timer_filtops, /* EVFILT_TIMER */ 14989749Sjlemon &file_filtops, /* EVFILT_NETDEV */ 15059290Sjlemon}; 15159290Sjlemon 15259290Sjlemonstatic int 15372521Sjlemonfilt_fileattach(struct knote *kn) 15459290Sjlemon{ 15572521Sjlemon 15672521Sjlemon return (fo_kqfilter(kn->kn_fp, kn)); 15759290Sjlemon} 15859290Sjlemon 15972521Sjlemon/*ARGSUSED*/ 16059290Sjlemonstatic int 16172521Sjlemonkqueue_kqfilter(struct file *fp, struct knote *kn) 16259290Sjlemon{ 16372521Sjlemon struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data; 16459290Sjlemon 16572521Sjlemon if (kn->kn_filter != EVFILT_READ) 16672521Sjlemon return (1); 16759290Sjlemon 16872521Sjlemon kn->kn_fop = &kqread_filtops; 16959290Sjlemon SLIST_INSERT_HEAD(&kq->kq_sel.si_note, kn, kn_selnext); 17059290Sjlemon return (0); 17159290Sjlemon} 17259290Sjlemon 17359290Sjlemonstatic void 17459290Sjlemonfilt_kqdetach(struct knote *kn) 17559290Sjlemon{ 17659290Sjlemon struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data; 17759290Sjlemon 17860938Sjake SLIST_REMOVE(&kq->kq_sel.si_note, kn, knote, kn_selnext); 17959290Sjlemon} 18059290Sjlemon 18159290Sjlemon/*ARGSUSED*/ 18259290Sjlemonstatic int 18359290Sjlemonfilt_kqueue(struct knote *kn, long hint) 18459290Sjlemon{ 18559290Sjlemon struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data; 18659290Sjlemon 18759290Sjlemon kn->kn_data = kq->kq_count; 18859290Sjlemon return (kn->kn_data > 0); 18959290Sjlemon} 19059290Sjlemon 19159290Sjlemonstatic int 19259290Sjlemonfilt_procattach(struct knote *kn) 19359290Sjlemon{ 19459290Sjlemon struct proc *p; 19575451Srwatson int error; 19659290Sjlemon 19759290Sjlemon p = pfind(kn->kn_id); 19859290Sjlemon if (p == NULL) 19959290Sjlemon return (ESRCH); 20096886Sjhb if ((error = p_cansee(curthread, p))) { 20175893Sjhb PROC_UNLOCK(p); 20275451Srwatson return (error); 20375893Sjhb } 20459290Sjlemon 20559290Sjlemon kn->kn_ptr.p_proc = p; 20659290Sjlemon kn->kn_flags |= EV_CLEAR; /* automatically set */ 20759290Sjlemon 20859290Sjlemon /* 20959290Sjlemon * internal flag indicating registration done by kernel 21059290Sjlemon */ 21159290Sjlemon if (kn->kn_flags & EV_FLAG1) { 21259290Sjlemon kn->kn_data = kn->kn_sdata; /* ppid */ 21359290Sjlemon kn->kn_fflags = NOTE_CHILD; 21459290Sjlemon kn->kn_flags &= ~EV_FLAG1; 21559290Sjlemon } 21659290Sjlemon 21759290Sjlemon SLIST_INSERT_HEAD(&p->p_klist, kn, kn_selnext); 21871500Sjhb PROC_UNLOCK(p); 21959290Sjlemon 22059290Sjlemon return (0); 22159290Sjlemon} 22259290Sjlemon 22359290Sjlemon/* 22459290Sjlemon * The knote may be attached to a different process, which may exit, 22559290Sjlemon * leaving nothing for the knote to be attached to. So when the process 22659290Sjlemon * exits, the knote is marked as DETACHED and also flagged as ONESHOT so 22759290Sjlemon * it will be deleted when read out. However, as part of the knote deletion, 22859290Sjlemon * this routine is called, so a check is needed to avoid actually performing 22959290Sjlemon * a detach, because the original process does not exist any more. 23059290Sjlemon */ 23159290Sjlemonstatic void 23259290Sjlemonfilt_procdetach(struct knote *kn) 23359290Sjlemon{ 23459290Sjlemon struct proc *p = kn->kn_ptr.p_proc; 23559290Sjlemon 23659290Sjlemon if (kn->kn_status & KN_DETACHED) 23759290Sjlemon return; 23859290Sjlemon 23971500Sjhb PROC_LOCK(p); 24060938Sjake SLIST_REMOVE(&p->p_klist, kn, knote, kn_selnext); 24171500Sjhb PROC_UNLOCK(p); 24259290Sjlemon} 24359290Sjlemon 24459290Sjlemonstatic int 24559290Sjlemonfilt_proc(struct knote *kn, long hint) 24659290Sjlemon{ 24759290Sjlemon u_int event; 24859290Sjlemon 24959290Sjlemon /* 25059290Sjlemon * mask off extra data 25159290Sjlemon */ 25259290Sjlemon event = (u_int)hint & NOTE_PCTRLMASK; 25359290Sjlemon 25459290Sjlemon /* 25559290Sjlemon * if the user is interested in this event, record it. 25659290Sjlemon */ 25759290Sjlemon if (kn->kn_sfflags & event) 25859290Sjlemon kn->kn_fflags |= event; 25959290Sjlemon 26059290Sjlemon /* 26159290Sjlemon * process is gone, so flag the event as finished. 26259290Sjlemon */ 26359290Sjlemon if (event == NOTE_EXIT) { 26459290Sjlemon kn->kn_status |= KN_DETACHED; 26559290Sjlemon kn->kn_flags |= (EV_EOF | EV_ONESHOT); 26659290Sjlemon return (1); 26759290Sjlemon } 26859290Sjlemon 26959290Sjlemon /* 27059290Sjlemon * process forked, and user wants to track the new process, 27159290Sjlemon * so attach a new knote to it, and immediately report an 27259290Sjlemon * event with the parent's pid. 27359290Sjlemon */ 27459290Sjlemon if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) { 27559290Sjlemon struct kevent kev; 27659290Sjlemon int error; 27759290Sjlemon 27859290Sjlemon /* 27959290Sjlemon * register knote with new process. 28059290Sjlemon */ 28159290Sjlemon kev.ident = hint & NOTE_PDATAMASK; /* pid */ 28259290Sjlemon kev.filter = kn->kn_filter; 28359290Sjlemon kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1; 28459290Sjlemon kev.fflags = kn->kn_sfflags; 28559290Sjlemon kev.data = kn->kn_id; /* parent */ 28661962Sjlemon kev.udata = kn->kn_kevent.udata; /* preserve udata */ 28759290Sjlemon error = kqueue_register(kn->kn_kq, &kev, NULL); 28859290Sjlemon if (error) 28959290Sjlemon kn->kn_fflags |= NOTE_TRACKERR; 29059290Sjlemon } 29159290Sjlemon 29259290Sjlemon return (kn->kn_fflags != 0); 29359290Sjlemon} 29459290Sjlemon 29579989Sjlemonstatic void 29679989Sjlemonfilt_timerexpire(void *knx) 29779989Sjlemon{ 29879989Sjlemon struct knote *kn = knx; 29984138Sjlemon struct callout *calloutp; 30079989Sjlemon struct timeval tv; 30179989Sjlemon int tticks; 30279989Sjlemon 30379989Sjlemon kn->kn_data++; 30479989Sjlemon KNOTE_ACTIVATE(kn); 30579989Sjlemon 30679989Sjlemon if ((kn->kn_flags & EV_ONESHOT) == 0) { 30779989Sjlemon tv.tv_sec = kn->kn_sdata / 1000; 30879989Sjlemon tv.tv_usec = (kn->kn_sdata % 1000) * 1000; 30979989Sjlemon tticks = tvtohz(&tv); 31084138Sjlemon calloutp = (struct callout *)kn->kn_hook; 31184138Sjlemon callout_reset(calloutp, tticks, filt_timerexpire, kn); 31279989Sjlemon } 31379989Sjlemon} 31479989Sjlemon 31579989Sjlemon/* 31679989Sjlemon * data contains amount of time to sleep, in milliseconds 31779989Sjlemon */ 31879989Sjlemonstatic int 31979989Sjlemonfilt_timerattach(struct knote *kn) 32079989Sjlemon{ 32184138Sjlemon struct callout *calloutp; 32279989Sjlemon struct timeval tv; 32379989Sjlemon int tticks; 32479989Sjlemon 32584138Sjlemon if (kq_ncallouts >= kq_calloutmax) 32684138Sjlemon return (ENOMEM); 32784138Sjlemon kq_ncallouts++; 32884138Sjlemon 32979989Sjlemon tv.tv_sec = kn->kn_sdata / 1000; 33079989Sjlemon tv.tv_usec = (kn->kn_sdata % 1000) * 1000; 33179989Sjlemon tticks = tvtohz(&tv); 33279989Sjlemon 33379989Sjlemon kn->kn_flags |= EV_CLEAR; /* automatically set */ 33484138Sjlemon MALLOC(calloutp, struct callout *, sizeof(*calloutp), 33584138Sjlemon M_KQUEUE, M_WAITOK); 33684138Sjlemon callout_init(calloutp, 0); 33784138Sjlemon callout_reset(calloutp, tticks, filt_timerexpire, kn); 33898998Salfred kn->kn_hook = calloutp; 33979989Sjlemon 34079989Sjlemon return (0); 34179989Sjlemon} 34279989Sjlemon 34379989Sjlemonstatic void 34479989Sjlemonfilt_timerdetach(struct knote *kn) 34579989Sjlemon{ 34684138Sjlemon struct callout *calloutp; 34779989Sjlemon 34884138Sjlemon calloutp = (struct callout *)kn->kn_hook; 34984138Sjlemon callout_stop(calloutp); 35084138Sjlemon FREE(calloutp, M_KQUEUE); 35184138Sjlemon kq_ncallouts--; 35279989Sjlemon} 35379989Sjlemon 35479989Sjlemonstatic int 35579989Sjlemonfilt_timer(struct knote *kn, long hint) 35679989Sjlemon{ 35779989Sjlemon 35879989Sjlemon return (kn->kn_data != 0); 35979989Sjlemon} 36079989Sjlemon 36182710Sdillon/* 36282710Sdillon * MPSAFE 36382710Sdillon */ 36461468Sjlemonint 36583366Sjuliankqueue(struct thread *td, struct kqueue_args *uap) 36659290Sjlemon{ 36782710Sdillon struct filedesc *fdp; 36859290Sjlemon struct kqueue *kq; 36961468Sjlemon struct file *fp; 37061468Sjlemon int fd, error; 37159290Sjlemon 37282710Sdillon mtx_lock(&Giant); 37383366Sjulian fdp = td->td_proc->p_fd; 37483366Sjulian error = falloc(td, &fp, &fd); 37561468Sjlemon if (error) 37682710Sdillon goto done2; 37789306Salfred kq = malloc(sizeof(struct kqueue), M_KQUEUE, M_WAITOK | M_ZERO); 37889306Salfred TAILQ_INIT(&kq->kq_head); 37989306Salfred FILE_LOCK(fp); 38061468Sjlemon fp->f_flag = FREAD | FWRITE; 38161468Sjlemon fp->f_type = DTYPE_KQUEUE; 38261468Sjlemon fp->f_ops = &kqueueops; 38359290Sjlemon TAILQ_INIT(&kq->kq_head); 38498998Salfred fp->f_data = kq; 38589306Salfred FILE_UNLOCK(fp); 38689306Salfred FILEDESC_LOCK(fdp); 38783366Sjulian td->td_retval[0] = fd; 38863470Sjlemon if (fdp->fd_knlistsize < 0) 38963470Sjlemon fdp->fd_knlistsize = 0; /* this process has a kq */ 39089306Salfred FILEDESC_UNLOCK(fdp); 39159290Sjlemon kq->kq_fdp = fdp; 39282710Sdillondone2: 39382710Sdillon mtx_unlock(&Giant); 39461468Sjlemon return (error); 39559290Sjlemon} 39659290Sjlemon 39759290Sjlemon#ifndef _SYS_SYSPROTO_H_ 39859290Sjlemonstruct kevent_args { 39959290Sjlemon int fd; 40063977Speter const struct kevent *changelist; 40159290Sjlemon int nchanges; 40263452Sjlemon struct kevent *eventlist; 40359290Sjlemon int nevents; 40463977Speter const struct timespec *timeout; 40559290Sjlemon}; 40659290Sjlemon#endif 40782710Sdillon/* 40882710Sdillon * MPSAFE 40982710Sdillon */ 41059290Sjlemonint 41183366Sjuliankevent(struct thread *td, struct kevent_args *uap) 41259290Sjlemon{ 41363452Sjlemon struct kevent *kevp; 41459290Sjlemon struct kqueue *kq; 41586341Sdillon struct file *fp; 41659290Sjlemon struct timespec ts; 41759290Sjlemon int i, n, nerrors, error; 41859290Sjlemon 41989319Salfred if ((error = fget(td, uap->fd, &fp)) != 0) 42089319Salfred return (error); 42189319Salfred if (fp->f_type != DTYPE_KQUEUE) { 42289319Salfred fdrop(fp, td); 42389306Salfred return (EBADF); 42482710Sdillon } 42559290Sjlemon if (uap->timeout != NULL) { 42663452Sjlemon error = copyin(uap->timeout, &ts, sizeof(ts)); 42759290Sjlemon if (error) 42889306Salfred goto done_nogiant; 42959290Sjlemon uap->timeout = &ts; 43059290Sjlemon } 43189306Salfred mtx_lock(&Giant); 43259290Sjlemon 43359290Sjlemon kq = (struct kqueue *)fp->f_data; 43459290Sjlemon nerrors = 0; 43559290Sjlemon 43659290Sjlemon while (uap->nchanges > 0) { 43759290Sjlemon n = uap->nchanges > KQ_NEVENTS ? KQ_NEVENTS : uap->nchanges; 43863452Sjlemon error = copyin(uap->changelist, kq->kq_kev, 43963452Sjlemon n * sizeof(struct kevent)); 44059290Sjlemon if (error) 44168883Sdillon goto done; 44259290Sjlemon for (i = 0; i < n; i++) { 44363452Sjlemon kevp = &kq->kq_kev[i]; 44463452Sjlemon kevp->flags &= ~EV_SYSFLAGS; 44583366Sjulian error = kqueue_register(kq, kevp, td); 44659290Sjlemon if (error) { 44759290Sjlemon if (uap->nevents != 0) { 44863452Sjlemon kevp->flags = EV_ERROR; 44963452Sjlemon kevp->data = error; 45098998Salfred (void) copyout(kevp, 45198998Salfred uap->eventlist, 45263452Sjlemon sizeof(*kevp)); 45359290Sjlemon uap->eventlist++; 45459290Sjlemon uap->nevents--; 45559290Sjlemon nerrors++; 45659290Sjlemon } else { 45768883Sdillon goto done; 45859290Sjlemon } 45959290Sjlemon } 46059290Sjlemon } 46159290Sjlemon uap->nchanges -= n; 46259290Sjlemon uap->changelist += n; 46359290Sjlemon } 46459290Sjlemon if (nerrors) { 46583366Sjulian td->td_retval[0] = nerrors; 46668883Sdillon error = 0; 46768883Sdillon goto done; 46859290Sjlemon } 46959290Sjlemon 47083366Sjulian error = kqueue_scan(fp, uap->nevents, uap->eventlist, uap->timeout, td); 47168883Sdillondone: 47289306Salfred mtx_unlock(&Giant); 47389306Salfreddone_nogiant: 47468883Sdillon if (fp != NULL) 47583366Sjulian fdrop(fp, td); 47659290Sjlemon return (error); 47759290Sjlemon} 47859290Sjlemon 47959290Sjlemonint 48088633Salfredkqueue_add_filteropts(int filt, struct filterops *filtops) 48188633Salfred{ 48288633Salfred 48388633Salfred if (filt > 0) 48488633Salfred panic("filt(%d) > 0", filt); 48588633Salfred if (filt + EVFILT_SYSCOUNT < 0) 48688633Salfred panic("filt(%d) + EVFILT_SYSCOUNT(%d) == %d < 0", 48788633Salfred filt, EVFILT_SYSCOUNT, filt + EVFILT_SYSCOUNT); 48888633Salfred if (sysfilt_ops[~filt] != &null_filtops) 48988633Salfred panic("sysfilt_ops[~filt(%d)] != &null_filtops", filt); 49088633Salfred sysfilt_ops[~filt] = filtops; 49188633Salfred return (0); 49288633Salfred} 49388633Salfred 49488633Salfredint 49588633Salfredkqueue_del_filteropts(int filt) 49688633Salfred{ 49788633Salfred 49888633Salfred if (filt > 0) 49988633Salfred panic("filt(%d) > 0", filt); 50088633Salfred if (filt + EVFILT_SYSCOUNT < 0) 50188633Salfred panic("filt(%d) + EVFILT_SYSCOUNT(%d) == %d < 0", 50288633Salfred filt, EVFILT_SYSCOUNT, filt + EVFILT_SYSCOUNT); 50388633Salfred if (sysfilt_ops[~filt] == &null_filtops) 50488633Salfred panic("sysfilt_ops[~filt(%d)] != &null_filtops", filt); 50588633Salfred sysfilt_ops[~filt] = &null_filtops; 50688633Salfred return (0); 50788633Salfred} 50888633Salfred 50988633Salfredint 51083366Sjuliankqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td) 51159290Sjlemon{ 51259290Sjlemon struct filedesc *fdp = kq->kq_fdp; 51359290Sjlemon struct filterops *fops; 51459290Sjlemon struct file *fp = NULL; 51559290Sjlemon struct knote *kn = NULL; 51659290Sjlemon int s, error = 0; 51759290Sjlemon 51859290Sjlemon if (kev->filter < 0) { 51959290Sjlemon if (kev->filter + EVFILT_SYSCOUNT < 0) 52059290Sjlemon return (EINVAL); 52159290Sjlemon fops = sysfilt_ops[~kev->filter]; /* to 0-base index */ 52259290Sjlemon } else { 52359290Sjlemon /* 52459290Sjlemon * XXX 52559290Sjlemon * filter attach routine is responsible for insuring that 52659290Sjlemon * the identifier can be attached to it. 52759290Sjlemon */ 52859290Sjlemon printf("unknown filter: %d\n", kev->filter); 52959290Sjlemon return (EINVAL); 53059290Sjlemon } 53159290Sjlemon 53289306Salfred FILEDESC_LOCK(fdp); 53359290Sjlemon if (fops->f_isfd) { 53464343Sjlemon /* validate descriptor */ 53559290Sjlemon if ((u_int)kev->ident >= fdp->fd_nfiles || 53689306Salfred (fp = fdp->fd_ofiles[kev->ident]) == NULL) { 53789306Salfred FILEDESC_UNLOCK(fdp); 53864343Sjlemon return (EBADF); 53989306Salfred } 54068883Sdillon fhold(fp); 54159290Sjlemon 54259290Sjlemon if (kev->ident < fdp->fd_knlistsize) { 54359290Sjlemon SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link) 54459290Sjlemon if (kq == kn->kn_kq && 54559290Sjlemon kev->filter == kn->kn_filter) 54659290Sjlemon break; 54759290Sjlemon } 54859290Sjlemon } else { 54959290Sjlemon if (fdp->fd_knhashmask != 0) { 55059290Sjlemon struct klist *list; 55159290Sjlemon 55259290Sjlemon list = &fdp->fd_knhash[ 55359290Sjlemon KN_HASH((u_long)kev->ident, fdp->fd_knhashmask)]; 55459290Sjlemon SLIST_FOREACH(kn, list, kn_link) 55559290Sjlemon if (kev->ident == kn->kn_id && 55659290Sjlemon kq == kn->kn_kq && 55759290Sjlemon kev->filter == kn->kn_filter) 55859290Sjlemon break; 55959290Sjlemon } 56059290Sjlemon } 56189306Salfred FILEDESC_UNLOCK(fdp); 56259290Sjlemon 56368883Sdillon if (kn == NULL && ((kev->flags & EV_ADD) == 0)) { 56468883Sdillon error = ENOENT; 56568883Sdillon goto done; 56668883Sdillon } 56759290Sjlemon 56859290Sjlemon /* 56959290Sjlemon * kn now contains the matching knote, or NULL if no match 57059290Sjlemon */ 57159290Sjlemon if (kev->flags & EV_ADD) { 57259290Sjlemon 57359290Sjlemon if (kn == NULL) { 57459290Sjlemon kn = knote_alloc(); 57568883Sdillon if (kn == NULL) { 57668883Sdillon error = ENOMEM; 57768883Sdillon goto done; 57868883Sdillon } 57959290Sjlemon kn->kn_fp = fp; 58059290Sjlemon kn->kn_kq = kq; 58159290Sjlemon kn->kn_fop = fops; 58259290Sjlemon 58368883Sdillon /* 58472958Sjlemon * apply reference count to knote structure, and 58568883Sdillon * do not release it at the end of this routine. 58668883Sdillon */ 58768883Sdillon fp = NULL; 58868883Sdillon 58961962Sjlemon kn->kn_sfflags = kev->fflags; 59061962Sjlemon kn->kn_sdata = kev->data; 59161962Sjlemon kev->fflags = 0; 59261962Sjlemon kev->data = 0; 59361962Sjlemon kn->kn_kevent = *kev; 59461962Sjlemon 59559290Sjlemon knote_attach(kn, fdp); 59659290Sjlemon if ((error = fops->f_attach(kn)) != 0) { 59783366Sjulian knote_drop(kn, td); 59859290Sjlemon goto done; 59959290Sjlemon } 60061962Sjlemon } else { 60161962Sjlemon /* 60261962Sjlemon * The user may change some filter values after the 60361962Sjlemon * initial EV_ADD, but doing so will not reset any 60461962Sjlemon * filter which have already been triggered. 60561962Sjlemon */ 60661962Sjlemon kn->kn_sfflags = kev->fflags; 60761962Sjlemon kn->kn_sdata = kev->data; 60861962Sjlemon kn->kn_kevent.udata = kev->udata; 60959290Sjlemon } 61061962Sjlemon 61159997Sjlemon s = splhigh(); 61259290Sjlemon if (kn->kn_fop->f_event(kn, 0)) 61359290Sjlemon KNOTE_ACTIVATE(kn); 61459997Sjlemon splx(s); 61561962Sjlemon 61659290Sjlemon } else if (kev->flags & EV_DELETE) { 61759290Sjlemon kn->kn_fop->f_detach(kn); 61883366Sjulian knote_drop(kn, td); 61959290Sjlemon goto done; 62059290Sjlemon } 62159290Sjlemon 62259290Sjlemon if ((kev->flags & EV_DISABLE) && 62359290Sjlemon ((kn->kn_status & KN_DISABLED) == 0)) { 62459290Sjlemon s = splhigh(); 62559290Sjlemon kn->kn_status |= KN_DISABLED; 62659290Sjlemon splx(s); 62759290Sjlemon } 62859290Sjlemon 62959290Sjlemon if ((kev->flags & EV_ENABLE) && (kn->kn_status & KN_DISABLED)) { 63059290Sjlemon s = splhigh(); 63159290Sjlemon kn->kn_status &= ~KN_DISABLED; 63259290Sjlemon if ((kn->kn_status & KN_ACTIVE) && 63359290Sjlemon ((kn->kn_status & KN_QUEUED) == 0)) 63459290Sjlemon knote_enqueue(kn); 63559290Sjlemon splx(s); 63659290Sjlemon } 63759290Sjlemon 63859290Sjlemondone: 63968883Sdillon if (fp != NULL) 64083366Sjulian fdrop(fp, td); 64159290Sjlemon return (error); 64259290Sjlemon} 64359290Sjlemon 64459290Sjlemonstatic int 64559290Sjlemonkqueue_scan(struct file *fp, int maxevents, struct kevent *ulistp, 64683366Sjulian const struct timespec *tsp, struct thread *td) 64759290Sjlemon{ 64889306Salfred struct kqueue *kq; 64959290Sjlemon struct kevent *kevp; 65059290Sjlemon struct timeval atv, rtv, ttv; 65159290Sjlemon struct knote *kn, marker; 65259290Sjlemon int s, count, timeout, nkev = 0, error = 0; 65359290Sjlemon 65489306Salfred FILE_LOCK_ASSERT(fp, MA_NOTOWNED); 65589306Salfred 65689306Salfred kq = (struct kqueue *)fp->f_data; 65759290Sjlemon count = maxevents; 65859290Sjlemon if (count == 0) 65959290Sjlemon goto done; 66059290Sjlemon 66164343Sjlemon if (tsp != NULL) { 66259290Sjlemon TIMESPEC_TO_TIMEVAL(&atv, tsp); 66364343Sjlemon if (itimerfix(&atv)) { 66459290Sjlemon error = EINVAL; 66559290Sjlemon goto done; 66659290Sjlemon } 66764343Sjlemon if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) 66864343Sjlemon timeout = -1; 66964343Sjlemon else 67064343Sjlemon timeout = atv.tv_sec > 24 * 60 * 60 ? 67164343Sjlemon 24 * 60 * 60 * hz : tvtohz(&atv); 67264343Sjlemon getmicrouptime(&rtv); 67364343Sjlemon timevaladd(&atv, &rtv); 67464343Sjlemon } else { 67564343Sjlemon atv.tv_sec = 0; 67664343Sjlemon atv.tv_usec = 0; 67759290Sjlemon timeout = 0; 67859290Sjlemon } 67959290Sjlemon goto start; 68059290Sjlemon 68159290Sjlemonretry: 68264343Sjlemon if (atv.tv_sec || atv.tv_usec) { 68359290Sjlemon getmicrouptime(&rtv); 68459290Sjlemon if (timevalcmp(&rtv, &atv, >=)) 68559290Sjlemon goto done; 68659290Sjlemon ttv = atv; 68759290Sjlemon timevalsub(&ttv, &rtv); 68859290Sjlemon timeout = ttv.tv_sec > 24 * 60 * 60 ? 68959290Sjlemon 24 * 60 * 60 * hz : tvtohz(&ttv); 69059290Sjlemon } 69159290Sjlemon 69259290Sjlemonstart: 69359290Sjlemon kevp = kq->kq_kev; 69459290Sjlemon s = splhigh(); 69559290Sjlemon if (kq->kq_count == 0) { 69664343Sjlemon if (timeout < 0) { 69764343Sjlemon error = EWOULDBLOCK; 69864343Sjlemon } else { 69964343Sjlemon kq->kq_state |= KQ_SLEEP; 70064343Sjlemon error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout); 70164343Sjlemon } 70259290Sjlemon splx(s); 70364084Sjlemon if (error == 0) 70459290Sjlemon goto retry; 70564084Sjlemon /* don't restart after signals... */ 70664084Sjlemon if (error == ERESTART) 70764084Sjlemon error = EINTR; 70864084Sjlemon else if (error == EWOULDBLOCK) 70959290Sjlemon error = 0; 71059290Sjlemon goto done; 71159290Sjlemon } 71259290Sjlemon 71359290Sjlemon TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe); 71459290Sjlemon while (count) { 71559290Sjlemon kn = TAILQ_FIRST(&kq->kq_head); 71659290Sjlemon TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); 71759290Sjlemon if (kn == &marker) { 71859290Sjlemon splx(s); 71959290Sjlemon if (count == maxevents) 72059290Sjlemon goto retry; 72159290Sjlemon goto done; 72259290Sjlemon } 72359290Sjlemon if (kn->kn_status & KN_DISABLED) { 72459290Sjlemon kn->kn_status &= ~KN_QUEUED; 72559290Sjlemon kq->kq_count--; 72659290Sjlemon continue; 72759290Sjlemon } 72859290Sjlemon if ((kn->kn_flags & EV_ONESHOT) == 0 && 72959290Sjlemon kn->kn_fop->f_event(kn, 0) == 0) { 73059290Sjlemon kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE); 73159290Sjlemon kq->kq_count--; 73259290Sjlemon continue; 73359290Sjlemon } 73459290Sjlemon *kevp = kn->kn_kevent; 73559290Sjlemon kevp++; 73659290Sjlemon nkev++; 73759290Sjlemon if (kn->kn_flags & EV_ONESHOT) { 73859290Sjlemon kn->kn_status &= ~KN_QUEUED; 73959290Sjlemon kq->kq_count--; 74059290Sjlemon splx(s); 74159290Sjlemon kn->kn_fop->f_detach(kn); 74283366Sjulian knote_drop(kn, td); 74359290Sjlemon s = splhigh(); 74459290Sjlemon } else if (kn->kn_flags & EV_CLEAR) { 74559290Sjlemon kn->kn_data = 0; 74659290Sjlemon kn->kn_fflags = 0; 74759290Sjlemon kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE); 74859290Sjlemon kq->kq_count--; 74959290Sjlemon } else { 75059290Sjlemon TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe); 75159290Sjlemon } 75259290Sjlemon count--; 75359290Sjlemon if (nkev == KQ_NEVENTS) { 75459290Sjlemon splx(s); 75598998Salfred error = copyout(&kq->kq_kev, ulistp, 75659290Sjlemon sizeof(struct kevent) * nkev); 75759290Sjlemon ulistp += nkev; 75859290Sjlemon nkev = 0; 75959290Sjlemon kevp = kq->kq_kev; 76059290Sjlemon s = splhigh(); 76159997Sjlemon if (error) 76259997Sjlemon break; 76359290Sjlemon } 76459290Sjlemon } 76559290Sjlemon TAILQ_REMOVE(&kq->kq_head, &marker, kn_tqe); 76659290Sjlemon splx(s); 76759290Sjlemondone: 76859290Sjlemon if (nkev != 0) 76998998Salfred error = copyout(&kq->kq_kev, ulistp, 77059290Sjlemon sizeof(struct kevent) * nkev); 77183366Sjulian td->td_retval[0] = maxevents - count; 77259290Sjlemon return (error); 77359290Sjlemon} 77459290Sjlemon 77559290Sjlemon/* 77659290Sjlemon * XXX 77759290Sjlemon * This could be expanded to call kqueue_scan, if desired. 77859290Sjlemon */ 77959290Sjlemon/*ARGSUSED*/ 78059290Sjlemonstatic int 781101941Srwatsonkqueue_read(struct file *fp, struct uio *uio, struct ucred *active_cred, 78283366Sjulian int flags, struct thread *td) 78359290Sjlemon{ 78459290Sjlemon return (ENXIO); 78559290Sjlemon} 78659290Sjlemon 78759290Sjlemon/*ARGSUSED*/ 78859290Sjlemonstatic int 789101941Srwatsonkqueue_write(struct file *fp, struct uio *uio, struct ucred *active_cred, 79083366Sjulian int flags, struct thread *td) 79159290Sjlemon{ 79259290Sjlemon return (ENXIO); 79359290Sjlemon} 79459290Sjlemon 79559290Sjlemon/*ARGSUSED*/ 79659290Sjlemonstatic int 79799009Salfredkqueue_ioctl(struct file *fp, u_long com, void *data, struct thread *td) 79859290Sjlemon{ 79959290Sjlemon return (ENOTTY); 80059290Sjlemon} 80159290Sjlemon 80259290Sjlemon/*ARGSUSED*/ 80359290Sjlemonstatic int 804101983Srwatsonkqueue_poll(struct file *fp, int events, struct ucred *active_cred, 805101983Srwatson struct thread *td) 80659290Sjlemon{ 80789306Salfred struct kqueue *kq; 80859290Sjlemon int revents = 0; 80959290Sjlemon int s = splnet(); 81059290Sjlemon 81189306Salfred kq = (struct kqueue *)fp->f_data; 81259290Sjlemon if (events & (POLLIN | POLLRDNORM)) { 81359290Sjlemon if (kq->kq_count) { 81459290Sjlemon revents |= events & (POLLIN | POLLRDNORM); 81559290Sjlemon } else { 81683805Sjhb selrecord(td, &kq->kq_sel); 81759290Sjlemon kq->kq_state |= KQ_SEL; 81859290Sjlemon } 81959290Sjlemon } 82059290Sjlemon splx(s); 82159290Sjlemon return (revents); 82259290Sjlemon} 82359290Sjlemon 82459290Sjlemon/*ARGSUSED*/ 82559290Sjlemonstatic int 826101983Srwatsonkqueue_stat(struct file *fp, struct stat *st, struct ucred *active_cred, 827101983Srwatson struct thread *td) 82859290Sjlemon{ 82989306Salfred struct kqueue *kq; 83059290Sjlemon 83189306Salfred kq = (struct kqueue *)fp->f_data; 83259290Sjlemon bzero((void *)st, sizeof(*st)); 83359290Sjlemon st->st_size = kq->kq_count; 83459290Sjlemon st->st_blksize = sizeof(struct kevent); 83562218Schris st->st_mode = S_IFIFO; 83659290Sjlemon return (0); 83759290Sjlemon} 83859290Sjlemon 83959290Sjlemon/*ARGSUSED*/ 84059290Sjlemonstatic int 84183366Sjuliankqueue_close(struct file *fp, struct thread *td) 84259290Sjlemon{ 84359290Sjlemon struct kqueue *kq = (struct kqueue *)fp->f_data; 84483366Sjulian struct filedesc *fdp = td->td_proc->p_fd; 84559290Sjlemon struct knote **knp, *kn, *kn0; 84659290Sjlemon int i; 84759290Sjlemon 84889306Salfred FILEDESC_LOCK(fdp); 84959290Sjlemon for (i = 0; i < fdp->fd_knlistsize; i++) { 85059290Sjlemon knp = &SLIST_FIRST(&fdp->fd_knlist[i]); 85159290Sjlemon kn = *knp; 85259290Sjlemon while (kn != NULL) { 85359290Sjlemon kn0 = SLIST_NEXT(kn, kn_link); 85459290Sjlemon if (kq == kn->kn_kq) { 85559290Sjlemon kn->kn_fop->f_detach(kn); 85689306Salfred *knp = kn0; 85789306Salfred FILE_LOCK(kn->kn_fp); 85889306Salfred FILEDESC_UNLOCK(fdp); 85989306Salfred fdrop_locked(kn->kn_fp, td); 86059290Sjlemon knote_free(kn); 86189306Salfred FILEDESC_LOCK(fdp); 86259290Sjlemon } else { 86359290Sjlemon knp = &SLIST_NEXT(kn, kn_link); 86459290Sjlemon } 86559290Sjlemon kn = kn0; 86659290Sjlemon } 86759290Sjlemon } 86859290Sjlemon if (fdp->fd_knhashmask != 0) { 86959290Sjlemon for (i = 0; i < fdp->fd_knhashmask + 1; i++) { 87059290Sjlemon knp = &SLIST_FIRST(&fdp->fd_knhash[i]); 87159290Sjlemon kn = *knp; 87259290Sjlemon while (kn != NULL) { 87359290Sjlemon kn0 = SLIST_NEXT(kn, kn_link); 87459290Sjlemon if (kq == kn->kn_kq) { 87559290Sjlemon kn->kn_fop->f_detach(kn); 87689306Salfred *knp = kn0; 87759290Sjlemon /* XXX non-fd release of kn->kn_ptr */ 87889306Salfred FILEDESC_UNLOCK(fdp); 87959290Sjlemon knote_free(kn); 88089306Salfred FILEDESC_LOCK(fdp); 88159290Sjlemon } else { 88259290Sjlemon knp = &SLIST_NEXT(kn, kn_link); 88359290Sjlemon } 88459290Sjlemon kn = kn0; 88559290Sjlemon } 88659290Sjlemon } 88759290Sjlemon } 88889306Salfred FILEDESC_UNLOCK(fdp); 88984138Sjlemon free(kq, M_KQUEUE); 89059290Sjlemon fp->f_data = NULL; 89159290Sjlemon 89259290Sjlemon return (0); 89359290Sjlemon} 89459290Sjlemon 89559290Sjlemonstatic void 89659290Sjlemonkqueue_wakeup(struct kqueue *kq) 89759290Sjlemon{ 89859290Sjlemon 89959290Sjlemon if (kq->kq_state & KQ_SLEEP) { 90059290Sjlemon kq->kq_state &= ~KQ_SLEEP; 90159290Sjlemon wakeup(kq); 90259290Sjlemon } 90359290Sjlemon if (kq->kq_state & KQ_SEL) { 90459290Sjlemon kq->kq_state &= ~KQ_SEL; 90559290Sjlemon selwakeup(&kq->kq_sel); 90659290Sjlemon } 90759290Sjlemon KNOTE(&kq->kq_sel.si_note, 0); 90859290Sjlemon} 90959290Sjlemon 91059290Sjlemon/* 91159290Sjlemon * walk down a list of knotes, activating them if their event has triggered. 91259290Sjlemon */ 91359290Sjlemonvoid 91459290Sjlemonknote(struct klist *list, long hint) 91559290Sjlemon{ 91659290Sjlemon struct knote *kn; 91759290Sjlemon 91859290Sjlemon SLIST_FOREACH(kn, list, kn_selnext) 91959290Sjlemon if (kn->kn_fop->f_event(kn, hint)) 92059290Sjlemon KNOTE_ACTIVATE(kn); 92159290Sjlemon} 92259290Sjlemon 92359290Sjlemon/* 92459290Sjlemon * remove all knotes from a specified klist 92559290Sjlemon */ 92659290Sjlemonvoid 92783366Sjulianknote_remove(struct thread *td, struct klist *list) 92859290Sjlemon{ 92959290Sjlemon struct knote *kn; 93059290Sjlemon 93159290Sjlemon while ((kn = SLIST_FIRST(list)) != NULL) { 93259290Sjlemon kn->kn_fop->f_detach(kn); 93383366Sjulian knote_drop(kn, td); 93459290Sjlemon } 93559290Sjlemon} 93659290Sjlemon 93759290Sjlemon/* 93859290Sjlemon * remove all knotes referencing a specified fd 93959290Sjlemon */ 94059290Sjlemonvoid 94183366Sjulianknote_fdclose(struct thread *td, int fd) 94259290Sjlemon{ 94383366Sjulian struct filedesc *fdp = td->td_proc->p_fd; 94489306Salfred struct klist *list; 94559290Sjlemon 94689306Salfred FILEDESC_LOCK(fdp); 94789306Salfred list = &fdp->fd_knlist[fd]; 94889306Salfred FILEDESC_UNLOCK(fdp); 94983366Sjulian knote_remove(td, list); 95059290Sjlemon} 95159290Sjlemon 95259290Sjlemonstatic void 95359290Sjlemonknote_attach(struct knote *kn, struct filedesc *fdp) 95459290Sjlemon{ 95589306Salfred struct klist *list, *oldlist; 95689306Salfred int size, newsize; 95759290Sjlemon 95889306Salfred FILEDESC_LOCK(fdp); 95989306Salfred 96059290Sjlemon if (! kn->kn_fop->f_isfd) { 96159290Sjlemon if (fdp->fd_knhashmask == 0) 96284138Sjlemon fdp->fd_knhash = hashinit(KN_HASHSIZE, M_KQUEUE, 96359290Sjlemon &fdp->fd_knhashmask); 96459290Sjlemon list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)]; 96559290Sjlemon goto done; 96659290Sjlemon } 96759290Sjlemon 96859290Sjlemon if (fdp->fd_knlistsize <= kn->kn_id) { 96989306Salfredretry: 97059290Sjlemon size = fdp->fd_knlistsize; 97159290Sjlemon while (size <= kn->kn_id) 97259290Sjlemon size += KQEXTENT; 97389306Salfred FILEDESC_UNLOCK(fdp); 97459290Sjlemon MALLOC(list, struct klist *, 97584138Sjlemon size * sizeof(struct klist *), M_KQUEUE, M_WAITOK); 97689306Salfred FILEDESC_LOCK(fdp); 97789306Salfred newsize = fdp->fd_knlistsize; 97889306Salfred while (newsize <= kn->kn_id) 97989306Salfred newsize += KQEXTENT; 98089306Salfred if (newsize != size) { 98189306Salfred FILEDESC_UNLOCK(fdp); 98289306Salfred free(list, M_TEMP); 98389306Salfred FILEDESC_LOCK(fdp); 98489306Salfred goto retry; 98589306Salfred } 98698998Salfred bcopy(fdp->fd_knlist, list, 98759290Sjlemon fdp->fd_knlistsize * sizeof(struct klist *)); 98859290Sjlemon bzero((caddr_t)list + 98959290Sjlemon fdp->fd_knlistsize * sizeof(struct klist *), 99059290Sjlemon (size - fdp->fd_knlistsize) * sizeof(struct klist *)); 99159290Sjlemon if (fdp->fd_knlist != NULL) 99289306Salfred oldlist = fdp->fd_knlist; 99389306Salfred else 99489306Salfred oldlist = NULL; 99559290Sjlemon fdp->fd_knlistsize = size; 99659290Sjlemon fdp->fd_knlist = list; 99789306Salfred FILEDESC_UNLOCK(fdp); 99889306Salfred if (oldlist != NULL) 99989306Salfred FREE(oldlist, M_KQUEUE); 100089306Salfred FILEDESC_LOCK(fdp); 100159290Sjlemon } 100259290Sjlemon list = &fdp->fd_knlist[kn->kn_id]; 100359290Sjlemondone: 100489306Salfred FILEDESC_UNLOCK(fdp); 100559290Sjlemon SLIST_INSERT_HEAD(list, kn, kn_link); 100659290Sjlemon kn->kn_status = 0; 100759290Sjlemon} 100859290Sjlemon 100959290Sjlemon/* 101059290Sjlemon * should be called at spl == 0, since we don't want to hold spl 101159290Sjlemon * while calling fdrop and free. 101259290Sjlemon */ 101359290Sjlemonstatic void 101483366Sjulianknote_drop(struct knote *kn, struct thread *td) 101559290Sjlemon{ 101683366Sjulian struct filedesc *fdp = td->td_proc->p_fd; 101759290Sjlemon struct klist *list; 101859290Sjlemon 101989306Salfred FILEDESC_LOCK(fdp); 102059290Sjlemon if (kn->kn_fop->f_isfd) 102159290Sjlemon list = &fdp->fd_knlist[kn->kn_id]; 102259290Sjlemon else 102359290Sjlemon list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)]; 102489306Salfred if (kn->kn_fop->f_isfd) 102589306Salfred FILE_LOCK(kn->kn_fp); 102689306Salfred FILEDESC_UNLOCK(fdp); 102759290Sjlemon 102860938Sjake SLIST_REMOVE(list, kn, knote, kn_link); 102959290Sjlemon if (kn->kn_status & KN_QUEUED) 103059290Sjlemon knote_dequeue(kn); 103159290Sjlemon if (kn->kn_fop->f_isfd) 103289306Salfred fdrop_locked(kn->kn_fp, td); 103359290Sjlemon knote_free(kn); 103459290Sjlemon} 103559290Sjlemon 103659290Sjlemon 103759290Sjlemonstatic void 103859290Sjlemonknote_enqueue(struct knote *kn) 103959290Sjlemon{ 104059290Sjlemon struct kqueue *kq = kn->kn_kq; 104159290Sjlemon int s = splhigh(); 104259290Sjlemon 104359997Sjlemon KASSERT((kn->kn_status & KN_QUEUED) == 0, ("knote already queued")); 104459997Sjlemon 104559290Sjlemon TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe); 104659290Sjlemon kn->kn_status |= KN_QUEUED; 104759290Sjlemon kq->kq_count++; 104859290Sjlemon splx(s); 104959290Sjlemon kqueue_wakeup(kq); 105059290Sjlemon} 105159290Sjlemon 105259290Sjlemonstatic void 105359290Sjlemonknote_dequeue(struct knote *kn) 105459290Sjlemon{ 105559290Sjlemon struct kqueue *kq = kn->kn_kq; 105659290Sjlemon int s = splhigh(); 105759290Sjlemon 105859997Sjlemon KASSERT(kn->kn_status & KN_QUEUED, ("knote not queued")); 105959997Sjlemon 106059290Sjlemon TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe); 106159290Sjlemon kn->kn_status &= ~KN_QUEUED; 106259290Sjlemon kq->kq_count--; 106359290Sjlemon splx(s); 106459290Sjlemon} 106559290Sjlemon 106659290Sjlemonstatic void 106759290Sjlemonknote_init(void) 106859290Sjlemon{ 106992751Sjeff knote_zone = uma_zcreate("KNOTE", sizeof(struct knote), NULL, NULL, 107092751Sjeff NULL, NULL, UMA_ALIGN_PTR, 0); 107192751Sjeff 107259290Sjlemon} 107359290SjlemonSYSINIT(knote, SI_SUB_PSEUDO, SI_ORDER_ANY, knote_init, NULL) 107459290Sjlemon 107559290Sjlemonstatic struct knote * 107659290Sjlemonknote_alloc(void) 107759290Sjlemon{ 107892751Sjeff return ((struct knote *)uma_zalloc(knote_zone, M_WAITOK)); 107959290Sjlemon} 108059290Sjlemon 108159290Sjlemonstatic void 108259290Sjlemonknote_free(struct knote *kn) 108359290Sjlemon{ 108492751Sjeff uma_zfree(knote_zone, kn); 108559290Sjlemon} 1086