在某些条件下,我想安排一个处理自定义数据的计时器(struct timer_list
)。该结构的function
字段包含将被触发的实际功能,定义如下:
void (*function)(unsigned long);
问题是我想传递一个指针而不是unsigned long
。我知道,根据体系结构的不同,int-ptr转换可能是安全的,也可能不是安全的,但我找不到是否所有的体系结构都将long
整数与指针对齐,所以我的问题是(事实上,二合一):
执行long
到void*
的强制转换是否安全?如果没有,我应该如何处理unsigned long
参数以在计时器函数中获得我想要的数据指针?
Linux内核4.15完全删除了数据字段,使这里的答案变得过时。根据我的推断,将参数传递给计时器回调的首选方法是将它们与计时器一起封装在一个结构中,并使用from_timer
宏来检索它们,这被定义为
#define from_timer(var, callback_timer, timer_fieldname)
container_of(callback_timer, typeof(*var), timer_fieldname)
因此,为了传递参数,请将一个额外的结构定义为
struct timer_data {
struct timer_list timer;
datatype data;
};
并将其传递给设置功能
struct timer_data *tmd = init_timer_data(); //your logic for init
timer_setup(&tmd->timer, callback, flags);
稍后,使用from_timer
检索参数。默认情况下,指向timer_list的指针被传递给回调函数,而不是4.15之前版本中的unsigned long data
。
void callback(struct timer_list *t) {
struct timer_data *tmd = from_timer(tmd, t, timer);
datatype data = tmd -> data;
}
在使用定时器函数和其他一些情况下,可以将指向数据结构的指针强制转换为unsigned long
,将其存储在struct timer_list
的data
字段中,并将定时器函数的参数强制转换回指向您的数据结构的指标。这似乎是一种常见的做法。
Linux驱动程序开发,第三版。ed.在第7章中就此事陈述如下:
如果需要在参数中传递多个项,可以将它们捆绑为一个数据结构,并将指针强制转换为无符号长,这在所有支持的体系结构上都是安全的做法,在内存管理中也很常见(如第15章所述)。
内核中有很多这样的例子,例如,请参阅ext4文件系统模块中的s_err_report
计时器。指向CCD_ 15的指针被传递到计时器函数,并如上所述强制转换为CCD_ 16和返回。
您可以使用传递的数字作为包含自定义数据结构的数组的索引。