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)

大家都在看

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