Search code examples
erlanglibxlcnode

erlang c-node passing binary objects


I was following Erlang C Nodes tutorial and was trying to make a wrapper call for libXl C library. In my C node a create a BookHandle and pass it as a response for one message call.

BookHandle book = xlCreateBook();
resp = erl_format("{ok, ~w}", erl_mk_binary(book, sizeof book));
erl_send(fd, fromp, resp);

My question is can I use that reponse to send another message to C node with that same object? For example to send

{any, 'c1@CST1'} ! {self(), {step2,Result}}, 

and in C node to have something like the code below to get the passed BookHandle

if (strncmp(ERL_ATOM_PTR(fnp), "step2", 3) == 0) {
    BookHandle book = (BookHandle)ERL_BIN_PTR(argp);
    xlBookLoad(book, "example.xls");
}

Is something like this even possible, or would creating a wrapper for specific function require to create BookHandle every time I send a message to C Node.

Sorry if this doesn't make any sense, I'm new to this all.


Solution

  • xlCreateBook() returns a pointer (BookHandle is actually a pointer to C++ object Book). So your code is serializing this pointer to an Erlang binary (probably 4 or 8 bytes long depending on your architecture) and unserializing it when passed back from an Erlang node.

    This essentially works.

    However, it has the following two drawbacks:

    • Erlang nodes can technically pass any pointer to your C node, even a pointer that does not point to a real Book structure. This could yield crashes or worse, data corruption.
    • The pointer can be lost (typically the Erlang process handling the book died) and this will yield a memory leak in your C node (as the Book will never be freed).

    For this reason, a stateless API design would be preferable, although it could be more complex eventually, especially if you want Erlang code to operate on Book structures.

    Alternatively, you could maintain a list of BookHandle and pass a reference to items in this list (an index or the pointer itself as you currently do, but checking it is indeed in the list when unserialized). This would solve the first issue.

    The second issue is more tricky. A solution would be to link the Erlang process that is responsible for a given Book and delete the Book if this process exits. Unfortunately, API for linking is just not there on the C-side. So you will need to link from the Erlang side (or just try the disabled C code to send LINK and UNLINK messages). The C node should associate each allocated Book to their respective Erlang pid owner and free these pointers if it receives an EXIT message signaling the owner process died.

    As a side-note, generating XLSX files (Office Open XML) is quite easy with Erlang and does not require an external library.