Linux kernel -- 定時器/jiffies

0. 測試環境

Linux 2.6.39 AT91SAM9G45

1. 定時器簡單的測試例子

#include <linux/timer.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");

struct timer_list tm;
static int num;
static void func()
{
    num++;
    mod_timer(&tm, jiffies + HZ);

    printk("Hello, timer :%d\n", num);
}

static int timer_init(void)
{
    num = 0;

    init_timer(&tm);
    tm.expires = jiffies + HZ;
    tm.function = func;
    add_timer(&tm);

    return 0;
}

static void timer_exit(void)
{
    del_timer(&tm);

    printk("remove timer\n");
}

module_init(timer_init);
module_exit(timer_exit);                                                                                                                                                       
Makefile

obj-m := timer.o
KERNEL := /Android/linux-2.6.39-android_altus
PWD := $(shell pwd)
modules:
    $(MAKE) -C $(KERNEL) M=$(PWD) modules

.PHONEY:clean
clean:
    rm -f *.o *.ko


insmod timer.ko

使用命令cat /proc/kmsg查看效果


2. jiffies和jiffies_64變量定義的位置

http://bbs.chinaunix.net/archiver/tid-1982818.html?page=2

jiffies_64獲取的驅動部分代碼

#include <linux/init.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>

#include <asm/uaccess.h>

#define JIFFIES_64_DEVICE_NODE_NAME  "jiffies_64"
#define JIFFIES_64_DEVICE_CLASS_NAME "jiffies_64"
#define JIFFIES_64_DEVICE_FILE_NAME  "jiffies_64"

static unsigned long long value_of_jiffies_64;
static dev_t devno;
static struct class *jiffies_64_class;
static struct cdev jiffies_64_dev;

static ssize_t jiffies_64_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
{
	if (buf == NULL || size != sizeof(value_of_jiffies_64))
		return -EINVAL;

	if (value_of_jiffies_64 == 0)
		value_of_jiffies_64 = get_jiffies_64();

	if (copy_to_user(buf, &value_of_jiffies_64, sizeof(value_of_jiffies_64))) 
		return -ENOMEM;

	memset(&value_of_jiffies_64, 0, sizeof(value_of_jiffies_64));

	return 0;
}

static ssize_t jiffies_64_open(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t jiffies_64_release(struct inode *inode, struct file *filp)
{
	return 0;
}

static struct file_operations jiffies_64_fops = {
	.owner = THIS_MODULE,
	.open = jiffies_64_open,
	.read = jiffies_64_read,
	.release = jiffies_64_release,
};

static ssize_t jiffies_64_val_show(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, jiffies_64_val_show, NULL);

static ssize_t jiffies_64_val_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	return snprintf(buf, PAGE_SIZE, "%lld\n", value_of_jiffies_64);
}

static int __init jiffies_64_init(void)
{
	int err = -1;
	struct device *device = NULL;

	err = alloc_chrdev_region(&devno, 0, 1, JIFFIES_64_DEVICE_NODE_NAME);
	if (err < 0) {
		printk(KERN_ALERT"Failed to alloc char dev region.\n");
		goto fail;
	}

	/* setup cdev */
	cdev_init(&jiffies_64_dev, &jiffies_64_fops);
	jiffies_64_dev.owner = THIS_MODULE;
	err = cdev_add(&jiffies_64_dev, devno, 1);
	if (err) {
		printk(KERN_ALERT"cdev_add failed.\n");
		goto unregister;
	}

	jiffies_64_class = class_create(THIS_MODULE, JIFFIES_64_DEVICE_CLASS_NAME);
	if (IS_ERR(jiffies_64_class)) {
		err = PTR_ERR(jiffies_64_class);
		printk(KERN_ALERT"Failed to create jiffies_64 class\n");
		goto destroy_cdev;
	}

	device = device_create(jiffies_64_class, NULL, devno, NULL, "%s", JIFFIES_64_DEVICE_FILE_NAME);
	if (IS_ERR(device)) {
		err = PTR_ERR(device);
		printk(KERN_ALERT"Failed to create jiffies_64 device.\n");
		goto destroy_class;
	}

	err = device_create_file(device, &dev_attr_val);
	if (err < 0) {
		printk(KERN_ALERT"Failed to create attribute val.\n");
		goto destroy_device;
	}

	return 0;

destroy_device:
	device_destroy(jiffies_64_class, devno);

destroy_class:
	class_destroy(jiffies_64_class);

destroy_cdev:
	cdev_del(&jiffies_64_dev);

unregister:
	unregister_chrdev_region(devno, 1);

fail:
	return err;
}

static void __exit jiffies_64_exit(void)
{
	if (jiffies_64_class) {
		device_destroy(jiffies_64_class, devno);
		class_destroy(jiffies_64_class);
	}

	cdev_del(&jiffies_64_dev);

	unregister_chrdev_region(devno, 1);
}

module_init(jiffies_64_init);
module_exit(jiffies_64_exit);
MODULE_LICENSE("GPL");

jiffies_64獲取的應用部分代碼

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define DEVICE_NODE_NAME "/dev/jiffies_64"

int main(int argc, char **argv)
{
	unsigned long long jiffies_64; /* It's in userspace, so without trouble */
	int fd = -1;

	fd = open(DEVICE_NODE_NAME, O_RDONLY);
	if (fd == -1) {
		perror(DEVICE_NODE_NAME);
		return -1;
	}

	read(fd, &jiffies_64, sizeof(jiffies_64));
	printf("jiffies_64 = %lld\n", jiffies_64);
	
	close(fd);
	return 0;
}


3. 在Linux內核中打印日誌時間戳

在編譯Linux內核,配置時:make menuconfig ---> Kernel hacking --> show timing information on printks

 當選中這個選項後,啓動內核,會在日誌信息前面加上時間戳。

從linux啓動信息可以看出,時間精確到微秒(us)。


討論羣:

Atmel技術交流討論羣
 羣號是305940105

Linux驅動開發調試羣
 羣號是297141784


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章