首页 > 系统相关 >《LINUX设备驱动程序》学习笔记 ——03

《LINUX设备驱动程序》学习笔记 ——03

时间:2023-09-16 11:22:47浏览次数:45  
标签:__ 03 函数 err 内核 模块 LINUX 驱动程序 goto

1. 学习模块前的一些基础知识

  头文件:内核是一个特定的环境,对需要和它接口的代码有其自己的一些要求,所以大部分的模块代码中都会包含相当数量的头文件,其中有几个头文件是专门用于模块的,因此会出现在每个可装载的模块中:

#include <linux/module.h>
#include <linux/init.h>

  对于部分需要在装载模块时进行传参,我们还需要加上头文件 moduleparam.h 。

  许可证:linux中内核模块分为专用模块、通用模块,如果不加上 MODULE_LICENSE 声明许可证,则会被视为私有模块,开发者不太愿意帮助内核装载私有模块而导致出现问题的用户。

2. 初始化和关闭

  初始化函数负责注册模块所提供的任何设施。定义通常如下:

static int __init initialization_founction(void)
{

}

  定义初始化函数时,static 声明该函数只在该文件中有意义,但这并非强制规定,因为即使不带有 static ,如果在内核其他文件中调用该函数也必须被显式导出(一种规范)。__init 在内核中表示该函数仅在初始化期间被使用,在模块装载完成后内核就会将该函数丢掉,这样该函数占用的空间就会被释放。__init 和 __initdata是可选的。(不允许在初始化完成后还要使用的函数中加这两个标记)。

  module_init 的使用是强制性的,没有这个定义,初始化函数永远不可能被调用。该函数会在模块的目标代码中增加一个特殊的段,用于说明初始化代码的位置。

  模块可以注册不同类型的设施,包括不同类型的设备、文件系统、密码变换等。对于每种设施对应有具体的内核函数来完成注册。在这期间,指针会被广泛的使用。

  grep register_ 可以找到大部分注册函数,因为 register_ 是注册函数的前缀。

3. 清除函数

  每个重要的模块都需要一个清除函数,函数定义如下

static void __exit cleanup_function(void)
{

}

  该函数没有返回值,所以被声明为void。__exit 修饰次标记该代码仅用于模块卸载,如果【1】模块被内嵌到内核中 或者【2】内核的配置不允许卸载模块,则被标记为 __exit 的函数会被简单的丢弃。(故被 __exit 标记的函数只允许在模块被卸载,或者系统关闭时才能被调用)

  如果一个模块没有定义清除函数,则内核不允许卸载该模块。

4. 初始化过程中的错误处理(要么继续前进,要么全身而退[goto函数有奇效])

  当我们在内核中注册设施时要时刻铭记注册可能会失败。即使是最简单的动作都需要内存分配,而所需要的内存可能无法获得。因此模块代码必须始终检查返回值,并确保所请求的操作已真正成功。

  继续前进:在注册设施时遇到任何错误,首先要判断模块是否可以继续初始化。通常,在某个注册失败后可以通过降低功能来继续运转。因此,只要可能,模块应该继续向前,并尽可能提供其功能。

  全身而退:LINUX中没有记录模块都注册了哪些设施,因此必须由模块自行撤销已注册的设施。若出于某种原因无法自行撤销,则内核会处于一种不稳定状态,这是因为内核中包含了一些指向并不明确的内部的代码指针。此时唯一有效的解决办法是重新引导系统。

5. goto和清除函数在撤销已注册设施时的选择

  goto 函数虽然经常被诟病,但是在处理错误时非常有用(有时甚至是唯一的情况)。因为通过goto处理错误可以避免大量复杂的、高度缩进的 ”结构化“ 逻辑。

int __init init_function(void)
{
    int err;
	
    err = register_this(ptr1, "skull");
	if (err)
		goto fail_this;
	err = register_that(ptr2, "skull");
    if (err)
        goto fail_that;
	err = register_those(ptr3, "skull");
	if (err)
		goto fail_those;

    return 0;
	
    fail_those: unregister_this(ptr2, "skull");
	fail_that: unregister_this(prt1, "skull");
	fail_this: return err;
}

  /******************************************* 以上代码中的处理顺序需要注意 ************************************/

  以上是一个简单的通过goto进行错误处理的示例,在出错时候使用goto语句,它将只撤销出错时刻以前所成功注册的那些设施。

  如果不用goto,有一种方法是通过记录任何成功注册的设施,然后在出错的时候调用模块的清除函数。清除函数将仅仅回滚已成功完成的步骤。然而这种方案需要更多的代码和CPU时间,在效率上不及 goto ,goto语句仍然是最好的错误恢复机制。

  但是当涉及大量设施的时候,goto 则会变得难以管理,因为所有用于清除设施的代码在初始化函数中重复,同时一些符号交织在一起。而此时合理使用清除函数能够减少代码的重复并且使得代码更清晰更有条理。以下是一个简单示例:

