diff options
author | Steve Vinoski <[email protected]> | 2014-03-28 09:10:48 -0400 |
---|---|---|
committer | Steve Vinoski <[email protected]> | 2014-03-28 09:10:48 -0400 |
commit | 4ec8d3be1936bda8cb69a97619e7b7796c54948a (patch) | |
tree | dcd3e009b193c3bf95b5d10071f8dbcbdd4a6982 | |
parent | 98ca47d657fafa4d91b128053e9286114115c0a8 (diff) | |
download | otp-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.c | 10 |
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); |