aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/beam_bif_load.c10
-rw-r--r--erts/emulator/beam/beam_catches.c128
-rw-r--r--erts/emulator/beam/beam_catches.h7
-rw-r--r--erts/emulator/beam/beam_load.c92
-rw-r--r--erts/emulator/beam/erl_init.c4
-rw-r--r--erts/emulator/beam/global.h44
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; i<ERTS_NUM_CODE_IX; i++) {
+ bccix[i] = bccix[i-1];
+ }
+ /* For initial load: */
+ IF_DEBUG(bccix[erts_loader_code_ix()].is_prepared = 1);
+}
+
+
+static void gc_old_vec(beam_catch_t* vec)
+{
+ int i;
+ for (i=0; i<ERTS_NUM_CODE_IX; i++) {
+ if (bccix[i].beam_catches == vec) {
+ return;
+ }
+ }
+ erts_free(ERTS_ALC_T_CODE, vec);
+}
+
+
+void beam_catches_start_load(void)
+{
+ ErtsCodeIndex dst = erts_loader_code_ix();
+ ErtsCodeIndex src = erts_active_code_ix();
+ beam_catch_t* prev_vec = bccix[dst].beam_catches;
+
+ ASSERT(!bccix[src].is_prepared && !bccix[dst].is_prepared);
- beam_catches = erts_alloc(ERTS_ALC_T_CODE, sizeof(beam_catch_t)*DEFAULT_TABSIZE);
+ bccix[dst] = bccix[src];
+ gc_old_vec(prev_vec);
+ IF_DEBUG(bccix[dst].is_prepared = 1);
+}
+
+void beam_catches_end_load(int commit)
+{
+ IF_DEBUG(bccix[erts_loader_code_ix()].is_prepared = 0);
}
unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr)
{
int i;
+ struct bc_code_ix* p = &bccix[erts_loader_code_ix()];
+ ASSERT(p->is_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"