1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(erts_literal_area_collector). 21 22-export([start/0, send_copy_request/3, release_area_switch/0]). 23 24%% Currently we only allow two outstanding literal 25%% copying jobs that garbage collect in order to 26%% copy the literals. Maybe we could allow more 27%% than two outstanding processes, but for now we 28%% play it safe... 29-define(MAX_GC_OUTSTND, 2). 30 31%% 32%% The erts_literal_area_collector is started at 33%% VM boot by the VM. It is a spawned as a system 34%% process, i.e, the whole VM will terminate if 35%% this process terminates. 36%% 37start() -> 38 process_flag(trap_exit, true), 39 msg_loop(undefined, 0, 0, []). 40 41%% 42%% The VM will send us a 'copy_literals' message 43%% when it has a new literal area that needs to 44%% be handled is added. We will also be informed 45%% about more areas when we call release_area_switch(). 46%% 47msg_loop(Area, Outstnd, GcOutstnd, NeedGC) -> 48 49 HibernateTmo = 50 if Area =:= undefined -> 51 60_000; 52 true -> 53 infinity 54 end, 55 56 receive 57 58 %% A new area to handle has arrived... 59 copy_literals when Outstnd == 0 -> 60 switch_area(); 61 62 %% Process (_Pid) has completed the request... 63 {copy_literals, {Area, _GcAllowed, _Pid}, ok} when Outstnd == 1 -> 64 switch_area(); %% Last process completed... 65 {copy_literals, {Area, false, _Pid}, ok} -> 66 msg_loop(Area, Outstnd-1, GcOutstnd, NeedGC); 67 {copy_literals, {Area, true, _Pid}, ok} when NeedGC == [] -> 68 msg_loop(Area, Outstnd-1, GcOutstnd-1, []); 69 {copy_literals, {Area, true, _Pid}, ok} -> 70 erts_literal_area_collector:send_copy_request(hd(NeedGC), Area, true), 71 msg_loop(Area, Outstnd-1, GcOutstnd, tl(NeedGC)); 72 73 %% Process (Pid) failed to complete the request 74 %% since it needs to garbage collect in order to 75 %% complete the request... 76 {copy_literals, {Area, false, Pid}, need_gc} when GcOutstnd < ?MAX_GC_OUTSTND -> 77 erts_literal_area_collector:send_copy_request(Pid, Area, true), 78 msg_loop(Area, Outstnd, GcOutstnd+1, NeedGC); 79 {copy_literals, {Area, false, Pid}, need_gc} -> 80 msg_loop(Area, Outstnd, GcOutstnd, [Pid|NeedGC]); 81 82 %% Not handled message regarding the area that we 83 %% currently are working with. Crash the VM so 84 %% we notice this bug... 85 {copy_literals, {Area, _, _}, _} = Msg when erlang:is_reference(Area) -> 86 exit({not_handled_message, Msg}); 87 88 %% Unexpected garbage message. Get rid of it... 89 _Ignore -> 90 msg_loop(Area, Outstnd, GcOutstnd, NeedGC) 91 after HibernateTmo -> 92 %% We hibernate in order to clear the heap completely. 93 erlang:hibernate(?MODULE, start, []) 94 end. 95 96switch_area() -> 97 Res = erts_literal_area_collector:release_area_switch(), 98 case Res of 99 false -> 100 %% No more areas to handle... 101 msg_loop(undefined, 0, 0, []); 102 true -> 103 %% Send requests to all processes to copy 104 %% all live data they have referring to the 105 %% literal area that is to be released... 106 Area = make_ref(), 107 Outstnd = send_copy_reqs(erlang:processes(), Area, false), 108 msg_loop(Area, Outstnd, 0, []) 109 end. 110 111send_copy_reqs(Ps, Area, GC) -> 112 send_copy_reqs(Ps, Area, GC, 0). 113 114send_copy_reqs([], _Area, _GC, N) -> 115 N; 116send_copy_reqs([P|Ps], Area, GC, N) -> 117 erts_literal_area_collector:send_copy_request(P, Area, GC), 118 send_copy_reqs(Ps, Area, GC, N+1). 119 120-spec release_area_switch() -> boolean(). 121 122release_area_switch() -> 123 erlang:nif_error(undef). %% Implemented in beam_bif_load.c 124 125-spec send_copy_request(To, AreaId, GcAllowed) -> 'ok' when 126 To :: pid(), 127 AreaId :: term(), 128 GcAllowed :: boolean(). 129 130send_copy_request(_To, _AreaId, _GcAllowed) -> 131 erlang:nif_error(undef). %% Implemented in beam_bif_load.c 132