emulator调试日志: driver篇

--------- driver篇 ---------------
driver一般通过erl_ddll.erl中的load_driver/2函数来实现.
load_driver(Path, Driver) ->
    do_load_driver(Path, Driver, [{driver_options,[kill_ports]}]).
...
do_load_driver(Path, Driver, DriverFlags) ->
    case erl_ddll:try_load(Path, Driver,[{monitor,pending_driver}]++DriverFlags) of
   
注意其中try_load的参数, OptionList为[{monitor,pending_driver}]++DriverFlags, 即 [{monitor,pending_driver}, {driver_options, [kill_ports]}].
详细意义见otp文档的erl_ddll:try_load/3注释.
        ...
由此可以看出最后还是委托到erl_ddll:try_load/3函数. 这个函数由bif实现, 具体实现在emulator/beam/erl_bif_ddll.c:139行
/*
 *    try_load(Path, Name, OptionList) -> {ok,Status} |
 *                                        {ok, PendingStatus, Ref} |
 *                                        {error, ErrorDesc}
 *       Path = Name = string() | atom()
 *     OptionList = [ Option ]
 *     Option = {driver_options, DriverOptionList} |
 *                {monitor,MonitorOption} |
 *                {reload, ReloadOption}
 *     DriverOptionList = [ DriverOption ]
 *     DriverOption = kill_ports
 *     MonitorOption = pending_driver | pending
 *     ReloadOption = pending_driver | pending
 *     Status = loaded | already_loaded | PendingStatus
 *     PendingStatus = pending_driver | pending_process
 *     Ref = ref()
 *     ErrorDesc = ErrorAtom | OpaqueError
 *     ErrorAtom = linked_in_driver | inconsistent |
 *                 permanent | pending
 */
/*
 * Try to load. If the driver is OK, add as LOADED.  If the driver is
 * UNLOAD, possibly change to reload and add as LOADED,
 * there should be no other
 * LOADED tagged pid's.  If the driver is RELOAD then add/increment as
 * LOADED (should be some LOADED pid).  If the driver is not present,
 * really load and add as LOADED {ok,loaded} {ok,pending_driver}
 * {error, permanent} {error,load_error()}
 */
BIF_RETTYPE erl_ddll_try_load_3(Process *p, Eterm path_term,
                Eterm name_term, Eterm options)
以上是定义.
步骤:
    1. 处理options列表, 获取driver名称以及路径.
    2. if ((de = lookup_driver(name)) != NULL) {...} 判断是否存在此driver,如果存在则reload它.
    3.
        3.1 加载driver .
               res = load_driver_entry(&dh, path, name)
                    res = do_load_driver_entry(dh, path, name)
                        res =  erts_sys_ddll_open(path, &(dh->handle)))
                        此函数通过dlopen调用了一个动态链接库*.so,返回操作此so文件的句柄handle. 以example1_drv为例,此处就是/root/erlang/book_code/src/ports/example1_drv.so
        3.2 初始化driver
                           res = erts_sys_ddll_load_driver_init(dh->handle,
                                  &init_handle)
                               res = erts_sys_ddll_sym(handle, "driver_init", &fn)
                               此函数通过 dlsym(handle, func_name)取得了so文件的driver_init函数的函数指针,在此例中即取得了example_lid.c中的
                                   DRIVER_INIT(example_drv) /* must match name in driver_entry */
                                {
                                    return &example_driver_entry;
                                }
                            此函数的指针.
        3.3 调用driver_init函数
                        dp = erts_sys_ddll_call_init(init_handle);
                    在此即返回了&example_driver_entry这个driver_entry结构体,赋给dp. 然后就可以用dp来干活啦.
        3.4 判断driver版本后,把driver加入到driver_list链表中去.
                        erts_add_driver_entry(dp,1); /* io.c */
    4.把当前进程proc加到driver handle的属性中,并重新分配一下堆空间后,再清理些用到的临时资源.返回.

说白了,driver的工作就是调一个*.so,然后找到这个so中的driver_init函数,调用它. 调用后,会返回一driver_entry结构体的实例. 这个结构体定义了driver的启动,停止,处理port command的函数指针, driver名称,超时时间, i/o操作等各种东西.
以后调用driver就是通过这个结构体的属性来指定了.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值