erl_interface

Serge Aleynikov serge@REDACTED
Wed May 28 02:02:44 CEST 2003


I wonder if someone could share erl_interface-based examples with me. 
I've been trying to write some code that passes either a tuple/list, or 
an integer from C to Erlang, and I am having a problem that in case of 
integers (see iterate() and finalize() below) Erlangs gets a response 
correctly, but in case of tuple/list (see initialize()), looks like 
Erlang is waiting for something in addition to what the port replies.  I 
can see in debugger that the Port sends everything normally, and then 
blocks on the read() function as expected.

Serge

--------------- C CODE -----------------


#include <erl_interface.h>
#include <ei.h>

#include <io.h>

#define OPT_INITIALIZE 1
#define OPT_ITERATE    2
#define OPT_FINALIZE   3

typedef unsigned char byte;

int read_cmd(byte *buf);
int write_cmd(byte *buf, int len);
int read_exact(byte *buf, int len);
int write_exact(byte *buf, int len);

//-----------------------------------------------------------------
// Interface routines
//-----------------------------------------------------------------
int initialize(int nGatewayID, ETERM *demand, ETERM *supply, ETERM *rates) {
   int nDemandLen = erl_length(demand);
   int nSupplyLen = erl_length(supply);
   int nRatesLen  = erl_length(rates);
   ETERM *list, *tuple, *arg1, *arg2;

   if (ERL_IS_LIST(demand)) {
     for (list = demand; ! ERL_IS_EMPTY_LIST(list);
          list=ERL_CONS_TAIL(list)) {
       tuple = ERL_CONS_HEAD(list);  // Fetch a record from the list
       arg1 = erl_element(1, tuple);
       arg2 = erl_element(2, tuple);
       // Check ERL_TUPLE_SIZE(tuple) == 2
       fprintf(stderr, "Gateway: %3d, Demand: %4d = %d\n",
               nGatewayID, ERL_INT_VALUE(arg1), ERL_INT_VALUE(arg2));
       erl_free_term(arg1);
       erl_free_term(arg2);
     }
   }
   return nDemandLen;
}

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

int finalize(int z) {
   return z*3;
}

int main(int argc, char *argv[]) {
   ETERM *tuple, *result;
   ETERM *fun, *arg1, *arg2, *arg3, *arg4;
   ETERM *array[10];
   int res, n;
   byte buf[1024];
   long allocated, freed;

   erl_init(NULL, 0);   // Initialize Erlang interface library

   while (read_cmd(buf) > 0) {
     // The parameters are coming encoded as a tuple
     tuple = erl_decode(buf);
     // Get the first element in the tuple.
     fun = erl_element(1, tuple);

     switch (ERL_INT_VALUE(fun)) {
       case OPT_INITIALIZE:
         if (ERL_TUPLE_SIZE(tuple) != 5) {
           result = erl_format("{error, {demand, tuple_size, ~i}}",
                               ERL_TUPLE_SIZE(tuple));
           // Note: The function above doesn't return.
         } else {
           // {init, GtwyID, Demand, Supply, Rates}
           arg1 = erl_element(2, tuple);
           arg2 = erl_element(3, tuple);
           arg3 = erl_element(4, tuple);
           arg4 = erl_element(5, tuple);
           res = initialize(ERL_INT_VALUE(arg1),  // GtwyID
                            arg2, arg3, arg4);
           erl_free_term(arg1);
           erl_free_term(arg2);
           erl_free_term(arg3);
           erl_free_term(arg4);
           result = erl_format("{ok, ~i}", res);
         }
         break;
       case OPT_ITERATE:
         res = 0; // iterate(ERL_INT_VALUE(argp));
         result = erl_mk_int(res);
         break;
       case OPT_FINALIZE:
         res = 0; // finalize(ERL_INT_VALUE(argp));
         result = erl_mk_int(res);
         break;
       default:
         res = -1;
     }

     if (!erl_encode(result, buf))
       erl_err_ret("Error in erl_encode(): %d!", erl_errno);
     else {
       n = erl_term_len(result);
       write_cmd(buf, n);
     }

     erl_free_compound(tuple);
     erl_free_term(fun);
     erl_free_compound((ETERM*)result);
   }
   return 0;
}

//-----------------------------------------------------------------
// Data marshaling routines
//-----------------------------------------------------------------
int read_cmd(byte *buf)
{
   int len;

   if (read_exact(buf, 2) != 2)
     return(-1);
   len = (buf[0] << 8) | buf[1];
   return read_exact(buf, len);
}

int write_cmd(byte *buf, int len)
{
   byte li;

   li = (len >> 8) & 0xff;
   write_exact(&li, 1);

   li = len & 0xff;
   write_exact(&li, 1);

   return write_exact(buf, len);
}

int read_exact(byte *buf, int len)
{
   int i, got=0;

   do {
     if ((i = read(0, buf+got, len-got)) <= 0)
       return(i);
     got += i;
   } while (got<len);

   return(len);
}

int write_exact(byte *buf, int len)
{
   int i, wrote = 0;

   do {
     if ((i = write(1, buf+wrote, len-wrote)) <= 0)
       return (i);
     wrote += i;
   } while (wrote<len);

   return (len);
}


--------------- Erlang CODE -----------------


-module(opt_local).
-export([start/1, stop/1]).
-export([initialize/5, iterate/2, finalize/2]).

% testing
-export([start/0, test/1]).

% internal
-export([init/1, loop/1]).

%%====================================================================
%%=====================  TEST CASES ==================================
%%====================================================================

start() ->
     start("../port/opt_model").

test(P) ->
     R = initialize(P, 1, [{1, 2}, {2, 3}], [], []),
     R1 = stop(P),
     {R, R1}.

%%======================================================================
%%================================= API ================================
%%======================================================================

start(ExtPrg) ->
     spawn_link(?MODULE, init, [ExtPrg]).
stop(Pid) ->
     Pid ! stop.

%%---------------------------------------------------------------------------
-define(opt_initialize, 1).
-define(opt_iterate,    2).
-define(opt_finalize,   3).
%%---------------------------------------------------------------------------

initialize(Pid, GtwyID, Demand, Supply, Rates) ->
     call_port(Pid, {?opt_initialize, GtwyID, Demand, Supply, Rates}).

iterate(Pid, GtwyID) ->
     call_port(Pid, {?opt_iterate, GtwyID}).

finalize(Pid, GtwyID) ->
     call_port(Pid, {?opt_finalize, GtwyID}).

%%======================================================================
%%===================== INTERNAL ROUTINES ==============================
%%======================================================================

init(ExtPrg) ->
     process_flag(trap_exit, true),
     Port = open_port({spawn, ExtPrg}, [{packet, 2}, binary]),
     loop(Port).

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

loop(Port) ->
     receive
         {call, Caller, Msg} ->
             io:format("Msg to port: ~p~n", [Msg]),
             Port ! {self(), {command, term_to_binary(Msg)}},
             receive
                 {Port, {data, Data}} ->
                     io:format("Response received: ", []),
                     io:format("~p~n", [binary_to_term(Data)]),
                     Caller ! binary_to_term(Data);
                 {'EXIT', Pid, Reason} ->
                     io:format("Port ~p crashed with reason: ~p~n",
                               [Pid, Reason]),
                     Caller ! {'EXIT', Pid, Reason},
                     exit(Reason)
             end,
             apply(?MODULE, loop, [Port]);
         stop ->
             Port ! {self(), close},
             receive
                 {Port, closed} -> exit(normal)
             end;
         {'EXIT', Port, Reason} ->
             exit({port_terminated, Reason})
     end.






More information about the erlang-questions mailing list