Makefile调试和内核定时器的使用

这周水一篇博客,先把量搞上去。

Makefile简明教程

常用函数

条件函数

$(if condition,then-part[,else-part])

编写驱动的Makefile

If KERNELRELEASE is defined, we've been invoked from the
kernel build system and can use its language.

ifneq ($(KERNELRELEASE),)
    obj-m := hello.o
Otherwise we were called directly from the command
line; invoke the kernel build system.

else
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
endif

变量obj-m表明了要构建内核模块所需要的生成的所有目标文件

KERNELRELEASE表示内核版本,主要用来创建内核安装目录和生成版本信息

Make调试

warning函数

用法:

$(warning “debug message”)

just-print选项

Makefile调试和内核定时器的使用

Makefile调试和内核定时器的使用

只打印生成target所需的command,但是并不执行command。但是存在两种例外情况,即使使用该选项也会执行command。

print-data-base

运行makefile,显示GNU版权信息以及make所运行的命令,然后输出它的内部数据库。数据库里的数据将会依据种类划分成以下几个组:

variables, directories, implicit rules, pattern-specific variables, files(explicit rules), vpath search path

warn-undefined-variables

显示makefile中未定义的变量,并告警

Makefile调试和内核定时器的使用

debug选项

开启debug选项,debug选项有五个调试级别,分别输出不同的调试信息,分别是:basic, verbose, implicit, jobs, all

当我们执行make –debug时只打印basic信息,包括没有更新的target和一些操作信息。如下所示,debug输出为上下两部分

上半部分为make版本信息,下半部分输出了要更新的target信息。

Makefile调试和内核定时器的使用

编写可调试的Makefile

1、良好的编码习惯

2、具保护功能的编码

makefile已经可以算是一门编程语言,因此编写过程中如果存在错误的代码路径,可以使用error函数去强制make退出

Makefile调试和内核定时器的使用

还可以使用自定义的assert函数

$(call assert,condition,message)
define assert
    $(if $1,,$(error Assertion failed: $2))
endef

$(call assert-file-exists,wildcard-pattern)
define assert-file-exists
    $(call assert,$($1),The variable "$1" is null)
endef

开启Shell的调试

make SHELL=”sh -x”

内核定时器的使用

结构体

struct timer_list {
    /*
     * All fields that change during normal runtime grouped to the
     * same cacheline
     */
    struct hlist_node   entry;
    unsigned long       expires;
    void            (*function)(struct timer_list *);
    u32         flags;
};

内核定时器通过哈希表去组织,entry字段表示哈希桶中的一个节点。expires表示定时器到期时间。function是和该定时器绑定的回调函数。flags用来指定该定时器的类型(timer.h中TIMER_*类型的宏)。

初始化定时器

定时器的初始化分成动态和静态两种方式,动态分配使用timer_setup完成,静态分配使用DEFINE_TIMER完成,静态分配实际上就是执行了一次结构体的初始化赋值操作。

DEFINE_TIMER—静态分配

#define __TIMER_INITIALIZER(_function, _flags) {        \
        .entry = { .next = TIMER_ENTRY_STATIC },    \
        .function = (_function),            \
        .flags = (_flags),              \
        __TIMER_LOCKDEP_MAP_INITIALIZER(        \
            __FILE__ ":" __stringify(__LINE__)) \
    }

#define DEFINE_TIMER(_name, _function)              \
    struct timer_list _name =               \
        __TIMER_INITIALIZER(_function, 0)

timer_setup—动态分配

#define timer_setup(timer, callback, flags)         \
    __init_timer((timer), (callback), (flags))

启动定时器

void add_timer(struct timer_list *timer)
{
    BUG_ON(timer_pending(timer));
    mod_timer(timer, timer->expires);
}

add_timer用来启动一个定时器,实现时会检查定时器的状态,如果处于挂起(pending)状态,则抛出Kernel Oops。否则调用mod_timer将该定时器加入到内核哈希表中。

修改定时器

mod_timer被用来修改定时器的到期时间

int mod_timer(struct timer_list *timer, unsigned long expires)
{
    return __mod_timer(timer, expires, 0);
}

销毁定时器

del_timer用来销毁定时器

int del_timer(struct timer_list *timer)
{
    struct timer_base *base;
    unsigned long flags;
    int ret = 0;

    debug_assert_init(timer);

    if (timer_pending(timer)) {
        base = lock_timer_base(timer, &flags);
        ret = detach_if_pending(timer, base, true);
        raw_spin_unlock_irqrestore(&base->lock, flags);
    }

    return ret;
}

代码示例

#include
#include
#include

struct timer_list my_timer;

void timer_func(struct timer_list *tl)
{
    printk("print a msg: hello, kernel, %ld\n", jiffies);
}

static int
timer_init(void)
{
    printk("init module");
    timer_setup(&my_timer, timer_func, 0);
    printk("setup timer in %ld\n", jiffies);
    mod_timer(&my_timer, jiffies+msecs_to_jiffies(2000));
    //add_timer(&my_timer);
    return 0;
}

static void
timer_exit(void)
{
    printk("exit module\n");
    del_timer(&my_timer);
}

module_init(timer_init);
module_exit(timer_exit);

MODULE_LICENSE("GPL");

