aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/erl_db_hash.c1
-rw-r--r--erts/emulator/nifs/common/net_nif.c3
-rw-r--r--erts/emulator/nifs/common/socket_nif.c142
-rw-r--r--erts/emulator/test/socket_SUITE.erl17
-rw-r--r--erts/emulator/test/socket_test_evaluator.erl101
5 files changed, 148 insertions, 116 deletions
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index fac4703620..f225730029 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -2214,6 +2214,7 @@ static int db_select_replace_hash(Process *p, DbTable *tbl, Eterm tid,
ctx.tb = &tbl->hash;
ctx.tid = tid;
ctx.prev_continuation_tptr = NULL;
+ ctx.safety = safety;
return match_traverse(
&ctx,
diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/net_nif.c
index 6c91bd74bd..252aa3c835 100644
--- a/erts/emulator/nifs/common/net_nif.c
+++ b/erts/emulator/nifs/common/net_nif.c
@@ -1363,7 +1363,7 @@ ERL_NIF_TERM encode_address_infos(ErlNifEnv* env,
NDBG( ("NET", "encode_address_infos -> len: %d\r\n", len) );
if (len > 0) {
- ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); // LEAK?
+ ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM));
unsigned int i = 0;
struct addrinfo* p = addrInfo;
@@ -1374,6 +1374,7 @@ ERL_NIF_TERM encode_address_infos(ErlNifEnv* env,
}
result = MKLA(env, array, len);
+ FREE(array);
} else {
result = MKEL(env);
}
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index bb3df85ea4..052c585032 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -2309,12 +2309,14 @@ static void dec_socket(int domain, int type, int protocol);
ERL_NIF_TERM sockRef);
ACTIVATE_NEXT_FUNCS_DEFS
#undef ACTIVATE_NEXT_FUNC_DEF
-
+
+/*
static BOOLEAN_T activate_next(ErlNifEnv* env,
SocketDescriptor* descP,
SocketRequestor* reqP,
SocketRequestQueue* q,
ERL_NIF_TERM sockRef);
+*/
/* *** acceptor_search4pid | writer_search4pid | reader_search4pid ***
* *** acceptor_push | writer_push | reader_push ***
@@ -17047,93 +17049,81 @@ int esock_select_cancel(ErlNifEnv* env,
* *** activate_next_writer ***
* *** activate_next_reader ***
*
- * This functions pops the writer queue and then selects until it
- * manages to successfully activate a writer or the queue is empty.
+ * This functions pops the requestors queue and then selects until it
+ * manages to successfully activate a requestor or the queue is empty.
+ * Return value indicates if a new requestor was activated or not.
*/
-#define ACTIVATE_NEXT_FUNCS \
- ACTIVATE_NEXT_FUNC_DECL(acceptor, currentAcceptor, acceptorsQ) \
- ACTIVATE_NEXT_FUNC_DECL(writer, currentWriter, writersQ) \
- ACTIVATE_NEXT_FUNC_DECL(reader, currentReader, readersQ)
+#define ACTIVATE_NEXT_FUNCS \
+ ACTIVATE_NEXT_FUNC_DECL(acceptor, read, currentAcceptor, acceptorsQ) \
+ ACTIVATE_NEXT_FUNC_DECL(writer, write, currentWriter, writersQ) \
+ ACTIVATE_NEXT_FUNC_DECL(reader, read, currentReader, readersQ)
-#define ACTIVATE_NEXT_FUNC_DECL(F, R, Q) \
+#define ACTIVATE_NEXT_FUNC_DECL(F, S, R, Q) \
static \
BOOLEAN_T activate_next_##F(ErlNifEnv* env, \
SocketDescriptor* descP, \
ERL_NIF_TERM sockRef) \
{ \
- return activate_next(env, descP, \
- &descP->R, &descP->Q, \
- sockRef); \
+ BOOLEAN_T popped, activated; \
+ int sres; \
+ SocketRequestor* reqP = &descP->R; \
+ SocketRequestQueue* q = &descP->Q; \
+ \
+ popped = FALSE; \
+ do { \
+ \
+ if (requestor_pop(q, reqP)) { \
+ \
+ /* There was another one */ \
+ \
+ SSDBG( descP, \
+ ("SOCKET", \
+ "activate_next_" #F " -> new (active) requestor: " \
+ "\r\n pid: %T" \
+ "\r\n ref: %T" \
+ "\r\n", reqP->pid, reqP->ref) ); \
+ \
+ if ((sres = esock_select_##S(env, descP->sock, descP, \
+ &reqP->pid, reqP->ref)) < 0) { \
+ /* We need to inform this process, reqP->pid, */ \
+ /* that we failed to select, so we don't leave */ \
+ /* it hanging. */ \
+ /* => send abort */ \
+ \
+ esock_send_abort_msg(env, sockRef, reqP->ref, \
+ sres, &reqP->pid); \
+ \
+ } else { \
+ \
+ /* Success: New requestor selected */ \
+ popped = TRUE; \
+ activated = FALSE; \
+ \
+ } \
+ \
+ } else { \
+ \
+ SSDBG( descP, \
+ ("SOCKET", \
+ "activate_next_" #F " -> no more requestors\r\n") ); \
+ \
+ popped = TRUE; \
+ activated = FALSE; \
+ } \
+ \
+ } while (!popped); \
+ \
+ SSDBG( descP, \
+ ("SOCKET", "activate_next_" #F " -> " \
+ "done with %s\r\n", B2S(activated)) ); \
+ \
+ return activated; \
}
ACTIVATE_NEXT_FUNCS
#undef ACTIVATE_NEXT_FUNC_DECL
-/* *** activate_next ***
- *
- * This functions pops the requestor queue and then selects until it
- * manages to successfully activate a new requestor or the queue is empty.
- * Return value indicates if a new requestor was activated or not.
- */
-
-static
-BOOLEAN_T activate_next(ErlNifEnv* env,
- SocketDescriptor* descP,
- SocketRequestor* reqP,
- SocketRequestQueue* q,
- ERL_NIF_TERM sockRef)
-{
- BOOLEAN_T popped, activated;
- int sres;
-
- popped = FALSE;
- do {
-
- if (requestor_pop(q, reqP)) {
-
- /* There was another one */
-
- SSDBG( descP,
- ("SOCKET", "activate_next -> new (active) requestor: "
- "\r\n pid: %T"
- "\r\n ref: %T"
- "\r\n", reqP->pid, reqP->ref) );
-
- if ((sres = esock_select_read(env, descP->sock, descP,
- &reqP->pid, reqP->ref)) < 0) {
- /* We need to inform this process, reqP->pid, that we
- * failed to select, so we don't leave it hanging.
- * => send abort
- */
-
- esock_send_abort_msg(env, sockRef, reqP->ref, sres, &reqP->pid);
-
- } else {
-
- /* Success: New requestor selected */
- popped = TRUE;
- activated = FALSE;
-
- }
-
- } else {
-
- SSDBG( descP,
- ("SOCKET", "send_activate_next -> no more requestors\r\n") );
-
- popped = TRUE;
- activated = FALSE;
- }
-
- } while (!popped);
-
- SSDBG( descP,
- ("SOCKET", "activate_next -> "
- "done with %s\r\n", B2S(activated)) );
-
- return activated;
-}
/* ----------------------------------------------------------------------
@@ -17730,7 +17720,7 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
if (COMPARE_PIDS(&descP->closerPid, &descP->currentAcceptor.pid) != 0) {
SSDBG( descP, ("SOCKET", "socket_stop -> "
"send abort message to current acceptor %T\r\n",
- descP->currentWriter.pid) );
+ descP->currentAcceptor.pid) );
if (esock_send_abort_msg(env,
sockRef,
descP->currentAcceptor.ref,
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index aec280485c..8a32efcd85 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -4541,7 +4541,7 @@ api_to_recv_tcp4(_Config) when is_list(_Config) ->
Recv = fun(Sock, To) -> socket:recv(Sock, 0, To) end,
InitState = #{domain => inet,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_tcp(InitState)
end).
@@ -4566,7 +4566,7 @@ api_to_recv_tcp6(_Config) when is_list(_Config) ->
end,
InitState = #{domain => inet6,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_tcp(InitState);
false ->
skip("ipv6 not supported")
@@ -4900,7 +4900,7 @@ api_to_recvfrom_udp4(_Config) when is_list(_Config) ->
Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end,
InitState = #{domain => inet,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_udp(InitState)
end).
@@ -4921,7 +4921,7 @@ api_to_recvfrom_udp6(_Config) when is_list(_Config) ->
Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end,
InitState = #{domain => inet6,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_udp(InitState)
end).
@@ -4984,6 +4984,7 @@ api_to_receive_udp(InitState) ->
%% *** Termination ***
#{desc => "close socket",
cmd => fun(#{sock := Sock} = _State) ->
+ socket:setopt(Sock, otp, debug, true),
sock_close(Sock),
ok
end},
@@ -5015,7 +5016,7 @@ api_to_recvmsg_udp4(_Config) when is_list(_Config) ->
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_udp(InitState)
end).
@@ -5036,7 +5037,7 @@ api_to_recvmsg_udp6(_Config) when is_list(_Config) ->
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_udp(InitState)
end).
@@ -5056,7 +5057,7 @@ api_to_recvmsg_tcp4(_Config) when is_list(_Config) ->
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_tcp(InitState)
end).
@@ -5077,7 +5078,7 @@ api_to_recvmsg_tcp6(_Config) when is_list(_Config) ->
Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end,
InitState = #{domain => inet6,
recv => Recv,
- timeout => 5000},
+ timeout => 2000},
ok = api_to_receive_tcp(InitState)
end).
diff --git a/erts/emulator/test/socket_test_evaluator.erl b/erts/emulator/test/socket_test_evaluator.erl
index bd86b3b92e..c5748ac21b 100644
--- a/erts/emulator/test/socket_test_evaluator.erl
+++ b/erts/emulator/test/socket_test_evaluator.erl
@@ -104,8 +104,9 @@ start(Name, Seq, InitState)
erlang:error({already_used, parent});
error ->
InitState2 = InitState#{parent => self()},
- {Pid, MRef} = erlang:spawn_monitor(
- fun() -> init(Name, Seq, InitState2) end),
+ Pid = erlang:spawn_link(
+ fun() -> init(Name, Seq, InitState2) end),
+ MRef = erlang:monitor(process, Pid),
#ev{name = Name, pid = Pid, mref = MRef}
end.
@@ -149,55 +150,93 @@ loop(ID, [#{desc := Desc,
Evs :: [ev()].
await_finish(Evs) ->
- await_finish(Evs, []).
+ await_finish(Evs, [], []).
-await_finish([], []) ->
+await_finish([], _, []) ->
ok;
-await_finish([], Fails) ->
+await_finish([], _OK, Fails) ->
?SEV_EPRINT("Fails: "
"~n ~p", [Fails]),
Fails;
-await_finish(Evs, Fails) ->
+await_finish(Evs, OK, Fails) ->
receive
%% Successfull termination of evaluator
{'DOWN', _MRef, process, Pid, normal} ->
- case lists:keysearch(Pid, #ev.pid, Evs) of
- {value, #ev{name = Name}} ->
- iprint("evaluator '~s' (~p) success", [Name, Pid]),
- NewEvs = lists:keydelete(Pid, #ev.pid, Evs),
- await_finish(NewEvs, Fails);
- false ->
- iprint("unknown process ~p died (normal)", [Pid]),
- await_finish(Evs, Fails)
- end;
+ {Evs2, OK2, Fails2} = await_finish_normal(Pid, Evs, OK, Fails),
+ await_finish(Evs2, OK2, Fails2);
+ {'EXIT', Pid, normal} ->
+ {Evs2, OK2, Fails2} = await_finish_normal(Pid, Evs, OK, Fails),
+ await_finish(Evs2, OK2, Fails2);
%% The evaluator can skip the teat case:
{'DOWN', _MRef, process, Pid, {skip, Reason}} ->
- case lists:keysearch(Pid, #ev.pid, Evs) of
- {value, #ev{name = Name}} ->
- iprint("evaluator '~s' (~p) issued SKIP: "
- "~n ~p", [Name, Pid, Reason]);
+ await_finish_skip(Pid, Reason, Evs, OK);
+ {'EXIT', Pid, {skip, Reason}} ->
+ await_finish_skip(Pid, Reason, Evs, OK);
+
+ %% Evaluator failed
+ {'DOWN', _MRef, process, Pid, Reason} ->
+ {Evs2, OK2, Fails2} = await_finish_fail(Pid, Reason, Evs, OK, Fails),
+ await_finish(Evs2, OK2, Fails2);
+ {'EXIT', Pid, Reason} ->
+ {Evs2, OK2, Fails2} = await_finish_fail(Pid, Reason, Evs, OK, Fails),
+ await_finish(Evs2, OK2, Fails2)
+ end.
+
+
+await_finish_normal(Pid, Evs, OK, Fails) ->
+ case lists:keysearch(Pid, #ev.pid, Evs) of
+ {value, #ev{name = Name}} ->
+ iprint("evaluator '~s' (~p) success", [Name, Pid]),
+ NewEvs = lists:keydelete(Pid, #ev.pid, Evs),
+ {NewEvs, [Pid|OK], Fails};
+ false ->
+ case lists:member(Pid, OK) of
+ true ->
+ ok;
+ false ->
+ iprint("unknown process ~p died (normal)", [Pid]),
+ ok
+ end,
+ {Evs, OK, Fails}
+ end.
+
+await_finish_skip(Pid, Reason, Evs, OK) ->
+ case lists:keysearch(Pid, #ev.pid, Evs) of
+ {value, #ev{name = Name}} ->
+ iprint("evaluator '~s' (~p) issued SKIP: "
+ "~n ~p", [Name, Pid, Reason]);
+ false ->
+ case lists:member(Pid, OK) of
+ true ->
+ ok;
false ->
iprint("unknown process ~p issued SKIP: "
"~n ~p", [Pid, Reason])
- end,
- ?LIB:skip(Reason);
+ end
+ end,
+ ?LIB:skip(Reason).
- %% Evaluator failed
- {'DOWN', _MRef, process, Pid, Reason} ->
- case lists:keysearch(Pid, #ev.pid, Evs) of
- {value, #ev{name = Name}} ->
- iprint("evaluator '~s' (~p) failed", [Name, Pid]),
- NewEvs = lists:keydelete(Pid, #ev.pid, Evs),
- await_finish(NewEvs, [{Pid, Reason}|Fails]);
+
+await_finish_fail(Pid, Reason, Evs, OK, Fails) ->
+ case lists:keysearch(Pid, #ev.pid, Evs) of
+ {value, #ev{name = Name}} ->
+ iprint("evaluator '~s' (~p) failed", [Name, Pid]),
+ NewEvs = lists:keydelete(Pid, #ev.pid, Evs),
+ {NewEvs, OK, [{Pid, Reason}|Fails]};
+ false ->
+ case lists:member(Pid, OK) of
+ true ->
+ ok;
false ->
iprint("unknown process ~p died: "
- "~n ~p", [Pid, Reason]),
- await_finish(Evs, Fails)
- end
+ "~n ~p", [Pid, Reason])
+ end,
+ {Evs, OK, Fails}
end.
+
%% ============================================================================
-spec announce_start(To) -> ok when