万卷书   首页 > 电脑书籍 > Linux >Linux内核模块编程--替任务调度
 
范例 sched.c

/* sched.c - 安排一个函数在每次定时器中断时被调用 */

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

/* 必要头文件 */

/* 标准头文件 */
#include /* 内核工作 */
#include /* 明确指定是模块 */

/* 处理 CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include
#endif

/* 我们使用 proc 文件系统所必要的 */
#include

/* 我们在这儿安排任务 */
#include

/* 我们也需要睡眠和唤醒的能力 */
#include

/* 2.2.3 版/usr/include/linux/version.h 包含该宏
* 但2.0.35 版不包含 - 加入以备需要 */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif

/* 定时器中断已经被调用的次数 */
static int TimerIntrpt = 0;

/* 这被清除模块使用,以防止当 intrpt_routine 仍在任务队列里时模块被清除 */
static struct wait_queue *WaitQ = NULL;

static void intrpt_routine(void *);

/* 这个任务的任务队列结构,来自 tqueue.h */
static struct tq_struct Task = {
NULL, /* 列表的下一项 - queue_task 将为我们做这个 */
0, /* 一个标志,意思是我们还没有被插入任务队列 */
intrpt_routine, /* 运行的函数 */
NULL /* 函数的void* 参数 */
};

/* 这个函数将在每次定时器中断时被调用。注意 void* 指针 -
* 任务函数可以用于多个目的,每次得到不同的参数。 */
static void intrpt_routine(void *irrelevant)
{
/* 增加计数器 */
TimerIntrpt++;

/* 如果清除模块想我们死亡 */
if (WaitQ != NULL)
wake_up(&WaitQ); /* 现在 cleanup_module 可以返回 */
else
/* 将我们放回任务队列 */
queue_task(&Task, &tq_timer);
}

/* 将数据放入proc 文件 */
int procfile_read(char *buffer,
char **buffer_location, off_t offset,
int buffer_length, int zero)
{
int len; /* 实际使用的字节数 */

/* 这是静态的因此当我们离开这个函数时它仍然在内存中 */
static char my_buffer[80];

static int count = 1;

/* 我们将所有的信息放在一个里面,因此当有人问我们是否有更多 信息时答案是否。 */
if (offset > 0)
return 0;

/* 填充缓冲区并得到它的长度 */
len = sprintf(my_buffer,
"Timer was called %d times so far\n",
TimerIntrpt);
count++;

/* 告诉调用我们的函数缓冲区在哪儿 */
*buffer_location = my_buffer;

/* 返回长度 */
return len;
}

struct proc_dir_entry Our_Proc_File =
{
0, /* 节点数 - 忽略,它将被 proc_register_dynamic 填充*/
5, /* 文件名长度 */
"sched", /* 文件名 */
S_IFREG | S_IRUGO,
/* 文件模式 - 这是一个可以被其拥有者,用户组和其他任何人读取的普通文件 */
1, /* 连接数 (文件被引用的目录)*/
0, 0, /* 文件的UID和GID - 我们将它赋予root */
80, /* 由ls报告的文件长度 */
NULL, /* 节点函数(连接,删除,等等) - 不支持 */
procfile_read,
/* 文件的读函数,当某人试图从中读什么时被调用 */
NULL
/* 可以在这儿设置一个填充文件节点的函数,以使我们可以修改权限,拥有关系等。 */
};

/* 初始化模块--登记 proc 文件 */
int init_module()
{
/* 将任务放置在 tq_timer 任务队列,因此在下次定时器中断时它将被执行 */
queue_task(&Task, &tq_timer);

/* proc_register_dynamic 成功则成功,否则失败 */
#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
}

/* 清除 */
void cleanup_module()
{
/* 注销 /proc 文件 */
proc_unregister(&proc_root, Our_Proc_File.low_ino);

/* 睡眠,直到 intrpt_routine 上次被调用。这是必要的,因为否则我们将释放 intrpt_routine
* 和tq_timer仍然引用的任务占有的内存。注意不允许信号中断。
*
* 既然 WaitQ 现在不为 NULL,这自动的告诉中断程序它死亡的时间到了。 */
sleep_on(&WaitQ);
}

上一页