参考

https://blog.csdn.net/hhhhhyyyyy8/article/details/102885037

http://abcdxyzk.github.io/blog/2013/07/01/kernel-timer/##

http://yannik520.github.io/linux_driver_code/timer/src/timer_module.c

https://www.cnblogs.com/Oude/articles/12039099.html

https://elixir.bootlin.com/linux/v4.19.190/source/kernel/time/timer.c

Original: https://www.cnblogs.com/dennis-wong/p/16276768.html
Author: 成蹊0xc000
Title: Makefile调试和内核定时器的使用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582764/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 安卓开发——WebView+Recyclerview文章详情页,解决高度问题

    安卓开发——WebView+Recyclerview文章详情页,解决高度问题 最近在写一个APP时,需要显示文章详情页,准备使用WebView和RecyclerView实现上面文章…

    Linux 2023年6月8日
    080
  • 让Mac界面和Windows界面在Laxcus集群操作系统上合体

    如果一套操作系统,同时拥有苹果Mac风格的图形桌面,和微软Windows风格的图形桌面,你会是一种什么样的体验? 最近,我们公司的GUI研发团队完成了这项技术突破,在持续不断地技术…

    Linux 2023年6月6日
    0104
  • 【数学建模相关】matplotlib画多个子图(散点图为例 左右对照画图)

    @ 例题 例图 代码展示 例题 乙醇偶合制备 C4 烯烃 C4 烯烃广泛应用于化工产品及医药的生产,乙醇是生产制备 C4 烯烃的原料。 在制备过程中,催化剂组合(即:Co 负载量、…

    Linux 2023年6月8日
    089
  • R语言-基础绘图

    一、R语言绘图系统 二、绘图函数 2.1 高水平绘图函数 plot() 绘制散点图等多种图形 hist() 直方图 boxplot() 箱线图 stripchart() 点图 ba…

    Linux 2023年6月8日
    053
  • 搭建k8s

    一、设置基本环境(需要开启超级用户权限) 安装控制selinux的命令: apt-get install -y selinux-utils 禁止selinux: setenforc…

    Linux 2023年5月27日
    075
  • cpp-函数

    1.基础概念 形参:用在定义、申明处的参数,用于说明参数的类型、名称 实参:用在函数调用,用…

    Linux 2023年6月7日
    0107
  • bash 中 echo & printf

    首先列一下今天收获的消息 sh是: Bourne Shell(/usr/bin/sh或/bin/sh) bash是: Bourne Again Shell(/bin/bash) p…

    Linux 2023年6月6日
    084
  • POJ1979(Red and Black)–FloodFill

    题目在这里 题目意思是这样的,一个人起始位置在 ‘@’ 处,他在途中能到达的地方为 ‘ . ‘ 而 ‘#’ …

    Linux 2023年6月7日
    092
  • 后端编写Swagger接口管理文档

    在后端开发当中,编写好多个接口后需要通过注解编写相应的接口文档提供给前端调用接口实现前后端分离。 Swagger接口管理文档 访问接口文档的网页:http://localhost:…

    Linux 2023年6月7日
    078
  • 020 Linux 20个宝藏命令案例

    1 JDK 相关的查找命令 (1)确认是否安装 JDK (2)查找 java 命令目录的位置 (3)查找 java 命令的位置的软链地址 (4)通过软链地址查找 JDK 的安装目录…

    Linux 2023年5月27日
    081
  • 2021年3月-第01阶段-Linux基础-Linux系统的启动流程

    Linux系统的启动流程 理解Linux操作系统启动流程,能有助于后期在企业中更好的维护Linux服务器,能快速定位系统问题,进而解决问题。 上图为Linux操作系统启动流程 1….

    Linux 2023年5月27日
    0102
  • rocksdb列族笔记

    1、简介 列族(Column Families)是rocksdb3.0提出的一个机制,用于对同一个数据库的记录(键值对)进行逻辑划分。默认情况下所有的记录都会存储在一个默认列族里(…

    Linux 2023年6月7日
    099
  • 高等代数:3 线性方程组的解集的结构

    3 线性方程组的解集的结构 1、定义1:数域K上所有n元有序数组组成的集合(K^{n}),连同定义在它上面的加法运算和数量乘法运算,以及满足的8条运算法则一起,称为数域K上的一个 …

    Linux 2023年6月8日
    085
  • Linux实用命令

    Linux实用命令 关于 Linux 中单双引号的区别: 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的; 双引号里可以有变量,双引号里可以出现转义字符 反引号 pa…

    Linux 2023年6月13日
    078
  • 【机器学习笔记】一元线性回归原理、公式及代码实现

    线性回归是逻辑回归的基础,逻辑回归又是神经网络的组成部分,用于解决2分类问题 线性回归是所有算法的基础 概念: 线性关系是指变量之间的关系是一次函数,一个自变量x和因变量y的关系表…

    Linux 2023年6月13日
    075
  • 由乐观锁延伸出的知识

    锁是网络数据库中的一个非常重要的概念,当多个用户同时对数据库并发操作时,会带来数据不一致的问题,所以,锁主要用于多用户环境下保证数据库完整性和一致性以商场的试衣间为例,每个试衣间都…

    Linux 2023年6月7日
    064
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球