一些关于Linux内核中常用的结构体函数表针的理解动机
在看linux内核代码的时侯常常就能看见一些结构体上面的成员跟我们往年见的到一些结构体不一样,常见的构架体如下边的代码:
struct a{
int i;
char b;
struct c;
};
而内核中又见有这样的一些结构体:
const struct a{
.a = read,
.b = write,
};
这些结构体我甚少见,但是好多书籍上没有见过这样的结构体,搜索了一些资料,写下一些对这种结构体的理解
事例
首先放上三段代码作为一个反例
先放上第一段代码:
struct address_space_operations {
int (*writepage)(struct page *page, struct writeback_control *wbc);
int (*readpage)(struct file *, struct page *);
/* Write back some dirty pages from this mapping. */
int (*writepages)(struct address_space *, struct writeback_control *);
/* Set a page dirty. Return true if this dirtied it */
int (*set_page_dirty)(struct page *page);
int (*readpages)(struct file *filp, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages);
int (*write_begin)(struct file *, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata);
int (*write_end)(struct file *, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata);
/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
sector_t (*bmap)(struct address_space *, sector_t);
void (*invalidatepage) (struct page *, unsigned int, unsigned int);
int (*releasepage) (struct page *, gfp_t);
}
这是第二段代码:
const struct address_space_operations v9fs_addr_operations = {
.readpage = v9fs_vfs_readpage,
.readpages = v9fs_vfs_readpages,
.set_page_dirty = __set_page_dirty_nobuffers,
.writepage = v9fs_vfs_writepage,
.write_begin = v9fs_write_begin,
.write_end = v9fs_write_end,
.releasepage = v9fs_release_page,
.invalidatepage = v9fs_invalidate_page,
.launder_page = v9fs_launder_page,
.direct_IO = v9fs_direct_IO,
};
这是第三段代码:
static int v9fs_vfs_readpage(struct file *filp, struct page *page)
{
return v9fs_fid_readpage(filp->private_data, page);
}
首先,我们可以看见,我们常见的那个结构体方式就是第二段代码中的这些方式。而看懂这些方式就是我们这个文章的目的。
我们先须要晓得的是,这个结构体上面的东西是函数表针,也就是说,这个成员的变量是跟函数有关的。
我们先看第二段代码,第二段代码不仅上面的东西以外,外边的那层还是我们熟悉的东西:结构体
const struct address_space_operations v9fs_addr_operations
听到这个,我们其实晓得了v9fs_addr_operations是类型为结构体address_space_operations的变量。
好了linux源码结构,如今我们晓得v9fs_addr_operations的类型是结构体address_space_operations,那我们就瞧瞧第一段代码:
第一段代码上面,我们看见了好多申明,比如
int (*readpage)(struct file *, struct page *);
这儿就是申明了结构体中address_space_operations的一个readpage的函数表针,说明了结构体address_space_operations中有一个名为readpage的,入参为(structfile*,structpage*)的一个函数。
至此,我们就晓得了这个结构体上面的申明是咋回事了。
之后我们再看回第二段代码,这时我们就晓得了v9fs_addr_operations中的readpage是指向函数v9fs_vfs_readpage的了。并且v9fs_vfs_readpage又是哪些东西呢?这个时侯请看第三段代码。
这儿就实现了v9fs_vfs_readpage。v9fs_vfs_readpage上面实际调用的是v9fs_fid_readpage(filp->private_data,page);这个函数。
为此linux论坛linux vi命令,大体的流程我归纳如下:
v9fs_addr_operations.readpage(filp->private_data,page)->v9fs_fid_readpage(filp->private_data,page);
那为何要搞的如此复杂呢?
我个人觉得linux源码结构,这些方式有点类似于面向对象的具象。把一大类具有相同特点的操作具象下来,用我们文章中的事例,对于地址空间的操作,基本就是读、写、设脏等等的操作,这样可以把这种操作具象成一个对象,在这儿用一个结构体structaddress_space_operations来搞定,这样,address_space_operations就是这种操作的一个父类。
之后如今要对v9fs进行操作,我们只须要实例化一个具体针对v9fs的对象,这时侯我们就生成一个类型为structaddress_space_operations的对象v9fs_addr_operations。在上面将须要调用的操作指向我们具体的函数,能够实现对于多种函数实现的情境下统一插口拉