From 4c5d33114edea787833d6aa1b0d51ea9d98b3321 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 16 Dec 2016 19:30:22 +0100 Subject: Add ErlNifSelectReturn --- erts/doc/src/erl_nif.xml | 35 +++++++++++++++++++++++++-- erts/emulator/beam/erl_drv_nif.h | 8 ++++++ erts/emulator/sys/common/erl_check_io.c | 27 ++++++++++----------- erts/emulator/sys/common/erl_check_io.h | 4 +-- erts/emulator/sys/unix/sys.c | 2 +- erts/emulator/test/nif_SUITE.erl | 18 ++++++++++---- erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 4 +-- 7 files changed, 72 insertions(+), 26 deletions(-) (limited to 'erts') diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 94aff7c67b..13b72863f3 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -2526,7 +2526,7 @@ enif_map_iterator_destroy(env, &iter); - int + enum ErlNifSelectReturn enif_select(ErlNifEnv* env, ErlNifEvent event, enum ErlNifSelectFlags mode, void* obj, Eterm ref) @@ -2567,7 +2567,38 @@ enif_map_iterator_destroy(env, &iter); the event object. This safe way of closing event objects must be used even if all notifications have been received and no further calls to enif_select have been made.

-

Returns 0 on success, or -1 if invalid arguments.

+

Returns an integer where different bits indicate the outcome of the call:

+ + ERL_NIF_SELECT_ERROR + The master error bit. It will always be set if the call failed for + any reason. + ERL_NIF_SELECT_STOP_CALLED + The stop callback was called directly by enif_select. + ERL_NIF_SELECT_STOP_SCHEDULED + The stop callback was scheduled to run on some other thread + or later by this thread. + ERL_NIF_SELECT_INVALID_EVENT + Argument event is not a valid OS event object. + ERL_NIF_SELECT_FAILED + The system call failed to add the event object to the poll set. + +

The return value from a successful call with mode as ERL_NIF_SELECT_STOP, + will contain either bit ERL_NIF_SELECT_STOP_CALLED or + ERL_NIF_SELECT_STOP_SCHEDULED.

+ +

Always use bitwise AND to test the return value. New significant bits + may be added in future releases to give more detailed information for both + failed and successful calls. Do NOT use equallity tests like ==, as + that may cause your application to stop working.

+

Example:

