diff options
author | Rickard Green <[email protected]> | 2017-06-08 14:45:52 +0200 |
---|---|---|
committer | Rickard Green <[email protected]> | 2017-06-08 14:45:52 +0200 |
commit | eefca18e8bed9f41ce65ae79fb1a5b614accbfde (patch) | |
tree | 7338c8b44999a6490bfada281110439639091705 /erts | |
parent | 72d8f7f0fa53063d16e82b033a2eae7349bcd662 (diff) | |
parent | 766294e485cfc0cf982426cccca0428529e589d8 (diff) | |
download | otp-eefca18e8bed9f41ce65ae79fb1a5b614accbfde.tar.gz otp-eefca18e8bed9f41ce65ae79fb1a5b614accbfde.tar.bz2 otp-eefca18e8bed9f41ce65ae79fb1a5b614accbfde.zip |
Merge branch 'rickard/purge-hibernated-20'
* rickard/purge-hibernated-20:
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
Diffstat (limited to 'erts')
-rw-r--r-- | erts/emulator/beam/beam_bif_load.c | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_gc.c | 36 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.c | 5 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.h | 1 | ||||
-rw-r--r-- | erts/emulator/test/code_SUITE.erl | 44 |
5 files changed, 74 insertions, 16 deletions
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 5aceae8ffe..007bf99b6e 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -1068,10 +1068,10 @@ return_ok: literal_gc: if (!gc_allowed) - return am_need_gc; + return am_need_gc; if (c_p->flags & F_DISABLE_GC) - return THE_NON_VALUE; + return THE_NON_VALUE; *redsp += erts_garbage_collect_literals(c_p, (Eterm *) literals, lit_bsize, oh, fcalls); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 2ff49c97b3..3c8bdaa62e 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -834,7 +834,7 @@ do_major_collection: 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(); @@ -891,8 +891,8 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) * Place all living data on a the new heap; deallocate any old heap. * Meant to be used by hibernate/3. */ -void -erts_garbage_collect_hibernate(Process* p) +static int +garbage_collect_hibernate(Process* p, int check_long_gc) { Uint heap_size; Eterm* heap; @@ -909,13 +909,13 @@ erts_garbage_collect_hibernate(Process* p) #ifdef ERTS_DIRTY_SCHEDULERS if (ERTS_SCHEDULER_IS_DIRTY(erts_proc_sched_data(p))) p->flags &= ~(F_DIRTY_GC_HIBERNATE|F_DIRTY_MAJOR_GC|F_DIRTY_MINOR_GC); - else { + else if (check_long_gc) { Uint flags = p->flags; p->flags |= F_NEED_FULLSWEEP; check_for_possibly_long_gc(p, (p->htop - p->heap) + p->mbuf_sz); if (p->flags & (F_DIRTY_MAJOR_GC|F_DIRTY_MINOR_GC)) { p->flags = flags|F_DIRTY_GC_HIBERNATE; - return; + return 1; } p->flags = flags; } @@ -1012,12 +1012,20 @@ 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); - BUMP_REDS(p, reds); + return reds; } +void +erts_garbage_collect_hibernate(Process* p) +{ + int reds = garbage_collect_hibernate(p, 1); + BUMP_REDS(p, reds); +} /* * HiPE native code stack scanning procedures: @@ -1090,6 +1098,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, Uint ygen_usage = 0; struct erl_off_heap_header** prev = NULL; Sint64 reds; + int hibernated = !!(p->flags & F_HIBERNATED); if (p->flags & (F_DISABLE_GC|F_DELAY_GC)) ERTS_INTERNAL_ERROR("GC disabled"); @@ -1104,10 +1113,13 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, if (ERTS_SCHEDULER_IS_DIRTY(erts_proc_sched_data(p))) p->flags &= ~F_DIRTY_CLA; else { + Uint size = byte_lit_size/sizeof(Uint); ygen_usage = young_gen_usage(p); - check_for_possibly_long_gc(p, - (byte_lit_size/sizeof(Uint) - + 2*ygen_usage)); + if (hibernated) + size = size*2 + 3*ygen_usage; + else + size = size + 2*ygen_usage; + check_for_possibly_long_gc(p, size); if (p->flags & F_DIRTY_MAJOR_GC) { p->flags |= F_DIRTY_CLA; return 10; @@ -1274,6 +1286,12 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC); reds += (Sint64) gc_cost((p->htop - p->heap) + byte_lit_size/sizeof(Uint), 0); + + if (hibernated) { + /* Restore the process into hibernated state... */ + reds += garbage_collect_hibernate(p, 0); + } + if (reds > INT_MAX) return INT_MAX; return (int) reds; diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 285fa05d63..fc2b34e70f 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -11220,8 +11220,9 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds) reds--; } else { - if (!minor_gc - || (!major_gc && type == ERTS_PSTT_GC_MAJOR)) { + if ((!minor_gc + || (!major_gc && type == ERTS_PSTT_GC_MAJOR)) + && !(c_p->flags & F_HIBERNATED)) { if (type == ERTS_PSTT_GC_MAJOR) { FLAGS(c_p) |= F_NEED_FULLSWEEP; } diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index d44e8c252d..9d7ba27c50 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1422,6 +1422,7 @@ extern int erts_system_profile_ts_type; #define F_DIRTY_GC_HIBERNATE (1 << 22) /* Dirty GC hibernate scheduled */ #define F_DIRTY_MAJOR_GC (1 << 23) /* Dirty major GC scheduled */ #define F_DIRTY_MINOR_GC (1 << 24) /* Dirty minor GC scheduled */ +#define F_HIBERNATED (1 << 25) /* 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 35f7baf2cf..ab0fc0d42c 100644 --- a/erts/emulator/test/code_SUITE.erl +++ b/erts/emulator/test/code_SUITE.erl @@ -358,9 +358,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(), @@ -383,6 +414,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 -> |