[erlang-questions] Static callback in NIF
Igor Clark
igor.clark@REDACTED
Sat Jul 2 00:41:38 CEST 2016
Ah, got you. I'm not explicitly creating any threads at all; I just pass the callback to the library code in load() and return, so it sounds like that's OK. Great news for me!
Thanks for your help Sverker.
Best,
Igor
> On Jul 1, 2016, at 11:08 AM, Sverker Eriksson <sverker.eriksson@REDACTED> wrote:
>
> 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