From 41cf0cb977472a15527b6ac693883daaa84faa5a Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 17 Jan 2012 11:18:26 +0100 Subject: erts: First stab at code_ix interface and beam_catches using it Code loading still blocking --- erts/emulator/beam/beam_bif_load.c | 10 ++- erts/emulator/beam/beam_catches.c | 128 +++++++++++++++++++++++++++---------- erts/emulator/beam/beam_catches.h | 7 +- erts/emulator/beam/beam_load.c | 92 ++++++++++++++++++++++++++ erts/emulator/beam/erl_init.c | 4 +- erts/emulator/beam/global.h | 44 +++++++++++++ 6 files changed, 249 insertions(+), 36 deletions(-) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 90baa6178e..a8ef198be5 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -86,11 +86,15 @@ load_module_2(BIF_ALIST_2) erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); + erts_start_loader_code_ix(); + reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); if (reason != NIL) { + erts_abort_loader_code_ix(); res = TUPLE2(hp, am_error, reason); } else { set_default_trace_pattern(BIF_ARG_1); + erts_commit_loader_code_ix(); res = TUPLE2(hp, am_module, BIF_ARG_1); } @@ -374,7 +378,8 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) code = modp->curr.code; end = (BeamInstr *)((char *)code + modp->curr.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length); + beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length, + erts_active_code_ix()); erts_free(ERTS_ALC_T_CODE, (void *) code); modp->curr.code = NULL; modp->curr.code_length = 0; @@ -667,7 +672,8 @@ purge_module(int module) code = modp->old.code; end = (BeamInstr *)((char *)code + modp->old.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->old.catches, code, modp->old.code_length); + beam_catches_delmod(modp->old.catches, code, modp->old.code_length, + erts_active_code_ix()); decrement_refc(code); erts_free(ERTS_ALC_T_CODE, (void *) code); modp->old.code = NULL; diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index 406ef1db5f..72bd3583e1 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -31,24 +31,77 @@ typedef struct { unsigned cdr; } beam_catch_t; -static int free_list; -static unsigned high_mark; -static unsigned tabsize; -static beam_catch_t *beam_catches; +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + +struct bc_code_ix { /*SVERK A better name maybe... */ + int free_list; + unsigned high_mark; + unsigned tabsize; + beam_catch_t *beam_catches; + + IF_DEBUG(int is_prepared;) +}; + +static struct bc_code_ix bccix[ERTS_NUM_CODE_IX]; void beam_catches_init(void) { - tabsize = DEFAULT_TABSIZE; - free_list = -1; - high_mark = 0; + int i; + + bccix[0].tabsize = DEFAULT_TABSIZE; + bccix[0].free_list = -1; + bccix[0].high_mark = 0; + bccix[0].beam_catches = erts_alloc(ERTS_ALC_T_CODE, + sizeof(beam_catch_t)*DEFAULT_TABSIZE); + IF_DEBUG(bccix[0].is_prepared = 0); + for (i=1; iis_prepared); /* * Allocate from free_list while it is non-empty. * If free_list is empty, allocate at high_mark. @@ -56,53 +109,64 @@ unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr) * This avoids the need to initialise the free list in * beam_catches_init(), which would cost O(TABSIZ) time. */ - if( free_list >= 0 ) { - i = free_list; - free_list = beam_catches[i].cdr; - } else if( high_mark < tabsize ) { - i = high_mark; - high_mark++; - } else { - /* No free slots and table is full: realloc table */ - tabsize = 2*tabsize; - beam_catches = erts_realloc(ERTS_ALC_T_CODE, beam_catches, sizeof(beam_catch_t)*tabsize); - i = high_mark; - high_mark++; + if (p->free_list >= 0) { + i = p->free_list; + p->free_list = p->beam_catches[i].cdr; + } + else { + if (p->high_mark >= p->tabsize) { + /* No free slots and table is full: realloc table */ + beam_catch_t* prev_vec = p->beam_catches; + unsigned newsize = p->tabsize*2; + + p->beam_catches = erts_alloc(ERTS_ALC_T_CODE, + newsize*sizeof(beam_catch_t)); + sys_memcpy(p->beam_catches, prev_vec, + p->tabsize*sizeof(beam_catch_t)); + gc_old_vec(prev_vec); + p->tabsize = newsize; + } + i = p->high_mark++; } - beam_catches[i].cp = cp; - beam_catches[i].cdr = cdr; + p->beam_catches[i].cp = cp; + p->beam_catches[i].cdr = cdr; return i; } BeamInstr *beam_catches_car(unsigned i) { - if( i >= tabsize ) { + struct bc_code_ix* p = &bccix[erts_active_code_ix()]; + + if (i >= p->tabsize ) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - return beam_catches[i].cp; + return p->beam_catches[i].cp; } -void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes) +void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, + ErtsCodeIndex code_ix) { + struct bc_code_ix* p = &bccix[code_ix]; unsigned i, cdr; + ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_loader_code_ix()].is_prepared); for(i = head; i != (unsigned)-1;) { - if( i >= tabsize ) { + if (i >= p->tabsize) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - if( (char*)beam_catches[i].cp - (char*)code >= code_bytes ) { + if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) { erl_exit(1, "beam_catches_delmod: item %#x has cp %#lx which is not " "in module's range [%#lx,%#lx[\r\n", - i, (long)beam_catches[i].cp, + i, (long)p->beam_catches[i].cp, (long)code, (long)((char*)code + code_bytes)); } - beam_catches[i].cp = 0; - cdr = beam_catches[i].cdr; - beam_catches[i].cdr = free_list; - free_list = i; + p->beam_catches[i].cp = 0; + cdr = p->beam_catches[i].cdr; + p->beam_catches[i].cdr = p->free_list; + p->free_list = i; i = cdr; } } diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h index 6223427f0d..970772806b 100644 --- a/erts/emulator/beam/beam_catches.h +++ b/erts/emulator/beam/beam_catches.h @@ -20,12 +20,17 @@ #ifndef __BEAM_CATCHES_H #define __BEAM_CATCHES_H +#include "global.h" /*SVERK the code_ix stuff */ + #define BEAM_CATCHES_NIL (-1) void beam_catches_init(void); +void beam_catches_start_load(void); +void beam_catches_end_load(int commit); unsigned beam_catches_cons(BeamInstr* cp, unsigned cdr); BeamInstr *beam_catches_car(unsigned i); -void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes); +void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes, + ErtsCodeIndex); #define catch_pc(x) beam_catches_car(catch_val((x))) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 27a5e72113..f7c8395cb6 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -6101,3 +6101,95 @@ static int safe_mul(UWord a, UWord b, UWord* resp) return (res / b) == a; } } + + +/*SVERK Do these deserve a file of their own maybe? */ + +static erts_smp_atomic32_t the_active_code_index; +static erts_smp_atomic32_t the_loader_code_index; + +#ifdef DEBUG +# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_loader_code_ix()) +#else +# define CIX_TRACE(text) +#endif + +void erts_code_ix_init(void) +{ + erts_smp_atomic32_init_nob(&the_active_code_index, 0); + erts_smp_atomic32_init_nob(&the_loader_code_index, 0); + CIX_TRACE("init"); +} +ErtsCodeIndex erts_active_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_active_code_index); +} +ErtsCodeIndex erts_loader_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_loader_code_index); +} + +/* Lock code_ix (enqueue and suspend until we get it) +*/ +void erts_lock_code_ix(void) +{ +} + +/* Unlock code_ix (resume first waiter) +*/ +void erts_unlock_code_ix(void) +{ +} + +void erts_start_loader_code_ix(void) +{ + beam_catches_start_load(); + /*SVERK and more to come I guess... + : + */ + CIX_TRACE("start"); +} + + +void erts_commit_loader_code_ix(void) +{ + beam_catches_end_load(1); + { + ErtsCodeIndex ix = erts_loader_code_ix(); + erts_smp_atomic32_set_nob(&the_active_code_index, ix); + ix = (ix + 1) % ERTS_NUM_CODE_IX; + erts_smp_atomic32_set_nob(&the_loader_code_index, ix); + } + CIX_TRACE("commit"); +} + +void erts_abort_loader_code_ix(void) +{ + beam_catches_end_load(0); + CIX_TRACE("abort"); +} + +/*SVERK old_code lock should maybe be part of module.c */ +void erts_rwlock_old_code(void) +{ +} +void erts_rwunlock_old_code(void) +{ +} +void erts_rlock_old_code(void) +{ +} +void erts_runlock_old_code(void) +{ +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_old_code_rlocked(void) +{ + return 1; +} +int erts_is_code_ix_locked(void) +{ + return 1; +} +#endif diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 717315d8bd..8d382057dc 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -236,7 +236,7 @@ void erl_error(char *fmt, va_list args) static int early_init(int *argc, char **argv); void -erts_short_init(void) +erts_short_init_SVERK_SAYS_NOT_USED(void) { int ncpu = early_init(NULL, NULL); erl_init(ncpu); @@ -264,6 +264,7 @@ erl_init(int ncpu) erts_init_trace(); erts_init_binary(); erts_init_bits(); + erts_code_ix_init(); erts_init_fun_table(); init_atom_table(); init_export_table(); @@ -1471,6 +1472,7 @@ erl_start(int argc, char **argv) init_shared_memory(boot_argc, boot_argv); load_preloaded(); + erts_commit_loader_code_ix(); erts_initialized = 1; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 46bc58891b..8745ca610b 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -28,6 +28,50 @@ #include "hash.h" #include "index.h" #include "atom.h" + +/*SVERK maybe put this is some other header, must be before module.h and export.h */ +#define ERTS_NUM_CODE_IX 3 +typedef unsigned ErtsCodeIndex; + +void erts_code_ix_init(void); +ErtsCodeIndex erts_active_code_ix(void); +ErtsCodeIndex erts_loader_code_ix(void); + +/* Lock code_ix (enqueue and suspend until we get it) +*/ +void erts_lock_code_ix(void); + +/*SVERK + erts_lock_code_ix(); + wait for thread progress + (we don't want any retarded threads with pointers to inactive Module) + Copy active -> loader + rlock old_code while copying Modules + Update loader + wait for thread progress + (we need a membarrier for everybody to "see" the new code) + Set loader as new active + erts_unlock_code_ix(); +}*/ + + +/* Unlock code_ix (resume first waiter) +*/ +void erts_unlock_code_ix(void); +void erts_start_loader_code_ix(void); +void erts_commit_loader_code_ix(void); +void erts_abort_loader_code_ix(void); + +void erts_rwlock_old_code(void); +void erts_rwunlock_old_code(void); +void erts_rlock_old_code(void); +void erts_runlock_old_code(void); + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_old_code_rlocked(void); +int erts_is_code_ix_locked(void); +#endif + #include "export.h" #include "module.h" #include "register.h" -- cgit v1.2.3