udelay & mdelay
driver常常會需要很短且精準的delay(n microsecond/millisecond),以完成sync。此時用jiffies就不恰當,第一單位不夠小,如果timer是100Hz,表示一個tick是10 millisecond。第二不夠準,因為透過scheduler。在kernel裡有兩個function來完成很小的delay,不使用jiffies:
在<linux/delay.h>
void udelay(unsigned long usecs) void mdelay(unsigned long msecs)
兩個都是busy waiting。udelay的實作要先談BogoMIPS,這個值是指在特定時間內CPU可執行多少個busy loop operation。也就是說,這個CPU不做任何事可以多快 (how fast a processor can do nothing)。這個值在kernel裡是一個叫做loops_per_jiffy的變數,在userspace則可在/proc/cpuinfo裡找到。而kernel是在init/main.c裡透過calibrate_delay()這個function來計算。值得一提的是這個值是跟performance沒太大關係的。
這個BogoMIPS主要就是用來實作udelay。udelay去算需要多少個loop operation來得到精確的delay。
使用udelay要小心overflow,它適合很短的delay,通常不超過1 millisecond。長一點的delay就用mdelay。要注意的是udelay和mdelay會影響performance,因為CPU無法做任何其他事,所以通常是用來delay以microsecond為單位比較適合。
schedule_timeout()
另一種delay是schedule_timeout()。與上述不同的是這會進入sleep state,直到指定的時間結束,而不是busy waiting。另一個是不那麼精確,因為睡完是進入run queue。使用方式是:
/* set task's state to interruptible sleep */ set_current_state(TASK_INTERRUPTIBLE); /* take a nap and wake up in "s" seconds */ schedule_timeout(s * HZ);
可看出這是使用jiffies。上面的code是將這個process在interruptible的情況下睡s秒。state必須要在TASK_INTERRUPTIBLE或是TASK_UNINTERRUPTIBLE執行schedule_timeout才會進入sleep。
Reference