我是靠谱客的博主 美丽故事,最近开发中收集的这篇文章主要介绍使用内核线程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在Linux内核驱动里或者是其它的Linux代码里面,也会有用到线程的时候。

这时候应该使用内核线程。内核线程其实就是守护进程。Linux内核的子系统
就是由这些内核线程构成的。
内核线程的创建方法:
 
  
可以看到主要有两个动作,创建和脱离。创建就是分配资源,脱离,就是为了使其成为内核的守护
进程,使其脱离与创建者的联系。调用daemonize()函数。
/*
 * Put all the gunge required to become a kernel thread without
 * attached user resources in one place where it belongs.
 */
void daemonize(const char *name, ...)
{
 va_list args;
 struct fs_struct *fs;
 sigset_t blocked;
 va_start(args, name);
 vsnprintf(current->comm, sizeof(current->comm), name, args);
 va_end(args);
 /*
  * If we were started as result of loading a module, close all of the
  * user space pages.  We don't need them, and if we didn't close them
  * they would be locked into memory.
  */
 exit_mm(current);    /*释放用户空间内存*/
 set_special_pids(1, 1);
 mutex_lock(&tty_mutex);
 current->signal->tty = NULL;
 mutex_unlock(&tty_mutex);
 /* Block and flush all signals */  /* 禁用所有信号 */
 sigfillset(&blocked);       
 sigprocmask(SIG_BLOCK, &blocked, NULL);
 flush_signals(current);
 /* Become as one with the init task */
 exit_fs(current); /* current->fs->count--; */ /* 释放文件 */
 fs = init_task.fs;
 current->fs = fs;
 atomic_inc(&fs->count);
 exit_namespace(current); /* 命名空间 */
 current->namespace = init_task.namespace;
 get_namespace(current->namespace);
  exit_files(current);
 current->files = init_task.files;
 atomic_inc(&current->files->count);
 reparent_to_init();  /* 父进程改为init进程 */
}
 
 
 
 
/*
 * Let kernel threads use this to say that they
 * allow a certain signal (since daemonize() will
 * have disabled all of them by default).
 */
int allow_signal(int sig)
{
 if (!valid_signal(sig) || sig < 1)
  return -EINVAL;
 spin_lock_irq(&current->sighand->siglock);
 sigdelset(&current->blocked, sig);
 if (!current->mm) {
  /* Kernel threads handle their own signals.
     Let the signal code know it'll be handled, so
     that they don't get converted to SIGKILL or
     just silently dropped */
  current->sighand->action[(sig)-1].sa.sa_handler = (void __user *)2;
 }
 recalc_sigpending();
 spin_unlock_irq(&current->sighand->siglock);
 return 0;
}
 因为在daemonize里面会禁用所有的信号,所以可以使用allow_signal来
恢复特定的信号。
 
 转载一篇关于内核线程特别好的一篇文章:
#include <linux/kernel.h>

#include <linux/module.h>



static pid_t thread_pid;

static struct completion thread_exited;

static int noop(void *dummy)

{

daemonize("mythread");

allow_signal(SIGTERM);

while (!signal_pending (current)) {

                /* do something else */

schedule();

}

complete_and_exit(&thread_exited, 1);

}



static int test_init(void)

{

init_completion(&thread_exited);

thread_pid = kernel_thread(noop, NULL, CLONE_KERNEL | SIGCHLD);

return 0;

}



static void test_exit(void) 

{

kill_proc (thread_pid, SIGTERM, 1);

wait_for_completion(&thread_exited);

}

module_init(test_init);

module_exit(test_exit);
 
 
”mythread“就是给这个内核线程取的名字, 可以用ps -A来查看。 
schedule()用于进程调度, 可以理解为放弃CPU的使用权. 
 
static int reporter_thread(void *__unused) 

/* 
* This thread doesn't need any user-level access, 
* so get rid of all our resources 
*/ 

daemonize("reported_thread"); 
allow_signal(SIGKILL); 
do { 
....... 

} while(1); 
complete_and_exit(&reporter_exited,0); 

static void page_fault_seeker_exit(void) 

.... 
kill_proc(pid, SIGKILL, 1); 

/*kernel thread must be killed before module unloaded 
*wait for the completion of kernel thread 
*/ 
wait_for_completion(&reporter_exited); 
... 


 
可以在非内核线程中调用kernel_thread, 但这样创建的线程必须在自己调用daemonize(...)来释放资源, 成为真正的内核线程。 

#include <linux/kernel.h> 
#include <linux/module.h> 

static int noop(void *dummy) 

