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