From 7a0a52a9a1adc8f87365936f4e76739b7850f1b3 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 12 Mar 2019 14:56:20 +0100 Subject: erts: Schedule resource destructors always to run user NIF code in a more known execution context. Fixes problems like user calling enif_whereis_pid() in destructor which may need to release process main lock in order to lock reg_tab. --- erts/emulator/beam/erl_bif_info.c | 23 +++++++++---------- erts/emulator/beam/erl_binary.h | 11 +++++++-- erts/emulator/beam/erl_nif.c | 28 ++++++++++++++++++----- erts/emulator/beam/erl_process.c | 32 ++++++++++++++++++--------- erts/emulator/beam/erl_process.h | 1 + erts/emulator/test/nif_SUITE.erl | 17 ++++++++++++-- erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 4 ++-- 7 files changed, 82 insertions(+), 34 deletions(-) diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 16c06766fb..83f98461a1 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -4596,18 +4596,17 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) } } else if (ERTS_IS_ATOM_STR("wait", BIF_ARG_1)) { - if (ERTS_IS_ATOM_STR("deallocations", BIF_ARG_2)) { - int flag = ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS; - if (erts_debug_wait_completed(BIF_P, flag)) { - ERTS_BIF_YIELD_RETURN(BIF_P, am_ok); - } - } - if (ERTS_IS_ATOM_STR("timer_cancellations", BIF_ARG_2)) { - int flag = ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS; - if (erts_debug_wait_completed(BIF_P, flag)) { - ERTS_BIF_YIELD_RETURN(BIF_P, am_ok); - } - } + int flag = 0; + if (ERTS_IS_ATOM_STR("deallocations", BIF_ARG_2)) + flag = ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS; + else if (ERTS_IS_ATOM_STR("timer_cancellations", BIF_ARG_2)) + flag = ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS; + else if (ERTS_IS_ATOM_STR("aux_work", BIF_ARG_2)) + flag = ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK; + + if (flag && erts_debug_wait_completed(BIF_P, flag)) { + ERTS_BIF_YIELD_RETURN(BIF_P, am_ok); + } } else if (ERTS_IS_ATOM_STR("broken_halt", BIF_ARG_1)) { erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h index 08edb43c49..2d6fe78757 100644 --- a/erts/emulator/beam/erl_binary.h +++ b/erts/emulator/beam/erl_binary.h @@ -315,6 +315,7 @@ ERTS_GLB_INLINE Binary *erts_bin_drv_alloc(Uint size); ERTS_GLB_INLINE Binary *erts_bin_nrml_alloc(Uint size); ERTS_GLB_INLINE Binary *erts_bin_realloc_fnf(Binary *bp, Uint size); ERTS_GLB_INLINE Binary *erts_bin_realloc(Binary *bp, Uint size); +ERTS_GLB_INLINE void erts_magic_binary_free(Binary *bp); ERTS_GLB_INLINE void erts_bin_free(Binary *bp); ERTS_GLB_INLINE void erts_bin_release(Binary *bp); ERTS_GLB_INLINE Binary *erts_create_magic_binary_x(Uint size, @@ -446,6 +447,13 @@ erts_bin_realloc(Binary *bp, Uint size) return nbp; } +ERTS_GLB_INLINE void +erts_magic_binary_free(Binary *bp) +{ + erts_magic_ref_remove_bin(ERTS_MAGIC_BIN_REFN(bp)); + erts_free(ERTS_MAGIC_BIN_ATYPE(bp), (void *) bp); +} + ERTS_GLB_INLINE void erts_bin_free(Binary *bp) { @@ -454,8 +462,7 @@ erts_bin_free(Binary *bp) /* Destructor took control of the deallocation */ return; } - erts_magic_ref_remove_bin(ERTS_MAGIC_BIN_REFN(bp)); - erts_free(ERTS_MAGIC_BIN_ATYPE(bp), (void *) bp); + erts_magic_binary_free(bp); } else if (bp->intern.flags & BIN_FLAG_DRV) erts_free(ERTS_ALC_T_DRV_BINARY, (void *) bp); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index ebef485b04..365559e2ad 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -987,7 +987,7 @@ static Eterm call_whereis(ErlNifEnv *env, Eterm name) int scheduler; execution_state(env, &c_p, &scheduler); - ASSERT((c_p && scheduler) || (!c_p && !scheduler)); + ASSERT(scheduler || !c_p); if (scheduler < 0) { /* dirty scheduler */ @@ -2361,10 +2361,26 @@ int erts_dbg_is_resource_dying(ErtsResource* resource) } #endif -# define NIF_RESOURCE_DTOR &nif_resource_dtor +#define NIF_RESOURCE_DTOR &nif_resource_dtor_prologue -static int nif_resource_dtor(Binary* bin) +static void run_resource_dtor(void* vbin); + +static int nif_resource_dtor_prologue(Binary* bin) { + /* + * Schedule user resource destructor as aux work to get a context + * where we know what locks we have for example. + */ + Uint sched_id = erts_get_scheduler_id(); + if (!sched_id) + sched_id = 1; + erts_schedule_misc_aux_work(sched_id, run_resource_dtor, bin); + return 0; /* don't free */ +} + +static void run_resource_dtor(void* vbin) +{ + Binary* bin = (Binary*) vbin; ErtsResource* resource = (ErtsResource*) ERTS_MAGIC_BIN_UNALIGNED_DATA(bin); ErlNifResourceType* type = resource->type; ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == NIF_RESOURCE_DTOR); @@ -2396,11 +2412,11 @@ static int nif_resource_dtor(Binary* bin) * If resource->monitors->refc != 0 there are * outstanding references to the resource from * monitors that has not been removed yet. - * nif_resource_dtor() will be called again this + * nif_resource_dtor_prologue() will be called again when this * reference count reach zero. */ if (refc != 0) - return 0; /* we'll be back... */ + return; /* we'll be back... */ erts_mtx_destroy(&rm->lock); } @@ -2417,7 +2433,7 @@ static int nif_resource_dtor(Binary* bin) steal_resource_type(type); erts_free(ERTS_ALC_T_NIF, type); } - return 1; + erts_magic_binary_free((Binary*)vbin); } void erts_resource_stop(ErtsResource* resource, ErlNifEvent e, diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index cc02fbad1e..438d88c346 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -2375,9 +2375,12 @@ struct debug_lop { static void later_thr_debug_wait_completed(void *vlop) { struct debug_lop *lop = vlop; - erts_aint32_t count = (erts_aint32_t) erts_no_schedulers; - count += 1; /* aux thread */ - if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == count) { + + if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == 1) { + erts_aint32_t count = (erts_aint32_t) erts_no_schedulers; + count += 1; /* aux thread */ + erts_atomic32_set_nob(&debug_wait_completed_count, count); + /* scheduler threads */ erts_schedule_multi_misc_aux_work(0, erts_no_schedulers, @@ -2395,19 +2398,28 @@ static void later_thr_debug_wait_completed(void *vlop) static void init_thr_debug_wait_completed(void *vproc) { - struct debug_lop* lop = erts_alloc(ERTS_ALC_T_DEBUG, - sizeof(struct debug_lop)); - lop->proc = vproc; - erts_schedule_thr_prgr_later_op(later_thr_debug_wait_completed, lop, &lop->lop); + if (debug_wait_completed_flags == ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK) { + if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == 1) { + erts_atomic32_set_nob(&debug_wait_completed_count, 0); + erts_resume((Process *) vproc, (ErtsProcLocks) 0); + erts_proc_dec_refc((Process *) vproc); + } + } + else { + struct debug_lop* lop = erts_alloc(ERTS_ALC_T_DEBUG, + sizeof(struct debug_lop)); + lop->proc = vproc; + erts_schedule_thr_prgr_later_op(later_thr_debug_wait_completed, lop, &lop->lop); + } } int erts_debug_wait_completed(Process *c_p, int flags) { - /* Only one process at a time can do this */ - erts_aint32_t count = (erts_aint32_t) (2*erts_no_schedulers); - count += 1; /* aux thread */ + /* Only one process at a time can do this, +1 to mark as busy */ + erts_aint32_t count = (erts_aint32_t) (erts_no_schedulers + 1); + if (0 == erts_atomic32_cmpxchg_mb(&debug_wait_completed_count, count, 0)) { diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 43937f216c..434b528c55 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1850,6 +1850,7 @@ Uint erts_debug_nbalance(void); #define ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS (1 << 0) #define ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS (1 << 1) +#define ERTS_DEBUG_WAIT_COMPLETED_AUX_WORK (1 << 2) int erts_debug_wait_completed(Process *c_p, int flags); diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index ca5f90621f..6ca0990a8a 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -28,6 +28,7 @@ -include_lib("stdlib/include/assert.hrl"). -export([all/0, suite/0, groups/0, + init_per_suite/1, end_per_suite/1, init_per_group/2, end_per_group/2, init_per_testcase/2, end_per_testcase/2, basic/1, reload_error/1, upgrade/1, heap_frag/1, @@ -105,6 +106,14 @@ all() -> nif_whereis, nif_whereis_parallel, nif_whereis_threaded, nif_ioq]. +init_per_suite(Config) -> + erts_debug:set_internal_state(available_internal_state, true), + Config. + +end_per_suite(_Config) -> + catch erts_debug:set_internal_state(available_internal_state, false), + ok. + groups() -> [{G, [], api_repeaters()} || G <- api_groups()] ++ @@ -114,7 +123,6 @@ groups() -> monitor_process_d, demonitor_process]}]. - api_groups() -> [api_latest, api_2_4, api_2_0]. api_repeaters() -> [upgrade, resource_takeover, t_on_load]. @@ -1711,6 +1719,7 @@ read_resource(Type, {Holder,Id}) -> forget_resource({Holder,Id}) -> Holder ! {self(), forget, Id}, {Holder, forget_ok, Id} = receive_any(), + erts_debug:set_internal_state(wait, aux_work), ok. @@ -3327,6 +3336,10 @@ make_unaligned_binary(Bin0) -> <<0:3,Bin:Size/binary,31:5>> = id(<<0:3,Bin0/binary,31:5>>), Bin. +last_resource_dtor_call() -> + erts_debug:set_internal_state(wait, aux_work), + last_resource_dtor_call_nif(). + id(I) -> I. %% The NIFs: @@ -3354,7 +3367,7 @@ make_resource(_) -> ?nif_stub. get_resource(_,_) -> ?nif_stub. release_resource(_) -> ?nif_stub. release_resource_from_thread(_) -> ?nif_stub. -last_resource_dtor_call() -> ?nif_stub. +last_resource_dtor_call_nif() -> ?nif_stub. make_new_resource(_,_) -> ?nif_stub. check_is(_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub. check_is_exception() -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index f2ce6dbe67..17ba3ce297 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -866,7 +866,7 @@ static ERL_NIF_TERM iolist_2_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar return enif_make_binary(env,&obin); } -static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM last_resource_dtor_call_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM ret; if (resource_dtor_last != NULL) { @@ -3512,7 +3512,7 @@ static ErlNifFunc nif_funcs[] = {"get_resource", 2, get_resource}, {"release_resource", 1, release_resource}, {"release_resource_from_thread", 1, release_resource_from_thread}, - {"last_resource_dtor_call", 0, last_resource_dtor_call}, + {"last_resource_dtor_call_nif", 0, last_resource_dtor_call_nif}, {"make_new_resource", 2, make_new_resource}, {"check_is", 11, check_is}, {"check_is_exception", 0, check_is_exception}, -- cgit v1.2.3 From 358df187825617008c2c3705c6b390f44978d4e3 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 19 Mar 2019 20:01:10 +0100 Subject: erts: Simplify nif_SUITE:nif_whereis* tests and change some argc checks from badarg to assert. --- erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 138 +++++++++++--------------- 1 file changed, 60 insertions(+), 78 deletions(-) diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 17ba3ce297..9ae5966e80 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -27,6 +27,7 @@ #ifndef __WIN32__ #include #include +#include #endif #include "nif_mod.h" @@ -707,28 +708,23 @@ static ERL_NIF_TERM tuple_2_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar static ERL_NIF_TERM is_identical(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - if (argc != 2) { - return enif_make_badarg(env); - } + assert(argc == 2); return enif_make_atom(env, (enif_is_identical(argv[0],argv[1]) ? "true" : "false")); } static ERL_NIF_TERM compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - if (argc != 2) { - return enif_make_badarg(env); - } + assert(argc == 2); return enif_make_int(env, enif_compare(argv[0],argv[1])); } static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - if (argc != 3) { - return enif_make_badarg(env); - } - ErlNifHash type; + ErlNifUInt64 salt; + + assert(argc == 3); if (enif_is_identical(argv[0], enif_make_atom(env, "internal"))) { type = ERL_NIF_INTERNAL_HASH; } @@ -739,7 +735,6 @@ static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] return enif_make_badarg(env); } - ErlNifUInt64 salt; if (! enif_get_uint64(env, argv[2], &salt)) { return enif_make_badarg(env); } @@ -1010,6 +1005,7 @@ static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TER static void* threaded_release_resource(void* resource) { enif_release_resource(resource); + return NULL; } static ERL_NIF_TERM release_resource_from_thread(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -1201,7 +1197,6 @@ static void fill(void* dst, unsigned bytes, int seed) enum { /* results */ WHEREIS_SUCCESS, - WHEREIS_ERROR_TYPE, WHEREIS_ERROR_LOOKUP, WHEREIS_ERROR_SEND, /* types */ @@ -1221,6 +1216,7 @@ typedef struct { whereis_term_data_t res; ErlNifTid tid; int type; + int rc; } whereis_thread_resource_t; static whereis_thread_resource_t* whereis_thread_resource_create(void) @@ -1239,15 +1235,17 @@ static void whereis_thread_resource_dtor(ErlNifEnv* env, void* obj) enif_free_env(rp->env); } -static int whereis_type(ERL_NIF_TERM type) +static int whereis_type(ERL_NIF_TERM type_term, int* type_p) { - if (enif_is_identical(type, atom_pid)) - return WHEREIS_LOOKUP_PID; - - if (enif_is_identical(type, atom_port)) - return WHEREIS_LOOKUP_PORT; - - return WHEREIS_ERROR_TYPE; + if (enif_is_identical(type_term, atom_pid)) { + *type_p = WHEREIS_LOOKUP_PID; + return 1; + } + if (enif_is_identical(type_term, atom_port)) { + *type_p = WHEREIS_LOOKUP_PORT; + return 1; + } + return 0; } static int whereis_lookup_internal( @@ -1261,7 +1259,7 @@ static int whereis_lookup_internal( return enif_whereis_port(env, name, & out->port) ? WHEREIS_SUCCESS : WHEREIS_ERROR_LOOKUP; - return WHEREIS_ERROR_TYPE; + abort(); } static int whereis_send_internal( @@ -1275,23 +1273,20 @@ static int whereis_send_internal( return enif_port_command(env, & to->port, NULL, msg) ? WHEREIS_SUCCESS : WHEREIS_ERROR_SEND; - return WHEREIS_ERROR_TYPE; + abort(); } -static int whereis_resolved_term( - ErlNifEnv* env, int type, whereis_term_data_t* res, ERL_NIF_TERM* out) +static ERL_NIF_TERM whereis_resolved_term( + ErlNifEnv* env, int type, whereis_term_data_t* res) { switch (type) { case WHEREIS_LOOKUP_PID: - *out = enif_make_pid(env, & res->pid); - break; + return enif_make_pid(env, &res->pid); case WHEREIS_LOOKUP_PORT: - *out = enif_make_port(env, & res->port); - break; + return enif_make_port(env, &res->port); default: - return WHEREIS_ERROR_TYPE; + abort(); } - return WHEREIS_SUCCESS; } static ERL_NIF_TERM whereis_result_term(ErlNifEnv* env, int result) @@ -1307,9 +1302,6 @@ static ERL_NIF_TERM whereis_result_term(ErlNifEnv* env, int result) case WHEREIS_ERROR_SEND: err = atom_send; break; - case WHEREIS_ERROR_TYPE: - err = atom_badarg; - break; default: err = enif_make_int(env, -result); break; @@ -1320,14 +1312,10 @@ static ERL_NIF_TERM whereis_result_term(ErlNifEnv* env, int result) static void* whereis_lookup_thread(void* arg) { whereis_thread_resource_t* rp = (whereis_thread_resource_t*) arg; - int rc; - /* enif_whereis_xxx should work with allocated or null env */ - rc = whereis_lookup_internal( - ((rp->type == WHEREIS_LOOKUP_PID) ? NULL : rp->env), - rp->type, rp->name, & rp->res); + rp->rc = whereis_lookup_internal(NULL, rp->type, rp->name, &rp->res); - return (((char*) NULL) + rc); + return NULL; } /* whereis_term(Type, Name) -> pid() | port() | false */ @@ -1338,17 +1326,14 @@ whereis_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ERL_NIF_TERM ret; int type, rc; - if (argc != 2) /* allow non-atom name for testing */ - return enif_make_badarg(env); - - if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE) + assert(argc == 2); + if (!whereis_type(argv[0], &type)) return enif_make_badarg(env); rc = whereis_lookup_internal(env, type, argv[1], & res); - if (rc == WHEREIS_SUCCESS) { - rc = whereis_resolved_term(env, type, & res, & ret); - } - return (rc == WHEREIS_SUCCESS) ? ret : atom_false; + return (rc == WHEREIS_SUCCESS ? + whereis_resolved_term(env, type, &res) : + atom_false); } /* whereis_send(Type, Name, Message) -> ok | {error, Reason} */ @@ -1358,10 +1343,11 @@ whereis_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) whereis_term_data_t to; int type, rc; - if (argc != 3 || !enif_is_atom(env, argv[1])) + assert(argc == 3); + if (!enif_is_atom(env, argv[1])) return enif_make_badarg(env); - if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE) + if (!whereis_type(argv[0], &type)) return enif_make_badarg(env); rc = whereis_lookup_internal(env, type, argv[1], & to); @@ -1378,10 +1364,11 @@ whereis_thd_lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) whereis_thread_resource_t* rp; int type, rc; - if (argc != 2 || !enif_is_atom(env, argv[1])) + assert(argc == 3); + if (!enif_is_atom(env, argv[1])) return enif_make_badarg(env); - if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE) + if (!whereis_type(argv[0], &type)) return enif_make_badarg(env); rp = whereis_thread_resource_create(); @@ -1406,22 +1393,21 @@ whereis_thd_result(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { whereis_thread_resource_t* rp; ERL_NIF_TERM ret; - char* thdret; /* so we can keep compilers happy converting to int */ - int rc; + int join_rc; - if (argc != 1 - || !enif_get_resource(env, argv[0], whereis_resource_type, (void**) & rp)) + assert(argc == 1); + if (!enif_get_resource(env, argv[0], whereis_resource_type, (void**) & rp)) return enif_make_badarg(env); - if ((rc = enif_thread_join(rp->tid, (void**) & thdret)) != 0) - return enif_make_tuple2(env, atom_error, enif_make_int(env, rc)); + if ((join_rc = enif_thread_join(rp->tid, NULL)) != 0) + return enif_make_tuple2(env, atom_error, enif_make_int(env, join_rc)); - rc = (int)(thdret - ((char*) NULL)); - if (rc == WHEREIS_SUCCESS) { - rc = whereis_resolved_term(env, rp->type, & rp->res, & ret); + if (rp->rc == WHEREIS_SUCCESS) { + ret = enif_make_tuple2(env, atom_ok, + whereis_resolved_term(env, rp->type, &rp->res)); } - ret = (rc == WHEREIS_SUCCESS) - ? enif_make_tuple2(env, atom_ok, ret) : whereis_result_term(env, rc); + else + ret = whereis_result_term(env, rp->rc); enif_release_resource(rp); return ret; @@ -1996,8 +1982,7 @@ static ERL_NIF_TERM nif_sched1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM call_nif_schedule(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM result; - if (argc != 2) - return enif_make_atom(env, "false"); + assert(argc == 2); result = enif_schedule_nif(env, "nif_sched1", 0, nif_sched1, argc, argv); assert(!enif_is_exception(env, result)); return result; @@ -2144,7 +2129,8 @@ static ERL_NIF_TERM maps_from_list_nif(ErlNifEnv* env, int argc, const ERL_NIF_T ERL_NIF_TERM result, cell; unsigned count; - if (argc != 1 || !enif_get_list_length(env, argv[0], &count)) { + assert(argc == 1); + if (!enif_get_list_length(env, argv[0], &count)) { return enif_make_badarg(env); } @@ -2191,7 +2177,8 @@ static ERL_NIF_TERM sorted_list_from_maps_nif(ErlNifEnv* env, int argc, const ER ErlNifMapIterator iter_b; int cnt, next_ret, prev_ret; - if (argc != 1 && !enif_is_map(env, map)) + assert(argc == 1); + if (!enif_is_map(env, map)) return enif_make_int(env, __LINE__); if(!enif_map_iterator_create(env, map, &iter_f, ERL_NIF_MAP_ITERATOR_FIRST)) @@ -2252,9 +2239,7 @@ static ERL_NIF_TERM monotonic_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM { ErlNifTimeUnit time_unit; - if (argc != 1) - return atom_false; - + assert(argc == 1); if (enif_compare(argv[0], atom_second) == 0) time_unit = ERL_NIF_SEC; else if (enif_compare(argv[0], atom_millisecond) == 0) @@ -2273,9 +2258,7 @@ static ERL_NIF_TERM time_offset(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg { ErlNifTimeUnit time_unit; - if (argc != 1) - return atom_false; - + assert(argc == 1); if (enif_compare(argv[0], atom_second) == 0) time_unit = ERL_NIF_SEC; else if (enif_compare(argv[0], atom_millisecond) == 0) @@ -2295,9 +2278,7 @@ static ERL_NIF_TERM convert_time_unit(ErlNifEnv* env, int argc, const ERL_NIF_TE ErlNifTime val; ErlNifTimeUnit from, to; - if (argc != 3) - return atom_false; - + assert(argc == 3); if (!enif_get_int64(env, argv[0], &i64)) return enif_make_badarg(env); @@ -3281,7 +3262,7 @@ static int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail, Erl } /* Attempt to write the data */ - n = writev(fd, sysiovec, iovcnt); + n = writev(fd, (struct iovec*)sysiovec, iovcnt); saved_errno = errno; if (enif_ioq_size(q) == 0) { @@ -3355,10 +3336,11 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) if (enif_is_identical(argv[0], enif_make_atom(env, "example"))) { #ifndef __WIN32__ - int fd[2], res = 0, cnt = 0, queue_cnt; + int fd[2], res = 0, cnt = 0; ERL_NIF_TERM tail; char buff[255]; - pipe(fd); + res = pipe(fd); + assert(res == 0); fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK); fcntl(fd[1], F_SETFL, fcntl(fd[1], F_GETFL) | O_NONBLOCK); -- cgit v1.2.3 From 6b414fbc67d2c7f703fe677f2acda1a6fa67d8ed Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 19 Mar 2019 20:01:45 +0100 Subject: erts: Add test of enif_whereis* from resource destructor --- erts/emulator/test/nif_SUITE.erl | 27 ++++++++++++++------- erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 34 ++++++++++++++++++--------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 6ca0990a8a..d8c2cb0e43 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -3065,22 +3065,31 @@ nif_whereis_threaded(Config) when is_list(Config) -> RegName = nif_whereis_test_threaded, undefined = erlang:whereis(RegName), - Ref = make_ref(), - {Pid, Mon} = spawn_monitor(?MODULE, nif_whereis_proxy, [Ref]), - true = register(RegName, Pid), + Self = self(), + true = register(RegName, Self), - {ok, ProcThr} = whereis_thd_lookup(pid, RegName), - {ok, Pid} = whereis_thd_result(ProcThr), + {ok, ProcThr} = whereis_thd_lookup(pid, RegName, "dtor to proc"), + {ok, Self} = whereis_thd_result(ProcThr), - Pid ! {Ref, quit}, - ok = receive {'DOWN', Mon, process, Pid, normal} -> ok end, + nif_whereis_threaded_2(RegName). + +nif_whereis_threaded_2(RegName) -> + erlang:garbage_collect(), + "dtor to proc" = receive_any(1000), + true = unregister(RegName), Port = open_port({spawn, echo_drv}, [eof]), true = register(RegName, Port), - {ok, PortThr} = whereis_thd_lookup(port, RegName), + {ok, PortThr} = whereis_thd_lookup(port, RegName, "dtor to port"), {ok, Port} = whereis_thd_result(PortThr), + nif_whereis_threaded_3(Port). + +nif_whereis_threaded_3(Port) -> + erlang:garbage_collect(), + {Port, {data, "dtor to port"}} = receive_any(1000), + port_close(Port), ok. @@ -3426,7 +3435,7 @@ ioq_nif(_,_,_,_) -> ?nif_stub. %% whereis whereis_send(_Type,_Name,_Msg) -> ?nif_stub. whereis_term(_Type,_Name) -> ?nif_stub. -whereis_thd_lookup(_Type,_Name) -> ?nif_stub. +whereis_thd_lookup(_Type,_Name, _Msg) -> ?nif_stub. whereis_thd_result(_Thd) -> ?nif_stub. %% maps diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 9ae5966e80..463aa3b246 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1217,6 +1217,7 @@ typedef struct { ErlNifTid tid; int type; int rc; + ERL_NIF_TERM dtor_msg; } whereis_thread_resource_t; static whereis_thread_resource_t* whereis_thread_resource_create(void) @@ -1229,9 +1230,21 @@ static whereis_thread_resource_t* whereis_thread_resource_create(void) return rp; } +static int whereis_lookup_internal(ErlNifEnv*, int type, ERL_NIF_TERM name, + whereis_term_data_t* out); +static int whereis_send_internal(ErlNifEnv*, int type, whereis_term_data_t* to, + ERL_NIF_TERM msg); + + static void whereis_thread_resource_dtor(ErlNifEnv* env, void* obj) { whereis_thread_resource_t* rp = (whereis_thread_resource_t*) obj; + whereis_term_data_t to; + + if (whereis_lookup_internal(env, rp->type, rp->name, &to) + == WHEREIS_SUCCESS) { + whereis_send_internal(env, rp->type, &to, rp->dtor_msg); + } enif_free_env(rp->env); } @@ -1323,7 +1336,6 @@ static ERL_NIF_TERM whereis_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { whereis_term_data_t res; - ERL_NIF_TERM ret; int type, rc; assert(argc == 2); @@ -1357,12 +1369,13 @@ whereis_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return whereis_result_term(env, rc); } -/* whereis_thd_lookup(Type, Name) -> {ok, Resource} | {error, SysErrno} */ +/* whereis_thd_lookup(Type, Name, DtorMsg) -> {ok, Resource} | {error, SysErrno} */ static ERL_NIF_TERM whereis_thd_lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { whereis_thread_resource_t* rp; int type, rc; + ERL_NIF_TERM ret; assert(argc == 3); if (!enif_is_atom(env, argv[1])) @@ -1374,17 +1387,17 @@ whereis_thd_lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) rp = whereis_thread_resource_create(); rp->type = type; rp->name = enif_make_copy(rp->env, argv[1]); + rp->dtor_msg = enif_make_copy(rp->env, argv[2]); rc = enif_thread_create( "nif_SUITE:whereis_thd", & rp->tid, whereis_lookup_thread, rp, NULL); - if (rc == 0) { - return enif_make_tuple2(env, atom_ok, enif_make_resource(env, rp)); - } - else { - enif_release_resource(rp); - return enif_make_tuple2(env, atom_error, enif_make_int(env, rc)); - } + if (rc == 0) + ret = enif_make_tuple2(env, atom_ok, enif_make_resource(env, rp)); + else + ret = enif_make_tuple2(env, atom_error, enif_make_int(env, rc)); + enif_release_resource(rp); + return ret; } /* whereis_thd_result(Resource) -> {ok, pid() | port()} | {error, ErrNum} */ @@ -1409,7 +1422,6 @@ whereis_thd_result(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) else ret = whereis_result_term(env, rp->rc); - enif_release_resource(rp); return ret; } @@ -3564,7 +3576,7 @@ static ErlNifFunc nif_funcs[] = {"monitor_frenzy_nif", 4, monitor_frenzy_nif}, {"whereis_send", 3, whereis_send}, {"whereis_term", 2, whereis_term}, - {"whereis_thd_lookup", 2, whereis_thd_lookup}, + {"whereis_thd_lookup", 3, whereis_thd_lookup}, {"whereis_thd_result", 1, whereis_thd_result}, {"ioq_nif", 1, ioq}, {"ioq_nif", 2, ioq}, -- cgit v1.2.3