在应用层,使用timeout是做不到延迟微秒级别,甚至在很多架构上,连ms都做不多,为什么这样说,线索如下:
timeout = ROUND_UP(usec, 1000000/HZ);
timeout += sec * (unsigned long) HZ;
#define ROUND_UP(x,y) (((x)+(y)-1)/(y)),这里假设sec为0。
在x86,hz为100,当usec<10000,也就是小于10ms的时候,在kernel里面,会认为,是一个10ms的timeout,也就是一个hz(一个时钟中断),所以精度只能到达10ms。
通过函数schedule_timeout,把进程主动调度出去,schedule()。
在kernel里面使用的udelay是完全不一样,
udelay 通过下面的来实现:
udelay函数通过BogoMIPS实现。Bogo的意思是Bogus,MIPS的意思是每秒百万条指令(million of instructions per second)
BogoMIPS纪录处理器在给定时间内忙循环执行的次数(该值存放在loops_per_jiffy),所以udelay函数仅仅需要根据指定时间在1秒所占的比例,就可以知道执行多少次循环能达到要求的推迟时间。
inline void __const_udelay( unsigned long xloops)
{
int d0;
xloops * = 4;
/* 这段汇编取出每CPU的loops_per_jiffy的值,*/
/* 乘上HZ表示每秒执行的指令条数,最后与xloops相乘 */
/* 乘法会溢出,将高32bit放入寄存器edx,将低32bit的值放入寄存器eax */
/* xloops保留了高32bit的值 */
__asm__ ( "mull %0"
: "=d" ( xloops) , "=&a" ( d0)
: "1" ( xloops) , "0"
( cpu_data[ raw_smp_processor_id( ) ] . loops_per_jiffy * ( HZ/ 4) ) ) ;
/* 调用__delay函数,这里之所以要再++,我估计是弥补低32bit的精度损失 */
__delay( + + xloops) ;
}
void __udelay( unsigned long usecs)
{
/* 微妙换算成秒,数值太小,乘上2**32,即左移32bit */
__const_udelay( usecs * 0x000010c7) ; /* 2**32 / 1000000 (rounded up) */
}
static void delay_loop( unsigned long loops)
{
int d0;
__asm__ __volatile__(
"/tjmp 1f/n"
".align 16/n"
"1:/tjmp 2f/n"
".align 16/n"
"2:/tdecl %0/n/tjns 2b"
: "=&a" ( d0)
: "0" ( loops) ) ;
}
static void ( * delay_fn) ( unsigned long ) = delay_loop;
void __delay( unsigned long loops)
{
delay_fn( loops) ;
}