[erlang-questions] Adding a NIF to prim_file

John Högberg john@REDACTED
Mon Apr 29 08:40:41 CEST 2019


Hi,

`prim_file` is a prebuilt module that's statically embedded into the
emulator, and the emulator crashes if there are any problems
initializing it. In this case you've added a function to the NIF but
haven't yet rebuilt the module, so it crashes when trying to inject the
non-existent `my_truncate_nif/1`.

To update these prebuilt modules, you need to run:

    ./otp_build update_preloaded --no-commit

Try doing this on a clean build without changes to the NIF (C code),
and then rebuild the emulator with the changes applied. Note that you
will need to rebuild the emulator every time you update the preloaded
modules for the changes to take effect.

Hope that helps!

Regards,
John Högberg

On Sun, 2019-04-28 at 17:59 -0300, Andre Nathan wrote:
> Hi
> 
> I'm trying to figure out how to add a NIF to the prim_file module.
> To 
> try to get it working, I'm just trying to add an existing function
> under 
> a different name:
> 
> In prim_file_nif.c I added the lines below:
> 
> WRAP_FILE_HANDLE_EXPORT(my_truncate_nif)
> 
> static ErlNifFunc nif_funcs[] = {
>    ...
>    {"my_truncate_nif", 1, my_truncate_nif,
> ERL_NIF_DIRTY_JOB_IO_BOUND},
>    ...
> };
> 
> Then I copied truncate_nif_impl and renamed the copy to 
> my_truncate_nif_impl.
> 
> 
> In prim_file.erl I copied the truncate function, renamed the copy to 
> my_truncate and changed it to call my_truncate_nif instead of 
> truncate_nif. Then I added
> 
> my_truncate_nif(_FileRef) ->
>    erlang:nif_error(undef).
> 
> However, when I try to build OTP, I get this error:
> 
> (no logger present) unexpected logger message: {log,error,"Error in 
> process ~p with exit 
> value:~n~p~n",[<0.0.0>,{{badmatch,{error,{bad_lib,"Function not
> found 
> prim_file:my_truncate_nif/1"}}},[{prim_file,on_load,0,[]},{erl_init,s
> tart,2,[]}]}],#{error_logger=>#{emulator=>true,tag=>error},gl=><0.0.0
> >,pid=><0.0.0>,time=>1556484838271817}}
> 
> Is there anything else I have to do to allow the new function to be 
> detected? I couldn't find any other references to truncate_nif that
> I 
> could replicate.
> 
> The full diff is pasted below.
> 
> Thanks,
> Andre
> 
> 
> diff --git a/erts/emulator/nifs/common/prim_file_nif.c 
> b/erts/emulator/nifs/common/prim_file_nif.c
> index 3df04e42e2..61a9b70679 100644
> --- a/erts/emulator/nifs/common/prim_file_nif.c
> +++ b/erts/emulator/nifs/common/prim_file_nif.c
> @@ -162,6 +162,7 @@ WRAP_FILE_HANDLE_EXPORT(allocate_nif)
>   WRAP_FILE_HANDLE_EXPORT(advise_nif)
>   WRAP_FILE_HANDLE_EXPORT(get_handle_nif)
>   WRAP_FILE_HANDLE_EXPORT(ipread_s32bu_p32bu_nif)
> +WRAP_FILE_HANDLE_EXPORT(my_truncate_nif)
> 
>   static ErlNifFunc nif_funcs[] = {
>       /* File handle ops */
> @@ -174,6 +175,7 @@ static ErlNifFunc nif_funcs[] = {
>       {"seek_nif", 3, seek_nif, ERL_NIF_DIRTY_JOB_IO_BOUND},
>       {"sync_nif", 2, sync_nif, ERL_NIF_DIRTY_JOB_IO_BOUND},
>       {"truncate_nif", 1, truncate_nif, ERL_NIF_DIRTY_JOB_IO_BOUND},
> +    {"my_truncate_nif", 1, my_truncate_nif,
> ERL_NIF_DIRTY_JOB_IO_BOUND},
>       {"allocate_nif", 3, allocate_nif, ERL_NIF_DIRTY_JOB_IO_BOUND},
>       {"advise_nif", 4, advise_nif, ERL_NIF_DIRTY_JOB_IO_BOUND},
> 
> @@ -721,6 +723,16 @@ static ERL_NIF_TERM sync_nif_impl(efile_data_t
> *d, 
> ErlNifEnv *env, int argc, con
>       return am_ok;
>   }
> 
> +static ERL_NIF_TERM my_truncate_nif_impl(efile_data_t *d, ErlNifEnv 
> *env, int argc, const ERL_NIF_TERM argv[]) {
> +    ASSERT(argc == 0);
> +
> +    if(!efile_truncate(d)) {
> +        return posix_error_to_tuple(env, d->posix_errno);
> +    }
> +
> +    return am_ok;
> +}
> +
>   static ERL_NIF_TERM truncate_nif_impl(efile_data_t *d, ErlNifEnv
> *env, 
> int argc, const ERL_NIF_TERM argv[]) {
>       ASSERT(argc == 0);
> 
> diff --git a/erts/preloaded/src/prim_file.erl 
> b/erts/preloaded/src/prim_file.erl
> index 1aa5d85c64..e350cd9a19 100644
> --- a/erts/preloaded/src/prim_file.erl
> +++ b/erts/preloaded/src/prim_file.erl
> @@ -22,7 +22,7 @@
>   -export([on_load/0]).
> 
>   -export([open/2, close/1,
> -         sync/1, datasync/1, truncate/1, advise/4, allocate/3,
> +         sync/1, datasync/1, truncate/1, my_truncate/1, advise/4, 
> allocate/3,
>            read_line/1, read/2, write/2, position/2,
>            pread/2, pread/3, pwrite/2, pwrite/3]).
> 
> 
> @@ -242,6 +242,15 @@ truncate(Fd) ->
>           error:badarg -> {error, badarg}
>       end.
> 
> +my_truncate(Fd) ->
> +    try
> +        #{ handle := FRef } = get_fd_data(Fd),
> +        reset_write_position(Fd),
> +        my_truncate_nif(FRef)
> +    catch
> +        error:badarg -> {error, badarg}
> +    end.
> +
>   advise(Fd, Offset, Length, Advise) ->
>       try
>           #{ handle := FRef } = get_fd_data(Fd),
> @@ -493,6 +502,8 @@ allocate_nif(_FileRef, _Offset, _Length) ->
>       erlang:nif_error(undef).
>   truncate_nif(_FileRef) ->
>       erlang:nif_error(undef).
> +my_truncate_nif(_FileRef) ->
> +    erlang:nif_error(undef).
>   get_handle_nif(_FileRef) ->
>       erlang:nif_error(undef).
>   delayed_close_nif(_FileRef) ->
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions




More information about the erlang-questions mailing list