Protect the event queue with a simple mutex; this only partially addresses

MP-safety issues in the event handling system.
This commit is contained in:
pk 2003-02-23 22:05:35 +00:00
parent 8bf6b72335
commit 025e435477
2 changed files with 31 additions and 10 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_event.c,v 1.11 2003/02/23 21:44:26 pk Exp $ */
/* $NetBSD: kern_event.c,v 1.12 2003/02/23 22:05:35 pk Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
* All rights reserved.
@ -626,6 +626,7 @@ sys_kqueue(struct lwp *l, void *v, register_t *retval)
fp->f_ops = &kqueueops;
kq = pool_get(&kqueue_pool, PR_WAITOK);
memset((char *)kq, 0, sizeof(struct kqueue));
simple_lock_init(&kq->kq_lock);
TAILQ_INIT(&kq->kq_head);
fp->f_data = (caddr_t)kq; /* store the kqueue with the fp */
*retval = fd;
@ -923,12 +924,14 @@ kqueue_scan(struct file *fp, size_t maxevents, struct kevent *ulistp,
start:
kevp = kq->kq_kev;
s = splsched();
simple_lock(&kq->kq_lock);
if (kq->kq_count == 0) {
if (timeout < 0) {
error = EWOULDBLOCK;
} else {
kq->kq_state |= KQ_SLEEP;
error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout);
error = ltsleep(kq, PSOCK | PCATCH | PNORELOCK,
"kqread", timeout, &kq->kq_lock);
}
splx(s);
if (error == 0)
@ -943,20 +946,26 @@ kqueue_scan(struct file *fp, size_t maxevents, struct kevent *ulistp,
/* mark end of knote list */
TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe);
simple_unlock(&kq->kq_lock);
while (count) { /* while user wants data ... */
simple_lock(&kq->kq_lock);
kn = TAILQ_FIRST(&kq->kq_head); /* get next knote */
TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
if (kn == &marker) { /* if it's our marker, stop */
/* What if it's some else's marker? */
simple_unlock(&kq->kq_lock);
splx(s);
if (count == maxevents)
goto retry;
goto done;
}
kq->kq_count--;
simple_unlock(&kq->kq_lock);
if (kn->kn_status & KN_DISABLED) {
/* don't want disabled events */
kn->kn_status &= ~KN_QUEUED;
kq->kq_count--;
continue;
}
if ((kn->kn_flags & EV_ONESHOT) == 0 &&
@ -966,7 +975,6 @@ kqueue_scan(struct file *fp, size_t maxevents, struct kevent *ulistp,
* triggered again, so de-queue.
*/
kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
kq->kq_count--;
continue;
}
*kevp = kn->kn_kevent;
@ -975,7 +983,6 @@ kqueue_scan(struct file *fp, size_t maxevents, struct kevent *ulistp,
if (kn->kn_flags & EV_ONESHOT) {
/* delete ONESHOT events after retrieval */
kn->kn_status &= ~KN_QUEUED;
kq->kq_count--;
splx(s);
kn->kn_fop->f_detach(kn);
knote_drop(kn, p, p->p_fd);
@ -985,10 +992,12 @@ kqueue_scan(struct file *fp, size_t maxevents, struct kevent *ulistp,
kn->kn_data = 0;
kn->kn_fflags = 0;
kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
kq->kq_count--;
} else {
/* add event back on list */
simple_lock(&kq->kq_lock);
TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
kq->kq_count++;
simple_unlock(&kq->kq_lock);
}
count--;
if (nkev == KQ_NEVENTS) {
@ -1006,7 +1015,9 @@ kqueue_scan(struct file *fp, size_t maxevents, struct kevent *ulistp,
}
/* remove marker */
simple_lock(&kq->kq_lock);
TAILQ_REMOVE(&kq->kq_head, &marker, kn_tqe);
simple_unlock(&kq->kq_lock);
splx(s);
done:
if (nkev != 0) {
@ -1209,7 +1220,10 @@ kqueue_close(struct file *fp, struct proc *p)
static void
kqueue_wakeup(struct kqueue *kq)
{
int s;
s = splsched();
simple_lock(&kq->kq_lock);
if (kq->kq_state & KQ_SLEEP) { /* if currently sleeping ... */
kq->kq_state &= ~KQ_SLEEP;
wakeup(kq); /* ... wakeup */
@ -1217,6 +1231,8 @@ kqueue_wakeup(struct kqueue *kq)
/* Notify select/poll and kevent. */
selnotify(&kq->kq_sel, 0);
simple_unlock(&kq->kq_lock);
splx(s);
}
/*
@ -1371,12 +1387,14 @@ knote_enqueue(struct knote *kn)
int s;
kq = kn->kn_kq;
s = splsched();
KASSERT((kn->kn_status & KN_QUEUED) == 0);
s = splsched();
simple_lock(&kq->kq_lock);
TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
kn->kn_status |= KN_QUEUED;
kq->kq_count++;
simple_unlock(&kq->kq_lock);
splx(s);
kqueue_wakeup(kq);
}
@ -1390,12 +1408,14 @@ knote_dequeue(struct knote *kn)
struct kqueue *kq;
int s;
kq = kn->kn_kq;
s = splsched();
KASSERT(kn->kn_status & KN_QUEUED);
kq = kn->kn_kq;
s = splsched();
simple_lock(&kq->kq_lock);
TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
kn->kn_status &= ~KN_QUEUED;
kq->kq_count--;
simple_unlock(&kq->kq_lock);
splx(s);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: eventvar.h,v 1.3 2002/10/23 09:14:56 jdolecek Exp $ */
/* $NetBSD: eventvar.h,v 1.4 2003/02/23 22:05:35 pk Exp $ */
/*-
* Copyright (c) 1999,2000 Jonathan Lemon <jlemon@FreeBSD.org>
* All rights reserved.
@ -38,6 +38,7 @@
struct kqueue {
TAILQ_HEAD(kqlist, knote) kq_head; /* list of pending event */
int kq_count; /* number of pending events */
struct simplelock kq_lock; /* mutex for queue access */
struct selinfo kq_sel;
struct filedesc *kq_fdp;
int kq_state;