设为首页 友情链接
在线留言 发表文章
加入收藏 广告联系

刺猬首页

| 专案技术 | 网络技术 | 图形图象 | 网络编程 | 网页设计 | 操作系统 | 服务器 | 技术白皮书 | 在线实验室 | 刺猬论坛 |
小说专版  | 数据库 | 设计赏析 | 存储频道 | 网络安全 | 私服架设 |  Solaris | 网站评估 | PC维护技巧 | 下载中心 | 博 客 |
专   题: | Linux | java | cisco | 防病毒 | 刀片 | SOA | iscsi | ASP.NET | SQL | Oracle |
您现在的位置: IT公社 IT community >> Linux专题 >> 内核研究 >> 教程正文 用户登录 新用户注册
专 题 栏 目
最 新 热 门
最 新 推 荐
相 关 文 章
Fedora Core linux中设置…
Linux操作系统桌面应用大…
Linux端口扫描工具nmap …
Linux下的 podcast 软件
Linux的使用,学好这,走…
Linux 入门常用命令
Linux中用ALSA驱动声卡流…
关于Linux系统中调整刷新…
Linux查看磁盘分区等命令…
在Linux系统中批量添加用…
  Linux系统进程间隔定时器Itimer(下)         
Linux系统进程间隔定时器Itimer(下)
 

7.7.3.1 getitimer()系统调用的实现

函数sys_getitimer()有两个参数:(1)which,指定查询调用进程的哪一个间隔定时器,其取值可以是ITIMER_REAL、ITIMER_VIRT和ITIMER_PROF三者之一。(2)value指针,指向用户空间中的一个itimerval结构,用于接收查询结果。该函数的源码如下:

/* SMP: Only we modify our itimer values. */ 

asmlinkage long sys_getitimer(int which, struct itimerval *value) 

{ 

int error = -EFAULT; 

struct itimerval get_buffer; 



if (value) { 

error = do_getitimer(which, &get_buffer); 

if (!error && 

copy_to_user(value, &get_buffer, sizeof(get_buffer))) 

error = -EFAULT; 

} 

return error; 

}

显然,sys_getitimer()函数主要通过do_getitimer()函数来查询当前进程的间隔定时器信息,并将查询结果保存在内核空间的结构变量get_buffer中。然后,调用copy_to_usr()宏将 get_buffer中结果拷贝到用户空间缓冲区中。

函数do_getitimer()的源码如下(kernel/itimer.c):

int do_getitimer(int which, struct itimerval *value) 

{ 

register unsigned long val, interval; 



switch (which) { 

case ITIMER_REAL: 

interval = current->it_real_incr; 

val = 0; 

/* 

* FIXME! This needs to be atomic, in case the kernel timer happens! 

*/ 

if (timer_pending(¤t->real_timer)) { 

val = current->real_timer.expires - jiffies; 



/* look out for negative/zero itimer.. */ 

if ((long) val <= 0) 

val = 1; 

} 

break; 

case ITIMER_VIRTUAL: 

val = current->it_virt_value; 

interval = current->it_virt_incr; 

break; 

case ITIMER_PROF: 

val = current->it_prof_value; 

interval = current->it_prof_incr; 

break; 

default: 

return(-EINVAL); 

} 

jiffiestotv(val, &value->it_value); 

jiffiestotv(interval, &value->it_interval); 

return 0; 

}

查询的过程如下:

(1)首先,用局部变量val和interval分别表示待查询间隔定时器的间隔计数器的当前值和初始值。

(2)如果which=ITIMER_REAL,则查询当前进程的 ITIMER_REAL间隔定时器。于是从current->it_real_incr中得到ITIMER_REAL间隔定时器的间隔计数器的初始值,并将其保存到interval局部变量中。而对于间隔计数器的当前值,由于ITITMER_REAL间隔定时器是通过real_timer这个内核动态定时器来实现的,因此不能通过current->it_real_value来获得ITIMER_REAL间隔定时器的间隔计数器的当前值,而必须通过real_timer来得到这个值。为此先用timer_pending()函数来判断current->real_timer是否已被起动。如果未启动,则说明ITIMER_REAL间隔定时器也未启动,因此其间隔计数器的当前值肯定是0。因此将val变量简单地置0就可以了。如果已经启动,则间隔计数器的当前值应该等于(timer_real.expires-jiffies)。

