Erlang Port drivers and Erl_interface

Casper casper2000a@REDACTED
Fri Jan 28 10:15:04 CET 2005


Hi Robert,

Thanks for the advice.

Let's say I sent the {Binary1, Atom1, {Atom2, Atom3, Binary2}, List1, Atom4}
tuple to the Port driver. The emulator call outputv callback function. How
will be the ErlIOVec vector I receive in the C side?

I went through the document you mentioned below. But still I'm not satisfied
with the info I got regarding event callback function and how I can use
ErlIOVec. I would like to know if I can use ei_encode/ei_decode to handle
ErlIOVec and when using other callback functions.

- Eranga



-----Original Message-----
From: owner-erlang-questions@REDACTED
[mailto:owner-erlang-questions@REDACTED] On Behalf Of Raimo Niskanen
Sent: Friday, January 28, 2005 2:02 PM
To: erlang-questions@REDACTED
Subject: Re: Erlang Port drivers and Erl_interface

casper2000a@REDACTED writes:

> Hi Robert,
> 
> This is really good information. Thanks a lot.
> 
> Have you used Port Driver call back functions outputv, event, etc. I have
2 concerns about them. 
> Unfortunately the documentation I found on them are not enough to absorb
the full working scenario 
> of them.
> 
> 1) In outputv, the erlang emulator sends the message as a ErlIOVec. I
wonder how I can use 
> ei_decode to extract the message.
> 

You can probably not. If the driver has got an outputv callback, it will
be used, and then the emulator does not have to copy binaries that are
sent to the port. If you send a list of binaries mixed with bytes, one
binary will be created to store the bytes, then an ErlIOVec is created
that contains pointers into the binaries - either to the common binary
for the odd bytes, or to the original binaries sent to the port. This
is a way to minimize copying of large amounts of data between the
erlang process and the driver.

> 2) I didn't find a good document on event call back function. What're the
information pass in as 
> ErlDrvEvent and ErlDrvEventData?
> 

Have a look at the Erts reference manual, there is some documentation
there.
http://www.erlang.se/doc/doc-5.4.3/erts-5.4.3/doc/html/part_frame.html
sections 3 and 6.

