summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjlemon <jlemon@FreeBSD.org>2000-04-16 18:53:38 +0000
committerjlemon <jlemon@FreeBSD.org>2000-04-16 18:53:38 +0000
commitc41c876463ee8c302f06554537e0fb22a3fcdca4 (patch)
treed2f87a6af04c4f35f243bf580d099496a4131330 /sys/kern
parentf8f9ad64d408b963d98d0e11b37e871763557e95 (diff)
downloadFreeBSD-src-c41c876463ee8c302f06554537e0fb22a3fcdca4.zip
FreeBSD-src-c41c876463ee8c302f06554537e0fb22a3fcdca4.tar.gz
Introduce kqueue() and kevent(), a kernel event notification facility.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/init_sysent.c4
-rw-r--r--sys/kern/kern_descrip.c26
-rw-r--r--sys/kern/kern_exec.c5
-rw-r--r--sys/kern/kern_exit.c5
-rw-r--r--sys/kern/kern_fork.c5
-rw-r--r--sys/kern/kern_sig.c51
-rw-r--r--sys/kern/sys_pipe.c67
-rw-r--r--sys/kern/syscalls.c4
-rw-r--r--sys/kern/syscalls.master5
-rw-r--r--sys/kern/uipc_sockbuf.c2
-rw-r--r--sys/kern/uipc_socket.c109
-rw-r--r--sys/kern/uipc_socket2.c2
-rw-r--r--sys/kern/uipc_syscalls.c4
-rw-r--r--sys/kern/vfs_aio.c107
-rw-r--r--sys/kern/vfs_vnops.c77
15 files changed, 465 insertions, 8 deletions
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 64722ba..7d3daa4 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.72 2000/01/19 06:01:07 rwatson Exp
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.73 2000/04/03 06:36:14 alfred Exp
*/
#include "opt_compat.h"
@@ -382,4 +382,6 @@ struct sysent sysent[] = {
{ 2, (sy_call_t *)aio_waitcomplete }, /* 359 = aio_waitcomplete */
{ 3, (sy_call_t *)getresuid }, /* 360 = getresuid */
{ 3, (sy_call_t *)getresgid }, /* 361 = getresgid */
+ { 0, (sy_call_t *)kqueue }, /* 362 = kqueue */
+ { 6, (sy_call_t *)kevent }, /* 363 = kevent */
};
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 1de896e..f0095c97 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -56,6 +56,7 @@
#include <sys/malloc.h>
#include <sys/unistd.h>
#include <sys/resourcevar.h>
+#include <sys/event.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -504,6 +505,8 @@ close(p, uap)
if (fd < fdp->fd_freefile)
fdp->fd_freefile = fd;
*pf = 0;
+ if (fd < fdp->fd_knlistsize)
+ knote_fdclose(p, fd);
return (closef(fp, p));
}
@@ -830,9 +833,7 @@ fdinit(p)
newfdp->fd_fd.fd_ofiles = newfdp->fd_dfiles;
newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
newfdp->fd_fd.fd_nfiles = NDFILE;
-
- newfdp->fd_fd.fd_freefile = 0;
- newfdp->fd_fd.fd_lastfile = 0;
+ newfdp->fd_fd.fd_knlistsize = -1;
return (&newfdp->fd_fd);
}
@@ -899,6 +900,21 @@ fdcopy(p)
newfdp->fd_nfiles = i;
bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
+
+ /*
+ * kq descriptors cannot be copied.
+ */
+ if (newfdp->fd_knlistsize != -1) {
+ fpp = newfdp->fd_ofiles;
+ for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
+ if (*fpp != NULL && (*fpp)->f_type == DTYPE_KQUEUE)
+ *fpp = NULL;
+ newfdp->fd_knlist = NULL;
+ newfdp->fd_knlistsize = -1;
+ newfdp->fd_knhash = NULL;
+ newfdp->fd_knhashmask = 0;
+ }
+
fpp = newfdp->fd_ofiles;
for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
if (*fpp != NULL)
@@ -933,6 +949,10 @@ fdfree(p)
vrele(fdp->fd_rdir);
if (fdp->fd_jdir)
vrele(fdp->fd_jdir);
+ if (fdp->fd_knlist)
+ FREE(fdp->fd_knlist, M_TEMP);
+ if (fdp->fd_knhash)
+ FREE(fdp->fd_knhash, M_TEMP);
FREE(fdp, M_FILEDESC);
}
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index ba88695..d9ae6a2 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -311,6 +311,11 @@ interpret:
p->p_textvp = ndp->ni_vp;
/*
+ * notify others that we exec'd
+ */
+ KNOTE(&p->p_klist, NOTE_EXEC);
+
+ /*
* If tracing the process, trap to debugger so breakpoints
* can be set before the program executes.
*/
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 9c2005c..9115f97 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -307,6 +307,11 @@ exit1(p, rv)
switchticks = ticks;
/*
+ * notify interested parties of our demise.
+ */
+ KNOTE(&p->p_klist, NOTE_EXIT);
+
+ /*
* Notify parent that we're gone. If parent has the PS_NOCLDWAIT
* flag set, notify process 1 instead (and hope it will handle
* this situation).
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index fc69d28..62296b2 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -509,6 +509,11 @@ again:
PRELE(p1);
/*
+ * tell any interested parties about the new process
+ */
+ KNOTE(&p1->p_klist, NOTE_FORK | p2->p_pid);
+
+ /*
* Preserve synchronization semantics of vfork. If waiting for
* child to exec or exit, set P_PPWAIT on child, and sleep on our
* proc (in case of exit).
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index e3e0e59..52136d6 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -49,6 +49,7 @@
#include <sys/resourcevar.h>
#include <sys/namei.h>
#include <sys/vnode.h>
+#include <sys/event.h>
#include <sys/proc.h>
#include <sys/pioctl.h>
#include <sys/systm.h>
@@ -81,6 +82,13 @@ static int sig_ffs __P((sigset_t *set));
static int sigprop __P((int sig));
static void stop __P((struct proc *));
+static int filt_sigattach(struct knote *kn);
+static void filt_sigdetach(struct knote *kn);
+static int filt_signal(struct knote *kn, long hint);
+
+struct filterops sig_filtops =
+ { 0, filt_sigattach, filt_sigdetach, filt_signal };
+
static int kern_logsigexit = 1;
SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW,
&kern_logsigexit, 0,
@@ -1002,6 +1010,8 @@ psignal(p, sig)
panic("psignal signal number");
}
+ KNOTE(&p->p_klist, NOTE_SIGNAL | sig);
+
prop = sigprop(sig);
/*
@@ -1688,3 +1698,44 @@ pgsigio(sigio, sig, checkctty)
psignal(p, sig);
}
}
+
+static int
+filt_sigattach(struct knote *kn)
+{
+ struct proc *p = curproc;
+
+ kn->kn_ptr.p_proc = p;
+ kn->kn_flags |= EV_CLEAR; /* automatically set */
+
+ /* XXX lock the proc here while adding to the list? */
+ SLIST_INSERT_HEAD(&p->p_klist, kn, kn_selnext);
+
+ return (0);
+}
+
+static void
+filt_sigdetach(struct knote *kn)
+{
+ struct proc *p = kn->kn_ptr.p_proc;
+
+ SLIST_REMOVE(&p->p_klist, kn, knote, kn_selnext);
+}
+
+/*
+ * signal knotes are shared with proc knotes, so we apply a mask to
+ * the hint in order to differentiate them from process hints. This
+ * could be avoided by using a signal-specific knote list, but probably
+ * isn't worth the trouble.
+ */
+static int
+filt_signal(struct knote *kn, long hint)
+{
+
+ if (hint & NOTE_SIGNAL) {
+ hint &= ~NOTE_SIGNAL;
+
+ if (kn->kn_id == hint)
+ kn->kn_data++;
+ }
+ return (kn->kn_data != 0);
+}
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index a181b5a..be86883 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -65,6 +65,7 @@
#include <sys/pipe.h>
#include <sys/vnode.h>
#include <sys/uio.h>
+#include <sys/event.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -100,6 +101,16 @@ static int pipe_ioctl __P((struct file *fp, u_long cmd, caddr_t data, struct pro
static struct fileops pipeops =
{ pipe_read, pipe_write, pipe_ioctl, pipe_poll, pipe_stat, pipe_close };
+static int filt_pipeattach(struct knote *kn);
+static void filt_pipedetach(struct knote *kn);
+static int filt_piperead(struct knote *kn, long hint);
+static int filt_pipewrite(struct knote *kn, long hint);
+
+struct filterops pipe_rwfiltops[] = {
+ { 1, filt_pipeattach, filt_pipedetach, filt_piperead },
+ { 1, filt_pipeattach, filt_pipedetach, filt_pipewrite },
+};
+
/*
* Default pipe buffer size(s), this can be kind-of large now because pipe
* space is pageable. The pipe code will try to maintain locality of
@@ -316,6 +327,7 @@ pipeselwakeup(cpipe)
}
if ((cpipe->pipe_state & PIPE_ASYNC) && cpipe->pipe_sigio)
pgsigio(cpipe->pipe_sigio, SIGIO, 0);
+ KNOTE(&cpipe->pipe_sel.si_note, 0);
}
/* ARGSUSED */
@@ -1159,3 +1171,58 @@ pipeclose(cpipe)
zfree(pipe_zone, cpipe);
}
}
+
+static int
+filt_pipeattach(struct knote *kn)
+{
+ struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
+
+ SLIST_INSERT_HEAD(&rpipe->pipe_sel.si_note, kn, kn_selnext);
+ return (0);
+}
+
+static void
+filt_pipedetach(struct knote *kn)
+{
+ struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
+
+ SLIST_REMOVE(&rpipe->pipe_sel.si_note, kn, knote, kn_selnext);
+}
+
+/*ARGSUSED*/
+static int
+filt_piperead(struct knote *kn, long hint)
+{
+ struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
+ struct pipe *wpipe = rpipe->pipe_peer;
+
+ kn->kn_data = rpipe->pipe_buffer.cnt;
+ if ((kn->kn_data == 0) && (rpipe->pipe_state & PIPE_DIRECTW))
+ kn->kn_data = rpipe->pipe_map.cnt;
+
+ if ((rpipe->pipe_state & PIPE_EOF) ||
+ (wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ return (kn->kn_data > 0);
+}
+
+/*ARGSUSED*/
+static int
+filt_pipewrite(struct knote *kn, long hint)
+{
+ struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
+ struct pipe *wpipe = rpipe->pipe_peer;
+
+ if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
+ kn->kn_data = 0;
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ kn->kn_data = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt;
+ if ((wpipe->pipe_state & PIPE_DIRECTW) == 0)
+ kn->kn_data = 0;
+
+ return (kn->kn_data >= PIPE_BUF);
+}
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index f4afc98..71a63f7 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: src/sys/kern/syscalls.master,v 1.72 2000/01/19 06:01:07 rwatson Exp
+ * created from FreeBSD: src/sys/kern/syscalls.master,v 1.73 2000/04/03 06:36:14 alfred Exp
*/
char *syscallnames[] = {
@@ -369,4 +369,6 @@ char *syscallnames[] = {
"aio_waitcomplete", /* 359 = aio_waitcomplete */
"getresuid", /* 360 = getresuid */
"getresgid", /* 361 = getresgid */
+ "kqueue", /* 362 = kqueue */
+ "kevent", /* 363 = kevent */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 89faed5..e4ba94a 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -515,3 +515,8 @@
359 STD BSD { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); }
360 STD BSD { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
361 STD BSD { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }
+362 STD BSD { int kqueue(void); }
+363 STD BSD { int kevent(int fd, \
+ int nchanges, struct kevent **changelist, \
+ int nevents, struct kevent *eventlist, \
+ struct timespec *timeout); }
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index 93d1fda..6184c23 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -51,6 +51,7 @@
#include <sys/signalvar.h>
#include <sys/sysctl.h>
#include <sys/aio.h> /* for aio_swake proto */
+#include <sys/event.h>
int maxsockets;
@@ -340,6 +341,7 @@ sowakeup(so, sb)
(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
if (sb->sb_flags & SB_AIO)
aio_swake(so, sb);
+ KNOTE(&sb->sb_sel.si_note, 0);
}
/*
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index e4433be..76495e1 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -40,8 +40,10 @@
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/domain.h>
+#include <sys/file.h> /* for struct knote */
#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/event.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/protosw.h>
@@ -55,6 +57,22 @@
#include <machine/limits.h>
+static int filt_sorattach(struct knote *kn);
+static void filt_sordetach(struct knote *kn);
+static int filt_soread(struct knote *kn, long hint);
+static int filt_sowattach(struct knote *kn);
+static void filt_sowdetach(struct knote *kn);
+static int filt_sowrite(struct knote *kn, long hint);
+static int filt_solisten(struct knote *kn, long hint);
+
+static struct filterops solisten_filtops =
+ { 1, filt_sorattach, filt_sordetach, filt_solisten };
+
+struct filterops so_rwfiltops[] = {
+ { 1, filt_sorattach, filt_sordetach, filt_soread },
+ { 1, filt_sowattach, filt_sowdetach, filt_sowrite },
+};
+
struct vm_zone *socket_zone;
so_gen_t so_gencnt; /* generation count for sockets */
@@ -1388,3 +1406,94 @@ sopoll(struct socket *so, int events, struct ucred *cred, struct proc *p)
splx(s);
return (revents);
}
+
+static int
+filt_sorattach(struct knote *kn)
+{
+ struct socket *so = (struct socket *)kn->kn_fp->f_data;
+ int s = splnet();
+
+ if (so->so_options & SO_ACCEPTCONN)
+ kn->kn_fop = &solisten_filtops;
+ SLIST_INSERT_HEAD(&so->so_rcv.sb_sel.si_note, kn, kn_selnext);
+ so->so_rcv.sb_flags |= SB_KNOTE;
+ splx(s);
+ return (0);
+}
+
+static void
+filt_sordetach(struct knote *kn)
+{
+ struct socket *so = (struct socket *)kn->kn_fp->f_data;
+ int s = splnet();
+
+ SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
+ if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
+ so->so_rcv.sb_flags &= ~SB_KNOTE;
+ splx(s);
+}
+
+/*ARGSUSED*/
+static int
+filt_soread(struct knote *kn, long hint)
+{
+ struct socket *so = (struct socket *)kn->kn_fp->f_data;
+
+ kn->kn_data = so->so_rcv.sb_cc;
+ if (so->so_state & SS_CANTRCVMORE) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ return (kn->kn_data > 0);
+}
+
+static int
+filt_sowattach(struct knote *kn)
+{
+ struct socket *so = (struct socket *)kn->kn_fp->f_data;
+ int s = splnet();
+
+ SLIST_INSERT_HEAD(&so->so_snd.sb_sel.si_note, kn, kn_selnext);
+ so->so_snd.sb_flags |= SB_KNOTE;
+ splx(s);
+ return (0);
+}
+
+static void
+filt_sowdetach(struct knote *kn)
+{
+ struct socket *so = (struct socket *)kn->kn_fp->f_data;
+ int s = splnet();
+
+ SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
+ if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
+ so->so_snd.sb_flags &= ~SB_KNOTE;
+ splx(s);
+}
+
+/*ARGSUSED*/
+static int
+filt_sowrite(struct knote *kn, long hint)
+{
+ struct socket *so = (struct socket *)kn->kn_fp->f_data;
+
+ kn->kn_data = sbspace(&so->so_snd);
+ if (so->so_state & SS_CANTSENDMORE) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ if (((so->so_state & SS_ISCONNECTED) == 0) &&
+ (so->so_proto->pr_flags & PR_CONNREQUIRED))
+ return (0);
+ return (kn->kn_data >= so->so_snd.sb_lowat);
+}
+
+/*ARGSUSED*/
+static int
+filt_solisten(struct knote *kn, long hint)
+{
+ struct socket *so = (struct socket *)kn->kn_fp->f_data;
+
+ kn->kn_data = so->so_qlen - so->so_incqlen;
+ return (! TAILQ_EMPTY(&so->so_comp));
+}
diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c
index 93d1fda..6184c23 100644
--- a/sys/kern/uipc_socket2.c
+++ b/sys/kern/uipc_socket2.c
@@ -51,6 +51,7 @@
#include <sys/signalvar.h>
#include <sys/sysctl.h>
#include <sys/aio.h> /* for aio_swake proto */
+#include <sys/event.h>
int maxsockets;
@@ -340,6 +341,7 @@ sowakeup(so, sb)
(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
if (sb->sb_flags & SB_AIO)
aio_swake(so, sb);
+ KNOTE(&sb->sb_sel.si_note, 0);
}
/*
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 268125f..298bbe1 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -46,6 +46,7 @@
#include <sys/sysproto.h>
#include <sys/malloc.h>
#include <sys/filedesc.h>
+#include <sys/event.h>
#include <sys/proc.h>
#include <sys/fcntl.h>
#include <sys/file.h>
@@ -256,6 +257,9 @@ accept1(p, uap, compat)
} else
p->p_retval[0] = fd;
+ /* connection has been removed from the listen queue */
+ KNOTE(&head->so_rcv.sb_sel.si_note, 0);
+
so->so_state &= ~SS_COMP;
so->so_head = NULL;
if (head->so_sigio != NULL)
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index 28c33cc..0e91fdf 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -38,6 +38,7 @@
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <sys/conf.h>
+#include <sys/event.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -210,6 +211,13 @@ static int aio_fphysio(struct proc *p, struct aiocblist *aiocbe, int type);
static int aio_qphysio(struct proc *p, struct aiocblist *iocb);
static void aio_daemon(void *uproc);
+static int filt_aioattach(struct knote *kn);
+static void filt_aiodetach(struct knote *kn);
+static int filt_aio(struct knote *kn, long hint);
+
+struct filterops aio_filtops =
+ { 0, filt_aioattach, filt_aiodetach, filt_aio };
+
SYSINIT(aio, SI_SUB_VFS, SI_ORDER_ANY, aio_onceonly, NULL);
static vm_zone_t kaio_zone = 0, aiop_zone = 0, aiocb_zone = 0, aiol_zone = 0;
@@ -328,6 +336,9 @@ aio_free_entry(struct aiocblist *aiocbe)
num_buf_aio--;
}
+ /* aiocbe is going away, we need to destroy any knotes */
+ knote_remove(p, &aiocbe->klist);
+
if ((ki->kaio_flags & KAIO_WAKEUP) || ((ki->kaio_flags & KAIO_RUNDOWN)
&& ((ki->kaio_buffer_count == 0) && (ki->kaio_queue_count == 0)))) {
ki->kaio_flags &= ~KAIO_WAKEUP;
@@ -806,6 +817,7 @@ aio_daemon(void *uproc)
plist);
}
splx(s);
+ KNOTE(&aiocbe->klist, 0);
if (aiocbe->jobflags & AIOCBLIST_RUNDOWN) {
wakeup(aiocbe);
@@ -933,7 +945,7 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
struct aio_liojob *lj;
int fd;
int s;
- int cnt;
+ int cnt, notify;
cb = &aiocbe->uaiocb;
fdp = p->p_fd;
@@ -1034,6 +1046,7 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
/* Perform transfer. */
DEV_STRATEGY(bp, 0);
+ notify = 0;
s = splbio();
/*
@@ -1059,9 +1072,12 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
TAILQ_REMOVE(&aio_bufjobs, aiocbe, list);
TAILQ_REMOVE(&ki->kaio_bufqueue, aiocbe, plist);
TAILQ_INSERT_TAIL(&ki->kaio_bufdone, aiocbe, plist);
+ notify = 1;
}
}
splx(s);
+ if (notify)
+ KNOTE(&aiocbe->klist, 0);
return 0;
doerror:
@@ -1174,7 +1190,7 @@ _aio_aqueue(struct proc *p, struct aiocb *job, struct aio_liojob *lj, int type)
unsigned int fd;
struct socket *so;
int s;
- int error;
+ int error = 0;
int opcode;
struct aiocblist *aiocbe;
struct aioproclist *aiop;
@@ -1187,6 +1203,7 @@ _aio_aqueue(struct proc *p, struct aiocb *job, struct aio_liojob *lj, int type)
aiocbe->inputcharge = 0;
aiocbe->outputcharge = 0;
+ SLIST_INIT(&aiocbe->klist);
suword(&job->_aiocb_private.status, -1);
suword(&job->_aiocb_private.error, 0);
@@ -1272,6 +1289,45 @@ _aio_aqueue(struct proc *p, struct aiocb *job, struct aio_liojob *lj, int type)
return EINVAL;
}
+ /*
+ * XXX
+ * Figure out how to do this properly. This currently won't
+ * work on the alpha, since we're passing in a pointer via
+ * aio_lio_opcode, which is an int.
+ */
+ {
+ struct kevent kev, *kevp;
+ struct kqueue *kq;
+
+ kevp = (struct kevent *)job->aio_lio_opcode;
+ if (kevp == NULL)
+ goto no_kqueue;
+
+ error = copyin((caddr_t)kevp, (caddr_t)&kev, sizeof(kev));
+ if (error)
+ goto aqueue_fail;
+
+ if ((u_int)kev.ident >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[kev.ident]) == NULL ||
+ (fp->f_type != DTYPE_KQUEUE)) {
+ error = EBADF;
+ goto aqueue_fail;
+ }
+ kq = (struct kqueue *)fp->f_data;
+ kev.ident = (u_long)aiocbe;
+ kev.filter = EVFILT_AIO;
+ kev.flags = EV_ADD | EV_ENABLE | EV_FLAG1;
+ error = kqueue_register(kq, &kev, p);
+aqueue_fail:
+ if (error) {
+ TAILQ_INSERT_HEAD(&aio_freejobs, aiocbe, list);
+ if (type == 0)
+ suword(&job->_aiocb_private.error, error);
+ return (error);
+ }
+no_kqueue:
+ }
+
suword(&job->_aiocb_private.error, EINPROGRESS);
aiocbe->uaiocb._aiocb_private.error = EINPROGRESS;
aiocbe->userproc = p;
@@ -1629,6 +1685,7 @@ aio_cancel(struct proc *p, struct aio_cancel_args *uap)
cbe->uaiocb._aiocb_private.status=-1;
cbe->uaiocb._aiocb_private.error=ECANCELED;
cancelled++;
+/* XXX cancelled, knote? */
if (cbe->uaiocb.aio_sigevent.sigev_notify ==
SIGEV_SIGNAL)
psignal(cbe->userproc, cbe->uaiocb.aio_sigevent.sigev_signo);
@@ -1667,6 +1724,7 @@ aio_cancel(struct proc *p, struct aio_cancel_args *uap)
cbe->jobstate = JOBST_JOBFINISHED;
cbe->uaiocb._aiocb_private.status = -1;
cbe->uaiocb._aiocb_private.error = ECANCELED;
+/* XXX cancelled, knote? */
if (cbe->uaiocb.aio_sigevent.sigev_notify ==
SIGEV_SIGNAL)
psignal(cbe->userproc, cbe->uaiocb.aio_sigevent.sigev_signo);
@@ -2173,7 +2231,8 @@ aio_physwakeup(struct buf *bp)
TAILQ_REMOVE(&aio_bufjobs, aiocbe, list);
TAILQ_REMOVE(&ki->kaio_bufqueue, aiocbe, plist);
TAILQ_INSERT_TAIL(&ki->kaio_bufdone, aiocbe, plist);
-
+
+ KNOTE(&aiocbe->klist, 0);
/* Do the wakeup. */
if (ki->kaio_flags & (KAIO_RUNDOWN|KAIO_WAKEUP)) {
ki->kaio_flags &= ~KAIO_WAKEUP;
@@ -2266,3 +2325,45 @@ aio_waitcomplete(struct proc *p, struct aio_waitcomplete_args *uap)
}
#endif /* VFS_AIO */
}
+
+static int
+filt_aioattach(struct knote *kn)
+{
+ struct aiocblist *aiocbe = (struct aiocblist *)kn->kn_id;
+
+ /*
+ * The aiocbe pointer must be validated before using it, so
+ * registration is restricted to the kernel; the user cannot
+ * set EV_FLAG1.
+ */
+ if ((kn->kn_flags & EV_FLAG1) == 0)
+ return (EPERM);
+ kn->kn_flags &= ~EV_FLAG1;
+
+ SLIST_INSERT_HEAD(&aiocbe->klist, kn, kn_selnext);
+
+ return (0);
+}
+
+static void
+filt_aiodetach(struct knote *kn)
+{
+ struct aiocblist *aiocbe = (struct aiocblist *)kn->kn_id;
+ int s = splhigh(); /* XXX no clue, so overkill */
+
+ SLIST_REMOVE(&aiocbe->klist, kn, knote, kn_selnext);
+ splx(s);
+}
+
+/*ARGSUSED*/
+static int
+filt_aio(struct knote *kn, long hint)
+{
+ struct aiocblist *aiocbe = (struct aiocblist *)kn->kn_id;
+
+ kn->kn_data = 0; /* XXX data returned? */
+ if (aiocbe->jobstate != JOBST_JOBFINISHED)
+ return (0);
+ kn->kn_flags |= EV_EOF;
+ return (1);
+}
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 9f1a387..705ac34 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -54,6 +54,9 @@
#include <sys/conf.h>
#include <vm/vm_zone.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+
static int vn_closefile __P((struct file *fp, struct proc *p));
static int vn_ioctl __P((struct file *fp, u_long com, caddr_t data,
struct proc *p));
@@ -68,6 +71,25 @@ static int vn_write __P((struct file *fp, struct uio *uio,
struct fileops vnops =
{ vn_read, vn_write, vn_ioctl, vn_poll, vn_statfile, vn_closefile };
+static int filt_nullattach(struct knote *kn);
+static int filt_vnattach(struct knote *kn);
+static void filt_vndetach(struct knote *kn);
+static int filt_vnode(struct knote *kn, long hint);
+static int filt_vnread(struct knote *kn, long hint);
+
+struct filterops vn_filtops =
+ { 1, filt_vnattach, filt_vndetach, filt_vnode };
+
+/*
+ * XXX
+ * filt_vnread is ufs-specific, so the attach routine should really
+ * switch out to different filterops based on the vn filetype
+ */
+struct filterops vn_rwfiltops[] = {
+ { 1, filt_vnattach, filt_vndetach, filt_vnread },
+ { 1, filt_nullattach, NULL, NULL },
+};
+
/*
* Common code for vnode open operations.
* Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
@@ -637,3 +659,58 @@ vn_closefile(fp, p)
return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
fp->f_cred, p));
}
+
+static int
+filt_vnattach(struct knote *kn)
+{
+ struct vnode *vp;
+
+ if (kn->kn_fp->f_type != DTYPE_VNODE &&
+ kn->kn_fp->f_type != DTYPE_FIFO)
+ return (EBADF);
+
+ vp = (struct vnode *)kn->kn_fp->f_data;
+
+ simple_lock(&vp->v_pollinfo.vpi_lock);
+ SLIST_INSERT_HEAD(&vp->v_pollinfo.vpi_selinfo.si_note, kn, kn_selnext);
+ simple_unlock(&vp->v_pollinfo.vpi_lock);
+
+ return (0);
+}
+
+static void
+filt_vndetach(struct knote *kn)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_fp->f_data;
+
+ simple_lock(&vp->v_pollinfo.vpi_lock);
+ SLIST_REMOVE(&vp->v_pollinfo.vpi_selinfo.si_note,
+ kn, knote, kn_selnext);
+ simple_unlock(&vp->v_pollinfo.vpi_lock);
+}
+
+static int
+filt_vnode(struct knote *kn, long hint)
+{
+
+ if (kn->kn_sfflags & hint)
+ kn->kn_fflags |= hint;
+ return (kn->kn_fflags != 0);
+}
+
+static int
+filt_nullattach(struct knote *kn)
+{
+ return (ENXIO);
+}
+
+/*ARGSUSED*/
+static int
+filt_vnread(struct knote *kn, long hint)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_fp->f_data;
+ struct inode *ip = VTOI(vp);
+
+ kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
+ return (kn->kn_data != 0);
+}
OpenPOWER on IntegriCloud