这周水一篇博客,先把量搞上去。
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选项
只打印生成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中未定义的变量,并告警
debug选项
开启debug选项,debug选项有五个调试级别,分别输出不同的调试信息,分别是:basic, verbose, implicit, jobs, all
当我们执行make –debug时只打印basic信息,包括没有更新的target和一些操作信息。如下所示,debug输出为上下两部分
上半部分为make版本信息,下半部分输出了要更新的target信息。
编写可调试的Makefile
1、良好的编码习惯
2、具保护功能的编码
makefile已经可以算是一门编程语言,因此编写过程中如果存在错误的代码路径,可以使用error函数去强制make退出
还可以使用自定义的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/
转载文章受原作者版权保护。转载请注明原作者出处!