del_timer与del_timer_sync的区别 测试结果与LKD3描述不同
本帖最后由 瀚海书香 于 2010-11-26 10:18 编辑根据LKD3上的说法,在允许睡眠的情况下,应该使用del_timer_sync函数来取消掉timer,因为del_timer在多核的系统上可能会导致core 1去del_timer时,core 0上正在运行timer,从而导致bug。但是我实际测试了一下在双核的情况下,并没有出现问题?
下面是我的测试代码。
timer的内核代码:#include <linux/module.h>
#include <linux/version.h>
#include <asm/param.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("timer");
struct timer_list timer;
static void fun(unsigned long arg)
{
char *v=arg;
unsigned long now = jiffies;
unsigned int i;
printk("%s\n",v);
while(jiffies < (now+10*HZ)){
cpu_relax();
}
/*for(i=0;i<20000;i++)
printk(KERN_INFO "%s\n",v);*/
printk("%s\n",v);
mod_timer(&timer,jiffies+HZ*5);
printk(KERN_ALERT "%u\n",HZ);
}
static int __init init(void)
{
char *var="ltw\n";
init_timer(&timer);
timer.function=&fun;
timer.expires=jiffies+HZ;
timer.data=var;
add_timer(&timer);
return 0;
}
static void __exit fini(void)
{
del_timer(&timer);
return;
}
module_init(init);
module_exit(fini);指定cpu去卸载模块的代码delmodule:#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <unistd.h>
#define __USE_GNU
#include <sched.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char* argv[])
{
int num = sysconf(_SC_NPROCESSORS_CONF);
int created_thread = 0;
int myid;
int i;
int j = 0;
cpu_set_t mask;
cpu_set_t get;
if (argc != 2){
printf("usage : ./cpu num\n");
exit(1);
}
myid = atoi(argv);
printf("system has %i processor(s). \n", num);
CPU_ZERO(&mask);
CPU_SET(myid, &mask);
if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
{
printf("warning: could not set CPU affinity, continuing...\n");
}
CPU_ZERO(&get);
if (sched_getaffinity(0, sizeof(get), &get) == -1)
for (i = 0; i < num; i++)
{
if (CPU_ISSET(i, &get))
printf("this process %d is running processor : %d\n",getpid(), i);
}
sleep(3);
system("rmmod timer.ko");
return 0;
}
首先在一个终端运行./delmodule 1指定cpu 1在3秒后执行rmmod. 同时在另一个终端运行insmod timer.ko. 运行结果:内核没有崩溃,在timer执行完后才delmodule才成功返回(大约十秒,而不是3秒)。
首先在一个终端运行./delmodule 0指定cpu 0在3秒后执行rmmod. 同时在另一个终端运行insmod timer.ko. 运行结果:内核没有崩溃,在timer执行完后才delmodule才成功返回(大约十秒,而不是3秒)。
是代码写的有问题还是测试方法有问题? 首先你定时器的时长为5秒,你能确保在卸载的时候该定时器正在执行吗? 回复 2# suiming2005
定时器的时长是5秒,但是定时器第一次被调用却是模块加载后1秒。 init_timer(&timer);
timer.function=&fun;
timer.expires=jiffies+HZ;
timer.data=var;
add_timer(&timer);
也就是说,首先执行delmodule,然后马上在另一个终端insmod。大约3秒钟后,delmodule开始rmmod,而这时timer应该执行了大约2秒,还没有完全执行完。 本帖最后由 kouu 于 2010-12-01 11:35 编辑
我觉得LZ的测试代码不造成内核崩溃是正常的。
del_timer要做的事情是把timer从待处理链表里面detach,并不是要销毁这个timer对象; 这件事情跟timer.function回调函数正在被执行本身毫无瓜葛,怎么可能会引起崩溃呢?
当然,这个地方确实是需要注意的,del_timer和timer.function是可以同时发生的。(del_timer和__run_timers都会给tvec_base上锁,但是__run_timers在调用timer.function的时候会先把锁释放掉。)
考虑下面一种情况:调用del_timer以后,我们可能会kfree(timer)把对象销毁掉、把与这个timer相关的对象也销毁掉(这些对象可能会被timer.function访问)。
而在timer.function里面,我们又可能会通过arg参数把timer传进去,然后调用mod_timer之类的;又或者会在timer.function里面访问那些与timer相关的对象(这些对象我们在del_timer之后已经销毁了……)。如果是这样,就应该使用del_timer_sync,必须等到timer.function完成了,才能做那些销毁工作。如果del_timer以后我们不对timer.function里面需要访问的任何数据产生影响,那么也就不需要del_timer_sync了。
话说回来,如果del_timer在SMP环境下随便怎么用有问题,那么这么久了,有问题怎么还不修,还留着这个函数干什么……
至于delmodule成功返回是在10秒之后(而不是3秒)的问题,我觉得是这样的:delmodule会把module的代码unmap掉,其中就包括timer.function。但是timer.function正在被调用呢,不可能把正在执行的代码卸掉吧~ 所以得等它调用完,也就等到10秒之后了。(这部分代码没看过,纯猜想。)
个人理解,欢迎讨论。 而在timer.function里面,我们又可能会通过arg参数把timer传进去,然后调用mod_timer之类的;又或者会在timer.function里面访问那些与timer相关的对象(这些对象我们在del_timer之后已经销毁了……)。如果是这样,就应该使用del_timer_sync,必须等到timer.function完成了,才能做那些销毁工作。
但是我的代码里的确是用来timer.data来传递了参数var的啊。比如timer的function函数就是通过arg来传递的啊。
static void fun(unsigned long arg)
{
char *v=arg;
。。。。。。
}
那按照大虾的说法,使用del_timer会出问题的啊? 而在timer.function里面,我们又可能会通过arg参数把timer传进去,然后调用mod_timer之类的;又或者会在timer.function里面访问那些与timer相关的对象(这些对象我们在del_timer之后已经销毁了……)
但是我的代码里的确是用来timer.data来传递了参数var的啊。比如timer的function函数就是通过arg来传递的啊 ...
瀚海书香 发表于 2010-12-01 13:02 http://linux.chinaunix.net/bbs/images/common/back.gif
按我的理解,关键不在于我们传了什么东西进去,而在于我们在timer.function里面引用的内存或者其他资源,可能已经被释放了。
为什么会被释放呢?因为我们错误的以为del_timer之后,这些“东西”就可以被释放。但是实际上,del_timer之后,timer.function可能还在运行,释放这些“东西”是可能会出问题的。
所以在释放这些“东西”之前,除了调用del_timer把timer从待处理队列里面detach之外,如果timer.function正在执行,还需要等它执行完。这就是del_timer_sync干的事情。
6.5.1.1. Dynamic timers and race conditionsBeing asynchronously activated, dynamic timers are prone to race conditions. For instance, consider a dynamic timer whose function acts on a discardable resource (e.g., a kernel module or a file data structure). Releasing the resource without stopping the timer may lead to data corruption if the timer function got activated when the resource no longer exists. Thus, a rule of thumb is to stop the timer before releasing the resource: ... del_timer(&t); X_Release_Resources( ); ...
In multiprocessor systems, however, this code is not safe because the timer function might already be running on another CPU when del_timer( ) is invoked. As a result, resources may be released while the timer function is still acting on them. To avoid this kind of race condition, the kernel offers the del_timer_sync( ) function. It removes the timer from the list, and then it checks whether the timer function is executed on another CPU; in such a case, del_timer_sync( ) waits until the timer function terminates.
又回头翻看了一下ULK3,我觉得里面这一段已经讲得很清楚了…… 回复 7# kouu
我也明白这段话的意思。
问题是,上面我列出的代码,按照ULK3的理论,应该使用del_timer_sync的,如果使用del_timer是会有问题的。但是为什么我使用del_timer却没有出问题啊? 我想你没明白这段文字的意思……
上面所说的是,del_timer(&t)之后,会调用X_Release_Resources( )来释放某些资源。而这些资源会被t.function使用。
由于del_timer调用之后,t.function可能正在其他CPU上运行,可能正在访问这些资源。而与此同时,这些资源又正在被X_Release_Resources释放……
在这样的情况下,才应该使用del_timer_sync,而不是del_timer。
如果你在del_timer之后不去释放资源,t.function需要访问的资源都正常,那么又怎么会崩溃呢?而你的测试代码不就没有牵涉资源释么~ 回复 9# kouu
多谢。终于搞明白了。原来意思是指del_timer()执行后,释放资源导致竞态问题。
我一直是以为在del_timer()这个函数中会释放某些内核自己创建定时器时分配的资源,从而导致竞态呢。呵呵多谢了
页:
[1]
2