定義list節點的資料結構
struct _job_list {
struct list_head all_jobs; /* 工作清單 */
void (*worker_handle)(char *); /* 執行工作的function */
void *worker_data; /* 執行工作所需資料 */
wait_queue_head_t todo; /* 用於同步boss與worker */
spinlock_t lock; /* 用於保護工作清單的鎖 */
};
boss在工作清單中加入jobs
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <job.h>
extern struct _job_list job_list;
static void run_umode_mkdir_app(char *data)
{
int result;
char path[] = "/bin/mkdir";
char *argv[] = { path, data, NULL };
char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
/* 執行一個user space的程式 */
result = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);
if (result == 0) {
printk("worker kthread: successfully executed %s application\n", path);
} else {
printk("worker kthread: failed to execute %s application\n", path);
}
}
static void run_umode_touch_app(char *data)
{
int result;
char path[] = "/bin/touch";
char *argv[] = { path, data, NULL };
char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
/* 執行一個user space的程式 */
result = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);
if (result == 0) {
printk("worker kthread: successfully executed %s application\n", path);
} else {
printk("worker kthread: failed to execute %s application\n", path);
}
}
static void run_umode_bash_app(char *data)
{
int result;
char path[] = "/bin/bash";
char *argv[] = { path, "-c", strcat("echo Boss said: you did good jobs! > ", data),
NULL };
char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
/* 執行一個user space的程式 */
result = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);
if (result == 0) {
printk("worker kthread: successfully executed %s application\n", path);
} else {
printk("worker kthread: failed to execute %s application\n", path);
}
}
static int __init boss_module_init(void)
{
struct _job_list *job1;
struct _job_list *job2;
struct _job_list *job3;
char *data_folder = "/jobs";
char *data_file = "/jobs/renee";
/* 為job配置一個大小為sizeof(work structure)核心記憶體空間 */
job1 = kmalloc(sizeof(struct _job_list), GFP_ATOMIC);
if (!job1) return -1;
/* 填寫work structure內容 */
job1->worker_handle = run_umode_mkdir_app; /* 執行工作的fuction */
job1->worker_data = data_folder; /* function的參數 */
job2 = kmalloc(sizeof(struct _job_list), GFP_ATOMIC);
if (!job2) return -1;
job2->worker_handle = run_umode_touch_app;
job2->worker_data = data_file;
job3 = kmalloc(sizeof(struct _job_list), GFP_ATOMIC);
if (!job3) return -1;
job3->worker_handle = run_umode_bash_app;
job3->worker_data = data_file;
spin_lock(&job_list.lock); /* 進入critical section存取前要上鎖 */
/* 將工作加入工作清單 */
list_add_tail(&job1->all_jobs, &job_list.all_jobs);
printk("boss: assigned 1st job to the worker\n");
list_add_tail(&job2->all_jobs, &job_list.all_jobs);
printk("boss: assigned 2nd job to the worker\n");
list_add_tail(&job3->all_jobs, &job_list.all_jobs);
printk("boss: assigned 3rd job to the worker\n");
wake_up(&job_list.todo); /* 喚醒worker thread */
spin_unlock(&job_list.lock); /* 離開critical section,進行解鎖 */
printk("Boss module loaded\n");
return 0;
}
static void __exit boss_module_exit(void)
{
printk("Boss module unloaded\n");
}
module_init(boss_module_init);
module_exit(boss_module_exit);
MODULE_DESCRIPTION("boss Module");
MODULE_LICENSE("GPL");
MODULE_ALIAS("boss module");
MODULE_AUTHOR("Renee's Blog");
worker執行工作清單中所有的jobs
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <job.h>
struct _job_list job_list;
EXPORT_SYMBOL(job_list);
int worker_pid;
static int worker(void* unused)
{
DECLARE_WAITQUEUE(wait, current);
daemonize("worker");
void (*worker_handle)(char *);
void *worker_data;
struct _job_list *job;
set_current_state(TASK_INTERRUPTIBLE);
allow_signal(SIGKILL);
while (1) {
add_wait_queue(&job_list.todo, &wait);
if (list_empty(&job_list.all_jobs)) {
schedule();
if (signal_pending(current)) {
break;
}
} else {
set_current_state(TASK_RUNNING);
}
remove_wait_queue(&job_list.todo, &wait);
/* 由於list是共享的資料結構,在進入critical section存取前要上鎖 */
spin_lock(&job_list.lock);
/* 如果list不為空,則取出節點,並執行節點裡面function */
while (!list_empty(&job_list.all_jobs)) {
/* 先存取list中第一個節點 */
job = list_entry(job_list.all_jobs.next, struct _job_list, all_jobs);
worker_handle = job->worker_handle;
worker_data = job->worker_data;
list_del(&job->all_jobs); /* 此節點已經被處理過,將它從list刪除 */
kfree(job); /* 釋放節點 */
spin_unlock(&job_list.lock); /* 離開critical section,進行解鎖 */
worker_handle(worker_data); /* 執行從節點取出的fuction */
printk("worker: finished a job\n");
spin_lock(&job_list.lock); /* 如果list不為空,會再進入critical section,
所以需要再次上鎖 */
}
spin_unlock(&job_list.lock); /* 離開critical section,進行解鎖 */
set_current_state(TASK_INTERRUPTIBLE);
}
remove_wait_queue(&job_list.todo, &wait);
return 0;
}
static int __init worker_module_init(void)
{
/* 初始化lock,用於保護list共享資料結構 */
spin_lock_init(&job_list.lock);
/* 初始化wait queue,用於同步boss與worker */
init_waitqueue_head(&job_list.todo);
/* 初始化list的head節點 */
INIT_LIST_HEAD(&job_list.all_jobs);
worker_pid = kernel_thread(worker, NULL, CLONE_FS |
CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
if(worker_pid > 0)
{
printk("Created the kthread of the worker PID = %d\n", worker_pid);
}
else
{
printk("Failed to create the kthread of the worker\n");
}
printk("Worker module loaded\n");
return 0;
}
static void __exit worker_module_exit(void)
{
if(worker_pid)
{
kill_pid(find_vpid(worker_pid), SIGKILL, 1);
}
printk("Worker module unloaded\n");
}
module_init(worker_module_init);
module_exit(worker_module_exit);
MODULE_DESCRIPTION("Worker Module");
MODULE_LICENSE("GPL");
MODULE_ALIAS("worker module");
MODULE_AUTHOR("Renee's Blog");
操作list的函式列表:
| 函式 | 說明 |
|---|---|
| INIT_LIST_HEAD() | 初始化list的head節點 |
| list_add() | 在head後方加入一個節點 |
| list_add_tail() | 在head前方加入一個節點 |
| list_del() | 刪除一個節點 |
| list_replace() | 一個節點取代另一個 |
| list_entry() | list中取得一個節點 |
| list_for_each_entry() | 走訪list所有節點 |
| list_for_each_entry_safe() | 走訪list所有節點,並確保不會刪除任何節點 |
| list_empty() | 確認list是否為空 |
| list_splice() | 一個list加入到另一個 |
沒有留言:
張貼留言