diff options
-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 |
4 files changed, 33 insertions, 13 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 d4385e3987..00fc6116e5 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 |