diff options
author | jeff <jeff@FreeBSD.org> | 2007-12-16 06:21:20 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2007-12-16 06:21:20 +0000 |
commit | 4ec9caf00c407884fc51ff18adb8ff16a5eb75c0 (patch) | |
tree | e3b97a4fccf98fcc3311ea54b086b57edb1abb4d /sys/kern/kern_event.c | |
parent | 436e8270ebc964cc1f1effe79ac5c10e92e78f7b (diff) | |
download | FreeBSD-src-4ec9caf00c407884fc51ff18adb8ff16a5eb75c0.zip FreeBSD-src-4ec9caf00c407884fc51ff18adb8ff16a5eb75c0.tar.gz |
Refactor select to reduce contention and hide internal implementation
details from consumers.
- Track individual selecters on a per-descriptor basis such that there
are no longer collisions and after sleeping for events only those
descriptors which triggered events must be rescaned.
- Protect the selinfo (per descriptor) structure with a mtx pool mutex.
mtx pool mutexes were chosen to preserve api compatibility with
existing code which does nothing but bzero() to setup selinfo
structures.
- Use a per-thread wait channel rather than a global wait channel.
- Hide select implementation details in a seltd structure which is
opaque to the rest of the kernel.
- Provide a 'selsocket' interface for those kernel consumers who wish to
select on a socket when they have no fd so they no longer have to
be aware of select implementation details.
Tested by: kris
Reviewed on: arch
Diffstat (limited to 'sys/kern/kern_event.c')
-rw-r--r-- | sys/kern/kern_event.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index aa446b6..4d75822 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1400,7 +1400,8 @@ kqueue_poll(struct file *fp, int events, struct ucred *active_cred, revents |= events & (POLLIN | POLLRDNORM); } else { selrecord(td, &kq->kq_sel); - kq->kq_state |= KQ_SEL; + if (SEL_WAITING(&kq->kq_sel)) + kq->kq_state |= KQ_SEL; } } kqueue_release(kq, 1); @@ -1486,8 +1487,9 @@ kqueue_close(struct file *fp, struct thread *td) } if ((kq->kq_state & KQ_SEL) == KQ_SEL) { - kq->kq_state &= ~KQ_SEL; selwakeuppri(&kq->kq_sel, PSOCK); + if (!SEL_WAITING(&kq->kq_sel)) + kq->kq_state &= ~KQ_SEL; } KQ_UNLOCK(kq); @@ -1522,8 +1524,9 @@ kqueue_wakeup(struct kqueue *kq) wakeup(kq); } if ((kq->kq_state & KQ_SEL) == KQ_SEL) { - kq->kq_state &= ~KQ_SEL; selwakeuppri(&kq->kq_sel, PSOCK); + if (!SEL_WAITING(&kq->kq_sel)) + kq->kq_state &= ~KQ_SEL; } if (!knlist_empty(&kq->kq_sel.si_note)) kqueue_schedtask(kq); |