(3)如果which=ITIMER_VIRT,则查询当前进程的ITIMER_VIRT间隔定时器。于是简单地将计数器初值it_virt_incr和当前值it_virt_value分别保存到局部变量interval和val中。

(4)如果which=ITIMER_PROF,则查询当前进程的ITIMER_PROF间隔定时器。于是简单地将计数器初值it_prof_incr和当前值it_prof_value分别保存到局部变量interval和val中。

(5)最后,通过转换函数jiffiestotv()将val和interval转换成timeval格式的时间值,并保存到value->it_value和value->it_interval中,作为查询结果返回。

7.7.3.2 setitimer()系统调用的实现

函数sys_setitimer()不仅设置调用进程的指定间隔定时器,而且还返回该间隔定时器的原有信息。它有三个参数:(1)which,含义与sys_getitimer()中的参数相同。(2)输入参数value,指向用户空间中的一个itimerval结构,含有待设置的新值。(3)输出参数ovalue,指向用户空间中的一个itimerval结构,用于接收间隔定时器的原有信息。

该函数的源码如下(kernel/itimer.c):

/* SMP: Again, only we play with our itimers, and signals are SMP safe 

* now so that is not an issue at all anymore. 

*/ 

asmlinkage long sys_setitimer(int which, struct itimerval *value, 

struct itimerval *ovalue) 

{ 

struct itimerval set_buffer, get_buffer; 

int error; 



if (value) { 

if(copy_from_user(&set_buffer, value, sizeof(set_buffer))) 

return -EFAULT; 

} else 

memset((char *) &set_buffer, 0, sizeof(set_buffer)); 



error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); 

if (error || !ovalue) 

return error; 



if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer))) 

return -EFAULT; 

return 0; 

}

对该函数的注释如下:

(1)在输入参数指针value非空的情况下,调用copy_from_user()宏将用户空间中的待设置信息拷贝到内核空间中的set_buffer结构变量中。如果value指针为空,则简单地将set_buffer结构变量全部置0。

(2)调用do_setitimer()函数完成实际的设置操作。如果输出参数 ovalue指针有效,则以内核变量get_buffer的地址作为do_setitimer()函数的第三那个调用参数,这样当 do_setitimer()函数返回时,get_buffer结构变量中就将含有当前进程的指定间隔定时器的原来信息。Do_setitimer()函数返回0值表示成功,非0值表示失败。

(3)在do_setitimer()函数返回非0值的情况下,或者ovalue指针为空的情况下(不需要输出间隔定时器的原有信息),函数就可以直接返回了。

(4)如果ovalue指针非空,调用copy_to_user()宏将get_buffer()结构变量中值拷贝到ovalue所指向的用户空间中去,以便让用户得到指定间隔定时器的原有信息值。

函数do_setitimer()的源码如下(kernel/itimer.c):

int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) 

{ 

register unsigned long i, j; 

int k; 



i = tvtojiffies(&value->it_interval); 

j = tvtojiffies(&value->it_value); 

if (ovalue && (k = do_getitimer(which, ovalue)) < 0) 

return k; 

switch (which) { 

case ITIMER_REAL: 

del_timer_sync(¤t->real_timer); 

current->it_real_value = j; 

current->it_real_incr = i; 

if (!j) 

break; 

if (j > (unsigned long) LONG_MAX) 

j = LONG_MAX; 

i = j + jiffies; 

current->real_timer.expires = i; 

add_timer(¤t->real_timer); 

break; 

case ITIMER_VIRTUAL: 

if (j) 

j++; 

current->it_virt_value = j; 

current->it_virt_incr = i; 

break; 

case ITIMER_PROF: 

if (j) 

j++; 

current->it_prof_value = j; 

current->it_prof_incr = i; 

break; 

default: 

return -EINVAL; 

} 

return 0; 

}

对该函数的注释如下:

(1)首先调用tvtojiffies()函数将timeval格式的初始值和当前值转换成以时钟滴答为单位的时间值。并分别保存在局部变量i和j中。

