[erlang-questions] Static callback in NIF

Sverker Eriksson sverker.eriksson@REDACTED
Fri Jul 1 20:08:14 CEST 2016


My mistake. I read "I create a static ErlNifEnv ..." and thought you did

static ErlNifEnv my_env;

which is not allowed and can only compile if you include internal headers.

As long as you only have one callback thread, then it's totally fine to 
allocate
one "static" ErlNifEnv, use that in your callback to create the message,
call enif_send() and then call enif_clear_env() to prepare for next 
callback.

/Sverker


On 07/01/2016 07:38 PM, Igor Clark wrote:
> Hi Sverker, thanks.
>
> I'm only using enif_alloc_env() to create the static ErlNifEnv, in the 
> NIF load(). I haven't had compiler warnings about it - certainly 
> haven't noticed any, and just did a clean+build to check.
>
> (I'm using the rebar3 port compiler on erlang 18.3, erts-7.3 on OSX 
> 10.11.5. It doesn't seem to show warnings without errors, and I can't 
> find a verbose mode - so I used 'rebar comp --verbose' to inspect 'cc' 
> lines and warnings, and there's nothing there about the static 
> ErlNifEnv, either.)
>
> I haven't been doing any digging in erts headers, as I'd be pretty 
> nervous about doing anything undocumented :-)
>
> Am I missing something?
>
> Cheers,
>
> Igor
>
>
> On 01/07/2016 08:18, Sverker Eriksson wrote:
>> The only legit way to create an ErlNifEnv is to call enif_alloc_env().
>>
>> I bet the compiler warned about your static ErlNifEnv
>> just before you went hunting for erts internal header files :-)
>>
>> In OTP-19.0 the 'msg_env' argument to enif_send() can be NULL
>> in which case the message will be copied and you can reuse
>> the environment for the next message with enif_clear_env().
>> This is effective if the message is small.
>>
>> /Sverker, Erlang/OTP
>>
>>
>> On 06/30/2016 08:31 PM, Igor Clark wrote:
>>> Thanks Daniel, good to hear.
>>>
>>> Thanks also Roger & Sergej for your replies. I'll try out 
>>> enif_alloc_env()'ing a new ErlNifEnv each time the callback uses 
>>> enif_send(), rather than just leaving it static.
>>>
>>> Cheers!
>>>
>>> Igor
>>>
>>> On 30/06/2016 07:45, Daniel Goertzen wrote:
>>>> Static vs priv_data are functionally the same here so it doesn't 
>>>> matter which way you go.  I can empathize with your sense of dread; 
>>>> there are a lot of rules to keep track of for keeping Undefined 
>>>> Behavior at bay.  But you seem to have a good handle on things.
>>>>
>>>> On Thu, Jun 30, 2016 at 6:02 AM Igor Clark <igor.clark@REDACTED 
>>>> <mailto:igor.clark@REDACTED>> wrote:
>>>>
>>>>     Hi folks,
>>>>
>>>>     I've got a NIF that uses some library code to talk to specific
>>>>     hardware.
>>>>     It's a hobby project with only one user (me) and no real 
>>>> performance
>>>>     concerns, so what I've got works well at the moment, but I 
>>>> think I'm
>>>>     doing some sneaky/dirty stuff and would like to know the best way
>>>>     to do
>>>>     what I need.
>>>>
>>>>     Sending messages outwards from erlang->C->HW is easy, very 
>>>> quick, and
>>>>     works fine. I return a pointer to the HW reference back to erlang
>>>>     using
>>>>     the enif_*_resource functions, and manage keeping track of
>>>>     everything on
>>>>     the erlang side, which feels pretty natural.
>>>>
>>>>     Coming the other way works fine too, but relies on a C function
>>>>     callback
>>>>     which gets called when the hardware has a message for me. Right 
>>>> now I
>>>>     just have a static function in the NIF C code which I pass to the
>>>>     library. I create a static ErlNifEnv on NIF load() which I keep 
>>>> around
>>>>     and use in the callback to send messages to a specified erlang 
>>>> Pid,
>>>>     passed in via enif_get_local_pid() in another NIF function and 
>>>> also
>>>>     stored statically. This works a treat, but I'm feeling some pretty
>>>>     strong dread that it's very much the wrong way to do things, and
>>>>     asking
>>>>     for scheduler headaches/explosions.
>>>>
>>>>     I'm planning to try storing the various resources in priv_data at
>>>>     load()
>>>>     time, on the theory that that way the memory would at least be 
>>>> managed
>>>>     by the NIF system rather than just as enif_alloc()'ing static
>>>>     pointers,
>>>>     but I'm not sure if that would make any diffrence if code 
>>>> external to
>>>>     the scheduler calls back into it.
>>>>
>>>>     I've looked into running this part as a C node or a port that 
>>>> sends
>>>>     messages with the HW data in a callback in its own process, and 
>>>> the
>>>>     communication seems straightforward enough, but it also seems 
>>>> like I
>>>>     immediately need to start designing mechanisms to deal with
>>>>     working out
>>>>     where to send received messages, almost a protocol in itself. 
>>>> Whereas
>>>>     with the NIF+callback method I have a lot of the work done for 
>>>> me -
>>>>     except, of course, for the synchronisation and memory management,
>>>>     which
>>>>     is the bit I'm worried about.
>>>>
>>>>     FWIW the callback code doesn't modify any of the static data
>>>>     structures
>>>>     directly, it just calls library code which uses the stored
>>>>     references to
>>>>     work out which hardware device & channel to send the message to.
>>>>
>>>>     What's the best practice here? Is a callback in a NIF OK if it's
>>>>     stored
>>>>     in priv_data, or is it never OK? What's the best way to do this if
>>>>     not?
>>>>
>>>>     Would appreciate any tips!
>>>>
>>>>     Cheers,
>>>>     Igor
>>>>     _______________________________________________
>>>>     erlang-questions mailing list
>>>> erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>>
>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> erlang-questions@REDACTED
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>
>
>




More information about the erlang-questions mailing list