linux内核中的 cpuinfo 模块使用此代码获取指向cpu的指针:
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
// (...)
struct seq_file *m = file->private_data;
void *p;
// (...)
p = m->op->start(m, &pos);
在proc.c:
中可以找到 start 方法static void *c_start(struct seq_file *m, loff_t *pos)
{
*pos = cpumask_next(*pos - 1, cpu_online_mask);
if ((*pos) < nr_cpu_ids)
return &cpu_data(*pos);
return NULL;
}
从中返回指向void*
的指针后,接下来将其传递给 show 方法:
err = m->op->show(m, p);
将指针指定为指向 cpuinfo_x86 的指针:
static int show_cpuinfo(struct seq_file *m, void *v)
{
struct cpuinfo_x86 *c = v;
unsigned int cpu;
int i;
cpu = c->cpu_index;
但是,如果我在我的代码(linux内核模块)中做了类似的事情:
get_online_cpus();
pos = kmalloc( sizeof( loff_t), GFP_KERNEL);
*pos = 0;
*pos = cpumask_next(*pos - 1, cpu_online_mask);
if ( (*pos) < nr_cpu_ids)
{
c = &cpu_data(*pos);
cpu = c->cpu_index; // SIGSEGV !
}
指针不正确(指向可能是有效地址的内容,但我无法访问它指向的内容)。如果我使用for_each_online_cpu
宏,则会发生同样的事情:
for_each_online_cpu( cpuid)
{
c = &cpu_data(cpuid);
为什么我会得到SIGSEGV?我知道 vfs 传递给 cpuinfo 的文件是特殊的顺序文件,但它似乎与cpu_data
宏无关。截至目前,我可以看到的唯一区别是,在第一种情况下,指针被传递给函数,然后在该函数内部分配,因此我们有一个堆栈框架等。这与优化有关吗?
如果我在单独的功能中进行分配,它可以工作:
static void*
mpsrv_get_cpu_ptr( loff_t *pos)
{
*pos = cpumask_next(*pos - 1, cpu_possible_mask);
if ( (*pos) < nr_cpu_ids)
return &cpu_data(*pos);
return NULL;
}
static void
mpsrv_stat_cpu( struct mpsrv_cpu_info *cpu_info, void *v)
{
struct cpuinfo_x86 *c = v; // OK
unsigned int cpu;
cpu = c->cpu_index; // OK
// (...)
}
// code
get_online_cpus();
pos = cpu_n = 0;
while ( ( p = mpsrv_get_cpu_ptr( &pos)))
{
mpsrv_stat_cpu( cpu_info, p);
++cpu_n;
++pos;
}
put_online_cpus();
cpuinfo.c 中的内核代码还返回一个指向 cpuinfo_x86 的指针,该指针是在单独的函数 c_start()中获得的。 如果需要一些其他信息,请告诉我。谢谢。