I'm struggling to understand the new workqueue API as of kernel 2.6.20 (
http://lwn.net/Articles/211279/). I'm trying to rework a couple of examples from 'The Linux Kernel Module Programming Guide' but I just don't understand thoroughly enough to get past these compile errors. Here's what I changed so far per this article (
http://lwn.net/Articles/213149/):
Code:
/*
* sched.c - scheduale a function to be called on every timer interrupt.
*
* Copyright (C) 2001 by Peter Jay Salzman
*/
/*
* The necessary header files
*/
/*
* Standard in kernel modules
*/
#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 */
struct proc_dir_entry *Our_Proc_File;
#define PROC_ENTRY_FILENAME "sched"
#define MY_WORK_QUEUE_NAME "WQsched.c"
/*
* The number of times the timer interrupt has been called so far
*/
static int TimerIntrpt = 0;
static void intrpt_routine(void *);
static int die = 0; /* set this to 1 for shutdown */
/*
* The work queue structure for this task, from workqueue.h
*/
static struct workqueue_struct *my_workqueue;
/*static struct work_struct Task;*/
static struct delayed_work Task;
/*static DECLARE_WORK(Task, intrpt_routine, NULL);*/
static DECLARE_DELAYED_WORK(Task, intrpt_routine); /* kernel 2.6.20 workqueue re-structured */
/*
* This function will be called on every timer interrupt. Notice the void*
* pointer - task functions can be used for more than one purpose, each time
* getting a different parameter.
*/
static void intrpt_routine(void *irrelevant)
{
/*
* Increment the counter
*/
TimerIntrpt++;
/*
* If cleanup wants us to die
*/
if (die == 0)
/*queue_delayed_work(my_workqueue, &Task, 100);*/
queue_delayed_work(my_workqueue, (struct delayed_work)&Task);
}
/*
* Put data into the proc fs file.
*/
ssize_t
procfile_read(char *buffer,
char **buffer_location,
off_t offset, int buffer_length, int *eof, void *data)
{
int len; /* The number of bytes actually used */
/*
* It's static so it will still be in memory
* when we leave this function
*/
static char my_buffer[80];
/*
* We give all of our information in one go, so if anybody asks us
* if we have more information the answer should always be no.
*/
if (offset > 0)
return 0;
/*
* Fill the buffer and get its length
*/
len = sprintf(my_buffer, "Timer called %d times so far\n", TimerIntrpt);
/*
* Tell the function which called us where the buffer is
*/
*buffer_location = my_buffer;
/*
* Return the length
*/
return len;
}
/*
* 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, &proc_root);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
PROC_ENTRY_FILENAME);
return -ENOMEM;
}
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 80;
/*
* Put the task in the work_timer task queue, so it will be executed at
* next timer interrupt
*/
my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME);
/*queue_delayed_work(my_workqueue, &Task, 100);*/
queue_delayed_work(my_workqueue, &Task); /* kernel 2.6.20 workqueue re-structured */
printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_FILENAME);
return 0;
}
/*
* Cleanup
*/
void __exit cleanup_module()
{
/*
return 0;
}
/*
* Cleanup
*/
void __exit cleanup_module()
{
/*
* Unregister our /proc file
*/
remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
printk(KERN_INFO "/proc/%s removed\n", PROC_ENTRY_FILENAME);
die = 1; /* keep intrp_routine from queueing itself */
cancel_delayed_work(&Task); /* no "new ones" */
flush_workqueue(my_workqueue); /* wait till all "old ones" finished */
destroy_workqueue(my_workqueue);
/*
* Sleep until intrpt_routine is called one last time. This is
* necessary, because otherwise we'll deallocate the memory holding
* intrpt_routine and Task while work_timer still references them.
* Notice that here we don't allow signals to interrupt us.
*
* Since WaitQ is now not NULL, this automatically tells the interrupt
* routine it's time to die.
*/
}
/*
* some work_queue related functions
* are just available to GPL licensed Modules
*/
but I get the following compile errors (note the compiler didn't like 'DECLARE_DELAYED_WORK' but I don't see what the problem is):
Code:
make
make -C /lib/modules/2.6.21/build M=/usr/local/src/LKMP modules
make[1]: Entering directory `/usr/src/linux-source-2.6.21'
CC [M] /usr/local/src/LKMP/sched.o
/usr/local/src/LKMP/sched.c:44: warning: initialization from incompatible pointer type
/usr/local/src/LKMP/sched.c: In function ‘intrpt_routine’:
/usr/local/src/LKMP/sched.c:63: error: conversion to non-scalar type requested
/usr/local/src/LKMP/sched.c:63: error: too few arguments to function ‘queue_delayed_work’
/usr/local/src/LKMP/sched.c: In function ‘init_module’:
/usr/local/src/LKMP/sched.c:135: error: too few arguments to function ‘queue_delayed_work’
make[2]: *** [/usr/local/src/LKMP/sched.o] Error 1
make[1]: *** [_module_/usr/local/src/LKMP] Error 2
make[1]: Leaving directory `/usr/src/linux-source-2.6.21'
make: *** [all] Error 2
I'll be trolling through the kernel source code for some concrete examples but this is a bear trying to understand. For example, the timer
struct was removed from the work_struct so now 'queue_delayed_work' takes 2 arguments instead of 3 so where do I put the delay?