Port Driver, outputv, binaries.
Matthew Sackman
matthew@REDACTED
Wed Dec 9 19:58:51 CET 2009
Hi,
So I'm writing a port driver for a linked in binary. I've implemented
outputv, and that seems to be working fine.
In order to see what I'm being sent, I have the following in C:
void dump_ev(ErlIOVec *ev) {
printf("total size: %d\r\nvec len: %d\r\n", ev->size, ev->vsize);
int idx;
for (idx = 0; idx < ev->vsize; ++idx) {
printf("iov[%d] = ", idx);
SysIOVec iov = ev->iov[idx];
printf("[base = %p, len = %zd]\r\n", iov.iov_base, iov.iov_len);
printf("binv[%d] = ", idx);
if (NULL == ev->binv[idx]) {
printf("NULL\r\n");
} else {
ErlDrvBinary* bin = ev->binv[idx];
printf("[orig_bytes = %p; orig_size = %zd]\r\n", bin->orig_bytes, bin->orig_size);
}
}
printf("done\r\n");
}
which is called at the start of outputv:
static void test_outputv(ErlDrvData drv_data, ErlIOVec *ev)
{
dump_ev(ev);
...
}
Now, in the shell, I do the following:
1> ok = erl_ddll:load_driver("ebin", "libtest"), Port = open_port({spawn_driver, libtest}, [binary]).
2> port_command(Port, [<<2>>,<<0,0,0,0,0,0,0,0>>,<<0>>,<<0>>,<<0>>]).
And I get out the following:
total size: 12
vec len: 6
iov[0] = [base = (nil), len = 0]
binv[0] = NULL
iov[1] = [base = 0x17a89b0, len = 1]
binv[1] = [orig_bytes = 0x17a89b0; orig_size = 1]
iov[2] = [base = 0x17a89e8, len = 8]
binv[2] = [orig_bytes = 0x17a89e8; orig_size = 8]
iov[3] = [base = 0x17a8a20, len = 1]
binv[3] = [orig_bytes = 0x17a8a20; orig_size = 1]
iov[4] = [base = 0x17a8a58, len = 1]
binv[4] = [orig_bytes = 0x17a8a58; orig_size = 1]
iov[5] = [base = 0x17a8a90, len = 1]
binv[5] = [orig_bytes = 0x17a8a90; orig_size = 1]
done
Which makes a lot of sense - each arg corresponds to an entry in the iov
and binv. That's all fine.
Now, in some erlang code (a gen_server) I have this:
init([]) ->
erl_ddll:start(),
ok = erl_ddll:load_driver("ebin", ?LIBNAME),
Port = open_port({spawn_driver, ?LIBNAME}, [binary, stream]),
{ok, Port}.
handle_call({tune, BNum, APow, FPow, Opts}, _From, Port) ->
Data = [<<2/native>>,
<<BNum:64/signed-integer-native>>,
<<APow:8/signed-integer-native>>,
<<FPow:8/signed-integer-native>>,
<<Opts:8/native>>],
port_command(Port, Data),
...
Then in the shell I do this:
1> {ok, Pid} = test_drv:start_link(), gen_server:call(Pid, {tune, 0, 0, 0, 0}).
and I get out:
total size: 12
vec len: 2
iov[0] = [base = (nil), len = 0]
binv[0] = NULL
iov[1] = [base = 0x1faded0, len = 12]
binv[1] = [orig_bytes = 0x1faded0; orig_size = 12]
done
Why on earth has it gone and pushed all those binaries into one big
binary? What on earth is the actual behaviour meant to be? Where is it
defined? How can I reliably pull args out of the iov and binv? Certainly
the behaviour is different to that in
http://www.erlang.org/pipermail/erlang-questions/2006-March/019818.html
In short, WTF?!
Matthew
More information about the erlang-questions
mailing list