> 3) Have you used anync or enq/deq functions in Port Driver? If you can
give me some help or sample 
> would be excellent.
> 
> 4) Please confirm you are discussing above a Port driver, but not a C Node
or Erl_Interface based 
> port.
> 
> 5) In your below example, in which call back functions can you call
handle_regular_message to 
> decode the function? Could you provide an example call back function.
> 
> Thanks in advance!
> Eranga
> 
> 
> 
> 
> Quoting Robert Raschke : > Quoting Robert Raschke :
> 
> > Hi Eranga,
> > 
> > you wrote:
> > > Let\'s say I want to pass a complex structure back and forth. And I
opened
> > > the linked-in driver port using binary. Then can I use term_to_binary
and
> > > binary_to_term in the Erlang side and erl_decode, erl_encode and other
erl
> > > interface functions in the C side?
> > 
> > I have been using the term_to_binary and binary_to_term functions as
> > well. In my C port program I use the ei_decode...() and
> > ei_encode...() functions. It took me a little bit to get used to the
> > way these functions handle the message buffer, but with a little bit
> > of experimentation you will get up and running quickly.
> > 
> > For example I send my requests from erlang in a predefined format
> > (obviously), and then I unpack it in my C program like this, with the
> > x_in buffer holding a message. It is very verbose, as I was learning
> > how the ei functions work while writing it.
> > 
> > static void
> > handle_regular_message(ei_x_buff *x_in, ei_x_buff *x_out)
> > {
> > int valid = 1;
> > int version;
> > int arity;
> > char call_atom[MAXATOMLEN];
> > erlang_pid from;
> > char fn_atom[MAXATOMLEN];
> > 
> > /*
> > Incoming message has to be
> > {call, Caller_Pid, Fn, [Params]}
> > with
> > call - the atom \'call\'
> > Caller_Pid - erlang pid of process that sent the message
> > Fn - name as atom of the function to invoke
> > Params - parameters to pass to Fn
> > 
> > For an invalid request message the return message has the form
> > {error, badmsg}
> > 
> > For a valid request message the return message has the form
> > {Caller_Pid, Result}
> > with
> > Result = ok | {ok, Value} | {error, internal, error} | {error, badarg,
> > args}
> > */
> > 
> > if (valid && ei_decode_version(x_in->buff, &x_in->index, &version) != 0)
{
> > fprintf(stderr, \"Warning: Ignoring received malformed message (bad
> > version).\\n\");
> > valid = 0;
> > }
> > 
> > if (valid && ei_decode_tuple_header(x_in->buff, &x_in->index, &arity) !=
0)
> > {
> > fprintf(stderr, \"Warning: Ignoring received malformed message (not
> > tuple).\\n\");
> > valid = 0;
> > }
> > if (valid && arity != 4) {
> > fprintf(stderr, \"Warning: Ignoring received malformed message (not
4-arity
> > tuple).\\n\");
> > valid = 0;
> > }
> > 
> > if (valid && ei_decode_atom(x_in->buff, &x_in->index, call_atom) != 0) {
> > fprintf(stderr, \"Warning: Ignoring received malformed message (first
tuple
> > element not atom).\\n\");
> > valid = 0;
> > }
> > if (valid && strcmp(call_atom, \"call\") != 0) {
> > fprintf(stderr, \"Warning: Ignoring received malformed message\"
> > \" (first tuple element not atom \'call\').\\n\");
> > valid = 0;
> > }
> > 
> > if (valid && ei_decode_pid(x_in->buff, &x_in->index, &from) != 0) {
> > fprintf(stderr, \"Warning: Ignoring received malformed message (Second
tuple
> > element not pid).\\n\");
> > valid = 0;
> > }
> > 
> > if (valid && ei_decode_atom(x_in->buff, &x_in->index, fn_atom) != 0) {
> > fprintf(stderr, \"Warning: Ignoring received malformed message (Third
tuple
> > element not atom).\\n\");
> > valid = 0;
> > }
> > 
> > if (valid) {
> > x_out->index = 0;
> > ei_x_encode_version(x_out);
> > ei_x_encode_tuple_header(x_out, 2);
> > ei_x_encode_pid(x_out, &from);
> > 
> > fprintf(stderr, \"Attempting to call e_%s().\\n\", fn_atom);
> > 
> > if (strcmp(fn_atom, \"my_fun_1\") == 0) my_fun_1(x_in, x_out);
> > else if (strcmp(fn_atom, \"my_fun_2\") == 0) my_fun_2(x_in, x_out);
> > else if (strcmp(fn_atom, \"my_fun_3\") == 0) my_fun_3(x_in, x_out);
> > else {
> > fprintf(stderr, \"Warning: Ignoring received malformed message\"
> > \" (Third tuple element not recognised function).\\n\");
> > valid = 0;
> > }
> > if (valid) {
> > fprintf(stderr, \"Returned from my_fun().\\n\");
> > }
> > }
> > 
> > if (! valid) {
> > x_out->index = 0;
> > ei_x_encode_version(x_out);
> > ei_x_encode_tuple_header(x_out, 2);
> > ei_x_encode_atom(x_out, \"error\");
> > ei_x_encode_atom(x_out, \"badmsg\");
> > }
> > }
> > 
> > Each function I invoke (my_fun()) takes apart the rest of the x_in
> > buffer, and completes the result buffer x_out (which gets sent back to
> > Erlang).
> > 
> > I hope this gets you further along,
> > Robby
> > 
> > 
> 
> --------------This mail sent through OmniBIS.com--------------
> 

-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB




More information about the erlang-questions mailing list