int i = 0; 
daemonize("mythread"); 
while(i++ < 5) { 
printk("current->mm = %pn", current->mm); 
printk("current->active_mm = %pn", current->active_mm); 
set_current_state(TASK_INTERRUPTIBLE); 
schedule_timeout(10 * HZ); 

return 0; 


static int test_init(void) 

kernel_thread(noop, NULL, CLONE_KERNEL | SIGCHLD); 
return 0; 


static void test_exit(void) {} 
module_init(test_init); 
module_exit(test_exit); 
 

这还有一个在其它内核线程中调用kernel_thread的例子。 这个的current->mm就为零了。 

static struct work_struct work; 
static int noop(void *dummy) 

printk("current->mm = %pn", current->mm); 
return 0; 

static void create_thread(void *dummy) 

kernel_thread(noop, NULL, CLONE_KERNEL | SIGCHLD); 

static int test_init(void) 

INIT_WORK(&work, create_thread, NULL); 
schedule_work(&work); 

static void test_exit(void) {} 
module_init(test_init); 
module_exit(test_exit);

大部分情况, 都可以创建一个 work_queue来代替。

 

 

/*
 * Let kernel threads use this to say that they
 * allow a certain signal (since daemonize() will
 * have disabled all of them by default).
 */
int allow_signal(int sig)



内核线程函数里先调用daemonize去掉mm,fs 等资源后   禁止所有信号

如果需要,调用allow_signal  允许某个信号

 

 

kernel daemons & blocking mutex

March 12, 2007 - 4:27am
Submitted by  milindchoudhary on March 12, 2007 - 4:27am.
linux

/********************************************************************
*Description :: A kernel module which creates 2 kernel threads.
* Converts both of them to daemons.Demonstrates the use of mutex
* to share a dummy resource between the two.
* The mutex is acquired using a blocking call :down_interruptible()
*Author :: Milind A Choudhary
*Date ::07-Dec-2005
********************************************************************/

#include
#include
#include
#include
#include
#include

/* The resource which will be shared */
struct data {
int num;
}data={11};

pid_t kthread_pid1 ;
pid_t kthread_pid2 ;
DECLARE_MUTEX(mutex);

/*Routine for the first thread */

int kthread_routine_1(void *kthread_num)
{
//int num=(int)(*(int*)kthread_num);
int num=1;
char kthread_name[15];

printk(KERN_INFO "Inside daemon_routine() n");
sprintf(kthread_name,"kern_daemon_%d",num);
daemonize(kthread_name);
allow_signal(SIGKILL);
allow_signal(SIGTERM);

do{
printk(KERN_INFO "kernel_daemon [%d] waiting to acquire mutexn",num);
if(!down_interruptible(&mutex)){
printk(KERN_INFO "kernel_daemon [%d] accessing the shared data=%dn",num,data.num);
data.num=11;
up(&mutex);
printk(KERN_INFO "kernel_daemon [%d] released the mutex data=%dn",num,data.num);
}else{
printk(KERN_INFO "kernel_daemon [%d] interrupted while acquiring the mutexn",num);
}

set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(5*HZ);

}while(!signal_pending(current));
return 0;
}

/*Routine for the second thread */

int kthread_routine_2(void *kthread_num)
{
//int num=(int)(*(int*)kthread_num);
int num=2;
char kthread_name[15];

printk(KERN_INFO "Inside daemon_routine() n");
sprintf(kthread_name,"kern_daemon_%d",num);
daemonize(kthread_name);
allow_signal(SIGKILL);
allow_signal(SIGTERM);

do{
printk(KERN_INFO "kernel_daemon [%d] waiting to acquire mutexn",num);
if(!down_interruptible(&mutex)){
printk(KERN_INFO "kernel_daemon [%d] accessing the shared data=%dn",num,data.num);
data.num=22;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(10*HZ);
up(&mutex);
printk(KERN_INFO "kernel_daemon [%d] released the mutex data=%dn",num,data.num);
}else{
printk(KERN_INFO "kernel_daemon [%d] interrupted while acquiring the mutexn",num);
}

set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(10*HZ);

}while(!signal_pending(current));
return 0;
}

int _init_(void)
{
int kthread_num =1;
printk(KERN_INFO"starting the first kernel threadn");
kthread_pid1 = kernel_thread(kthread_routine_1,NULL,0);
if(kthread_pid1< 0 ){
printk(KERN_ALERT "Kernel thread [1] creation failedn");
return -1;
}
kthread_num=2;
printk(KERN_INFO"starting the second kernel threadn");
kthread_pid2 = kernel_thread(kthread_routine_2,NULL,0);
if(kthread_pid2 < 0 ){
printk(KERN_ALERT "Kernel thread [2] creation failedn");
return -1;
}

return 0;
}

void _fini_(void)
{
printk(KERN_INFO"kernel daemon [1] terminatingn");
if(kill_proc(kthread_pid1,SIGTERM,1) == -ESRCH){
printk(KERN_ERR "kernel thread1 pid::%d already deadn",kthread_pid1);
init_MUTEX(&mutex);
}
printk(KERN_INFO"kernel daemon [2] terminatingn");
if(kill_proc(kthread_pid2,SIGTERM,1) == -ESRCH){
printk(KERN_ERR "kernel thread2 pid::%d already deadn",kthread_pid2);
init_MUTEX(&mutex);
}
}

module_init(_init_);
module_exit(_fini_);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Demonstrates use of mutex");
MODULE_AUTHOR("Milind A Choudhary");

 

 

/*
* file mythread.c
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/param.h>
#include <linux/jiffies.h>

#include <asm/system.h> 
#include <asm/processor.h>
#include <asm/signal.h>

/*
        struct student {
                int age;
                char name[128];
                int score;
        };
*/

static pid_t thread_id;
struct completion exit_completion;

int my_fuction(void *arg)
{
        daemonize("demo-thread"); 
        allow_signal(SIGKILL);

        while(!signal_pending(current))
        {
                printk("jiffies is %lun", jiffies);

                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(10 * HZ);
        }


        complete_and_exit(&exit_completion, 1);
        return 0;
}

static int __init init(void)
{
        thread_id = kernel_thread(my_fuction, NULL, CLONE_FS | CLONE_FILES);
        return 0;
}

static void __exit fini(void)
{
        kill_proc(thread_id, SIGKILL, 1);
        wait_for_completion(&exit_completion);
        printk("Goodbyen");
}

module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");

最后

以上就是美丽故事为你收集整理的使用内核线程的全部内容,希望文章能够帮你解决使用内核线程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部