+ +retval = enif_select(env, fd, ERL_NIF_SELECT_READ, resource, ref); +if (retval & ERL_NIF_SELECT_ERROR) { + /* handle error */ +} +/* Success! */ + +
diff --git a/erts/emulator/beam/erl_drv_nif.h b/erts/emulator/beam/erl_drv_nif.h index e4ebcdb1d4..46bb06d642 100644 --- a/erts/emulator/beam/erl_drv_nif.h +++ b/erts/emulator/beam/erl_drv_nif.h @@ -56,6 +56,14 @@ enum ErlNifSelectFlags { ERL_NIF_SELECT_STOP = (1 << 2) }; +enum ErlNifSelectReturn { + ERL_NIF_SELECT_ERROR = (1 << 0), + ERL_NIF_SELECT_STOP_CALLED = (1 << 1), + ERL_NIF_SELECT_STOP_SCHEDULED = (1 << 2), + ERL_NIF_SELECT_INVALID_EVENT = (1 << 3), + ERL_NIF_SELECT_FAILED = (1 << 4) +}; + #ifdef SIZEOF_CHAR # define SIZEOF_CHAR_SAVED__ SIZEOF_CHAR # undef SIZEOF_CHAR diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index a533a10c22..4fc95624c7 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -1198,7 +1198,7 @@ done_unknown: return ret; } -int +enum ErlNifSelectReturn ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, ErlNifEvent e, enum ErlNifSelectFlags mode, @@ -1213,7 +1213,7 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, ErtsPollEvents new_events, old_events; ErtsDrvEventState *state; int wake_poller; - int ret; + enum ErlNifSelectReturn ret; enum { NO_STOP=0, CALL_STOP, CALL_STOP_AND_RELEASE } call_stop = NO_STOP; #if ERTS_CIO_HAVE_DRV_EVENT ErtsDrvEventDataState *free_event = NULL; @@ -1227,11 +1227,11 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS if ((unsigned)fd >= (unsigned)erts_smp_atomic_read_nob(&drv_ev_state_len)) { if (fd < 0) { - return -1; + return ERL_NIF_SELECT_ERROR | ERL_NIF_SELECT_INVALID_EVENT; } if (fd >= max_fds) { nif_select_large_fd_error(fd, mode, resource, ref); - return -1; + return ERL_NIF_SELECT_ERROR | ERL_NIF_SELECT_INVALID_EVENT; } grow_drv_ev_state(fd); } @@ -1250,7 +1250,7 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, if (IS_FD_UNKNOWN(state)) { /* fast track to stop callback */ call_stop = CALL_STOP; - ret = 0; + ret = ERL_NIF_SELECT_STOP_CALLED; goto done_unknown; } on = 0; @@ -1303,7 +1303,7 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, print_nif_select_op(dsbufp, fd, mode, resource, ref); steal_pending_stop_nif(dsbufp, resource, state, mode, on); if (state->type == ERTS_EV_TYPE_STOP_NIF) { - ret = 0; + ret = ERL_NIF_SELECT_STOP_SCHEDULED; /* ?? */ goto done; } ASSERT(state->type == ERTS_EV_TYPE_NONE); @@ -1325,7 +1325,7 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, state->driver.nif->out.ddeselect_cnt = 0; state->driver.stop.resource = NULL; } - ret = -1; + ret = ERL_NIF_SELECT_ERROR | ERL_NIF_SELECT_FAILED; goto done; } @@ -1339,8 +1339,7 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, || state->type == ERTS_EV_TYPE_NONE); state->events = new_events; - if (ctl_events) { - if (on) { + if (on) { Uint32* refn; if (!state->driver.nif) state->driver.nif = alloc_nif_select_data(); @@ -1379,8 +1378,9 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, } state->driver.nif->out.ddeselect_cnt = 0; } - } - else { /* off */ + ret = 0; + } + else { /* off */ if (state->type == ERTS_EV_TYPE_NIF) { //erts_fprintf(stderr, "SVERK: enif select clear fd=%d inpid=%T inrsrc=%p\n", // state->fd, state->driver.nif->inpid, @@ -1408,6 +1408,7 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, call_stop = CALL_STOP; } state->type = ERTS_EV_TYPE_NONE; + ret = ERL_NIF_SELECT_STOP_CALLED; } else { /* Not safe to close fd, postpone stop_select callback. */ @@ -1418,12 +1419,10 @@ ERTS_CIO_EXPORT(enif_select)(ErlNifEnv* env, enif_keep_resource(resource); } state->type = ERTS_EV_TYPE_STOP_NIF; + ret = ERL_NIF_SELECT_STOP_SCHEDULED; } - } } - ret = 0; - done: check_fd_cleanup(state, diff --git a/erts/emulator/sys/common/erl_check_io.h b/erts/emulator/sys/common/erl_check_io.h index 242e7cfcf5..41e2e9210a 100644 --- a/erts/emulator/sys/common/erl_check_io.h +++ b/erts/emulator/sys/common/erl_check_io.h @@ -34,8 +34,8 @@ int driver_select_kp(ErlDrvPort, ErlDrvEvent, int, int); int driver_select_nkp(ErlDrvPort, ErlDrvEvent, int, int); -int enif_select_kp(ErlNifEnv*, ErlNifEvent, enum ErlNifSelectFlags, void*, Eterm); -int enif_select_nkp(ErlNifEnv*, ErlNifEvent, enum ErlNifSelectFlags, void*, Eterm); +enum ErlNifSelectReturn enif_select_kp(ErlNifEnv*, ErlNifEvent, enum ErlNifSelectFlags, void*, Eterm); +enum ErlNifSelectReturn enif_select_nkp(ErlNifEnv*, ErlNifEvent, enum ErlNifSelectFlags, void*, Eterm); int driver_event_kp(ErlDrvPort, ErlDrvEvent, ErlDrvEventData); int driver_event_nkp(ErlDrvPort, ErlDrvEvent, ErlDrvEventData); Uint erts_check_io_size_kp(void); diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 789b455f2d..5ce57b7b1b 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -161,7 +161,7 @@ int erts_use_kernel_poll = 0; struct { int (*select)(ErlDrvPort, ErlDrvEvent, int, int); - int (*enif_select)(ErlNifEnv*, ErlNifEvent, enum ErlNifSelectFlags, void*, Eterm); + enum ErlNifSelectReturn (*enif_select)(ErlNifEnv*, ErlNifEvent, enum ErlNifSelectFlags, void*, Eterm); int (*event)(ErlDrvPort, ErlDrvEvent, ErlDrvEventData); void (*check_io_as_interrupt)(void); void (*check_io_interrupt)(int); diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index c2429c3405..8795a3b24a 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -440,6 +440,13 @@ t_on_load(Config) when is_list(Config) -> -define(ERL_NIF_SELECT_WRITE, (1 bsl 1)). -define(ERL_NIF_SELECT_STOP, (1 bsl 2)). +-define(ERL_NIF_SELECT_ERROR, (1 bsl 0)). +-define(ERL_NIF_SELECT_STOP_CALLED, (1 bsl 1)). +-define(ERL_NIF_SELECT_STOP_SCHEDULED, (1 bsl 2)). +-define(ERL_NIF_SELECT_INVALID_EVENT, (1 bsl 3)). +-define(ERL_NIF_SELECT_FAILED, (1 bsl 4)). + + select(Config) when is_list(Config) -> ensure_lib_loaded(Config), @@ -470,7 +477,7 @@ select(Config) when is_list(Config) -> %% Close write and wait for EOF eagain = read_nif(R, 1), - 0 = select_nif(W,?ERL_NIF_SELECT_STOP,W,Ref), + check_stop_ret(select_nif(W,?ERL_NIF_SELECT_STOP,W,Ref)), timer:sleep(10), {1, {W_ptr,_}} = last_fd_stop_call(), true = is_closed_nif(W), @@ -479,7 +486,7 @@ select(Config) when is_list(Config) -> [{select, R, Ref, ready_input}] = flush(), eof = read_nif(R,1), - 0 = select_nif(R,?ERL_NIF_SELECT_STOP,R,Ref), + check_stop_ret(select_nif(R,?ERL_NIF_SELECT_STOP,R,Ref)), timer:sleep(10), {1, {R_ptr,_}} = last_fd_stop_call(), true = is_closed_nif(R), @@ -521,12 +528,12 @@ select_2(Config) -> done = receive_any(), [] = flush(), - 0 = select_nif(R,?ERL_NIF_SELECT_STOP,R,Ref1), + check_stop_ret(select_nif(R,?ERL_NIF_SELECT_STOP,R,Ref1)), timer:sleep(10), {1, {R_ptr,_}} = last_fd_stop_call(), true = is_closed_nif(R), - 0 = select_nif(W,?ERL_NIF_SELECT_STOP,W,Ref1), + ?ERL_NIF_SELECT_STOP_CALLED = select_nif(W,?ERL_NIF_SELECT_STOP,W,Ref1), timer:sleep(10), {1, {W_ptr,1}} = last_fd_stop_call(), true = is_closed_nif(W), @@ -538,7 +545,8 @@ select_3(Config) -> {_,_,2} = last_resource_dtor_call(), ok. - +check_stop_ret(?ERL_NIF_SELECT_STOP_CALLED) -> ok; +check_stop_ret(?ERL_NIF_SELECT_STOP_SCHEDULED) -> ok. write_full(W, C) -> write_full(W, C, <<>>). diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 813d19ae90..d2af081a22 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2042,7 +2042,7 @@ static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv enum ErlNifSelectFlags mode; void* obj; ERL_NIF_TERM ref; - int retval; + enum ErlNifSelectReturn retval; if (!get_fd(env, argv[0], &fdr) || !enif_get_uint(env, argv[1], &mode) @@ -2056,7 +2056,7 @@ static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv fdr->was_selected = 1; retval = enif_select(env, fdr->fd, mode, obj, ref); - return enif_make_int(env, retval); + return enif_make_int(env, (int)retval); } static ERL_NIF_TERM pipe_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -- cgit v1.2.3