如何将自定义参数传递给 linux 计时器的函数?

Rer*_*ito 3 c pointers linux-kernel

在某些情况下,我想安排一个struct timer_list适用于自定义数据的计时器 ( )。该function结构体的字段保存将被触发的实际功能,定义如下:

void (*function)(unsigned long);
Run Code Online (Sandbox Code Playgroud)

问题是我想传递一个指针而不是unsigned long. 我知道根据架构的不同,int-ptr 转换可能安全也可能不安全,但是我找不到所有架构是否都将long整数与指针对齐,所以这是我的问题(实际上是二合一):

执行 a longto void*cast是否安全?如果不是,我应该如何处理unsigned long参数以在计时器函数中获取我想要的数据指针?

Eug*_*ene 5

对于计时器函数和其他一些情况,可以指向数据结构的指针转换为unsigned long,将其存储在data的字段中struct timer_list,并将计时器函数的参数转换回指向数据结构的指针。这似乎是一种常见的做法。

Linux 驱动程序开发,第三。编辑。第 7 章就此问题作出如下规定:

如果需要在参数中传递多个项目,可以将它们捆绑为单个数据结构,并传递一个转换为 unsigned long 的指针,这是所有支持的体系结构上的安全做法,并且在内存管理中很常见(如第 15 章所述)。

内核中有很多这样的例子,例如, ext4文件系统模块中的s_err_report定时器。指向的指针struct super_block被传递给计时器函数,并unsigned long如上所述进行强制转换。


Luk*_*uke 5

Linux 内核 4.15完全删除了数据字段,使此处的答案过时。根据我的推断,将参数传递给计时器回调的首选方法是将它们与计时器一起包含在一个结构中,并使用from_timer宏来检索它们,其定义为

#define from_timer(var, callback_timer, timer_fieldname) \
    container_of(callback_timer, typeof(*var), timer_fieldname) 
Run Code Online (Sandbox Code Playgroud)

所以为了传递参数,定义一个额外的结构为

struct timer_data {
    struct timer_list timer;
    datatype data;
};
Run Code Online (Sandbox Code Playgroud)

并将其传递给设置功能

struct timer_data *tmd = init_timer_data(); //your logic for init
timer_setup(&tmd->timer, callback, flags);
Run Code Online (Sandbox Code Playgroud)

稍后,使用from_timer来检索参数。默认情况下,将指向 timer_list 的指针传递给回调函数,而不是unsigned long data4.15 之前的版本。

void callback(struct timer_list *t) {
    struct timer_data *tmd = from_timer(tmd, t, timer);
    datatype data = tmd -> data;
}
Run Code Online (Sandbox Code Playgroud)