summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/erl_nif_api_funcs.h
diff options
context:
space:
mode:
authorSteve Vinoski <vinoski@ieee.org>2014-05-29 22:10:06 -0400
committerRickard Green <rickard@erlang.org>2014-08-28 21:21:58 +0200
commite167bca85a86cc7a149d53da5cdd08b0905e71a6 (patch)
treeee19044424013e6955694ec6f8c963da9a3eab1b /erts/emulator/beam/erl_nif_api_funcs.h
parentceb0e42d0b06f67fe0b18d44c47809e969c75997 (diff)
downloaderlang-e167bca85a86cc7a149d53da5cdd08b0905e71a6.tar.gz
add enif_schedule_nif() to NIF API
In the #erlang IRC channel Anthony Ramine once mentioned the idea of allowing a NIF to use an emulator trap, similar to a BIF trap, to schedule another NIF for execution. This is exactly how dirty NIFs were implemented for Erlang/OTP 17.0, so this commit refactors and generalizes that dirty NIF code to support a new enif_schedule_nif() API function. The enif_schedule_nif() function allows a long-running NIF to be broken into separate NIF invocations. The NIF first executes part of the long-running task, then calls enif_schedule_nif() to schedule a NIF for later execution to continue the task. Any number of NIFs can be scheduled in this manner, one after another. Since the emulator regains control between invocations, this helps avoid problems caused by native code tying up scheduler threads for too long. The enif_schedule_nif() function also replaces the original experimental dirty NIF API. The function takes a flags parameter that a caller can use to indicate the NIF should be scheduled onto either a dirty CPU scheduler thread, a dirty I/O scheduler thread, or scheduled as a regular NIF on a regular scheduler thread. With this change, the original experimental enif_schedule_dirty_nif(), enif_schedule_dirty_nif_finalizer() and enif_dirty_nif_finalizer() API functions are no longer needed and have been removed. Explicit scheduling of a dirty NIF finalization function is no longer necessary; if an application wants similar functionality, it can have a dirty NIF just invoke enif_schedule_nif() to schedule a non-dirty NIF to complete its task. Lift the restriction that dirty NIFs can't call enif_make_badarg() to raise an exception. This was a problem with the original dirty NIF API because it forced developers to get and check all incoming arguments in a regular NIF, and then schedule the dirty NIF which then had to get all the arguments again. Now, the argument checking can be done in the dirty NIF and it can call enif_make_badarg() itself to flag incorrect arguments. Extend the ErlNifFunc struct with a new flags field that allows NIFs to be declared as dirty. The default value for this field is 0, indicating a regular NIF, so it's backwards compatible with all existing statically initialized ErlNifFunc struct instances, and so such instances require no code changes. Defining the flags field with a value of ERL_NIF_DIRTY_JOB_CPU_BOUND indicates that the NIF should execute on a dirty CPU scheduler thread, or defining it with a value of ERL_NIF_DIRTY_JOB_IO_BOUND indicates that the NIF should execute on a dirty I/O scheduler thread. Any other flags field value causes a NIF library loading error. Extend the ErlNifEntry struct with a new options field that indicates whether a NIF library was built with support for optional features such as dirty NIFs. When a NIF library is loaded, the runtime checks the options field to ensure compatibility. If a NIF library built with dirty NIF support is loaded into a runtime that does not support dirty NIFs, and the library defines one or more ErlNifFunc entries with non-zero flags fields indicating dirty NIFs, a NIF library loading error results. There is no error if a NIF library built with dirty NIF support is loaded into a runtime that does not support dirty NIFs but the library does not have any dirty NIFs. It is also not an error if a library without dirty NIF support is loaded into a runtime built with dirty NIF support. Add documentation and tests for enif_schedule_nif().
Diffstat (limited to 'erts/emulator/beam/erl_nif_api_funcs.h')
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h8
1 files changed, 2 insertions, 6 deletions
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index d7c554e60b..be39816a64 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -141,10 +141,8 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_number,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(void*,enif_dlopen,(const char* lib, void (*err_handler)(void*,const char*), void* err_arg));
ERL_NIF_API_FUNC_DECL(void*,enif_dlsym,(void* handle, const char* symbol, void (*err_handler)(void*,const char*), void* err_arg));
ERL_NIF_API_FUNC_DECL(int,enif_consume_timeslice,(ErlNifEnv*, int percent));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_schedule_nif,(ErlNifEnv*,const char*,int,ERL_NIF_TERM (*)(ErlNifEnv*,int,const ERL_NIF_TERM[]),int,const ERL_NIF_TERM[]));
#ifdef ERL_NIF_DIRTY_SCHEDULER_SUPPORT
-ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_schedule_dirty_nif,(ErlNifEnv*,int,ERL_NIF_TERM (*)(ErlNifEnv*,int,const ERL_NIF_TERM[]),int,const ERL_NIF_TERM[]));
-ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_schedule_dirty_nif_finalizer,(ErlNifEnv*,ERL_NIF_TERM,ERL_NIF_TERM (*)(ErlNifEnv*,ERL_NIF_TERM)));
-ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_dirty_nif_finalizer,(ErlNifEnv*,ERL_NIF_TERM));
ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*));
ERL_NIF_API_FUNC_DECL(int,enif_have_dirty_schedulers,(void));
#endif
@@ -289,10 +287,8 @@ ERL_NIF_API_FUNC_DECL(int, enif_map_iterator_get_pair, (ErlNifEnv *env, ErlNifMa
# define enif_dlopen ERL_NIF_API_FUNC_MACRO(enif_dlopen)
# define enif_dlsym ERL_NIF_API_FUNC_MACRO(enif_dlsym)
# define enif_consume_timeslice ERL_NIF_API_FUNC_MACRO(enif_consume_timeslice)
+# define enif_schedule_nif ERL_NIF_API_FUNC_MACRO(enif_schedule_nif)
#ifdef ERL_NIF_DIRTY_SCHEDULER_SUPPORT
-# define enif_schedule_dirty_nif ERL_NIF_API_FUNC_MACRO(enif_schedule_dirty_nif)
-# define enif_schedule_dirty_nif_finalizer ERL_NIF_API_FUNC_MACRO(enif_schedule_dirty_nif_finalizer)
-# define enif_dirty_nif_finalizer ERL_NIF_API_FUNC_MACRO(enif_dirty_nif_finalizer)
# define enif_is_on_dirty_scheduler ERL_NIF_API_FUNC_MACRO(enif_is_on_dirty_scheduler)
# define enif_have_dirty_schedulers ERL_NIF_API_FUNC_MACRO(enif_have_dirty_schedulers)
#endif