【问题标题】:Erlang driver erl_errno issueErlang 驱动程序 erl_errno 问题
【发布时间】:2015-09-03 05:54:36
【问题描述】:

我在玩erl_driver。我的驱动程序的开始回调如下:

ErlDrvData drv_start(ErlDrvPort port, char* command) { char* file_name = command + sizeof(drv_name); GenTtyData* port_data = (GenTtyData*)driver_alloc(sizeof(GenTtyData)); erl_errno = gt_open(file_name, &port_data->file); if (erl_errno != 0) { // Assertion there is just to show you my intention assert(erl_errno == ENOENT); driver_free(port_data); return ERL_DRV_ERROR_ERRNO; } return port_data; }

Documentation says

ErlDrvData (start)(ErlDrvPort port, char command)

This is called when the driver is instantiated, when open_port/2 is called. The driver should return a number >= 0 or a pointer, or if the driver can't be started, one of three error codes should be returned:

ERL_DRV_ERROR_GENERAL - general error, no error code

ERL_DRV_ERROR_ERRNO - error with error code in erl_errno

ERL_DRV_ERROR_BADARG - error, badarg

If an error code is returned, the port isn't started.

所以我希望erlang:open_port/2 将发送包含错误描述的退出信号(例如eacces,或enotty)。但是,在测试中我有

{'EXIT', {unknown, [{erlang,open_port,[{spawn,"gen_tty_drv non_existent.tty"},[]],[]}, {gen_tty,open,1, [{file, "/home/vkovalev/workspace/gen_tty_drv/_build/test/lib/gen_tty/src/gen_tty.erl"}, {line,48}]}, {gen_tty_drv_SUITE,open_non_existent_file,1, [{file, "/home/vkovalev/workspace/gen_tty_drv/test/gen_tty_drv_SUITE.erl"}, {line,29}]}, {test_server,ts_tc,3,[{file,"test_server.erl"},{line,1450}]}, {test_server,run_test_case_eval1,6, [{file,"test_server.erl"},{line,1026}]}, {test_server,run_test_case_eval,9, [{file,"test_server.erl"},{line,968}]}]}}

似乎 erlang 没有看到或无法解码错误原因并发送unknown。那么我的start 回调有什么问题?

【问题讨论】:

    标签: erlang erlang-driver


    【解决方案1】:

    这似乎是文档或代码中的错误。如果调用驱动程序start 函数的代码发现该函数返回ERL_DRV_ERROR_ERRNOit takes the error number from errno, not erl_errno无论如何,从 otp master commit dc35ae6c 开始,这是正确的,大致是 Erlang 版本 18.0-rc2;您可能发现在以后的版本中有所不同)。

    为了证明这一点,我编写了一个驱动程序start 函数,它显式设置errno

    static ErlDrvData
    my_driver_start(ErlDrvPort port, char *command)
    {
        errno = ETXTBSY;
        return ERL_DRV_ERROR_ERRNO;
    }
    

    通过这种方法,我得到了您想要的结果:

    1> my_driver:start().
    ** exception error: etxtbsy
         in function  open_port/2
            called as open_port({spawn,my_driver},[binary])
         in call from my_driver:start/0 (my_driver.erl, line 10)
    

    但是,以同样的方式设置erl_errno 并没有产生这个结果。如果我明确地将errno 设置为垃圾值,然后将erl_errno 设置为有效的错误号,如下所示:

    static ErlDrvData
    my_driver_start(ErlDrvPort port, char *command)
    {
        errno = 3245690989;
        erl_errno = ETXTBSY;
        return ERL_DRV_ERROR_ERRNO;
    }
    

    然后我得到和你一样的unknown 结果:

    1> my_driver:start().
    ** exception error: unknown
         in function  open_port/2
            called as open_port({spawn,my_driver},[binary])
         in call from my_driver:start/0 (my_driver.erl, line 10)
    

    更新:我就此联系了 OTP 团队的成员,他们通过电子邮件回复说这是一个文档错误,这意味着使用 errno 而不是 erl_errno 是正确的解决方案。他们说这部分驱动代码一直用errno

    更新 2:自 Erlang 18.0 起,此问题已在 driver_entry documentation 中得到修复。

    【讨论】:

    • 没错!而已。非常感谢您链接到beam/io.c。我自己找不到这个代码。
    猜你喜欢
    • 2021-12-25
    • 2016-12-06
    • 1970-01-01
    • 2012-04-02
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 2013-10-17
    相关资源
    最近更新 更多