diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c index aec2938b614..5a88fe8e689 100644 --- a/erts/emulator/beam/erl_ptab.c +++ b/erts/emulator/beam/erl_ptab.c @@ -1478,7 +1478,12 @@ erts_ptab_processes_next(Process *c_p, ErtsPTab *ptab, Uint first) Eterm* hp; Eterm *hp_end; +#ifdef DEBUG + int max_pids = 1; +#else int max_pids = MAX(ERTS_BIF_REDS_LEFT(c_p), 1); +#endif + int num_pids = 0; int n = max_pids * ERTS_PTAB_REDS_MULTIPLIER; limit = MIN(ptab->r.o.max, first+n); @@ -1500,7 +1505,7 @@ erts_ptab_processes_next(Process *c_p, ErtsPTab *ptab, Uint first) return THE_NON_VALUE; } - need = n * 2; + need = 3 + max_pids * 2; hp = HAlloc(c_p, need); /* we need two heap words for each id */ hp_end = hp + need; res = make_list(hp); @@ -1524,6 +1529,7 @@ erts_ptab_processes_next(Process *c_p, ErtsPTab *ptab, Uint first) scanned = (i - first) / ERTS_PTAB_REDS_MULTIPLIER + 1; res = TUPLE2(hp, make_small(i), res); + hp += 3; HRelease(c_p, hp_end, hp); BUMP_REDS(c_p, scanned); diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 2315ec37840..66aa14509c5 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index 4ce0d155b78..0707c4ecf10 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam index 1792384c6a7..998d9a22087 100644 Binary files a/erts/preloaded/ebin/erts_literal_area_collector.beam and b/erts/preloaded/ebin/erts_literal_area_collector.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index 569d61e1119..6ed3b1ba338 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index ba2e278717d..08294adf3b4 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -120,7 +120,7 @@ do_purge(Mod, Reqs) -> false -> {{false, false}, Reqs}; true -> - {DidKill, NewReqs} = check_proc_code(erlang:processes(), + {DidKill, NewReqs} = check_proc_code(erlang:processes_iterator(), Mod, true, Reqs), true = erts_internal:purge_module(Mod, complete), {{true, DidKill}, NewReqs} @@ -144,7 +144,7 @@ do_soft_purge(Mod, Reqs) -> false -> {true, Reqs}; true -> - {PurgeOp, NewReqs} = check_proc_code(erlang:processes(), + {PurgeOp, NewReqs} = check_proc_code(erlang:processes_iterator(), Mod, false, Reqs), {erts_internal:purge_module(Mod, PurgeOp), NewReqs} end. @@ -172,7 +172,7 @@ do_finish_after_on_load(Mod, Keep, Reqs) -> Reqs; true -> {_DidKill, NewReqs} = - check_proc_code(erlang:processes(), + check_proc_code(erlang:processes_iterator(), Mod, true, Reqs), true = erts_internal:purge_module(Mod, complete), NewReqs @@ -181,7 +181,7 @@ do_finish_after_on_load(Mod, Keep, Reqs) -> %% -%% check_proc_code(Pids, Mod, Hard, Preqs) - Send asynchronous +%% check_proc_code(ProcessesIterator, Mod, Hard, Preqs) - Send asynchronous %% requests to all processes to perform a check_process_code %% operation. Each process will check their own state and %% reply with the result. If 'Hard' equals @@ -208,7 +208,7 @@ do_finish_after_on_load(Mod, Keep, Reqs) -> waiting = [], killed = false}). -check_proc_code(Pids, Mod, Hard, PReqs) -> +check_proc_code(Iter, Mod, Hard, PReqs) -> Tag = erlang:make_ref(), OReqLim = erlang:system_info(outstanding_system_requests_limit), CpcS = #cpc_static{hard = Hard, @@ -222,26 +222,26 @@ check_proc_code(Pids, Mod, Hard, PReqs) -> OReqLim end, KS = #cpc_kill{outstanding_limit = KillLimit}, - cpc_receive(CpcS, cpc_make_requests(CpcS, KS, 0, Pids), KS, []). + cpc_receive(CpcS, cpc_make_requests(CpcS, KS, 0, Iter), KS, []). cpc_receive(#cpc_static{hard = true} = CpcS, - {0, []}, + {0, none}, #cpc_kill{outstanding = [], waiting = [], killed = Killed}, PReqs) -> %% No outstanding cpc requests. We did a hard check, so result is %% whether or not we killed any processes... cpc_result(CpcS, PReqs, Killed); -cpc_receive(#cpc_static{hard = false} = CpcS, {0, []}, _KillState, PReqs) -> +cpc_receive(#cpc_static{hard = false} = CpcS, {0, none}, _KillState, PReqs) -> %% No outstanding cpc requests and we did a soft check that succeeded... cpc_result(CpcS, PReqs, complete); -cpc_receive(#cpc_static{tag = Tag} = CpcS, {NoReq, PidsLeft} = ReqInfo, +cpc_receive(#cpc_static{tag = Tag} = CpcS, {NoReq, Iter} = ReqInfo, KillState0, PReqs) -> receive {check_process_code, {Tag, _Pid}, false} -> %% Process not referring the module; done with this process... cpc_receive(CpcS, cpc_make_requests(CpcS, KillState0, - NoReq-1, PidsLeft), + NoReq-1, Iter), KillState0, PReqs); {check_process_code, {Tag, Pid}, true} -> @@ -258,7 +258,7 @@ cpc_receive(#cpc_static{tag = Tag} = CpcS, {NoReq, PidsLeft} = ReqInfo, KillState1 = cpc_sched_kill(Pid, KillState0), cpc_receive(CpcS, cpc_make_requests(CpcS, KillState1, - NoReq-1, PidsLeft), + NoReq-1, Iter), KillState1, PReqs) end; @@ -266,7 +266,7 @@ cpc_receive(#cpc_static{tag = Tag} = CpcS, {NoReq, PidsLeft} = ReqInfo, KillState1 = cpc_handle_down(MonRef, KillState0), cpc_receive(CpcS, cpc_make_requests(CpcS, KillState1, - NoReq, PidsLeft), + NoReq, Iter), KillState1, PReqs); PReq when element(1, PReq) == purge; @@ -341,16 +341,20 @@ cpc_request(#cpc_static{tag = Tag, module = Mod}, Pid) -> erts_internal:request_system_task(Pid, normal, {check_process_code, {Tag, Pid}, Mod}). -cpc_make_requests(#cpc_static{}, #cpc_kill{}, NoCpcReqs, []) -> - {NoCpcReqs, []}; +cpc_make_requests(#cpc_static{}, #cpc_kill{}, NoCpcReqs, none) -> + {NoCpcReqs, none}; cpc_make_requests(#cpc_static{oreq_limit = Limit}, #cpc_kill{no_outstanding = NoKillReqs}, - NoCpcReqs, Pids) when Limit =< NoCpcReqs + NoKillReqs -> - {NoCpcReqs, Pids}; + NoCpcReqs, Iter) when Limit =< NoCpcReqs + NoKillReqs -> + {NoCpcReqs, Iter}; cpc_make_requests(#cpc_static{} = CpcS, #cpc_kill{} = KS, - NoCpcReqs, [Pid|Pids]) -> - cpc_request(CpcS, Pid), - cpc_make_requests(CpcS, KS, NoCpcReqs+1, Pids). + NoCpcReqs, Iter0) -> + case erlang:processes_next(Iter0) of + none -> {NoCpcReqs, none}; + {Pid, Iter1} -> + cpc_request(CpcS, Pid), + cpc_make_requests(CpcS, KS, NoCpcReqs+1, Iter1) + end. change_prio(From, Ref, Prio) -> try @@ -391,7 +395,7 @@ do_test_soft_purge(Mod, From, Ref, Reqs) -> _ = test_progress(continued, From, Ref, TestRes), {true, Reqs}; true -> - {PurgeOp, NewReqs} = check_proc_code(erlang:processes(), + {PurgeOp, NewReqs} = check_proc_code(erlang:processes_iterator(), Mod, false, Reqs), _ = test_progress(continued, From, Ref, TestRes), {erts_internal:purge_module(Mod, PurgeOp), NewReqs} @@ -405,7 +409,7 @@ do_test_hard_purge(Mod, From, Ref, Reqs) -> _ = test_progress(continued, From, Ref, TestRes), {{false, false}, Reqs}; true -> - {DidKill, NewReqs} = check_proc_code(erlang:processes(), + {DidKill, NewReqs} = check_proc_code(erlang:processes_iterator(), Mod, true, Reqs), _ = test_progress(continued, From, Ref, TestRes), true = erts_internal:purge_module(Mod, complete), diff --git a/erts/preloaded/src/erts_literal_area_collector.erl b/erts/preloaded/src/erts_literal_area_collector.erl index 40a3f268590..57d66ee830e 100644 --- a/erts/preloaded/src/erts_literal_area_collector.erl +++ b/erts/preloaded/src/erts_literal_area_collector.erl @@ -37,7 +37,7 @@ %% start() -> process_flag(trap_exit, true), - msg_loop(undefined, {0, []}, 0, []). + msg_loop(undefined, {0, none}, 0, []). %% %% The VM will send us a 'copy_literals' message @@ -63,16 +63,17 @@ msg_loop(Area, {Ongoing, NeedIReq} = OReqInfo, GcOutstnd, NeedGC) -> switch_area(); %% Process (_Pid) has completed the request... - {copy_literals, {Area, _ReqType, _Pid}, ok} when Ongoing == 1, - NeedIReq == [] -> - switch_area(); %% Last process completed... {copy_literals, {Area, init, _Pid}, ok} -> - msg_loop(Area, check_send_copy_req(Area, Ongoing-1, NeedIReq), - GcOutstnd, NeedGC); + case check_send_copy_req(Area, Ongoing-1, NeedIReq) of + {0, none} -> switch_area(); %% Last process completed... + NewOReqInfo -> msg_loop(Area, NewOReqInfo, GcOutstnd, NeedGC) + end; {copy_literals, {Area, ReqType, _Pid}, ok} when NeedGC == [], ReqType /= init -> - msg_loop(Area, check_send_copy_req(Area, Ongoing-1, NeedIReq), - GcOutstnd-1, []); + case check_send_copy_req(Area, Ongoing-1, NeedIReq) of + {0, none} -> switch_area(); %% Last process completed... + NewOReqInfo -> msg_loop(Area, NewOReqInfo, GcOutstnd-1, []) + end; {copy_literals, {Area, ReqType, _Pid}, ok} when ReqType /= init -> [{GCPid,GCWork} | NewNeedGC] = NeedGC, send_copy_req(GCPid, Area, GCWork), @@ -117,7 +118,7 @@ switch_area() -> case Res of false -> %% No more areas to handle... - msg_loop(undefined, {0, []}, 0, []); + msg_loop(undefined, {0, none}, 0, []); true -> %% Send requests to OReqLim processes to copy %% all live data they have referring to the @@ -126,27 +127,35 @@ switch_area() -> %% processes when responses comes back until %% all processes have been handled... Area = make_ref(), - Pids = erlang:processes(), + Iter = erlang:processes_iterator(), OReqLim = erlang:system_info(outstanding_system_requests_limit), - msg_loop(Area, send_copy_reqs(Pids, Area, OReqLim), 0, []) + msg_loop(Area, send_copy_reqs(Iter, Area, OReqLim), 0, []) end. -check_send_copy_req(_Area, Ongoing, []) -> - {Ongoing, []}; -check_send_copy_req(Area, Ongoing, [Pid|Pids]) -> - send_copy_req(Pid, Area, init), - {Ongoing+1, Pids}. - -send_copy_reqs(Ps, Area, OReqLim) -> - send_copy_reqs(Ps, Area, OReqLim, 0). - -send_copy_reqs([], _Area, _OReqLim, N) -> - {N, []}; -send_copy_reqs(Ps, _Area, OReqLim, N) when N >= OReqLim -> - {N, Ps}; -send_copy_reqs([P|Ps], Area, OReqLim, N) -> - send_copy_req(P, Area, init), - send_copy_reqs(Ps, Area, OReqLim, N+1). +check_send_copy_req(_Area, Ongoing, none) -> + {Ongoing, none}; +check_send_copy_req(Area, Ongoing, Iter0) -> + case erlang:processes_next(Iter0) of + none -> + {Ongoing, none}; + {Pid, Iter1} -> + send_copy_req(Pid, Area, init), + {Ongoing+1, Iter1} + end. + +send_copy_reqs(Iter, Area, OReqLim) -> + send_copy_reqs(Iter, Area, OReqLim, 0). + +send_copy_reqs(Iter, _Area, OReqLim, N) when N >= OReqLim -> + {N, Iter}; +send_copy_reqs(Iter0, Area, OReqLim, N) -> + case erlang:processes_next(Iter0) of + none -> + {N, none}; + {Pid, Iter1} -> + send_copy_req(Pid, Area, init), + send_copy_reqs(Iter1, Area, OReqLim, N+1) + end. send_copy_req(P, Area, How) -> erts_literal_area_collector:send_copy_request(P, Area, How). diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 3f03c689262..f556c9dccd4 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -947,7 +947,7 @@ clear_system(Unload,BootPid,State) -> Logger = get_logger(State#state.kernel), shutdown_pids(Heart,Logger,BootPid,State), Unload andalso unload(Heart), - kill_em([Logger]), + exit(Logger,kill), Unload andalso do_unload([logger_server]). flush() -> @@ -1060,30 +1060,27 @@ resend(_) -> %% %% Kill all existing pids in the system (except init and heart). kill_all_pids(Heart,Logger) -> - case get_pids(Heart,Logger) of - [] -> - ok; - Pids -> - kill_em(Pids), - kill_all_pids(Heart,Logger) % Continue until all are really killed. + Iter = erlang:processes_iterator(), + case kill_pids(Heart, Logger, Iter, false) of + true -> + % Continue until all are really killed. + kill_all_pids(Heart, Logger); + false -> + ok + end. + +kill_pids(Heart, Logger, Iter0, MorePids) -> + case erlang:processes_next(Iter0) of + none -> MorePids; + {Pid, Iter1} -> + case erts_internal:is_system_process(Pid) orelse + lists:member(Pid, [Heart, Logger, self()]) of + true -> kill_pids(Heart, Logger, Iter1, MorePids); + false -> + exit(Pid, kill), + kill_pids(Heart, Logger, Iter1, true) + end end. - -%% All except system processes. -get_pids(Heart,Logger) -> - Pids = [P || P <- processes(), not erts_internal:is_system_process(P)], - delete(Heart,Logger,self(),Pids). - -delete(Heart,Logger,Init,[Heart|Pids]) -> delete(Heart,Logger,Init,Pids); -delete(Heart,Logger,Init,[Logger|Pids]) -> delete(Heart,Logger,Init,Pids); -delete(Heart,Logger,Init,[Init|Pids]) -> delete(Heart,Logger,Init,Pids); -delete(Heart,Logger,Init,[Pid|Pids]) -> [Pid|delete(Heart,Logger,Init,Pids)]; -delete(_,_,_,[]) -> []. - -kill_em([Pid|Pids]) -> - exit(Pid,kill), - kill_em(Pids); -kill_em([]) -> - ok. %% %% Kill all existing ports in the system (except the heart port),