Linux 内核的面向对象设计思想

使用C语言实现面向对象设计的方法


Linux内核用C语言实现了面向对象的设计思想。即使用了三方面的特性:封装、继承、多态。

使用结构体实现了对对象的封装;某一结构体成员中含有其他结构体的实例,实现了一个结构体对另一个结构体的继承;使用成员函数指针的结构体,通过对该结构体中同一个函数指针赋不同的值,调用同一个成员,实际上就会调用不同的函数,实现多态

结构体中的参数中有一个参数是指向这个结构体的指针,相当于this指针。使用C语言模拟面向对象的设计机制,使程序员方便对对象的构造、析构、拷贝、赋值等操作。

类的多态特征是linux内核经常用到的。例如在驱动代码中使用函数指针来定义一组设备操作函数,从而模拟了多态的特点。

1、封装

封装就是把一个抽象的事物的属性和属性的操作方法打包在一起,外界的模块只能通过这个抽象事物对外提供的函数接口,对其属性进行访问。在C++或其他高级语言中,封装通常被称作“类”。而 C 语言一般使用结构体对事物进行封装。

使用结构体可以很好地对数据进行封装,并且需要通过指定的操作函数对结构体内的数据进行访问。

每个操作函数的第一个参数是对象本身的指针,通过这个指针去访问具体对象里面的属性。这是因为在 C 语言中不存在像 C++ 语言那样的 this 指针,所以我们只能显式地通过函数传参的方式,让函数内部可以访问对象实例的其他成员。

2、继承

继承就是基于一个已有的类(一般称作父类或基类),再去重新声明或创建一个新的类,这个类可以称为子类或派生类。子类或派生类可以访问父类的数据和函数,然后子类里面又添加了自己的属性和数据。在 C 语言里面,可以通过结构体嵌套的方式去实现类的单继承(暂不考虑多重继承),但有一点注意事项,就是在结构体嵌套时,父类对象需要放在结构体成员的第一个位置。

3、多态

在C++中,多态是通过动态绑定实现的,程序在运行的时候,基类会通过虚函数表来查找子类的多态函数实现,在Linux内核中,模拟多态的方法要简单一些,实际上是在基类的函数方法中,通过获取子类对象,再嵌套调用子类对象的同名函数来实现的。

举例

file_operations 很好地展示了结构体如何使用这种机制来定义一组文件操作的方式。用这种方式,Linux很好地贯彻了所有的设备都是文件这种概念。不同的设备可以有不同的处理函数,但使用相同的接口(read,write…),这样就把底层设备的差异在文件系统这一层隔离开来。

在Linux内核设备驱动中,在用户态open一个字符设备,然后调用字符设备的read、write、等函数,最终也会调用到内核态设备驱动程序相应的read、write函数的实现,从而模拟了通过基类与多态函数的特性来访问子类的目的。

实际上,Linux内核会维护基类与子类cdev对象实例的链表,当用户态发起read/write/ioctl等字符设备系统调用函数时,read/write/ioctl等字符设备系统调用函数会通过/dev/*下的字符设备,设备节点号的方式(主节点号major,次节点号minor)从cdev链表的子类中,找到对应子类的cdev对象实例,然后判断是否为空并调用子类cdev->ops->read/write/ioctl等实际子类的多态函数实现,从而最终实现了通过访问基类的多态函数,最终访问到子类实际的多态函数,这个面向对象的特性。

struct file_operations 
{
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ......
};

Linux内核中也经常用到类的继承关系。这种关系使用C也很容易模拟,就是使用结构体嵌套(platform_device中嵌套了device )。但是不能直接引用。也不能通过基类访问子类,但是可以通过一个宏定义(container_of(ptr, type, member))来访问。

struct platform_device 
{
	const char	* name;
	int	 id;
	struct device dev;
	u32	 num_resources;
	struct resource	* resource;
	const struct platform_device_id	*id_entry;
	/* arch specific additions */
	struct pdev_archdata	archdata;
};


通过基类访问子类的方法

在面向对象编程中,通过继承关系,我们将子类对象赋值给基类对象的时候,可以通过基类对象,调用多态函数访问子类对象的实际函数。


驱动和设备匹配

总线对设备和驱动进行匹配probe,首先是对某个驱动或设备链表进行遍历(mach),然后一一匹配。Linux使用总线的概念来管理设备与驱动。在某种具体的总线上,挂着同种类的设备与驱动。从内核视角来看,想找某种设备,就从具体的某个总线上寻找,然后遍历这条总线。

添加一个设备,主要的工作是初始化设备结构体,并把它添加到对应的总线上去。在总线上将去匹配挂在该总线上的驱动。

… … … … … …

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值