c - 为linux内核中的struct数组分配内存并得到奇怪的输出od structs ids
问题描述
我在 linux 内核中编写了一个程序,它应该为 5 个具有唯一 ID 的简单结构分配内存,所以我在构造函数中使用静态 int 并递增它,最后我只是将消息打印到缓冲区。当我看到缓冲区时,我得到了一个奇怪的结果,因为 id 的值像 0、64、128、192、256我很惊讶,因为我认为我会看到像 0、1、2、3、4 这样的值。为什么我得到这样的结果是有问题吗?
输出:
[2653.505140]示例结构ID:0
[2653.505143]示例字符串字段内容:测试
[2653.526565]示例结构ID:64
[2653.526568]示例字符串字段内容:测试
[2653.526623]示例结构ID:128
[2653.526625]示例字符串字段内容测试
[2653.550439] 示例结构 id:192
[2653.550443] 示例字符串字段内容:测试
[2653.550513] 示例结构 id:256
[2653.550514] 示例字符串字段内容:测试
有我的代码:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
} *example_struct_pointer[5];
static struct kmem_cache *example_cachep[5];
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Test";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Example struct id: %d\n",example->id);
pr_notice("Example string field content: %s\n",example->example_string);
}
static int __init zad1_init(void)
{
int i;
for(i = 0; i < 5; i++){
example_cachep[i] = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep[i])) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep[i]));
return -ENOMEM;
}
}
for(i = 0; i < 5; i++){
example_struct_pointer[i] = (struct example_struct *) kmem_cache_alloc(example_cachep[i],GFP_KERNEL);
if(IS_ERR(example_struct_pointer[i])) {
pr_alert("Error allocating form cache: %ld\n", PTR_ERR(example_struct_pointer[i]));
kmem_cache_destroy(example_cachep[i]);
return -ENOMEM;
}
}
return 0;
}
static void __exit zad1_exit(void)
{
int i;
for(i = 0; i < 5; i++){
if(example_cachep[i]) {
if(example_struct_pointer[i]) {
print_example_struct(example_struct_pointer[i]);
kmem_cache_free(example_cachep[i],example_struct_pointer[i]);
}
kmem_cache_destroy(example_cachep[i]);
}
}
}
module_init(zad1_init);
module_exit(zad1_exit);
MODULE_LICENSE("GPL");
解决方案
ctor
函数的参数kmem_cache_create
不是常识中的构造函数。
不能保证给定的函数只会被调用一次,并且只有在从缓存中请求对象时才会被调用。保证实际上是相反的(mm/slab_common.c:389):
* The @ctor is run when new pages are allocated by the cache.
因此,调用的次数可能ctor
比从缓存中请求的对象数量多得多。
如果你只是想分配和初始化几个对象,那么只需定义相应的构造函数:
// Single cache can be used for allocate multiple object.
// No needs to define a cache-per-object.
static struct kmem_cache* example_cachep;
// Constructor for the object of type 'example_struct'.
static struct example_struct* create_example_object(void)
{
static unsigned int id;
struct example_struct *example = kmem_cache_alloc(example_cachep, GFP_KERNEL);
if (example != NULL)
{
example->id = id;
strcpy(example->example_string, "Test");
id++;
}
return example;
}
static int __init zad1_init(void)
{
// ...
// Create the cache.
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
// create several 'example' objects.
for(i = 0; i < 5; i++){
example_struct_pointer[i] = create_example_object();
if(example_struct_pointer[i] == NULL)
{
// ... Somehow process the allocation failure.
}
}
return 0;
}
ctor
参数对于仅初始化对象的某些字段很有用。这样的初始化可以节省一点时间(稍微提高性能),但只有在以下两个条件都适用时:
- 您从缓存中主动创建(分配 + 初始化)和销毁(解除分配)对象。
- 您要初始化的字段在刚刚初始化的对象和将要被释放的对象中具有完全相同的值。
例如,您usage_count
的对象中可能有一个字段,当一个对象刚刚初始化和一个对象将被释放时,该字段都等于 0。
ctor
此类字段的用处在于,ctor
可能不会为先前从同一缓存中释放的已分配对象调用它。也就是说,您可以通过不初始化已经具有所需值的字段来节省时间。
因为不初始化单个(或多个)值只能节省一点时间,但ctor
调用的次数可能比需要的次数多,所以您应该仔细衡量您是否真的获得了性能而不是失去它。