Loading

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选项

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

运行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 <linux/timer.h>
#include <linux/module.h>
#include <linux/jiffies.h>

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

posted @ 2022-05-16 14:05  成蹊0xc000  阅读(101)  评论(0编辑  收藏  举报