免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2376 | 回复: 5
打印 上一主题 下一主题

新手关于一个内核模块代码简单例子的疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-01-18 02:11 |只看该作者 |倒序浏览
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>

/* 无论什么时候,一个KLD被装载进内核或从内核中卸载时,必须调用一个被称为模块事件处理程序的函数。
每个KLD必须包含一个事件处理程序。以下为本例的事件处理程序。*/

static int
load(struct module *module, int cmd, void *arg)
               /*关于此函数在中的定义:
               typedef int (*modeventhand_t)(module_t, int /* modeventtype_t */
, void *);
               module_t是一个指向模块的结构指针。
               modeventtype_t类型是int,搞不懂。其在<sys/module.h>中的定义为:
                             typedef enum modeventtype {
     MOD_LOAD,     /* Set when module is loaded. */
     MOD_UNLOAD,    /* Set when module is unloaded. */
     MOD_SHUTDOWN,     /* Set on shutdown. */
     MOD_QUIESCE     /* Set on quiesce. */
                             } modeventtype_t;
               下面用switch语句判断MOD_LOAD与MOD_UNLOAD时程序的行为。EOPNOTSUPP则表示未定义的操作。*/
{
    int error = 0;

    switch (cmd) {
        case MOD_LOAD:
        uprintf("Hello, world!\n");
        break;

    case MOD_UNLOAD:
        uprintf("Good-bye, cruel world!\n");
        break;

    default:
        error = EOPNOTSUPP;
        break;
    }

    return(error);//注意此*modeventhand_t返回的error的值,不出意外应该为"Hello, world!"这样的字符串。

}//本例事件处理函数load完成。


/* hello_mod在下面的DECLARE_MODULE被调用,在此定义。按照 DECLARE_MODULE的定义,你必须为第二个形参data
提供一个moduledata类型的参数。*/

static moduledata_t hello_mod = {
    "hello",     /* 此处定义模块正式名称 */
    load,         /* 模块的事件处理函数 */
    NULL         /* 额外,留空即可。 */
};

/*通过调用 DECLARE_MODULE 宏可以完成必须的把自己链接以及注册到内核中的工作。此宏在中
的定义如下:
            #define DECLARE_MODULE(name, data, sub, order)                 \
     MODULE_METADATA(_md_##name, MDT_MODULE, &data, #name);         \
     SYSINIT(name##module, sub, order, module_register_init, &data)     \
     struct __hack
     name作为字符串传递指定模块的名称。
     data作为moduledata 结构传递模块的正式名称和调用的事件处理函数。
     moduledata 结构在头文件中定义如下:
     typedef struct moduledata {
     const char *name;         /* module name */

     modeventhand_t evhand;         /* event handler */
     void *priv;             /* extra data */
                  } moduledata_t;
       sub它指定系统启动接口,定义了模块的类型。<sys/kernel.h> 头文件中的sysinit_sub_id枚举列表中查看。
          根据我们的目的,我们总是设置这个参数为SI_SUB_DRIVERS。SI_SUB_DRIVERS是在注册一个设备驱动程序时使用的。
       order参数指定模块在模块子系统中初始化的次序。你可以在<sys/kernel.h>头文件中的sysinit_elem_order 枚举列表中查看它的有效项。
            根据我们的目的,我们总是设置这个参数为SI_ORDER_MIDDLE,它在KLD初始化过程中处于中间位置。
*/
DECLARE_MODULE(hello, hello_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);

/*如此可知:本例使用DECLARE_MODULE声明了hello模块并调用moduledata类型的hello_mod得到了模块的正式名称和触发的事件处理函数load。根据
惯例讲DECLARE_MODULE的sub和order设置成了SI_SUB_DRIVERS和SI_ORDER_MIDDLE。触发事件处理函数load后便达到了装载时显示"Hello, world!"
卸载时显示"Good-bye, cruel world!"的功能。*/
问题有两个:
1,DECLARE_MODULE调用hello_mod后没看到谁最后去调用load了
2,没有哪句话显式的为load形参逐个赋值?

不好意思,新手不会C,今天阅读一个文档卡在这里了。希望各位高人不吝赐教^_^

论坛徽章:
0
2 [报告]
发表于 2008-01-18 10:00 |只看该作者
DECLARE_MODULE调用hello_mod后没看到谁最后去调用load了
我搜索了一下,是freebsd的模块吧
根据linux DECLARE_MODULE把hello_mod放在某个地方,然后内核能找到,调用它的函数
内核会封装好参数给load

论坛徽章:
0
3 [报告]
发表于 2008-01-19 01:39 |只看该作者
是FreeBSD的代码。但是恕我愚钝,LS的意思我没怎么看明白

论坛徽章:
0
4 [报告]
发表于 2008-01-19 10:10 |只看该作者
是我没说清楚,我也不了解,不过和linux是类似的
可以参考http://www.freebsdchina.org/forum/viewtopic.php?t=34251

论坛徽章:
0
5 [报告]
发表于 2008-01-19 21:10 |只看该作者

那个DECLARE_MODULE应该是一个编译器指令,将这个函数得指针存在一个特定的段中,将来在加载模块的时候,系统从特定段中读取函数指针地址,并且调用之。

论坛徽章:
0
6 [报告]
发表于 2008-01-20 02:26 |只看该作者
非常感谢LS两位的解答,正在看:)
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP