Ethernet device polling(4)

ether_pollでは、netisrを使った定期的pollingの他にもCPUのidle時に実行されるidle pollが実装されているようだ。
以下、その実装を見ていく。

SYSINITにより、poll_idle()を実行するプロセスidlepollが作成・実行される。

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)

poll_idleはlowest priorityに設定され、CPUがidleになった時だけether_poll()を実行する。

static void
poll_idle(void)
{
	struct thread *td = curthread;
	struct rtprio rtp;

	rtp.prio = RTP_PRIO_MAX;	/* lowest priority */
	rtp.type = RTP_PRIO_IDLE;
	PROC_SLOCK(td->td_proc);
	rtp_to_pri(&rtp, td);
	PROC_SUNLOCK(td->td_proc);

	for (;;) {
		if (poll_in_idle_loop && poll_handlers > 0) {
			idlepoll_sleeping = 0;
			ether_poll(poll_each_burst);
			thread_lock(td);
			mi_switch(SW_VOL, NULL);
			thread_unlock(td);
		} else {
			idlepoll_sleeping = 1;
			tsleep(&idlepoll_sleeping, 0, "pollid", hz * 3);
		}
	}
}

ether_poll()は単にhandlerを実行する。

/*
 * ether_poll is called from the idle loop.
 */
void
ether_poll(int count)
{
	int i;

	mtx_lock(&poll_mtx);

	if (count > poll_each_burst)
		count = poll_each_burst;

	for (i = 0 ; i < poll_handlers ; i++)
		pr[i].handler(pr[i].ifp, POLL_ONLY, count);

	mtx_unlock(&poll_mtx);
}

poll_each_burstで長すぎるpollingを抑止する点以外は、ミニマムで非常にわかりやすい実装になっている。
というか、netisr側が複雑すぎるだけだと思うが。