谷动谷力

标题: Linux 内核的 C 语言编程范式 [打印本页]

作者: 谷谷小师妹    时间: 2023-3-7 23:24
标题: Linux 内核的 C 语言编程范式
Linux 内核的 C 语言编程范式



不同的编程语言具有不同的抽象原语(如下),有的原语抽象层次低,有的原语抽象层次高。其中函数式、DSL是这几年十分热门的编程语言概念。

Linux kernel 是个与硬件打交道、用 C 语言开发的几十年的巨型软件项目。它的开发语言是 C,作为一门过程式语言,好像离对象式、函数式、DSL这些编程范式很远,无法将这些优秀的编程范式的威力发挥在 Linux Kernel 项目上。

但是,果真如此么?

2. 面向对象式Linux Kernel编程2.1 面向对象编程介绍

面向对象编程的定义:

Object-oriented programming attempts to provide a model for programming based on objects. Object-oriented programming integrates code and data using the concept of an "object". An object is an abstract data type with the addition of polymorphism and inheritance. An object has both state (data) and behavior (code).

从中可以看出,面对对象式编程的基本特征:

不管是用什么编程语言,只要能满足这些特征,那就是面对对象范式。C++、Java语言因为提供了对这些特征直接表达的语法,所以对面对对象编程十分友好。虽然C语言没有这些原语支持,但是同样也能做到面对对象。

2.2 封装

封装的特点:

封装的实现方法:

封装示例:

A模块头文件scan.h中要声明接口: int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips);
而 struct ubi_vid_hdr 的类型定义在 ubi-media.h。scan.h
不应该#include "ubi-media.h",而是声明 struct ubi_vid_hdr;
数据类型struct ubi_volume_desc
只在某个c文件中实现中使用,因此数据类型struct ubi_volume_desc放在这个c文件中定义。
在其头文件中声明 struct ubi_volume_desc类型,导出接口的参数使用这个类型指针。
2.3 Linux设备模型面向对象设计

Linux设备模型是Linux Kernel中抽象编程的最佳范本,它分解抽象设备模型 6 个最基本的对象,其他所有对象由这些对象组合派生而来。

Linux设备模型继承关系示图:

Linux设备模型继承实现细节局部图:

3. 函数式 Linux Kernel 编程3.1 函数式编程介绍

函数式编程的定义:

functional programming is a programming paradigm, a style of building the structure and elements of computer programs, that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data. It is a declarative programming paradigm, which means programming is done with expressions.

函数式编程的基本特征:

函数式编程常用技术:

3.2 一等函数

函数是函数式编程的“一等公民”,可以在任何位置定义、使用,如变量、函数入参、返回值。这一点C语言完全可以做到,Kernel中也有不少编程实例,如下面这个示例中crystalhd_get_cmd_proc就是个高阶函数,它的返回值是一个函数指针。

typedef enum BC_STATUS(*crystalhd_cmd_proc)(struct crystalhd_cmd *,
                     struct crystalhd_ioctl_data *);            
crystalhd_cmd_proc crystalhd_get_cmd_proc(struct crystalhd_cmd *ctx,
                 uint32_t cmd, struct crystalhd_user *uc){
    crystalhd_cmd_proc cproc = NULL;
    for (i = 0; i < tbl_sz; i++) {
            ...
            cproc = g_crystalhd_cproc_tbl.cmd_proc;
            break;
        }
    }
    return cproc;
}
3.3 闭包

闭包是高阶函数的一种表现形式,可以理解为函数与其环境数据的结合体。它主要有2个作用:

C语言的主要有如下应用场景:

如下的示例中,device_for_each_child就符合闭包的定义:是函数fn与其环境数据data的结合体。

int device_for_each_child(struct device *parent, void *data,
              int (*fn)(struct device *dev, void *data)){
    struct klist_iter i; struct device *child; int error = 0;
    klist_iter_init(&parent->p->klist_children, &i);
    while ((child = next_device(&i)) && !error)
        error = fn(child, data);
    klist_iter_exit(&i);
    return error;
}

device_for_each_child(dev, NULL, device_check_offline);
result = device_for_each_child(dev, addrp, i2cdev_check_mux_children);
device_for_each_child(&dev->dev, &status, slot_reset_iter);
4. 事件驱动Linux Kernel编程4.1 事件驱动编程介绍

事件驱动编程的定义:

Event-driven programming is a programming paradigm in which the flow of the program is determined by events such as user actions (mouse clicks, key presses), sensor outputs, or messages from other programs/threads. Event-driven programming is the dominant paradigm used in graphical user interfaces and other applications (e.g. JavaScript web applications) that are centered on performing certain actions in response to user input.

事件驱动编程的优点:

事件的定义:

事件驱动编程的实现原则:

事件驱动编程的实现三部曲:

事件驱动编程的结构化设计:

事件驱动编程的实现技术:

4.2 Linux设备热插拔事件驱动设计热插拔事件定义enum kobject_action {
KOBJ_ADD,
KOBJ_REMOVE,
KOBJ_CHANGE,
KOBJ_MOVE,
KOBJ_ONLINE,
KOBJ_OFFLINE,
KOBJ_MAX
};

热插拔消息格式定义

"add@/class/input/input9/mouse2\0 // message
ACTION=add\0 // action type
DEVPATH=/class/input/input9/mouse2\0 // path in /sys
SUBSYSTEM=input\0 // subsystem (class)
SEQNUM=1064\0 // sequence number
PHYSDEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0\0 // device path in /sys
PHYSDEVBUS=usb\0 // bus
PHYSDEVDRIVER=usbhid\0 // driver
MAJOR=13\0 // major number
MINOR=34\0", // minor number
热插拔事件驱动工作流程
热插拔事件处理流程5. 领域特定语言(DSL) Linux Kernel编程5.1 领域特定语言介绍

DSL编程的定义:

A domain-specific language (DSL) is a computer language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains, and lacks specialized features for a particular domain.

领域特定语言又分为内部DSL和外部DSL,它们具有共同的特征:

5.2 内部DSL内部DSL是嵌入到开发语言内部,与开发语言混合使用的DSL,它可以是一个接口,如printf,也可以是一个宏,如下示例:UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100, "Nokia", "N80", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY )

UNUSUAL_DEV呈现了2种信息,一种是设备id_table信息,用于驱动匹配,一种是unusual_dev_list,用于标示非标准设备。

5.3 外部DSL

外部DSL独立于开发语言使用,自身具有一定的语言完备性。

Linux Kernel中的设备树描述模型是个很好的外部DSL的例子。如下图(左)所示,它描述的是系统中的设备层次关系,这种DSL与领域模型(如下图右)处在同一语义层次上,表达的语法基本就是领域语言,十分贴切自然。

设备树描述文件(DTS)经过解释器(DTC)转成成字节描述文件(DTB),DTB通过引导加载程序(bootloader)传给内核用于设备的扫描、配置和初始化。详细的启动流程如下: 设备树处理流程
原文:https://www.cnblogs.com/wahaha02/p/10147639.html







欢迎光临 谷动谷力 (http://bbs.sunsili.com/) Powered by Discuz! X3.2