aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRickard Green <[email protected]>2017-06-02 14:12:23 +0200
committerRickard Green <[email protected]>2017-06-02 14:12:23 +0200
commite98b1cac4b31050f4887dfa4f115b4b9ffb82168 (patch)
tree8ee90db3f653cf71b06cf9c1db0b4d7e830f7e14
parent2b41d8f318b7e5ec139d42fd2f01a132699be839 (diff)
parent39a41b0472f275e71ae9bb6abf3bb8b3c995b8e3 (diff)
downloadotp-e98b1cac4b31050f4887dfa4f115b4b9ffb82168.tar.gz
otp-e98b1cac4b31050f4887dfa4f115b4b9ffb82168.tar.bz2
otp-e98b1cac4b31050f4887dfa4f115b4b9ffb82168.zip
Merge branch 'rickard/purge-hibernated-19' into HEAD
OTP-14444 * rickard/purge-hibernated-19: Update testcase to check that purge handle hibernated process correct Do not GC hibernated process from other processes Fix check_process_code() on hibernated process
-rw-r--r--erts/emulator/beam/beam_bif_load.c46
-rw-r--r--erts/emulator/beam/erl_gc.c5
-rw-r--r--erts/emulator/beam/erl_process.c3
-rw-r--r--erts/emulator/beam/erl_process.h1
-rw-r--r--erts/emulator/test/code_SUITE.erl44
5 files changed, 82 insertions, 17 deletions
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 5969197168..b072e84c64 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -1043,23 +1043,32 @@ erts_proc_copy_literal_area(Process *c_p, int *redsp, int fcalls, int gc_allowed
return am_ok;
-literal_gc:
+literal_gc: {
+ int hibernated = !!(c_p->flags & F_HIBERNATED);
+ int gc_cost;
- if (!gc_allowed)
- return am_need_gc;
+ if (!gc_allowed)
+ return am_need_gc;
- if (c_p->flags & F_DISABLE_GC)
- return THE_NON_VALUE;
+ if (c_p->flags & F_DISABLE_GC)
+ return THE_NON_VALUE;
- FLAGS(c_p) |= F_NEED_FULLSWEEP;
+ FLAGS(c_p) |= F_NEED_FULLSWEEP;
- *redsp += erts_garbage_collect_nobump(c_p, 0, c_p->arg_reg, c_p->arity, fcalls);
+ gc_cost = erts_garbage_collect_nobump(c_p, 0, c_p->arg_reg, c_p->arity, fcalls);
+ *redsp += gc_cost;
- erts_garbage_collect_literals(c_p, (Eterm *) literals, lit_bsize, oh);
+ erts_garbage_collect_literals(c_p, (Eterm *) literals, lit_bsize, oh);
- *redsp += lit_bsize / 64; /* Need, better value... */
+ *redsp += lit_bsize / 64; /* Need, better value... */
- return am_ok;
+ if (hibernated) {
+ erts_garbage_collect_hibernate(c_p);
+ *redsp += gc_cost;
+ }
+
+ return am_ok;
+ }
}
static Eterm
@@ -1141,6 +1150,8 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls
Eterm* sp;
int done_gc = 0;
int need_gc = 0;
+ int hibernated = !!(rp->flags & F_HIBERNATED);
+ int gc_cost = 0;
ErtsMessage *msgp;
ErlHeapFragment *hfrag;
@@ -1269,8 +1280,13 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls
while (1) {
/* Check heap, stack etc... */
- if (check_mod_funs(rp, &rp->off_heap, mod_start, mod_size))
+ if (check_mod_funs(rp, &rp->off_heap, mod_start, mod_size)) {
+ if (hibernated) {
+ /* GC wont help; everything on heap is live... */
+ return am_true;
+ }
goto try_gc;
+ }
if (any_heap_ref_ptrs(&rp->fvalue, &rp->fvalue+1, literals, lit_bsize)) {
rp->freason = EXC_NULL;
rp->fvalue = NIL;
@@ -1355,7 +1371,9 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls
if (need_gc & ERTS_ORDINARY_GC__) {
FLAGS(rp) |= F_NEED_FULLSWEEP;
- *redsp += erts_garbage_collect_nobump(rp, 0, rp->arg_reg, rp->arity, fcalls);
+ gc_cost = erts_garbage_collect_nobump(rp, 0, rp->arg_reg, rp->arity, fcalls);
+ ASSERT(!hibernated || (need_gc & ERTS_LITERAL_GC__));
+ *redsp += gc_cost;
done_gc |= ERTS_ORDINARY_GC__;
}
if (need_gc & ERTS_LITERAL_GC__) {
@@ -1364,6 +1382,10 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls
*redsp += lit_bsize / 64; /* Need, better value... */
erts_garbage_collect_literals(rp, (Eterm*)literals, lit_bsize, oh);
done_gc |= ERTS_LITERAL_GC__;
+ if (hibernated) {
+ erts_garbage_collect_hibernate(rp);
+ *redsp += gc_cost;
+ }
}
need_gc = 0;
}
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 6f641a1ea7..adba3c1d62 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -738,7 +738,7 @@ do_major_collection:
esdp->gc_info.garbage_cols++;
esdp->gc_info.reclaimed += reclaimed_now;
- FLAGS(p) &= ~F_FORCE_GC;
+ FLAGS(p) &= ~(F_FORCE_GC|F_HIBERNATED);
p->live_hf_end = ERTS_INVALID_HFRAG_PTR;
ERTS_MSACC_POP_STATE_M();
@@ -903,6 +903,8 @@ erts_garbage_collect_hibernate(Process* p)
ErtsGcQuickSanityCheck(p);
+ p->flags |= F_HIBERNATED;
+
erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC);
reds = gc_cost(actual_size, actual_size);
@@ -1132,6 +1134,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
/*
* Restore status.
*/
+ p->flags &= ~F_HIBERNATED;
erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC);
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index bc59147c6c..52fc00daac 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -10421,7 +10421,8 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds)
reds--;
}
else {
- if (!garbage_collected) {
+ if (!garbage_collected
+ && !(c_p->flags & F_HIBERNATED)) {
FLAGS(c_p) |= F_NEED_FULLSWEEP;
reds -= scheduler_gc_proc(c_p, reds);
garbage_collected = 1;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 3347a7a60e..ec2ecdcc42 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1394,6 +1394,7 @@ extern int erts_system_profile_ts_type;
#define F_HAVE_BLCKD_NMSCHED (1 << 18) /* Process has blocked normal multi-scheduling */
#define F_HIPE_MODE (1 << 19)
#define F_DELAYED_DEL_PROC (1 << 20) /* Delay delete process (dirty proc exit case) */
+#define F_HIBERNATED (1 << 21) /* Hibernated */
/*
* F_DISABLE_GC and F_DELAY_GC are similar. Both will prevent
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index 34515efa3d..bb04a084a6 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -645,9 +645,40 @@ constant_pools(Config) when is_list(Config) ->
erlang:purge_module(literals),
OldHeap ! done,
receive
- {'EXIT',OldHeap,{A,B,C,[1,2,3|_]=Seq}} when length(Seq) =:= 16 ->
- ok
- end.
+ {'EXIT',OldHeap,{A,B,C,[1,2,3|_]=Seq}} when length(Seq) =:= 16 ->
+ ok
+ end,
+
+ {module,literals} = erlang:load_module(literals, Code),
+ %% Have a hibernated process that references the literals
+ %% in the 'literals' module.
+ {Hib, Mon} = spawn_monitor(fun() -> hibernated(Self) end),
+ receive go -> ok end,
+ [{heap_size,OldHeapSz},
+ {total_heap_size,OldTotHeapSz}] = process_info(Hib, [heap_size,
+ total_heap_size]),
+ OldHeapSz = OldTotHeapSz,
+ io:format("OldHeapSz=~p OldTotHeapSz=~p~n", [OldHeapSz, OldTotHeapSz]),
+ true = erlang:delete_module(literals),
+ false = erlang:check_process_code(Hib, literals),
+ erlang:check_process_code(self(), literals),
+ erlang:purge_module(literals),
+ receive after 1000 -> ok end,
+ [{heap_size,HeapSz},
+ {total_heap_size,TotHeapSz}] = process_info(Hib, [heap_size,
+ total_heap_size]),
+ io:format("HeapSz=~p TotHeapSz=~p~n", [HeapSz, TotHeapSz]),
+ Hib ! hej,
+ receive
+ {'DOWN', Mon, process, Hib, Reason} ->
+ {undef, [{no_module,
+ no_function,
+ [{A,B,C,[1,2,3|_]=Seq}], _}]} = Reason,
+ 16 = length(Seq)
+ end,
+ HeapSz = TotHeapSz, %% Ensure restored to hibernated state...
+ true = HeapSz > OldHeapSz,
+ ok.
no_old_heap(Parent) ->
A = literals:a(),
@@ -670,6 +701,13 @@ old_heap(Parent) ->
exit(Res)
end.
+hibernated(Parent) ->
+ A = literals:a(),
+ B = literals:b(),
+ Res = {A,B,literals:huge_bignum(),lists:seq(1, 16)},
+ Parent ! go,
+ erlang:hibernate(no_module, no_function, [Res]).
+
create_old_heap() ->
case process_info(self(), [heap_size,total_heap_size]) of
[{heap_size,Sz},{total_heap_size,Total}] when Sz < Total ->