定義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加入到另一個 |
沒有留言:
張貼留言