home   |   -   |   A-Z   |  


sched.c

/* sched.c - schedule a function to be called on

* every timer interrupt.

*/

/* Copyright (C) 1998 by Ori Pomerantz */


/* The necessary header files */

/* Standard in kernel modules */

#include /* We're doing kernel work */

#include /* Specifically, a module */


/* Deal with CONFIG_MODVERSIONS */

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include

#endif


/* Necessary because we use the proc fs */

#include


/* We scheduale tasks here */

#include


/* We also need the ability to put ourselves to sleep

* and wake up later */

#include


/* In 2.2.3 /usr/include/linux/version.h includes a

* macro for this, but 2.0.35 doesn't - so I add it

* here if necessary. */

#ifndef KERNEL_VERSION

#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))

#endif


/* The number of times the timer interrupt has been

* called so far */

static int TimerIntrpt = 0;


/* This is used by cleanup, to prevent the module from

* being unloaded while intrpt_routine is still in

* the task queue */

static struct wait_queue *WaitQ = NULL;

static void intrpt_routine(void *);


/* The task queue structure for this task, from tqueue.h */

static struct tq_struct Task = {

NULL, /* Next item in list - queue_task will do

* this for us */

0, /* A flag meaning we haven't been inserted

* into a task queue yet */

intrpt_routine, /* The function to run */

NULL /* The void* parameter for that function */

};


/* 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 (WaitQ != NULL) wake_up(&WaitQ);

/* Now cleanup_module can return */

else queue_task(&Task, &tq_timer);

/* Put ourselves back in the task queue */

}


/* Put data into the proc fs file. */

int procfile_read(char *buffer, char **buffer_location, off_t offset,int buffer_length, int zero) {

int len; /* The number of bytes actually used */

/* This is static so it will still be in memory

* when we leave this function */

static char my_buffer[80];

static int count = 1;

/* We give all of our information in one go, so if

* the 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 was called %d times so far\n",TimerIntrpt);

count++;

/* Tell the function which called us where the buffer is */

*buffer_location = my_buffer;

/* Return the length */

return len;

}


struct proc_dir_entry Our_Proc_File ={

0, /* Inode number - ignore, it will be filled by

* proc_register_dynamic */

5, /* Length of the file name */

"sched", /* The file name */

S_IFREG | S_IRUGO,

/* File mode - this is a regular file which can

* be read by its owner, its group, and everybody else */

1, /* Number of links (directories where

* the file is referenced) */

0, 0, /* The uid and gid for the file - we give it to root */

80, /* The size of the file reported by ls. */

NULL, /* functions which can be done on the

* inode (linking, removing, etc.) - we don't

* support any. */

procfile_read,

/* The read function for this file, the function called

* when somebody tries to read something from it. */

NULL

/* We could have here a function to fill the

* file's inode, to enable us to play with

* permissions, ownership, etc. */

};


/* Initialize the module - register the proc file */

int init_module() {

/* Put the task in the tq_timer task queue, so it

* will be executed at next timer interrupt */

queue_task(&Task, &tq_timer);

/* Success if proc_register_dynamic is a success,

* failure otherwise */

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)

return proc_register(&proc_root, &Our_Proc_File);

#else

return proc_register_dynamic(&proc_root, &Our_Proc_File);

#endif

}


/* Cleanup */

void cleanup_module() {

/* Unregister our /proc file */

proc_unregister(&proc_root, Our_Proc_File.low_ino);

/* 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 tq_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. */

sleep_on(&WaitQ);

}


| Linux |