From 387ff8e3347d21e9ca5ad3d8c3a694bc79d38bca Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 8 Dec 2016 19:26:14 +0100 Subject: Add stop arguments: fd and is_direct_call --- erts/doc/src/erl_nif.xml | 6 ++- erts/emulator/beam/erl_nif.c | 5 ++- erts/emulator/beam/erl_nif.h | 16 +++---- erts/emulator/beam/global.h | 2 +- erts/emulator/sys/common/erl_check_io.c | 8 +++- erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 65 +++++++++++++-------------- 6 files changed, 53 insertions(+), 49 deletions(-) (limited to 'erts') diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index e7073a962f..94aff7c67b 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -718,10 +718,12 @@ typedef void ErlNifResourceDtor(ErlNifEnv* env, void* obj); ErlNifResourceStop -typedef void ErlNifResourceStop(ErlNifEnv* env, void* obj); +typedef void ErlNifResourceStop(ErlNifEnv* env, void* obj, ErlNifEvent event, int is_direct_call);

The function prototype of a resource stop function, called on the behalf of - enif_select.

+ enif_select. obj is the resource, event is OS event, + is_direct_call is true if the call is made directly from enif_select + or false if it is a scheduled call (potentially from another thread).

ErlNifCharEncoding diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 27abba7cfd..4e41944ccb 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -2124,12 +2124,13 @@ static void nif_resource_dtor(Binary* bin) } } -void erts_resource_stop(ErlNifResource* resource) +void erts_resource_stop(ErlNifResource* resource, ErlNifEvent e, + int is_direct_call) { struct enif_msg_environment_t msg_env; ASSERT(resource->type->stop); pre_nif_noproc(&msg_env, resource->type->owner, NULL); - resource->type->stop(&msg_env.env, resource->data); + resource->type->stop(&msg_env.env, resource->data, e, is_direct_call); post_nif_noproc(&msg_env); } diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index bf0f7b1f15..78e0fa1864 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -138,18 +138,18 @@ typedef struct void* ref_bin; }ErlNifBinary; -typedef struct { - void (*dtor)(ErlNifEnv* env, void* obj); - void (*stop)(ErlNifEnv* env, void* obj); /* at ERL_NIF_SELECT_STOP event */ -} ErlNifResourceTypeInit; +//#ifndef ERL_SYS_DRV +typedef int ErlNifEvent; /* An event to be selected on. */ +//#endif typedef struct enif_resource_type_t ErlNifResourceType; typedef void ErlNifResourceDtor(ErlNifEnv*, void*); -typedef void ErlNifResourceStop(ErlNifEnv*, void*); +typedef void ErlNifResourceStop(ErlNifEnv*, void*, ErlNifEvent, int is_direct_call); -//#ifndef ERL_SYS_DRV -typedef int ErlNifEvent; /* An event to be selected on. */ -//#endif +typedef struct { + ErlNifResourceDtor* dtor; + ErlNifResourceStop* stop; /* at ERL_NIF_SELECT_STOP event */ +} ErlNifResourceTypeInit; typedef enum { diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 5c5693a315..2decb56544 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -95,7 +95,7 @@ extern void erts_pre_dirty_nif(ErtsSchedulerData *, struct erl_module_nif*); extern void erts_post_dirty_nif(struct enif_environment_t* env); #endif -extern void erts_resource_stop(ErlNifResource* resource); +extern void erts_resource_stop(ErlNifResource*, ErlNifEvent, int is_direct_call); extern Eterm erts_nif_taints(Process* p); extern void erts_print_nif_taints(fmtfn_t to, void* to_arg); void erts_unload_nif(struct erl_module_nif* nif); diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index aeda49b2c6..a533a10c22 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -450,7 +450,7 @@ forget_removed(struct pollset_info* psi) } } if (resource) { - erts_resource_stop(resource); + erts_resource_stop(resource, (ErlNifEvent)fd, 0); enif_release_resource(resource->data); } @@ -1436,7 +1436,7 @@ done: done_unknown: erts_smp_mtx_unlock(fd_mtx(fd)); if (call_stop) { - erts_resource_stop(resource); + erts_resource_stop(resource, (ErlNifEvent)fd, 1); if (call_stop == CALL_STOP_AND_RELEASE) { enif_release_resource(resource->data); } @@ -2141,6 +2141,10 @@ ERTS_CIO_EXPORT(erts_check_io_interrupt_timed)(int set, ERTS_CIO_POLL_INTR_TMD(pollset.ps, set, timeout_time); } +/* + * Number of ignored events, for a lingering fd added by enif_select(), + * until we deselect fd-event from pollset. + */ #define ERTS_NIF_DELAYED_DESELECT 20 void diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index f6ccd3e6ba..878a9ffda9 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -108,13 +108,14 @@ struct binary_resource { static ErlNifResourceType* fd_resource_type; static void fd_resource_dtor(ErlNifEnv* env, void* obj); -static void fd_resource_stop(ErlNifEnv* env, void* obj); +static void fd_resource_stop(ErlNifEnv* env, void* obj, ErlNifEvent, int); static ErlNifResourceTypeInit fd_rt_init = { fd_resource_dtor, fd_resource_stop }; struct fd_resource { int fd; + int was_selected; }; @@ -1128,10 +1129,6 @@ static ERL_NIF_TERM make_term_string(struct make_term_info* mti, int n) { return enif_make_string(mti->dst_env, "Hello!", ERL_NIF_LATIN1); } -static ERL_NIF_TERM make_term_ref(struct make_term_info* mti, int n) -{ - return enif_make_ref(mti->dst_env); -} static ERL_NIF_TERM make_term_sub_binary(struct make_term_info* mti, int n) { ERL_NIF_TERM orig; @@ -1239,7 +1236,6 @@ static Make_term_Func* make_funcs[] = { make_term_atom, make_term_existing_atom, make_term_string, - //make_term_ref, make_term_sub_binary, make_term_uint, make_term_long, @@ -2032,26 +2028,23 @@ static ERL_NIF_TERM format_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg } -static int get_fd(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifEvent* fd) +static int get_fd(ErlNifEnv* env, ERL_NIF_TERM term, struct fd_resource** rsrc) { - struct fd_resource* rsrc; - - if (!enif_get_resource(env, term, fd_resource_type, (void**)&rsrc)) { + if (!enif_get_resource(env, term, fd_resource_type, (void**)rsrc)) { return 0; } - *fd = rsrc->fd; return 1; } static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ErlNifEvent e; + struct fd_resource* fdr; enum ErlNifSelectFlags mode; void* obj; ERL_NIF_TERM ref; int retval; - if (!get_fd(env, argv[0], &e) + if (!get_fd(env, argv[0], &fdr) || !enif_get_uint(env, argv[1], &mode) || !enif_get_resource(env, argv[2], fd_resource_type, &obj)) { @@ -2060,7 +2053,8 @@ static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv ref = argv[3]; - retval = enif_select(env, e, mode, obj, ref); + fdr->was_selected = 1; + retval = enif_select(env, fdr->fd, mode, obj, ref); return enif_make_int(env, retval); } @@ -2070,7 +2064,6 @@ static ERL_NIF_TERM pipe_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] struct fd_resource* read_rsrc; struct fd_resource* write_rsrc; ERL_NIF_TERM read_fd, write_fd; - unsigned char *inp, *outp; int fds[2], flags; if (pipe(fds) < 0) @@ -2099,16 +2092,16 @@ static ERL_NIF_TERM pipe_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] static ERL_NIF_TERM write_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ErlNifEvent fd; + struct fd_resource* fdr; ErlNifBinary bin; int n, written = 0; - if (!get_fd(env, argv[0], &fd) + if (!get_fd(env, argv[0], &fdr) || !enif_inspect_binary(env, argv[1], &bin)) return enif_make_badarg(env); for (;;) { - n = write(fd, bin.data + written, bin.size - written); + n = write(fdr->fd, bin.data + written, bin.size - written); if (n >= 0) { written += n; if (written == bin.size) { @@ -2129,19 +2122,19 @@ static ERL_NIF_TERM write_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ static ERL_NIF_TERM read_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ErlNifEvent fd; + struct fd_resource* fdr; unsigned char* buf; - int n, count, nread = 0; + int n, count; ERL_NIF_TERM res; - if (!get_fd(env, argv[0], &fd) + if (!get_fd(env, argv[0], &fdr) || !enif_get_int(env, argv[1], &count) || count < 1) return enif_make_badarg(env); buf = enif_make_new_binary(env, count, &res); for (;;) { - n = read(fd, buf, count); + n = read(fdr->fd, buf, count); if (n > 0) { if (n < count) { res = enif_make_sub_binary(env, res, 0, n); @@ -2165,29 +2158,33 @@ static ERL_NIF_TERM read_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] static ERL_NIF_TERM is_closed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ErlNifEvent fd; + struct fd_resource* fdr; - if (!get_fd(env, argv[0], &fd)) + if (!get_fd(env, argv[0], &fdr)) return enif_make_badarg(env); - return fd < 0 ? atom_true : atom_false; + return fdr->fd < 0 ? atom_true : atom_false; } static void fd_resource_dtor(ErlNifEnv* env, void* obj) { - struct fd_resource* rsrc = (struct fd_resource*)obj; + struct fd_resource* fdr = (struct fd_resource*)obj; resource_dtor(env, obj); - if (rsrc->fd >= 0) - close(rsrc->fd); + if (fdr->fd >= 0) { + assert(!fdr->was_selected); + close(fdr->fd); + } } -static void fd_resource_stop(ErlNifEnv* env, void* obj) +static void fd_resource_stop(ErlNifEnv* env, void* obj, ErlNifEvent fd, + int is_direct_call) { - struct fd_resource* rsrc = (struct fd_resource*)obj; - if (rsrc->fd >= 0) { - close(rsrc->fd); - rsrc->fd = -1; /* thread safety ? */ - } + struct fd_resource* fdr = (struct fd_resource*)obj; + assert(fd == fdr->fd); + assert(fd >= 0); + close(fd); + fdr->fd = -1; /* thread safety ? */ + fdr->was_selected = 0; } -- cgit v1.2.3