内核中如何实现周期性的任务执行

来源:互联网 发布:淘宝二手店铺怎么开 编辑:程序博客网 时间:2024/05/19 23:58
/*
本实例主要测试的是:内核中如何实现周期性的任务执行。
如果驱动程序中需要执行周期性的动作,可使用以下三种方式之一。

基本思路为:创建work,让创建的work调度到linux系统内核queue还是自己创建的queue。
默认的工作队列是把创建的任务提交给特定的内核线程来执行,这个特定的内核线程是:event/n,n是处理器的编号,单处理器中n为0,
即为event/0这样一个内核线程。这个event的workqueue的实现是在 Init_workqueues()中实现的,可以参看workqueue.c。

*/

/*有俩种work类型
#define DECLARE_WORK(n, f) struct work_struct n = __WORK_INITIALIZER(n, f)

#define DECLARE_DELAYED_WORK(n, f) struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)

创建工作队列的方法如下:
#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)
#define create_rt_workqueue(name) __create_workqueue((name), 0, 0, 1)
#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1, 0)
#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0, 0)

下面是在特定的workqueue上面对work的调度,
extern int queue_work(struct workqueue_struct *wq, struct work_struct *work);
extern int queue_work_on(int cpu, struct workqueue_struct *wq,struct work_struct *work);
extern int queue_delayed_work(struct workqueue_struct *wq,struct delayed_work *work, unsigned long delay);
extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,struct delayed_work *work, unsigned long delay);
下面是在默认的workqueue即event上面对work进行调度。
extern int schedule_work(struct work_struct *work);
extern int schedule_work_on(int cpu, struct work_struct *work);
extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,unsigned long delay);
对应,可以从其中可以看出,有俩种不同的 work结构体,(struct work_struct)和(struct delayed_work)。
都是针对work的调度。

extern void destroy_workqueue(struct workqueue_struct *wq);
*/

#include <linux/kernel.h> /* We're doing kernel work */#include <linux/module.h> /* Specifically, a module */#include <linux/proc_fs.h> /* Necessary because we use the proc fs */#include <linux/workqueue.h> /* We scheduale tasks here */#include <linux/sched.h> /* We need to put ourselves to sleep and wake up later */#include <linux/init.h> /* For __init and __exit */#include <linux/interrupt.h> /* For irqreturn_t */#include <asm/delay.h>#include <linux/delay.h>struct proc_dir_entry *Our_Proc_File;#define PROC_ENTRY_FILENAME "testsched"#define MY_WORK_QUEUE_NAME "WQsched.c"/*有俩种work类型#define DECLARE_WORK(n, f)struct work_struct n = __WORK_INITIALIZER(n, f)#define DECLARE_DELAYED_WORK(n, f)struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)创建工作队列的方法如下:#define create_workqueue(name) __create_workqueue((name), 0, 0, 0)#define create_rt_workqueue(name) __create_workqueue((name), 0, 0, 1)#define create_freezeable_workqueue(name) __create_workqueue((name), 1, 1, 0)#define create_singlethread_workqueue(name) __create_workqueue((name), 1, 0, 0)extern int queue_work(struct workqueue_struct *wq, struct work_struct *work);extern int queue_work_on(int cpu, struct workqueue_struct *wq,struct work_struct *work);extern int queue_delayed_work(struct workqueue_struct *wq,struct delayed_work *work, unsigned long delay);extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,struct delayed_work *work, unsigned long delay);与extern int schedule_work(struct work_struct *work);extern int schedule_work_on(int cpu, struct work_struct *work);extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay);extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,unsigned long delay);对应,可以从其中可以看出,有俩种不同的 work结构体,(struct work_struct)和(struct delayed_work)。都是针对work的调度。extern void destroy_workqueue(struct workqueue_struct *wq);*//*本实例主要测试的是:内核中如何实现周期性的任务执行。如果驱动程序中需要执行周期性的动作,可使用以下三种方式之一。基本思路为:创建work,让创建的work调度到linux系统内核queue还是自己创建的queue。*/static int TimerIntrpt = 0;#define IS_DELAY_WORK 3struct work_struct      led_event;static void led_event_work_func(struct work_struct **work);void init_work(){INIT_WORK(&led_event, led_event_work_func);schedule_work(&led_event);}void led_event_work_func(struct work_struct **work){ TimerIntrpt++;//if(TimerIntrpt>2000) if(0){  // cancel_delayed_work(&led_event); printk("cancel_delayed_work\n");}else{//printk("TimerIntrpt:%d\n",TimerIntrpt);msleep(20);schedule_work(&led_event);} }ssize_tprocfile_read(char *buffer,char **buffer_location,off_t offset, int buffer_length, int *eof, void *data){int len; /* The number of bytes actually used */static char my_buffer[80];len = sprintf(my_buffer, "Timer called %d times so far\n", TimerIntrpt);strcpy(buffer,my_buffer);return len;}static struct workqueue_struct *led_wq;static void led_work_func(struct work_struct *);static DECLARE_WORK(led_task, led_work_func);static void led_work_func (struct work_struct *unused){/** Increment the counter*/TimerIntrpt++;if(TimerIntrpt>2000){//cancel_work_sync(&led_task); printk("cancel_delayed_work\n");}else{printk("TimerIntrpt:%d\n",TimerIntrpt);queue_work(led_wq, &led_task);}}static int init_start_task(void) { led_wq = create_workqueue("led_wq"); queue_work(led_wq, &led_task); return 0;}static void delayed_led_work_func(struct work_struct *);static DECLARE_DELAYED_WORK(delayed_led_task, delayed_led_work_func);static void delayed_led_work_func (struct work_struct *unused){/** Increment the counter*/TimerIntrpt++;if(TimerIntrpt>20){cancel_delayed_work(&delayed_led_task); printk("cancel_delayed_work\n");}else{printk("TimerIntrpt:%d\n",TimerIntrpt);queue_delayed_work(led_wq, &delayed_led_task, 250);}}static int init_delayed_start_task(void) {//led_wq = create_singlethread_workqueue("led_wq"); led_wq = create_workqueue("led_wq"); queue_delayed_work(led_wq, &delayed_led_task, 0);return 0;}/** Initialize the module ? register the proc file*/int __init init_module(){/** Create our /proc file*/Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL);if (Our_Proc_File == NULL) {remove_proc_entry(PROC_ENTRY_FILENAME, NULL);printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",PROC_ENTRY_FILENAME);return ENOMEM;}Our_Proc_File->read_proc = procfile_read;printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_FILENAME);#if IS_DELAY_WORK==1init_delayed_start_task();#elif (IS_DELAY_WORK==2)init_start_task();#elseinit_work();#endif return 0;}/** Cleanup*/void __exit cleanup_module(){/** Unregister our /proc file*/remove_proc_entry(PROC_ENTRY_FILENAME, NULL);printk(KERN_INFO "/proc/%s removed\n", PROC_ENTRY_FILENAME);#if (IS_DELAY_WORK==1)cancel_delayed_work(&delayed_led_task); flush_workqueue(led_wq); /* wait till all "old ones" finished */destroy_workqueue(led_wq);#elif(IS_DELAY_WORK==2)cancel_delayed_work(&led_task);flush_workqueue(led_wq); /* wait till all "old ones" finished */destroy_workqueue(led_wq);#else//cancel_delayed_work(&led_event); #endif }MODULE_LICENSE("GPL");MODULE_AUTHOR("suiyuan from test"); MODULE_DESCRIPTION("shech driver for testing ");



原创粉丝点击