登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Code@Pig Home

喜欢背着一袋Code傻笑的Pig .. 忧美.欢笑.记忆.忘却 .之. 角落

 
 
 

日志

 
 

[每日一Errr~lang] 给erlang增加自定义模块 ---- C Port Driver  

2010-08-26 16:18:05|  分类: lang_erlang |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
从官方抄过来的例子,代码流,并讲解需要注意的地方。
http://www.erlang.org/doc/tutorial/c_portdriver.html

erlang 把自定义模块叫做 driver。

自定义模块与 erlang process 在同一进程:(速度快)
erl proc  <---->  port  <---->  YourMod

不同进程:(安全)
erl proc <-----> port  <--- pipe ---> YourMod

--------------------------------------------------------------------
%% 实现一个模块,把 Port 的访问封装下
-module(complex5).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).

start(SharedLib) ->
    case erl_ddll:load_driver(".", SharedLib) of
        ok -> ok;
        {error, already_loaded} -> ok;
        {error, Desc} ->
            io:format("~p~n", [Desc]),
            exit({error, could_not_load_driver})
    end,
    spawn(?MODULE, init, [SharedLib]).

init(SharedLib) ->
    register(complex, self()),
    Port = open_port({spawn, SharedLib}, []),
    loop(Port).

stop() ->
    complex ! stop.

loop(Port) ->
    receive
        {call, Caller, Msg} ->
            Port ! {self(), {command, encode(Msg)}},
            receive
                {Port, {data, Data}} ->
                    Caller ! {complex, decode(Data)}
            end,
            loop(Port)
    end.

encode({foo, X}) -> [1, X];
encode({bar, Y}) -> [2, Y].

decode([Int]) -> Int.

foo(X) ->
    call_port({foo, X}).

bar(Y) ->
    call_port({bar, Y}).

call_port(Msg) ->
    complex ! {call, self(), Msg},
    receive
        {complex, Result} ->
            Result
    end.
--------------------------------------------------------------------
#include <stdio.h>
#include <erl_driver.h>

typedef struct {
    ErlDrvPort port;
} example_data;

static ErlDrvData
example_drv_start(ErlDrvPort port, char *buff)
{
    example_data *d = (example_data *) driver_alloc(sizeof(example_data));
    d->port = port;
    return (ErlDrvData) d;
}

static void
example_drv_stop(ErlDrvData handle)
{
    driver_free((char*)handle);
}

static void
example_drv_output(ErlDrvData handle, char *buff, int bufflen)
{
    example_data *d = (example_data *)handle;
    char fn = buff[0], arg = buff[1], res;

    if ( fn == 1 )
        res = arg + 1;
    else if ( fn == 2 )
        res = arg * 2;

    driver_output(d->port, &res, 1);
}

ErlDrvEntry example_driver_entry = {
    NULL,
    example_drv_start,
    example_drv_stop,
    example_drv_output,
    NULL,
    NULL,
    "exampledrv",
    NULL,
    NULL,
    NULL,
    NULL
};

DRIVER_INIT(exampledrv)          // 注意:这里的名字 exampledrv,要和上面 example_driver_entry 中的 "exampledrv" 名字一样
{
    return &example_driver_entry;
}
--------------------------------------------------------------------
gcc -o exampledrv.so -I/usr/local/lib/erlang/usr/include/ -fpic -shared port_driver.c
--------------------------------------------------------------------
1> c(complex5).
{ok,complex5}
2> complex5:start("exampledrv").
<0.38.0>
3> complex5:foo(10).
11
4> complex5:bar(20).
40
--------------------------------------------------------------------

我这里演示的是 同一进程 的情况。
需要注意的是,erl_ddll:load_driver() 的模块名,是不包含 .so 后缀的,但实际的动态库文件需要 .so 后缀,否则返回 {error, {open_error, -11}}。
而且,模块名 exampledrv 要与动态库文件名一致,否则返回:bad_driver_name
  评论这张
 
阅读(1626)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018