aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_poll.c
diff options
context:
space:
mode:
authorLuigi Rizzo <luigi@FreeBSD.org>2001-12-19 00:53:24 +0000
committerLuigi Rizzo <luigi@FreeBSD.org>2001-12-19 00:53:24 +0000
commitd105c784d584bac2bdb5aea33b9f0582ab4ddf40 (patch)
treefb12a94e11c8a6f3660b42b61b4bb003d29dbb1e /sys/kern/kern_poll.c
parent885ccc61f2e01896a312fc107099764f681d9f61 (diff)
downloadsrc-d105c784d584bac2bdb5aea33b9f0582ab4ddf40.tar.gz
src-d105c784d584bac2bdb5aea33b9f0582ab4ddf40.zip
Complete the device polling support by adding a thread in charge
of polling interfaces at the lowest possible priority (this might result in softnetisr being scheduled, but there is no risk of livelock because they have a higher priority than this thread).
Notes
Notes: svn path=/head/; revision=88156
Diffstat (limited to 'sys/kern/kern_poll.c')
-rw-r--r--sys/kern/kern_poll.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/sys/kern/kern_poll.c b/sys/kern/kern_poll.c
index 763e5cb25628..5a2051fcb406 100644
--- a/sys/kern/kern_poll.c
+++ b/sys/kern/kern_poll.c
@@ -34,6 +34,10 @@
#include <net/if.h> /* for IFF_* flags */
#include <net/netisr.h> /* for NETISR_POLL */
+#include <sys/proc.h>
+#include <sys/resourcevar.h>
+#include <sys/kthread.h>
+
#ifdef SMP
#error DEVICE_POLLING is not compatible with SMP
#endif
@@ -132,6 +136,14 @@ static u_int32_t poll_handlers; /* next free entry in pr[]. */
SYSCTL_ULONG(_kern_polling, OID_AUTO, handlers, CTLFLAG_RD,
&poll_handlers, 0, "Number of registered poll handlers");
+static u_int32_t poll_in_idle=1; /* boolean */
+SYSCTL_ULONG(_kern_polling, OID_AUTO, poll_in_idle, CTLFLAG_RW,
+ &poll_in_idle, 0, "Poll during idle loop");
+
+static u_int32_t idlepoll_sleeping; /* idlepoll is sleeping */
+SYSCTL_ULONG(_kern_polling, OID_AUTO, idlepoll_sleeping, CTLFLAG_RD,
+ &idlepoll_sleeping, 0, "idlepoll is sleeping");
+
static int polling = 0; /* global polling enable */
SYSCTL_ULONG(_kern_polling, OID_AUTO, enable, CTLFLAG_RW,
&polling, 0, "Polling enabled");
@@ -382,6 +394,8 @@ ether_poll_register(poll_handler_t *h, struct ifnet *ifp)
poll_handlers++;
ifp->if_ipending |= IFF_POLLING;
splx(s);
+ if (idlepoll_sleeping)
+ wakeup(&idlepoll_sleeping);
return 1; /* polling enabled in next call */
}
@@ -420,3 +434,44 @@ ether_poll_deregister(struct ifnet *ifp)
mtx_unlock(&Giant);
return 1;
}
+
+static void
+poll_idle(void)
+{
+ struct thread *td = curthread;
+ struct rtprio rtp;
+ int pri;
+
+ rtp.prio = RTP_PRIO_MAX; /* lowest priority */
+ rtp.type = RTP_PRIO_IDLE;
+ mtx_lock_spin(&sched_lock);
+ rtp_to_pri(&rtp, &td->td_ksegrp->kg_pri);
+ pri = td->td_ksegrp->kg_pri.pri_level;
+ mtx_unlock_spin(&sched_lock);
+
+ for (;;) {
+ if (poll_in_idle && poll_handlers > 0) {
+ idlepoll_sleeping = 0;
+ mtx_lock(&Giant);
+ ether_poll(poll_each_burst);
+ mtx_unlock(&Giant);
+ mtx_assert(&Giant, MA_NOTOWNED);
+ mtx_lock_spin(&sched_lock);
+ setrunqueue(td);
+ td->td_proc->p_stats->p_ru.ru_nvcsw++;
+ mi_switch();
+ mtx_unlock_spin(&sched_lock);
+ } else {
+ idlepoll_sleeping = 1;
+ tsleep(&idlepoll_sleeping, pri, "pollid", hz * 3);
+ }
+ }
+}
+
+static struct proc *idlepoll;
+static struct kproc_desc idlepoll_kp = {
+ "idlepoll",
+ poll_idle,
+ &idlepoll
+};
+SYSINIT(idlepoll, SI_SUB_KTHREAD_VM, SI_ORDER_ANY, kproc_start, &idlepoll_kp)