diff options
-rw-r--r-- | erts/emulator/beam/erl_process.c | 2 | ||||
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 7 | ||||
-rw-r--r-- | erts/etc/win32/nsis/erlang20.nsi | 8 | ||||
-rw-r--r-- | erts/etc/win32/wsl_tools/SetupWSLcross.bat | 10 | ||||
-rw-r--r-- | lib/compiler/src/beam_ssa_bool.erl | 8 | ||||
-rw-r--r-- | lib/compiler/test/guard_SUITE.erl | 25 | ||||
-rw-r--r-- | lib/kernel/test/gen_sctp_SUITE.erl | 152 | ||||
-rw-r--r-- | lib/kernel/test/gen_udp_SUITE.erl | 84 |
8 files changed, 265 insertions, 31 deletions
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 0a1e274396..6c83693df8 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -11188,7 +11188,7 @@ erts_set_gc_state(Process *c_p, int enable) first1 = dgc_tsk_qs->q[prio]; last1 = first1->prev; first2 = stsk_qs->q[prio]; - last2 = first1->prev; + last2 = first2->prev; last1->next = first2; first2->prev = last1; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 42a5936513..6797b5d32f 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -12254,14 +12254,15 @@ static void packet_inet_stop(ErlDrvData e) into "udp_descriptor*" or "inet_descriptor*": */ udp_descriptor * udesc = (udp_descriptor*) e; - inet_descriptor* descr = INETP(udesc); + inet_descriptor* desc = INETP(udesc); if (udesc->i_buf != NULL) { release_buffer(udesc->i_buf); udesc->i_buf = NULL; } - ASSERT(NO_SUBSCRIBERS(&(descr->empty_out_q_subs))); - inet_stop(descr); + ASSERT(NO_SUBSCRIBERS(&(desc->empty_out_q_subs))); + async_error_am_all(desc, am_closed); + inet_stop(desc); } static int packet_error(udp_descriptor* udesc, int err) diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi index 63e63a06cb..950f3ec0a3 100644 --- a/erts/etc/win32/nsis/erlang20.nsi +++ b/erts/etc/win32/nsis/erlang20.nsi @@ -52,7 +52,7 @@ Var STARTMENU_FOLDER !define MY_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
;General
- OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_VERSION}.exe"
+ OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_RELEASE_VERSION}.exe"
;Folder selection page
!if ${WINTYPE} == "win64"
@@ -68,7 +68,7 @@ Var STARTMENU_FOLDER !if ${WINTYPE} == "win64"
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (x64)"
!else
- !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION}"
+ !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (i386)"
!endif
;--------------------------------
@@ -201,7 +201,7 @@ done_startmenu: WriteRegStr HKLM \
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
- "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})"
WriteRegStr HKLM \
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
"UninstallString" "$INSTDIR\Uninstall.exe"
@@ -225,7 +225,7 @@ done_startmenu: WriteRegStr HKCU \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
- "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})"
WriteRegStr HKCU \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
"UninstallString" "$INSTDIR\Uninstall.exe"
diff --git a/erts/etc/win32/wsl_tools/SetupWSLcross.bat b/erts/etc/win32/wsl_tools/SetupWSLcross.bat index 860a7d5e60..5de4cd8bb1 100644 --- a/erts/etc/win32/wsl_tools/SetupWSLcross.bat +++ b/erts/etc/win32/wsl_tools/SetupWSLcross.bat @@ -8,11 +8,6 @@ IF "%~1"=="x64" GOTO search GOTO badarg :search -IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat". ( - call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %~1 > nul - goto continue -) - IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat". ( call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" %~1 > nul goto continue @@ -33,6 +28,11 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat". goto continue ) +IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat". ( + call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %~1 > nul + goto continue +) + GOTO no_vcvars :continue diff --git a/lib/compiler/src/beam_ssa_bool.erl b/lib/compiler/src/beam_ssa_bool.erl index 2a3f093f14..5b81ca2be1 100644 --- a/lib/compiler/src/beam_ssa_bool.erl +++ b/lib/compiler/src/beam_ssa_bool.erl @@ -922,9 +922,11 @@ opt_digraph_instr(#b_set{dst=Dst}=I, G0, St) -> %% Rewriting 'xor' is not practical. Fortunately, %% 'xor' is almost never used in practice. not_possible(); - #b_set{op={bif,'not'},args=[#b_var{}=Bool]} -> - G = convert_to_br_node(I, Fail, G1, St), - redirect_test(Bool, {fail,Succ}, G, St); + #b_set{op={bif,'not'}} -> + %% This is suprisingly rare. The previous attempt to + %% optimize it was broken, which wasn't noticed because + %% very few test cases triggered this code. + not_possible(); #b_set{op=phi,dst=Bool} -> Vtx = get_vertex(Bool, St), G2 = del_out_edges(Vtx, G1), diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index 178e74a3e8..2c935c1c57 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -2301,6 +2301,7 @@ beam_bool_SUITE(_Config) -> recv_semi(), andalso_repeated_var(), erl1253(), + erl1246(), ok. before_and_inside_if() -> @@ -2598,6 +2599,30 @@ andalso_repeated_var() -> andalso_repeated_var(B) when B andalso B -> ok; andalso_repeated_var(_) -> error. +-record(erl1246, {tran_stat = 0}). + +erl1246() -> + false = erl1246(#erl1246{tran_stat = 0}, #{cid => 1131}), + false = erl1246(#erl1246{tran_stat = 12}, #{cid => 1131}), + false = erl1246(#erl1246{tran_stat = 12}, #{cid => 9502}), + true = erl1246(#erl1246{tran_stat = 0}, #{cid => 9502}), + ok. + +erl1246(Rec, #{cid := CollID}) -> + {GiftCollID, _} = erl1246_conf(gift_coll), + IsTranStat = Rec#erl1246.tran_stat =:= erl1246_conf(transform_id), + if + %% Optimization of 'not' in a guard was broken. + CollID =:= GiftCollID andalso not IsTranStat -> + true; + true -> + false + end. + +erl1246_conf(gift_coll) -> {9502, {112, 45}}; +erl1246_conf(transform_id) -> 12; +erl1246_conf(_) -> undefined. + erl1253() -> ok = erl1253_orelse_false(a, a, any), ok = erl1253_orelse_false(a, a, true), diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 65183d83cc..55109a5178 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -41,7 +41,8 @@ peeloff_active_once/1, peeloff_active_true/1, peeloff_active_n/1, buffers/1, names_unihoming_ipv4/1, names_unihoming_ipv6/1, - names_multihoming_ipv4/1, names_multihoming_ipv6/1]). + names_multihoming_ipv4/1, names_multihoming_ipv6/1, + recv_close/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -56,10 +57,25 @@ all() -> {group,G}]. groups() -> - [{smoke,[],[basic,basic_stream]}, - {old_solaris,[],[skip_old_solaris]}, - {extensive,[], - [api_open_close, api_listen, api_connect_init, + [ + {smoke, [], smoke_cases()}, + {old_solaris, [], old_solaris_cases()}, + {extensive, [], extensive_cases()} + ]. + +smoke_cases() -> + [ + basic, + basic_stream + ]. + +old_solaris_cases() -> + [ + skip_old_solaris + ]. + +extensive_cases() -> + [api_open_close, api_listen, api_connect_init, api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, open_multihoming_ipv4_socket, open_unihoming_ipv6_socket, @@ -68,7 +84,8 @@ groups() -> xfer_stream_min, peeloff_active_once, peeloff_active_true, peeloff_active_n, buffers, names_unihoming_ipv4, names_unihoming_ipv6, - names_multihoming_ipv4, names_multihoming_ipv6]}]. + names_multihoming_ipv4, names_multihoming_ipv6, + recv_close]. init_per_suite(_Config) -> case gen_sctp:open() of @@ -1511,6 +1528,111 @@ recv_comm_up_eventually(S) -> recv_comm_up_eventually(S) end. + +%% +recv_close(Config) when is_list(Config) -> + p("create server socket (and listen)"), + {ok, S} = gen_sctp:open(), + gen_sctp:listen(S, true), + {ok, SPort} = inet:port(S), + + p("create client socket (and connect)"), + {ok, C} = gen_sctp:open(), + {ok, _} = gen_sctp:connect(C, localhost, SPort, []), + + TC = self(), + RECV = fun() -> + p("try setup recv(s)"), + ok = recv_close_setup_recv(S), + p("announce ready"), + TC ! {self(), ready}, + p("try data recv"), + Res = gen_sctp:recv(S), + p("recv res: " + "~n ~p", [Res]), + exit(Res) + end, + p("spawn reader - then await reader ready"), + {Pid, MRef} = spawn_monitor(RECV), + receive + {'DOWN', MRef, process, Pid, PreReason} -> + %% Make sure it does not die for some other reason... + p("unexpected reader termination:" + "~n ~p", [PreReason]), + (catch gen_sctp:close(S)), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected pre close from reader (~p): ~p", + [Pid, PreReason]); + {Pid, ready} -> + p("reader ready"), + ok + after 30000 -> % Just in case... + %% This is **extreme**, but there is no way to know + %% how long it will take to iterate through all the + %% addresses of a host... + p("reader ready timeout"), + (catch gen_sctp:close(S)), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected pre close timeout (~p)", [Pid]) + end, + + p("\"ensure\" reader reading..."), + receive + Any -> + p("Received unexpected message: " + "~n ~p", [Any]), + (catch gen_sctp:close(S)), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected message: ~p", [Any]) + after 5000 -> + ok + end, + + p("close server socket"), + ok = gen_sctp:close(S), + p("await reader termination"), + receive + {'DOWN', MRef, process, Pid, {error, closed}} -> + p("expected reader termination result"), + (catch gen_sctp:close(C)), + ok; + {'DOWN', MRef, process, Pid, PostReason} -> + p("unexpected reader termination: " + "~n ~p", [PostReason]), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected post close from reader (~p): ~p", + [Pid, PostReason]) + after 5000 -> + p("unexpected reader termination timeout"), + demonitor(MRef, [flush]), + (catch gen_sctp:close(C)), + exit(Pid, kill), + ?line ct:fail("Reader (~p) termination timeout", [Pid]) + end, + p("close client socket"), + (catch gen_sctp:close(C)), + p("done"), + ok. + + +recv_close_setup_recv(S) -> + recv_close_setup_recv(S, 1). + +recv_close_setup_recv(S, N) -> + p("try setup recv ~w", [N]), + case gen_sctp:recv(S, 5000) of + {ok, {Addr, + Port, + _AncData, + Data}} when is_tuple(Addr) andalso is_integer(Port) -> + p("setup recv ~w: " + "~n ~p", [N, Data]), + recv_close_setup_recv(S, N+1); + {error, timeout} -> + ok + end. + + %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% socket gen_server ultra light @@ -1745,3 +1867,21 @@ match_unless_solaris(A, B) -> timestamp() -> erlang:monotonic_time(). + +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp({_N1, _N2, N3} = TS) -> + {_Date, Time} = calendar:now_to_local_time(TS), + {Hour, Min, Sec} = Time, + FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.3.0w", + [Hour, Min, Sec, N3 div 1000]), + lists:flatten(FormatTS). + +p(F) -> + p(F, []). + +p(F, A) -> + io:format("~s ~p " ++ F ++ "~n", [formated_timestamp(), self() | A]). + + diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index 2720d3cc77..7ec553ec51 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -40,25 +40,45 @@ recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1, sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1, local_basic/1, local_unbound/1, - local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]). + local_fdopen/1, local_fdopen_unbound/1, local_abstract/1, + recv_close/1]). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,1}}]. all() -> - [send_to_closed, buffer_size, binary_passive_recv, max_buffer_size, - bad_address, read_packets, recv_poll_after_active_once, - open_fd, connect, - implicit_inet6, active_n, + [ + send_to_closed, + buffer_size, + binary_passive_recv, + max_buffer_size, + bad_address, + read_packets, + recv_poll_after_active_once, + open_fd, + connect, + implicit_inet6, + active_n, recvtos, recvtosttl, recvttl, recvtclass, sendtos, sendtosttl, sendttl, sendtclass, - {group, local}]. + {group, local}, + recv_close + ]. groups() -> - [{local, [], - [local_basic, local_unbound, - local_fdopen, local_fdopen_unbound, local_abstract]}]. + [ + {local, [], local_cases()} + ]. + +local_cases() -> + [ + local_basic, + local_unbound, + local_fdopen, + local_fdopen_unbound, + local_abstract + ]. init_per_suite(Config) -> Config. @@ -969,6 +989,52 @@ local_handshake(S, SAddr, C, CAddr) -> end. + + +%%------------------------------------------------------------- +%% Open a passive socket. Create a socket that reads from it. +%% Then close the socket. +recv_close(Config) when is_list(Config) -> + {ok, Sock} = gen_udp:open(0, [{active, false}]), + RECV = fun() -> + io:format("~p try recv~n", [self()]), + Res = gen_udp:recv(Sock, 0), + io:format("~p recv res: ~p~n", [self(), Res]), + exit(Res) + end, + io:format("~p spawn reader", [self()]), + {Pid, MRef} = spawn_monitor(RECV), + receive + {'DOWN', MRef, process, Pid, PreReason} -> + %% Make sure id does not die for some other reason... + ?line ct:fail("Unexpected pre close from reader (~p): ~p", + [Pid, PreReason]) + after 5000 -> % Just in case... + ok + end, + io:format("~p close socket", [self()]), + ok = gen_udp:close(Sock), + io:format("~p await reader termination", [self()]), + receive + {'DOWN', MRef, process, Pid, {error, closed}} -> + io:format("~p expected reader termination result", [self()]), + ok; + {'DOWN', MRef, process, Pid, PostReason} -> + io:format("~p unexpected reader termination: ~p", + [self(), PostReason]), + ?line ct:fail("Unexpected post close from reader (~p): ~p", + [Pid, PostReason]) + after 5000 -> + io:format("~p unexpected reader termination timeout", [self()]), + demonitor(MRef, [flush]), + exit(Pid, kill), + ?line ct:fail("Reader (~p) termination timeout", [Pid]) + end, + ok. + + + + %% %% Utils %% |