LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel
User Name
Password
Linux - Kernel This forum is for all discussion relating to the Linux kernel.

Notices


Reply
  Search this Thread
Old 09-03-2007, 06:23 PM   #1
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180
Blog Entries: 1

Rep: Reputation: 32
Question Does anyone understand exactly how to schedule work in kernel >= 2.6.20?


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?
 
Old 09-03-2007, 11:39 PM   #2
sixerjman
Member
 
Registered: Sep 2004
Distribution: Debian Testing / Unstable
Posts: 180

Original Poster
Blog Entries: 1

Rep: Reputation: 32
This works

#include <linux/version.h>
...
/* workqueue API changed in kernel 2.6.20 */
#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) )
static struct work_struct Task;
static DECLARE_WORK(Task, intrpt_routine, NULL);
#else
static DECLARE_DELAYED_WORK(Task, intrpt_routine);
#endif

Found an example of this technique in 'fs/nfsd/nfs4state.c'. BTW, the doc
in the previously listed article (http://lwn.net/Articles/211279/) is wrong, queue_delayed_work still takes an unsigned long delay argument as the third parm.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
trying to understand kernel config class_struggle Linux - General 5 05-06-2010 02:55 AM
LXer: Schedule Tasks Using Gnome-schedule (cron & at GUI) LXer Syndicated Linux News 0 07-28-2007 12:31 AM
Question about threads (I don't understand how they work) zahadumy Programming 10 12-13-2005 12:19 PM
cron jobs work fine when invoked from webmin but fail on schedule jillu Linux - Enterprise 3 01-20-2005 01:34 PM
i want others to understand my handy-work rblampain Programming 3 10-31-2004 01:15 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel

All times are GMT -5. The time now is 11:10 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration