diff options
author | Björn Gustavsson <bjorn@erlang.org> | 2023-02-17 12:39:00 +0100 |
---|---|---|
committer | Björn Gustavsson <bjorn@erlang.org> | 2023-02-17 12:39:00 +0100 |
commit | 27a4de60666b786ecb3e11644c16626b2ffdd9ae (patch) | |
tree | 20858374a4072d3b65039b1191d8239cd697966c /erts | |
parent | 265f8d15ec4f94262908d1b5a9c7ca69427367aa (diff) | |
parent | d60625283288c09a24631ad8c3b923c605a0c5c5 (diff) | |
download | erlang-27a4de60666b786ecb3e11644c16626b2ffdd9ae.tar.gz |
Merge branch 'bjorn/erts/max_heap_size/25/OTP-18463' into maint
* bjorn/erts/max_heap_size/25/OTP-18463:
Exit process immediately when the max heap size is exceeded
Diffstat (limited to 'erts')
-rw-r--r-- | erts/emulator/beam/emu/bs_instrs.tab | 1 | ||||
-rw-r--r-- | erts/emulator/beam/emu/instrs.tab | 1 | ||||
-rw-r--r-- | erts/emulator/beam/emu/macros.tab | 8 | ||||
-rw-r--r-- | erts/emulator/beam/jit/arm/beam_asm_global.cpp | 4 | ||||
-rw-r--r-- | erts/emulator/beam/jit/x86/beam_asm_global.cpp | 16 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 107 |
6 files changed, 136 insertions, 1 deletions
diff --git a/erts/emulator/beam/emu/bs_instrs.tab b/erts/emulator/beam/emu/bs_instrs.tab index 846e4b6f2c..b5fa518312 100644 --- a/erts/emulator/beam/emu/bs_instrs.tab +++ b/erts/emulator/beam/emu/bs_instrs.tab @@ -132,6 +132,7 @@ TEST_BIN_VHEAP(VNh, Nh, Live) { ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); SWAPIN; + $MAYBE_EXIT_AFTER_GC(); } HEAP_SPACE_VERIFIED(need); } diff --git a/erts/emulator/beam/emu/instrs.tab b/erts/emulator/beam/emu/instrs.tab index 2c39d885ef..0ca0d71a2d 100644 --- a/erts/emulator/beam/emu/instrs.tab +++ b/erts/emulator/beam/emu/instrs.tab @@ -1124,6 +1124,7 @@ catch_end(Y) { ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); SWAPIN; + $MAYBE_EXIT_AFTER_GC(); } r(0) = TUPLE2(HTOP, am_EXIT, x(1)); HTOP += 3; diff --git a/erts/emulator/beam/emu/macros.tab b/erts/emulator/beam/emu/macros.tab index cef41e89f7..b65e01553a 100644 --- a/erts/emulator/beam/emu/macros.tab +++ b/erts/emulator/beam/emu/macros.tab @@ -74,6 +74,12 @@ GC_SWAPOUT() { c_p->i = I; } +MAYBE_EXIT_AFTER_GC() { + if (ERTS_PSFLG_EXITING & erts_atomic32_read_nob(&c_p->state)) { + goto context_switch3; + } +} + GC_TEST(Ns, Nh, Live) { Uint need = $Nh + $Ns; if (ERTS_UNLIKELY((E - HTOP) < (need + S_RESERVED))) { @@ -83,6 +89,7 @@ GC_TEST(Ns, Nh, Live) { ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); SWAPIN; + $MAYBE_EXIT_AFTER_GC(); } HEAP_SPACE_VERIFIED($Nh); } @@ -98,6 +105,7 @@ GC_TEST_PRESERVE(NeedHeap, Live, PreserveTerm) { PROCESS_MAIN_CHK_LOCKS(c_p); $PreserveTerm = reg[$Live]; SWAPIN; + $MAYBE_EXIT_AFTER_GC(); } HEAP_SPACE_VERIFIED($NeedHeap); } diff --git a/erts/emulator/beam/jit/arm/beam_asm_global.cpp b/erts/emulator/beam/jit/arm/beam_asm_global.cpp index 6185c70fcb..b4655b6c19 100644 --- a/erts/emulator/beam/jit/arm/beam_asm_global.cpp +++ b/erts/emulator/beam/jit/arm/beam_asm_global.cpp @@ -120,6 +120,10 @@ void BeamGlobalAssembler::emit_garbage_collect() { emit_leave_runtime<Update::eStack | Update::eHeap | Update::eXRegs>(); emit_leave_runtime_frame(); + a.ldr(TMP1.w(), arm::Mem(c_p, offsetof(Process, state.value))); + a.tst(TMP1, imm(ERTS_PSFLG_EXITING)); + a.b_ne(labels[do_schedule]); + a.ret(a64::x30); } diff --git a/erts/emulator/beam/jit/x86/beam_asm_global.cpp b/erts/emulator/beam/jit/x86/beam_asm_global.cpp index 59eaf057f3..3e588d3d45 100644 --- a/erts/emulator/beam/jit/x86/beam_asm_global.cpp +++ b/erts/emulator/beam/jit/x86/beam_asm_global.cpp @@ -95,6 +95,8 @@ BeamGlobalAssembler::BeamGlobalAssembler(JitAllocator *allocator) /* ARG3 = (HTOP + S_RESERVED + bytes needed) !! * ARG4 = Live registers */ void BeamGlobalAssembler::emit_garbage_collect() { + Label exiting = a.newLabel(); + emit_enter_frame(); /* Convert ARG3 to words needed and move it to the correct argument slot. @@ -126,9 +128,21 @@ void BeamGlobalAssembler::emit_garbage_collect() { a.sub(FCALLS, RET); emit_leave_runtime<Update::eStack | Update::eHeap>(); - emit_leave_frame(); +#ifdef WIN32 + a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.value))); +#else + a.mov(ARG1d, x86::dword_ptr(c_p, offsetof(Process, state.counter))); +#endif + a.test(ARG1d, imm(ERTS_PSFLG_EXITING)); + a.short_().jne(exiting); + + emit_leave_frame(); a.ret(); + + a.bind(exiting); + emit_unwind_frame(); + a.jmp(labels[do_schedule]); } /* Handles trapping to exports from C code, setting registers up in the same diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 9ab2366c58..89d37d4f3e 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -60,6 +60,7 @@ process_flag_fullsweep_after/1, process_flag_heap_size/1, command_line_max_heap_size/1, spawn_opt_heap_size/1, spawn_opt_max_heap_size/1, + more_spawn_opt_max_heap_size/1, processes_large_tab/1, processes_default_tab/1, processes_small_tab/1, processes_this_tab/1, processes_apply_trap/1, processes_last_call_trap/1, processes_gc_trap/1, @@ -118,6 +119,7 @@ all() -> process_flag_fullsweep_after, process_flag_heap_size, command_line_max_heap_size, spawn_opt_heap_size, spawn_opt_max_heap_size, + more_spawn_opt_max_heap_size, spawn_huge_arglist, otp_6237, {group, spawn_request}, @@ -2713,6 +2715,111 @@ flush() -> ok end. +%% Make sure that when maximum allowed heap size is exceeded, the +%% process will actually terminate. +%% +%% Despite the timetrap and limit of number of iterations, bugs +%% provoked by the test case can cause the runtime system to hang in +%% this test case. +more_spawn_opt_max_heap_size(_Config) -> + ct:timetrap({minutes,1}), + Funs = [fun build_and_bif/0, + fun build_bin_and_bif/0, + fun build_and_recv_timeout/0, + fun build_and_recv_msg/0, + fun bif_and_recv_timeout/0, + fun bif_and_recv_msg/0 + ], + _ = [begin + {Pid,Ref} = spawn_opt(F, [{max_heap_size, + #{size => 233, kill => true, + error_logger => false}}, + monitor]), + io:format("~p ~p\n", [Pid,F]), + receive + {'DOWN',Ref,process,Pid,Reason} -> + killed = Reason + end + end || F <- Funs], + ok. + +%% This number should be greater than the default heap size. +-define(MANY_ITERATIONS, 10_000). + +build_and_bif() -> + build_and_bif(?MANY_ITERATIONS, []). + +build_and_bif(0, Acc0) -> + Acc0; +build_and_bif(N, Acc0) -> + Acc = [0|Acc0], + _ = erlang:crc32(Acc), + build_and_bif(N-1, Acc). + +build_bin_and_bif() -> + build_bin_and_bif(?MANY_ITERATIONS, <<>>). + +build_bin_and_bif(0, Acc0) -> + Acc0; +build_bin_and_bif(N, Acc0) -> + Acc = <<0, Acc0/binary>>, + _ = erlang:crc32(Acc), + build_bin_and_bif(N-1, Acc). + +build_and_recv_timeout() -> + build_and_recv_timeout(?MANY_ITERATIONS, []). + +build_and_recv_timeout(0, Acc0) -> + Acc0; +build_and_recv_timeout(N, Acc0) -> + Acc = [0|Acc0], + receive + after 1 -> + ok + end, + build_and_recv_timeout(N-1, Acc). + +build_and_recv_msg() -> + build_and_recv_msg(?MANY_ITERATIONS, []). + +build_and_recv_msg(0, Acc0) -> + Acc0; +build_and_recv_msg(N, Acc0) -> + Acc = [0|Acc0], + receive + _ -> + ok + after 0 -> + ok + end, + build_and_recv_msg(N-1, Acc). + +bif_and_recv_timeout() -> + Bin = <<0:?MANY_ITERATIONS/unit:8>>, + bif_and_recv_timeout(Bin). + +bif_and_recv_timeout(Bin) -> + List = binary_to_list(Bin), + receive + after 1 -> + ok + end, + List. + +bif_and_recv_msg() -> + Bin = <<0:?MANY_ITERATIONS/unit:8>>, + bif_and_recv_msg(Bin). + +bif_and_recv_msg(Bin) -> + List = binary_to_list(Bin), + receive + _ -> + ok + after 0 -> + ok + end, + List. + %% error_logger report handler proxy init(Pid) -> {ok, Pid}. |