lundi 15 novembre 2010

Things learned while writing an erlang driver

  I've spent a couple of days writing an erlang binding for zfec. The binding takes the form of a driver, that is, a shared library written in C that communicates with erlang according to the defined interface.

  The reference doc was ambiguous for some points, which gets summarized here:

Q: How is the Command parameter of open_port() passed to the ErlDriverEntry .start callback ?
A: The Command is a string, and the first word (whitespace-separated) must be the name of the driver. The whole string, including the driver name, is passed to the callback.

Q: If I send a list of binaries to the port, can I expect to get every one of them separately with the outputv callback ? How does the SysIOVec struct work ?
A: NO. Small binaries, and presumably sub binaries spliced from a common one, may get merged in the resulting ErlIOVec. I've written this to iterate over an ErlIOVec. The doc defines:

typedef struct {
  int vsize;
  int size;
  SysIOVec* iov;
  ErlDrvBinary** binv;

and does not define (because it is platform-dependant, but in this case we want Unix):

typedef struct {
    char *iov_base;
    size_t iov_len;

size is the total byte size of the whole ErlIOVec. vsize is the number of chunks (which may not match the number of binaries in the original iolist). iov and binv both are arrays of size vsize.

binv references the parent refc binaries (so the same binary can appear twice, and you may not be interested in all its data). Use this to manipulate the refcounter of the binary if you need to keep the data around.

iov is the chunks of data you are actually interested in. The two fields should be self-explanatory :)

Q: Is it OK to define the outputv callback and not output one ?
A: yes, you will receive an IOVec with a single chunk

Q: Why does open_port seemingly randomly fail with "bad argument" ? 
A: It will if you try to open a driver that is not loaded. Now, erl_ddll is smart and remembers who loaded which driver, and will unload a driver when it is not needed anymore. If you are testing from the shell, getting an uncaught exception will terminate the shell process and start a new one, which may cause your driver to get unloaded.

Q: Why is erl_ddll:load/2 asking for a path ? What is a reasonable value to provide ?
A: According to the OTP doc, the standard way is to use code:priv_dir(app_name)

Aucun commentaire:

Also check me out on Mastodon