内核模块编写问题总结

  • 原文地址 http://www.blogbus.com/wanderer-zjhit-logs/183074985.html  这个博客的作者写的文章不错,可以常去看看。

  • 0 内核全局符号只有使用了EXPORT_SYMBOL导出的才能被模块通过内核头文件引用;否则会提示:undefined symbol,此时只能通过查看地址强转的方式引用,但是失去了可移植性;如果某些全局变量使用的是EXPORT_SYMBOL_GPL导出的,必须在内核模块中用MODULE_LICENSE("GPL");申明方可使用,否则会出现提示:unsigned symbol find_vpid(err 0)错误提示
    1 多个线程间的同步问题
    问题1.1插入模块后,内核子线程会执行周期性的调度,直到内核卸载,但是卸载时,子内核线程可能一般处于睡眠状态,此时如果模块卸载,即模块占用的内核系统资源会被释放,如果此时子线程被调度执行,会出现错误,用dmesg -c查看如下所示:
    kernel_thread_helper->testThread->__wake_up-->__wake_up_common,EIP = NULL
    解决办法:
    卸载模块时,必须首先唤醒子线程,让子线程先退出,然后进行卸载过程<也可以调用daemonize()函数使子线程成为daemon,但是那样只能在系统关机时关闭子线程,不符合要求>
    问题1.2 两个子线程细粒度的同步
    最简单方法,是等待线程调用msleep睡眠若干个时钟周期,不同系统上的jiffies周期长度不一样,大约10ms,显然粒度不够;另一种是父线程通过sleep_on_timeout来睡眠等待,类似于用户态进程间同步的信号量实现方法,粒度可以达到us级别;最高级别的是直接在父线程中通过schedule()来实现实时切换,以等待子线程限制性,类似于锁的实现机制,实时级别更高
    2 解决内核子线程defunct问题
    关于子进程僵死的问题网页上一大堆,都是将用户层子线程的处理办法,都是采用信号处理机制实现,这种机制实现于线程从内核态返回到用户态的过程中,通过系统时钟来确保其实现,内核模块永远在内核中运行,且我的内核模块中由于父线程是个周期性线程,为了效率也不能及时回收每个已结束子线程的task_struct资源。从而,模块运行一段时间,用ps aux可以查看到大量的defunct状态的子线程,由于内核中的进程数是有限制的,这样会降低系统的效率。内核defunct子线程如何及时清除呢?有两种方法:
    2.1 子线程主动与父线程脱离关系
    这种方式非常好,类似于用户态线程的pthread_detach函数,将子线程与init线程建立关系,从而当子线程结束时,让init守护线程为其收尸,方法如下:
    subProcess->parent = subProcess->real_parent = init_pid_ns.child_reaper
    list_del(&subProcess->sibling);
    list_add(&subProcess->sibling,&subProcess->parent->children);
    2.2 父线程被动结束父子关系:
    此时又有两种方法:
    2.2.1 同步等待子线程结束,并回收其资源
    当子线程通过return函数结束自身运行时,task->state:TASK_DEAD,task->exit_state:EXIT_ZOMBIO
    按道理,子线程退出时应该像父线程发送SIGCHLD信号,但是经过测试,内核中子线程退出时,并未向父线程发送SIGCHLD信号;测试如下:
    子线程执行程序:
    static int loop(void* ptr)
    {
    printk("in loop\n");
    (*((do_notify_parentt)(0xc105a1f0)))(current,SIGCHLD);
    //return 0;
    // (*((sys_exitt)(0xc104bd60)))(0);    这三个都测过

    }
    父线程:

    int force_init(void)
    {

    struct sigpending* sigpending = &current->signal->shared_pending; //sys_exit发送给该变量

    sigset_t * set = &sigpending->signal;

    sigset_t* set2 = &current->pending;
    ...
    if(set2->sig[sig/__NSIG_BPW] & 1 <<(sig % __NSIG_BPW))
    printk("match2,%lu\n",set2->sig[0]);
     if(set->sig[sig/__NSIG_BPW] & 1 <<(sig % __NSIG_BPW))
     printk("match,%lu\n",set->sig[0]);

    }
    结果父线程中没有显示信息

    此时父线程主要通过循环检测子线程状态,当发现子线程处于EXIT_ZOMBIL状态时,利用未导出函数实现回收子线程资源:(*((release_taskk)(0xc104a4b0)))(sub);

    2.2.2 父线程通过采用2.1类似方法断绝父子关系:
    父线程循环执行下面函数:
    struct list_head* list;
    list_for_each(list,&current->children){
    task = list_entry(list,struct task_struct,sibling);
    if(task->pid == subPid)
    break;
    }
    subProcess->parent = subProcess->real_parent = init_pid_ns.child_reaper
    list_del(&subProcess->sibling);
    list_add(&subProcess->sibling,&subProcess->parent->children);

    面临困惑:在proc文件下利用proc_mkdir,和proc_create_entry新建了大量的目录和文件,但是,在图形界面有一个目录无法打开,一打开就死机;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值