struct something *item1;
struct something *item2;
int stuff_ok;
/* 清除函数(注意,此处清除函数并没有被__exit标记!) */
void my_cleanup(void) {
    if (item1)
        release_thing(item1);
    if (item2)
        release_thing(item2);
    if (stuff_ok)
        unregister_stuff();
    return;
}
/* 初始化函数 */
int __init my_init(void) {
    int err = -ENOMEN;
    
    item1 = allocate_thing(arguments);
    item2 = allocate_thing2(arguments2);
    if (!item1 ||!item2) 
        goto fail;
    err = register_stuff(item1, item2);
    if (!err)
        stuff_ok = 1;
    else
        goto fail;
    return 0;

fail:
    my_cleanup();
    return err;
}

  

标签:__,03,函数,err,内核,模块,LINUX,驱动程序,goto
From: https://www.cnblogs.com/hw-blog/p/17706479.html

相关文章

  • Linux find
    1.find介绍linux查找命令find是linux运维中很重要、很常用的命令之一,find用于根据指定条件的匹配参数来搜索和查找文件和目录列表,我们可以通过权限、用户、用户组、文件类型、日期、大小等条件来查找文件。2.find语法find语法find[查找路径][查找条件][处理动作]查找路径:指定的......
  • 《LINUX设备驱动程序》学习笔记 ——02
    1.编译模块构造内核模块之前,需要注意以下条件:正确版本的编译器、模块工具和其他必要的工具。太新的或太老的工具都会对使得模块构造后产生许多复杂的问题,因为内核源代码对编译器做了大量假定,因此新的(或旧的)编译器版本可能导致问题出现。另外,尽量运行和模块对应的内核版......
  • Linux CentOS7 开启SSH访问配置
    0、检查是否安装SSHrpm-qa|grepssh图为已安装的输出 1、安装文本编辑器 1.1、安装vimyum-yinstallvim安装openssh-serveryuminstall-yopensslopenssh-server 2、安装与配置SSH服务 2.1、安装openssh-serveryuminstall-yopensslopenssh-s......
  • Linux CentOS7 关闭防火墙
    1、查看防火墙状态systemctlstatusfirewalld.serviceactive(running)表示防火墙已打开2、关闭防火墙systemctlstopfirewalld.service3、再次查看防火墙状态,确认已关闭systemctlstatusfirewalld.service4、永久关闭防火墙,不执行禁用将在重启后防火墙自动开启s......
  • Codeforces Global Round 17 A. Anti Light's Cell Guessing
    给一个\(n\timesm\)的网格,里面藏了一个炸弹\((x_0,y_0)\)。你可以选择\(k\)个坐标\((x_1,y_1),(x_2,y_2),\cdots,(x_k,y_k)\)。第\(i\)次选择计算机会回复你一个数\(d_i=|x_0-x_i|+|y_0-y_i|\)。至少需要选出多少个坐标才能确定\((x_0,y_0)\)的位......
  • 树莓派4b装系统到运行 Blazor Linux 本地程序全记录
    在Linux下运行gui程序,咱也是第一次做,属于是瞎子过河乱摸一通,写得有什么不对和可以优化的地方,希望各位看官斧正斧正.1.下载烧录器https://www.raspberrypi.com/software/我选择的是Raspbian64位系统,并配置好ssh账号密码,wifi,以便启动后可以直接黑屏ssh连接2.启用roo......
  • Linux操作系统详解
    引言Linux是一个开源的Unix-like操作系统。它是由芬兰计算机科学家LinusTorvalds于1991年首次发布。Linux以其稳定性,安全性和灵活性而受到欢迎,并被广泛用于服务器,超级计算机,嵌入式系统和许多其他平台。在某些领域,例如智能手机和平板电脑(主要是Android操作系统),Linux的衍生品也非常......
  • kali linux换源
    换源地址vim/etc/apt/sources.list#Seehttps://www.kali.org/docs/general-use/kali-linux-sources-list-repositories/#debhttp://http.kali.org/kalikali-rollingmaincontribnon-freedebhttps://mirrors.tuna.tsinghua.edu.cn/kalikali-rollingmaincontribnon-f......
  • 米联客MLK_CA03核心模块硬件手册
    1产品概述随着科技的发展,现有的数字产品已经不能满足人们在通信基础设施、医疗电子、工业控制等行业的需求,设计出更高的处理带宽,更广的应用范围、更低的使用功耗的芯片成为芯片厂商的追求。安路科技PH1A系列FPGA包含更多逻辑单元、高速串行的I/O、丰富的存储资源和IP资源,定......
  • NOI Linux 及 Vim
    快考试了,临时报一下佛脚,祝各位\(RP++\)!Linuxls:listshow显示当前目录内容ls-l长列表显示ls-a显示隐藏文件cd:changedirectory改变目录cd..返回上一级cd../..返回上一级的上一级cd/homecdname进入名为name的目录pwd:printwritingdirec......