Linux Kernel module programming-scheduling tasks

Source: Internet
Author: User
Linux Kernel module programming-Job Scheduling-Linux general technology-Linux programming and kernel information. The following is a detailed description. Often, we have 'housework management' tasks that need to be done at some time or occasionally. If the task is completed by a process, we can put it in the crontab file. If the task is completed by the kernel module, there are two possibilities. The first is to place a process in the crontab file to wake up the module by calling the system when necessary, for example, by opening the file. This is very inefficient, but -- we run a new process that is not in the crontab, read a new executable process to the memory, and all this is just to wake up the kernel module in the memory.

Instead, we can create a function that is called once for every timer interruption. Our solution is to create a Task contained in the tq_struct structure, which contains the pointer of the function. Then we use queue_task to place the task in the task list called tq_timer, which is a list of tasks that will be executed when the next timer is interrupted. Because we want this function to continue to be executed when the next timer is interrupted, we need to put it back into tq_timer after it is called.

This also needs to be remembered. When a module is removed by rmmod, its reference counter is checked first. If it is 0, module_cleanup will be called. Then the module and all its functions are cleared from the memory. No one checks whether the timer task list contains such a pointer to a function that is no longer visible. After a while (from the computer's point of view, and from the human's point of view, it's nothing, it's less than 1% seconds ), the kernel has a timer interrupt and tries to call the functions in the task list. Unfortunately, that function is not there. In most cases, the page in which it is located is not used, and you will get an ugly error message. However, if some other code is currently in the same memory location, it will become very ugly. Unfortunately, there is no simple way to unregister a task from the task list.

Since cleanup_module cannot return error code (it is a void function), the solution is not to let it return at all. Instead, it calls sleep_on or module_sleep_on (they are actually the same. ) Sleep the rmmod process. Before that, it sets a global variable to notify the function that will be called to stop connecting itself when the timer is interrupted. Then, when the next timer is interrupted, the rmmod process is awakened. It is safe to remove the module when our function is no longer in that queue.

Example sched. c

/* Sched. c-schedule a function to be called every time the timer is interrupted */

/* Copy right (C) 1998 by Ori Pomerantz */

/* Required header files */

/* Standard header file */
# Include/* kernel work */
# Include/* explicitly specify a module */

/* Process CONFIG_MODVERSIONS */
# If CONFIG_MODVERSIONS = 1
# Define MODVERSIONS
# Include
# Endif

/* What we need to use the proc file system */
# Include

/* We will arrange the task here */
# Include

/* We also need the ability to sleep and wake up */
# Include

/* 2.2.3/usr/include/linux/version. h contains the macro
* Version 2.0.35 is not included.-Add it as needed */
# Ifndef KERNEL_VERSION
# Define KERNEL_VERSION (a, B, c) (a) x 65536 + (B) * 256 + (c ))
# Endif

/* Number of times the timer has been called for interruption */
Static int TimerIntrpt = 0;

/* This is used by the clearing module to prevent the module from being cleared when intrpt_routine is still in the task queue */
Static struct wait_queue * WaitQ = NULL;

Static void intrpt_routine (void *);

/* The task queue structure of this task, from tqueue. h */
Static struct tq_struct Task = {
NULL,/* The next item in the list-queue_task will do this for us */
0,/* indicates that we have not been inserted into the task queue */
Intrpt_routine,/* Running function */
NULL/* void * parameter of the function */
};

/* This function will be called every time the timer is interrupted. Note void * pointer-
* The task function can be used for multiple purposes to obtain different parameters each time. */
Static void intrpt_routine (void * irrelevant)
{
/* Add a counter */
TimerIntrpt ++;

/* If the cleanup module wants us to die */
If (WaitQ! = NULL)
Wake_up (& WaitQ);/* Currently cleanup_module can return */
Else
/* Put us back into the task queue */
Queue_task (& Task, & tq_timer );
}

/* Put data in the proc file */
Int procfile_read (char * buffer,
Char ** buffer_location, off_t offset,
Int buffer_length, int zero)
{
Int len;/* actual number of bytes used */

/* This is static. Therefore, when we leave this function, it is still in memory */
Static char my_buffer [80];

Static int count = 1;

/* We put all the information in one, so when someone asks us if we have more information, is the answer. */
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 us where to call our Function Buffer */
* Buffer_location = my_buffer;

/* Return length */
Return len;
}

Struct proc_dir_entry Our_Proc_File =
{
0,/* number of nodes-ignore, it will be filled by proc_register_dynamic */
5,/* file name length */
"Sched",/* file name */
S_IFREG | S_IRUGO,
/* File mode-this is a common file that can be read by its owner, user group, and anyone else */
1,/* connections (directory referenced by the file )*/
0, 0,/* file UID and GID-we give it to root */
80,/* file length reported by ls */
NULL,/* node functions (connection, deletion, and so on)-Not Supported */
Procfile_read,
/* File Read function, called when someone tries to read from it */
NULL
/* You can set a function to fill in the file node here, so that we can modify permissions and have relationships. */
};

/* Initialize the module -- register the proc file */
Int init_module ()
{
/* Place the task in the tq_timer task queue, so it will be executed when the timer is interrupted next time */
Queue_task (& Task, & tq_timer );

/* If proc_register_dynamic is successful, the operation succeeds. Otherwise, the operation fails */
# 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
}

/* Clear */
Void cleanup_module ()
{
/* Log out of the/proc file */
Proc_unregister (& proc_root, Our_Proc_File.low_ino );

/* Sleep until intrpt_routine is called last time. This is necessary, because otherwise we will release intrpt_routine
* And tq_timer still reference the memory occupied by the task. Do not interrupt the signal.
*
* Since WaitQ is not NULL now, it automatically tells the interrupt program that it has been killed. */
Sleep_on (& WaitQ );
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.