aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2018-12-06 20:35:59 +0100
committerSverker Eriksson <[email protected]>2018-12-20 17:07:48 +0100
commit619514492966ba6b7c6e6fee807329c81c8bf7a8 (patch)
tree2ce1dd48ddbbea7e769bb530158508bda6d13c57 /erts/emulator/sys
parent04c70cafd0ba107e7644462bebcc2db05cc996e4 (diff)
downloadotp-619514492966ba6b7c6e6fee807329c81c8bf7a8.tar.gz
otp-619514492966ba6b7c6e6fee807329c81c8bf7a8.tar.bz2
otp-619514492966ba6b7c6e6fee807329c81c8bf7a8.zip
erts: Add ERL_NIF_SELECT_CUSTOM_MSG
Diffstat (limited to 'erts/emulator/sys')
-rw-r--r--erts/emulator/sys/common/erl_check_io.c183
-rw-r--r--erts/emulator/sys/common/erl_check_io.h3
2 files changed, 103 insertions, 83 deletions
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index b4609007c9..487b9cba40 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -591,6 +591,90 @@ abort_tasks(ErtsDrvEventState *state, int mode)
}
}
+static void prepare_select_msg(struct erts_nif_select_event* e,
+ enum ErlNifSelectFlags mode,
+ Eterm recipient,
+ ErtsResource* resource,
+ Eterm msg,
+ Eterm event_atom)
+{
+ ErtsMessage* mp;
+ Eterm* hp;
+ Eterm* hp_start;
+ Uint hsz;
+
+ if (is_not_nil(e->pid)) {
+ ASSERT(e->mp);
+ erts_cleanup_messages(e->mp);
+ }
+
+ if (mode & ERL_NIF_SELECT_CUSTOM_MSG) {
+ hsz = size_object(msg);
+ mp = erts_alloc_message(hsz, &hp);
+ hp_start = hp;
+ ERL_MESSAGE_TERM(mp) = copy_struct(msg, hsz, &hp, &mp->hfrag.off_heap);
+ }
+ else {
+ ErtsBinary* bin;
+ Eterm resource_term, ref_term, tuple;
+
+ /* {select, Resource, Ref, EventAtom} */
+ hsz = 5 + ERTS_MAGIC_REF_THING_SIZE;
+ if (is_internal_ref(msg))
+ hsz += ERTS_REF_THING_SIZE;
+ else
+ ASSERT(is_immed(msg));
+
+ mp = erts_alloc_message(hsz, &hp);
+ hp_start = hp;
+
+ bin = ERTS_MAGIC_BIN_FROM_UNALIGNED_DATA(resource);
+ resource_term = erts_mk_magic_ref(&hp, &mp->hfrag.off_heap, &bin->binary);
+ if (is_internal_ref(msg)) {
+ Uint32* refn = internal_ref_numbers(msg);
+ write_ref_thing(hp, refn[0], refn[1], refn[2]);
+ ref_term = make_internal_ref(hp);
+ hp += ERTS_REF_THING_SIZE;
+ }
+ else {
+ ASSERT(is_immed(msg));
+ ref_term = msg;
+ }
+ tuple = TUPLE4(hp, am_select, resource_term, ref_term, event_atom);
+ hp += 5;
+ ERL_MESSAGE_TERM(mp) = tuple;
+ }
+ ASSERT(hp == hp_start + hsz); (void)hp_start;
+
+ ASSERT(is_not_nil(recipient));
+ e->pid = recipient;
+ e->mp = mp;
+}
+
+static ERTS_INLINE void send_select_msg(struct erts_nif_select_event* e)
+{
+ Process* rp = erts_proc_lookup(e->pid);
+
+ ASSERT(is_internal_pid(e->pid));
+ if (!rp) {
+ erts_cleanup_messages(e->mp);
+ return;
+ }
+
+ erts_queue_message(rp, 0, e->mp, ERL_MESSAGE_TERM(e->mp), am_system);
+}
+
+static void clear_select_event(struct erts_nif_select_event* e)
+{
+ if (is_not_nil(e->pid)) {
+ /* Discard unsent message */
+ ASSERT(e->mp);
+ erts_cleanup_messages(e->mp);
+ e->mp = NULL;
+ e->pid = NIL;
+ }
+}
+
static void
deselect(ErtsDrvEventState *state, int mode)
{
@@ -621,8 +705,8 @@ deselect(ErtsDrvEventState *state, int mode)
erts_io_control(state, ERTS_POLL_OP_DEL, 0);
switch (state->type) {
case ERTS_EV_TYPE_NIF:
- state->driver.nif->in.pid = NIL;
- state->driver.nif->out.pid = NIL;
+ clear_select_event(&state->driver.nif->in);
+ clear_select_event(&state->driver.nif->out);
enif_release_resource(state->driver.stop.resource->data);
state->driver.stop.resource = NULL;
break;
@@ -948,7 +1032,7 @@ enif_select(ErlNifEnv* env,
enum ErlNifSelectFlags mode,
void* obj,
const ErlNifPid* pid,
- Eterm ref)
+ Eterm msg)
{
int on;
ErtsResource* resource = DATA_TO_RESOURCE(obj);
@@ -966,7 +1050,7 @@ enif_select(ErlNifEnv* env,
#ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS
if (!grow_drv_ev_state(fd)) {
- if (fd > 0) nif_select_large_fd_error(fd, mode, resource, ref);
+ if (fd > 0) nif_select_large_fd_error(fd, mode, resource, msg);
return INT_MIN | ERL_NIF_SELECT_INVALID_EVENT;
}
#endif
@@ -1012,21 +1096,21 @@ enif_select(ErlNifEnv* env,
* Changing process and/or ref is ok (I think?).
*/
if (state->driver.stop.resource != resource)
- nif_select_steal(state, ERL_DRV_READ | ERL_DRV_WRITE, resource, ref);
+ nif_select_steal(state, ERL_DRV_READ | ERL_DRV_WRITE, resource, msg);
break;
case ERTS_EV_TYPE_DRV_SEL:
- nif_select_steal(state, mode, resource, ref);
+ nif_select_steal(state, mode, resource, msg);
break;
case ERTS_EV_TYPE_STOP_USE: {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- print_nif_select_op(dsbufp, fd, mode, resource, ref);
+ print_nif_select_op(dsbufp, fd, mode, resource, msg);
steal_pending_stop_use(dsbufp, ERTS_INVALID_ERL_DRV_PORT, state, mode, on);
ASSERT(state->type == ERTS_EV_TYPE_NONE);
break;
}
case ERTS_EV_TYPE_STOP_NIF: {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- print_nif_select_op(dsbufp, fd, mode, resource, ref);
+ print_nif_select_op(dsbufp, fd, mode, resource, msg);
steal_pending_stop_nif(dsbufp, resource, state, mode, on);
if (state->type == ERTS_EV_TYPE_STOP_NIF) {
ret = ERL_NIF_SELECT_STOP_SCHEDULED; /* ?? */
@@ -1082,7 +1166,6 @@ enif_select(ErlNifEnv* env,
if (on) {
const Eterm recipient = pid ? pid->pid : env->proc->common.id;
- Uint32* refn;
if (!state->driver.nif)
state->driver.nif = alloc_nif_select_data();
if (state->type == ERTS_EV_TYPE_NONE) {
@@ -1093,28 +1176,12 @@ enif_select(ErlNifEnv* env,
ASSERT(state->type == ERTS_EV_TYPE_NIF);
ASSERT(state->driver.stop.resource == resource);
if (mode & ERL_DRV_READ) {
- state->driver.nif->in.pid = recipient;
- if (is_immed(ref)) {
- state->driver.nif->in.immed = ref;
- } else {
- ASSERT(is_internal_ref(ref));
- refn = internal_ref_numbers(ref);
- state->driver.nif->in.immed = THE_NON_VALUE;
- sys_memcpy(state->driver.nif->in.refn, refn,
- sizeof(state->driver.nif->in.refn));
- }
+ prepare_select_msg(&state->driver.nif->in, mode, recipient,
+ resource, msg, am_ready_input);
}
if (mode & ERL_DRV_WRITE) {
- state->driver.nif->out.pid = recipient;
- if (is_immed(ref)) {
- state->driver.nif->out.immed = ref;
- } else {
- ASSERT(is_internal_ref(ref));
- refn = internal_ref_numbers(ref);
- state->driver.nif->out.immed = THE_NON_VALUE;
- sys_memcpy(state->driver.nif->out.refn, refn,
- sizeof(state->driver.nif->out.refn));
- }
+ prepare_select_msg(&state->driver.nif->out, mode, recipient,
+ resource, msg, am_ready_output);
}
ret = 0;
}
@@ -1123,12 +1190,12 @@ enif_select(ErlNifEnv* env,
if (state->type == ERTS_EV_TYPE_NIF) {
if (mode & ERL_NIF_SELECT_READ
&& is_not_nil(state->driver.nif->in.pid)) {
- state->driver.nif->in.pid = NIL;
+ clear_select_event(&state->driver.nif->in);
ret |= ERL_NIF_SELECT_READ_CANCELLED;
}
if (mode & ERL_NIF_SELECT_WRITE
&& is_not_nil(state->driver.nif->out.pid)) {
- state->driver.nif->out.pid = NIL;
+ clear_select_event(&state->driver.nif->out);
ret |= ERL_NIF_SELECT_WRITE_CANCELLED;
}
}
@@ -1545,53 +1612,6 @@ oready(Eterm id, ErtsDrvEventState *state)
}
}
-static ERTS_INLINE void
-send_event_tuple(struct erts_nif_select_event* e, ErtsResource* resource,
- Eterm event_atom)
-{
- Process* rp = erts_proc_lookup(e->pid);
- ErtsProcLocks rp_locks = 0;
- ErtsMessage* mp;
- ErlOffHeap* ohp;
- ErtsBinary* bin;
- Eterm* hp;
- Uint hsz;
- Eterm resource_term, ref_term, tuple;
-
- if (!rp) {
- return;
- }
-
- bin = ERTS_MAGIC_BIN_FROM_UNALIGNED_DATA(resource);
-
- /* {select, Resource, Ref, EventAtom} */
- if (is_value(e->immed)) {
- hsz = 5 + ERTS_MAGIC_REF_THING_SIZE;
- }
- else {
- hsz = 5 + ERTS_MAGIC_REF_THING_SIZE + ERTS_REF_THING_SIZE;
- }
-
- mp = erts_alloc_message_heap(rp, &rp_locks, hsz, &hp, &ohp);
-
- resource_term = erts_mk_magic_ref(&hp, ohp, &bin->binary);
- if (is_value(e->immed)) {
- ASSERT(is_immed(e->immed));
- ref_term = e->immed;
- }
- else {
- write_ref_thing(hp, e->refn[0], e->refn[1], e->refn[2]);
- ref_term = make_internal_ref(hp);
- hp += ERTS_REF_THING_SIZE;
- }
- tuple = TUPLE4(hp, am_select, resource_term, ref_term, event_atom);
-
- erts_queue_message(rp, rp_locks, mp, tuple, am_system);
-
- if (rp_locks)
- erts_proc_unlock(rp, rp_locks);
-}
-
static void bad_fd_in_pollset(ErtsDrvEventState *, Eterm inport, Eterm outport);
void
@@ -1765,7 +1785,6 @@ erts_check_io(ErtsPollThread *psi, ErtsMonotonicTime timeout_time)
case ERTS_EV_TYPE_NIF: { /* Requested via enif_select()... */
struct erts_nif_select_event in = {NIL};
struct erts_nif_select_event out = {NIL};
- ErtsResource* resource = NULL;
if (revents & (ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT)) {
if (revents & ERTS_POLL_EV_OUT) {
@@ -1773,6 +1792,7 @@ erts_check_io(ErtsPollThread *psi, ErtsMonotonicTime timeout_time)
out = state->driver.nif->out;
resource = state->driver.stop.resource;
state->driver.nif->out.pid = NIL;
+ state->driver.nif->out.mp = NULL;
}
}
if (revents & ERTS_POLL_EV_IN) {
@@ -1780,6 +1800,7 @@ erts_check_io(ErtsPollThread *psi, ErtsMonotonicTime timeout_time)
in = state->driver.nif->in;
resource = state->driver.stop.resource;
state->driver.nif->in.pid = NIL;
+ state->driver.nif->in.mp = NULL;
}
}
state->events &= ~revents;
@@ -1792,10 +1813,10 @@ erts_check_io(ErtsPollThread *psi, ErtsMonotonicTime timeout_time)
erts_mtx_unlock(fd_mtx(fd));
if (is_not_nil(in.pid)) {
- send_event_tuple(&in, resource, am_ready_input);
+ send_select_msg(&in);
}
if (is_not_nil(out.pid)) {
- send_event_tuple(&out, resource, am_ready_output);
+ send_select_msg(&out);
}
continue;
}
diff --git a/erts/emulator/sys/common/erl_check_io.h b/erts/emulator/sys/common/erl_check_io.h
index 31182be5ec..0f3fc4f7a2 100644
--- a/erts/emulator/sys/common/erl_check_io.h
+++ b/erts/emulator/sys/common/erl_check_io.h
@@ -138,8 +138,7 @@ typedef struct {
struct erts_nif_select_event {
Eterm pid;
- Eterm immed;
- Uint32 refn[ERTS_REF_NUMBERS];
+ ErtsMessage *mp;
};
typedef struct {