(三)
学号:14130140377
Email:[email protected]
教师:朱光明
##Tasklet与工作队列 ###一、实验目的
掌握字符设备驱动程序中Tasklet和工作队列的编写和调用方法。
分析对比Tasklet和工作队列的差异。 ###二、实验要求
按实验内容编写驱动程序及测试程序
编译驱动程序
在嵌入式设备上加载驱动程序并进行测试
分析对比Tasklet和工作队列的差异
###三、实验内容
写一个简单的驱动程序,要求:
- 定义一个Tasklet和一个工作队列,实现打印输出;
- 定义两个定时器,定时器周期分别为T1和T2;
- T1周期到时调度Tasklet,T2周期到时调度工作队列;
- 在加载驱动模块时注册Tasklet和工作队列
- 在卸载驱动模块时销毁Tasklet和工作队列
###四、实验步骤
参考《嵌入式系统设计》课程第07讲内容,根据实验内容要求设计编写驱动程序及应用程序
编译和加载驱动程序
进行驱动程序测试
卸载驱动程序
make成功
将文件通过网线和路由器将文件发送到树莓派中
insmod 动态加载模块 查看当前的模块
dmesg 查看任务调度过程
设置tasklet和workqueue的时延
#define TIMER_TASKLET_DELAY (7*HZ);
#define TIMER_WORKQUEUE_DELAY (9*HZ);
tasklet worker
void tasklet_worker(unsigned long data) {
printk("tasklet\n");
}
workqueue
void workqueue_worker(void * data) {
printk("workqueue\n");
}
调度tasklet
void timer_tasklet(unsigned long arg) {
tasklet_schedule(&task);
struct timer_list* pTimer = (struct timer_struct *)arg;
pTimer->expires += TIMER_TASKLET_DELAY;
add_timer(pTimer);
}
调度workqueue
void timer_workqueue(unsigned long arg) {
if(queue_work(workq,&workw) != 1)
printk("TASK: fail to add workqueue\n");
struct timer_list* pTimer = (struct timer_struct *)arg;
pTimer->expires += TIMER_TASKLET_DELAY;
add_timer(pTimer);
}
加载模块
static int init_task_m(void) {
printk("TASK: start\n");
init_timer(&tasklet_timer);
init_timer(&workq_timer);
unsigned long j = jiffies;
tasklet_timer.expires = j + TIMER_TASKLET_DELAY;
tasklet_timer.function = timer_tasklet;
tasklet_timer.data = (unsigned long)(&tasklet_timer);
workq_timer.expires = j + TIMER_WORKQUEUE_DELAY;
workq_timer.function = timer_workqueue;
workq_timer.data = (unsigned long)(&workq_timer);
tasklet_init(&task,tasklet_worker,NULL);
workq = create_singlethread_workqueue("led_task");
add_timer(&tasklet_timer);
add_timer(&workq_timer);
}
卸载模块
static void exit_task_m(void) {
printk("TASK: end\n");
del_timer(&tasklet_timer);
del_timer(&workq_timer);
tasklet_kill(&task);
destroy_workqueue(workq);
}
Makefile:
obj-m:=taskmod.o
taskmod-y:=tasklet_work.o
KERNELBUILD:=../../linux-rpi-4.4.y/
ccflags-y := -std=gnu99
module: tasklet_work.c
$(MAKE) ARCH=arm -C $(KERNELBUILD) M=$(shell pwd) modules ARCH=arm CROSS_COMPILE=armv7-rpi2-linux-gnueabihf-
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
代码清单:
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#define TASKLET_PUT_STR (_tasklet_str)
#define TASKLET_PUT_STR_SIZE (sizeof(TASKLET_PUT_STR)+1)
#define WORKQUEUE_PUT_STR (_workqueue_str)
#define WORKQUEUE_PUT_STR_SIZE (sizeof(TASKLET_PUT_STR)+1)
// tasklet
void tasklet_worker(unsigned long);
struct tasklet_struct task;
// workqueue
void workqueue_worker(void *);
struct workqueue_struct* workq;
static DECLARE_WORK(workw,workqueue_worker);
// timer
// for tasklet
void timer_tasklet(unsigned long);
struct timer_list tasklet_timer;
#define TIMER_TASKLET_DELAY (7*HZ);
// for workqueue
void timer_workqueue(unsigned long);
struct timer_list workq_timer;
#define TIMER_WORKQUEUE_DELAY (9*HZ);
// tasklet worker
void tasklet_worker(unsigned long data) {
printk("tasklet\n");
}
// workqueue
void workqueue_worker(void * data) {
printk("workqueue\n");
}
void timer_tasklet(unsigned long arg) {
tasklet_schedule(&task);
struct timer_list* pTimer = (struct timer_struct *)arg;
pTimer->expires += TIMER_TASKLET_DELAY;
add_timer(pTimer);
}
void timer_workqueue(unsigned long arg) {
if(queue_work(workq,&workw) != 1)
printk("TASK: fail to add workqueue\n");
struct timer_list* pTimer = (struct timer_struct *)arg;
pTimer->expires += TIMER_TASKLET_DELAY;
add_timer(pTimer);
}
// INIT
static int init_task_m(void) {
printk("TASK: start\n");
init_timer(&tasklet_timer);
init_timer(&workq_timer);
unsigned long j = jiffies;
tasklet_timer.expires = j + TIMER_TASKLET_DELAY;
tasklet_timer.function = timer_tasklet;
tasklet_timer.data = (unsigned long)(&tasklet_timer);
workq_timer.expires = j + TIMER_WORKQUEUE_DELAY;
workq_timer.function = timer_workqueue;
workq_timer.data = (unsigned long)(&workq_timer);
tasklet_init(&task,tasklet_worker,NULL);
workq = create_singlethread_workqueue("led_task");
add_timer(&tasklet_timer);
add_timer(&workq_timer);
}
// EXIT
static void exit_task_m(void) {
printk("TASK: end\n");
del_timer(&tasklet_timer);
del_timer(&workq_timer);
tasklet_kill(&task);
destroy_workqueue(workq);
}
module_init(init_task_m);
module_exit(exit_task_m);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kangkang");