[erlang-questions] calling FUN from NIF

Scott Lystig Fritchie fritchie@REDACTED
Tue Sep 13 23:29:20 CEST 2011


Paul Davis <paul.joseph.davis@REDACTED> wrote:

pd> On the other hand, there are planned enhancements to the NIF api to
pd> allow such awesomeness. See Rickard's talk at [1].

If you can't wait for that kind of awesomeness, I *know* that it's
possible to do what you're looking for via a driver instead of a NIF.
(Because I saw some of Tony Rogvall's driver code from a decade ago to
it.  :-)  With a bit of enginuity, perhaps the technique could also be
applied to NIFs.

   Note: this is just a sketch from memory poisoned by a lot of
   intervening time.  Also note that the Erlang process that makes the
   initial call to the driver is the samem process that executes the
   driver's Erlang callback function, i.e., PID <a.b.c>.

   This is a mash-up attempt to show that time flows as you read from
   top to bottom.  Note that the way this is sketched, the driver can
   request more than one callback be executed on the Erlang side of the
   world.

Erlang code                         C code in driver
Erlang process <a.b.c>              Deep in the virtual machine
----------------------              ---------------------------

drv_command(Port,
         SerializedCommandData)

                                    driver's struct erl_drv_entry.outputv
                                    function(): calculate stuff, decides
                                    that it needs to call an Erlang
                                    callback function, sends reply to
                                    request a callback function call.
                                    Store intermediate state in driver's
                                    private data.

%% Code path on first call:
%% driver sends us ?WantCallback

get_port_answer(Port) ->
  receive
    {Port, {data, [Response|Rest]=_Data}} ->
      case Response of
        ?WantCallback ->
          {M, F, As} = decode_callback_request(Rest),
          Answer = erlang:apply(M, F, As),
          % Encode answer and send it back to
          % driver via drv_command() or whatever
          get_port_answer(Port);
        ?FinalAnswer ->
	  % Decode and return to caller
          decode_final_answer(Rest)
      end
  end.

                                   Erlang send us an encoded callback
				   reply.  Decode the reply, fetch our
				   intermediate state out of my private
				   data, and continue calculating.
				   [...] Ah, I'm done, so I reply with my
				   final answer.

%% This time, get_port_answer()
%% will receive a message with
%% ?FinalAnswer tag.

-Scott



More information about the erlang-questions mailing list