aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Vinoski <[email protected]>2014-03-28 09:10:48 -0400
committerSteve Vinoski <[email protected]>2014-03-28 09:10:48 -0400
commit4ec8d3be1936bda8cb69a97619e7b7796c54948a (patch)
treedcd3e009b193c3bf95b5d10071f8dbcbdd4a6982
parent98ca47d657fafa4d91b128053e9286114115c0a8 (diff)
downloadotp-4ec8d3be1936bda8cb69a97619e7b7796c54948a.tar.gz
otp-4ec8d3be1936bda8cb69a97619e7b7796c54948a.tar.bz2
otp-4ec8d3be1936bda8cb69a97619e7b7796c54948a.zip
prevent NIF purge during dirty NIF execution
Reference-count the NIF before and after invoking a NIF on dirty schedulers to prevent having the NIF purged during the call.
-rw-r--r--erts/emulator/beam/erl_nif.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index f503b222d0..ff551ea3af 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1543,7 +1543,7 @@ static ERL_NIF_TERM
execute_dirty_nif_finalizer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
Eterm* reg = ERTS_PROC_GET_SCHDATA(env->proc)->x_reg_array;
- ERL_NIF_TERM result = (ERL_NIF_TERM) reg[0];
+ ERL_NIF_TERM result, dirty_result = (ERL_NIF_TERM) reg[0];
typedef ERL_NIF_TERM (*FinalizerFP)(ErlNifEnv*, ERL_NIF_TERM);
FinalizerFP fp;
#if HAVE_INT64 && SIZEOF_LONG != 8
@@ -1553,7 +1553,11 @@ execute_dirty_nif_finalizer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ASSERT(sizeof(fp) <= sizeof(unsigned long));
enif_get_ulong(env, reg[1], (unsigned long *) &fp);
#endif
- return (*fp)(env, result);
+ result = (*fp)(env, dirty_result);
+ if (erts_refc_dectest(&env->mod_nif->rt_dtor_cnt, 0) == 0
+ && env->mod_nif->mod == NULL)
+ close_lib(env->mod_nif);
+ return result;
}
#endif /* ERTS_DIRTY_SCHEDULERS */
@@ -1606,6 +1610,8 @@ enif_schedule_dirty_nif(ErlNifEnv* env, int flags,
ep->m = env->mod_nif;
proc->freason = TRAP;
+ erts_refc_inc(&env->mod_nif->rt_dtor_cnt, 1);
+
return THE_NON_VALUE;
#else
return (*fp)(env, argc, argv);