Linuxデバイスドライバを書いるとき、insmod module.ko, rmmod moduleを繰り返しているうちに、デバッグメッセージがいつ実行したドライバのメッセージがわからなくなる。いつ実行したか確実にわかるように、insmod, rmmodなどを実行したとき、printk()で現在の時刻を表示したいのだが、ctime(3)のような関数がカーネル内では存在しないようだ。

do_gettimeofday()でUNIX時間を取得し変換する方法もあるが、しかしこの方法は結構めんどくさいのもっと手軽にRTC(Real Time Clock)の情報を使えばいいのではないかと思う。サンプルのプログラムは以下の様になる。

testdrv.c

#include <linux/init.h>
#include <linux/module.h>
#include <asm-generic/rtc.h>
MODULE_LICENSE("Dual BSD/GPL");

static char *months[12] ={"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

#define LOG(msg, ...)				\
	_log(__FILE__, __LINE__);		\
	printk(msg, ## __VA_ARGS__)

static inline void _log(const char *file, const int line)
{
	struct rtc_time t;
	get_rtc_time(&t);

	printk("%s %d %d:%d:%d %d: %s:%d: ",
	       months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
               t.tm_sec, 2000 + (t.tm_year % 10), file, line);
}

static int testdrv_init(void)
{
	LOG("test driver init");

	return 0;
}

static void testdrv_exit(void)
{
	LOG("test driver exit");
}

module_init(testdrv_init);
module_exit(testdrv_exit);

Makefile

obj-m := testdrv.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)

.PHONY: modules
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD)

.PHONY: clean
clean:
	rm -rf *.o *~ core .*.cmd *.ko *.mod.c .tmp_versions Module.symvers

上のコードを試すと以下のような出力結果を得られる。

$ make
$ sudo insmod testdrv.ko
$ dmesg
...
...
Sep 17 2:34:20 2007: /home/yusuke/work/testdrv/testdrv.c:22: test driver init
$ sudo rmmod testdrv
$ dmesg
...
...
Sep 17 2:40:41 2007: /home/yusuke/work/testdrv/testdrv.c:29: test driver exit