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側が複雑すぎるだけだと思うが。