summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_poll.c
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2001-12-19 00:53:24 +0000
committerluigi <luigi@FreeBSD.org>2001-12-19 00:53:24 +0000
commitb6f2ecc1bc577a570ceedb0703995500720edece (patch)
treefb12a94e11c8a6f3660b42b61b4bb003d29dbb1e /sys/kern/kern_poll.c
parent5463e6afe56977ea4feef1f96bc380644a508627 (diff)
downloadFreeBSD-src-b6f2ecc1bc577a570ceedb0703995500720edece.zip
FreeBSD-src-b6f2ecc1bc577a570ceedb0703995500720edece.tar.gz
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).
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 763e5cb..5a2051f 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)
OpenPOWER on IntegriCloud