[erlang-questions] Problem with using Port drivers - need advice

Dmitriy Gorbenko <>
Fri Sep 7 21:55:28 CEST 2007


Hi all.

I am a beginner in erlang, so I go to
http://erlang.org//doc/tutorial/part_frame.html, find there chapter "6
Port drivers", and tries to compile entire chain.

At first, I guess it is a mistake:

unix> gcc -o exampledrv -fpic -shared complex.c port_driver.c

I think must be wrote like this:

unix> gcc -o example_drv -fpic -shared complex.c port_driver.c



Well, I create C source file, and tries to compile it:

-----------8<----------------------------------------------------------------
 ~/try/erl $ cat so_file.c

#include <stdio.h>
#include "erl_driver.h"

int foo(int x) {
  return x+1;
}

int bar(int y) {
  return y*2;
}


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 = foo(arg);
    } else if (fn == 2) {
      res = bar(arg);
    }
    driver_output(d->port, &res, 1);
}

ErlDrvEntry example_driver_entry = {
    NULL,                       // F_PTR init, N/A
    example_drv_start,          // L_PTR start, called when port is opened
    example_drv_stop,           // F_PTR stop, called when port is closed
    example_drv_output,         // F_PTR output, called when erlang has sent
    NULL,                       // F_PTR ready_input, called when input
descriptor ready
    NULL,                       // F_PTR ready_output, called when
output descriptor ready
    "example_drv",              // char *driver_name, the argument to
open_port
    NULL,                       // F_PTR finish, called when unloaded
    NULL,                       // F_PTR control, port_command callback
    NULL,                       // F_PTR timeout, reserved
    NULL                        // F_PTR outputv, reserved
};

DRIVER_INIT(example_drv) // must match name in driver_entry
{
    return &example_driver_entry;
}
 ~/try/erl $ gcc -o example_drv -fpic -shared so_file.c
-I/usr/lib64/erlang/usr/include
 ~/try/erl $
-----------8<----------------------------------------------------------------

Next, goes Erlang code:

-----------8<----------------------------------------------------------------
 ~/try/erl $ cat test.erl

-module(test).
-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;
        _ -> 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.

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

call_port(Msg) ->
    complex ! {call, self(), Msg},
    receive
        {complex, Result} ->
            Result
    end.

loop(Port) ->
    receive
        {call, Caller, Msg} ->
            Port ! {self(), {command, encode(Msg)}},
            receive
                {Port, {data, Data}} ->
                    Caller ! {complex, decode(Data)}
            end,
            loop(Port);
        stop ->
            Port ! {self(), close},
            receive
                {Port, closed} ->
                    exit(normal)
            end;
        {'EXIT', Port, Reason} ->
            io:format("~p ~n", [Reason]),
            exit(port_terminated)
    end.

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

decode([Int]) -> Int.
 ~/try/erl $
-----------8<----------------------------------------------------------------


Then, running test.erl:
-----------8<----------------------------------------------------------------
 ~/try/erl $ erl -name 
Erlang (BEAM) emulator version 5.5.5 [source] [64-bit] [async-threads:0]
[kernel-poll:false]

Eshell V5.5.5  (abort with ^G)
()1> c(test).
{ok,test}
()2> test:start("example_drv").
** exited: {error,could_not_load_driver} **
()3>
User switch command
 --> q
 ~/try/erl $ 
-----------8<----------------------------------------------------------------

Could anyone help me ?
Thanks.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 2244 bytes
Desc: S/MIME Cryptographic Signature
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20070907/bf2cb428/attachment.bin>


More information about the erlang-questions mailing list