(2)如果ovalue指针非空,则调用do_getitimer()函数查询指定间隔定时器的原来信息。如果do_getitimer()函数返回负值,说明出错。因此就要直接返回错误值。否则继续向下执行开始真正地设置指定的间隔定时器。

(3)如果which=ITITMER_REAL,表示设置ITIMER_REAL 间隔定时器。(a)调用del_timer_sync()函数(该函数在单CPU系统中就是del_timer()函数)将当前进程的 real_timer定时器从内核动态定时器链表中删除。(b)将it_real_incr和it_real_value分别设置为局部变量i和j。(c)如果j=0,说明不必启动real_timer定时器,因此执行break语句退出switch…case控制结构,而直接返回。(d)将 real_timer的expires成员设置成(jiffies+当前值j),然后调用add_timer()函数将当前进程的real_timer定时器加入到内核动态定时器链表中,从而启动该定时器。

(4)如果which=ITIMER_VIRT,则简单地用局部变量i和j的值分别更新it_virt_incr和it_virt_value就可以了。

(5)如果which=ITIMER_PROF,则简单地用局部变量i和j的值分别更新it_prof_incr和it_prof_value就可以了。

(6)最后,返回0值表示成功。

7.7.3.3 alarm系统调用

系统调用alarm可以让调用进程在指定的秒数间隔后收到一个SIGALRM信号。它只有一个参数seconds,指定以秒数计的定时间隔。函数sys_alarm()的源码如下(kernel/timer.c):

/* 

* For backwards compatibility? This can be done in libc so Alpha 

* and all newer ports shouldn't need it. 

*/ 

asmlinkage unsigned long sys_alarm(unsigned int seconds) 

{ 

struct itimerval it_new, it_old; 

unsigned int oldalarm; 



it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; 

it_new.it_value.tv_sec = seconds; 

it_new.it_value.tv_usec = 0; 

do_setitimer(ITIMER_REAL, &it_new, &it_old); 

oldalarm = it_old.it_value.tv_sec; 

/* ehhh.. We can't return 0 if we have an alarm pending.. */ 

/* And we'd better return too much than too little anyway */ 

if (it_old.it_value.tv_usec) 

oldalarm++; 

return oldalarm; 

}

这个系统调用实际上就是启动进程的ITIMER_REAL间隔定时器。因此它完全可放到用户空间的C函数库(比如libc和glibc)中来实现。但是为了保此内核的向后兼容性,2.4.0版的内核仍然将这个syscall放在内核空间中来实现。函数sys_alarm()的实现过程如下:

(1)根据参数seconds的值构造一个itimerval结构变量it_new。注意!由于alarm启动的ITIMER_REAL间隔定时器是一次性而不是循环重复的,因此it_new变量中的it_interval成员一定要设置为0。

(2)调用函数do_setitimer()函数以新构造的定时器it_new来启动当前进程的ITIMER_REAL定时器,同时将该间隔定时器的原定时间隔保存到局部变量it_old中。

(3)返回值oldalarm表示以秒数计的ITIMER_REAL间隔定时器的原定时间隔值。因此先把it_old.it_value.tv_sec赋给oldalarm,并且在it_old.it_value.tv_usec非0的情况下,将oldalarm的值加1(也即不足1秒补足1秒)。

Linux联盟收集整理

频道声明:本频道的文章除部分特别声明禁止转载的专稿外,可以自由转载.但请务必注明出出处和原始作者 文章版权归本频道与文章作者所有.对于被频道转载文章的个人和网站,我们表示深深的谢意。

原始作者:佚名 录入时间:2007-1-2 4:07:48
信息来源:不详 投稿信箱:itqoo@126.com
教程录入:itqoo    责任编辑:itqoo 
  • 上一个教程:

  • 下一个教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    - 关于我们 - 合作伙伴 - 友情链接 - 广告刊登 - 投稿热线 - 在线留言版权声明联系方式 -
    IT公社版权所有 粤ICP备05127012号
    Copyrigh@2005-2006 itqoo.com.Inc All Rights Reserved  推荐分辨率 1024*768
    联系站长:E-Mail:itqoo@126.com     MSN:urchincc@hotmail.com    QQ:点击这里给我发消息
    特别感谢:亿太网络提供空间支持