aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/beam_debug.c31
-rw-r--r--erts/emulator/beam/erl_db_hash.c60
-rw-r--r--erts/emulator/beam/erl_debug.c3
-rw-r--r--erts/emulator/beam/erl_map.c5
-rw-r--r--erts/emulator/beam/erl_printf_term.c8
-rw-r--r--erts/emulator/beam/erl_process.c43
-rw-r--r--erts/emulator/beam/erl_term.c1
-rw-r--r--erts/emulator/beam/erl_term.h3
-rw-r--r--erts/emulator/beam/erl_threads.h10
-rw-r--r--erts/emulator/beam/utils.c1
10 files changed, 118 insertions, 47 deletions
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index c756de8c8e..c774a70d4c 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -298,8 +298,8 @@ erts_debug_disassemble_1(BIF_ALIST_1)
(void) erts_bld_uword(NULL, &hsz, (BeamInstr) code_ptr);
hp = HAlloc(p, hsz);
addr = erts_bld_uword(&hp, NULL, (BeamInstr) code_ptr);
- ASSERT(is_atom(funcinfo[0]));
- ASSERT(is_atom(funcinfo[1]));
+ ASSERT(is_atom(funcinfo[0]) || funcinfo[0] == NIL);
+ ASSERT(is_atom(funcinfo[1]) || funcinfo[1] == NIL);
mfa = TUPLE3(hp, (Eterm) funcinfo[0], (Eterm) funcinfo[1], make_small((Eterm) funcinfo[2]));
hp += 4;
return TUPLE3(hp, addr, bin, mfa);
@@ -669,7 +669,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
case op_new_map_dII:
case op_update_map_assoc_jsdII:
case op_update_map_exact_jsdII:
- case op_i_get_map_elements_fsI:
{
int n = unpacked[-1];
@@ -693,6 +692,32 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
}
}
break;
+ case op_i_get_map_elements_fsI:
+ {
+ int n = unpacked[-1];
+
+ while (n > 0) {
+ if (n % 3 == 1) {
+ erts_print(to, to_arg, " %X", ap[0]);
+ } else if (!is_header(ap[0])) {
+ erts_print(to, to_arg, " %T", (Eterm) ap[0]);
+ } else {
+ switch ((ap[0] >> 2) & 0x03) {
+ case R_REG_DEF:
+ erts_print(to, to_arg, " x(0)");
+ break;
+ case X_REG_DEF:
+ erts_print(to, to_arg, " x(%d)", ap[0] >> 4);
+ break;
+ case Y_REG_DEF:
+ erts_print(to, to_arg, " y(%d)", ap[0] >> 4);
+ break;
+ }
+ }
+ ap++, size++, n--;
+ }
+ }
+ break;
}
erts_print(to, to_arg, "\n");
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 81b0c4465c..98a2e2842a 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -148,8 +148,11 @@ static ERTS_INLINE Uint hash_to_ix(DbTableHash* tb, HashValue hval)
}
/* Remember a slot containing a pseudo-deleted item (INVALID_HASH)
-*/
-static ERTS_INLINE void add_fixed_deletion(DbTableHash* tb, int ix)
+ * Return false if we got raced by unfixing thread
+ * and the object should be deleted for real.
+ */
+static ERTS_INLINE int add_fixed_deletion(DbTableHash* tb, int ix,
+ erts_aint_t fixated_by_me)
{
erts_aint_t was_next;
erts_aint_t exp_next;
@@ -160,12 +163,18 @@ static ERTS_INLINE void add_fixed_deletion(DbTableHash* tb, int ix)
fixd->slot = ix;
was_next = erts_smp_atomic_read_acqb(&tb->fixdel);
do { /* Lockless atomic insertion in linked list: */
- exp_next = was_next;
+ if (NFIXED(tb) <= fixated_by_me) {
+ erts_db_free(ERTS_ALC_T_DB_FIX_DEL, (DbTable*)tb,
+ fixd, sizeof(FixedDeletion));
+ return 0; /* raced by unfixer */
+ }
+ exp_next = was_next;
fixd->next = (FixedDeletion*) exp_next;
- was_next = erts_smp_atomic_cmpxchg_relb(&tb->fixdel,
- (erts_aint_t) fixd,
- exp_next);
+ was_next = erts_smp_atomic_cmpxchg_mb(&tb->fixdel,
+ (erts_aint_t) fixd,
+ exp_next);
}while (was_next != exp_next);
+ return 1;
}
@@ -607,8 +616,8 @@ void db_unfix_table_hash(DbTableHash *tb)
|| (erts_smp_lc_rwmtx_is_rlocked(&tb->common.rwlock)
&& !tb->common.is_thread_safe));
restart:
- fixdel = (FixedDeletion*) erts_smp_atomic_xchg_acqb(&tb->fixdel,
- (erts_aint_t) NULL);
+ fixdel = (FixedDeletion*) erts_smp_atomic_xchg_mb(&tb->fixdel,
+ (erts_aint_t) NULL);
while (fixdel != NULL) {
FixedDeletion *fx = fixdel;
int ix = fx->slot;
@@ -1142,9 +1151,9 @@ int db_erase_hash(DbTable *tbl, Eterm key, Eterm *ret)
while(b != 0) {
if (has_live_key(tb,b,key,hval)) {
--nitems_diff;
- if (nitems_diff == -1 && IS_FIXED(tb)) {
+ if (nitems_diff == -1 && IS_FIXED(tb)
+ && add_fixed_deletion(tb, ix, 0)) {
/* Pseudo remove (no need to keep several of same key) */
- add_fixed_deletion(tb, ix);
b->hvalue = INVALID_HASH;
} else {
*bp = b->next;
@@ -1196,9 +1205,8 @@ static int db_erase_object_hash(DbTable *tbl, Eterm object, Eterm *ret)
++nkeys;
if (db_eq(&tb->common,object, &b->dbterm)) {
--nitems_diff;
- if (nkeys==1 && IS_FIXED(tb)) { /* Pseudo remove */
- add_fixed_deletion(tb,ix);
- b->hvalue = INVALID_HASH;
+ if (nkeys==1 && IS_FIXED(tb) && add_fixed_deletion(tb,ix,0)) {
+ b->hvalue = INVALID_HASH; /* Pseudo remove */
bp = &b->next;
b = b->next;
} else {
@@ -1820,14 +1828,17 @@ static int db_select_delete_hash(Process *p,
int did_erase = 0;
if (db_match_dbterm(&tb->common, p, mpi.mp, 0,
&(*current)->dbterm, NULL, 0) == am_true) {
+ HashDbTerm *del;
if (NFIXED(tb) > fixated_by_me) { /* fixated by others? */
if (slot_ix != last_pseudo_delete) {
- add_fixed_deletion(tb, slot_ix);
- last_pseudo_delete = slot_ix;
+ if (!add_fixed_deletion(tb, slot_ix, fixated_by_me))
+ goto do_erase;
+ last_pseudo_delete = slot_ix;
}
(*current)->hvalue = INVALID_HASH;
} else {
- HashDbTerm *del = *current;
+ do_erase:
+ del = *current;
*current = (*current)->next;
free_term(tb, del);
did_erase = 1;
@@ -1931,14 +1942,17 @@ static int db_select_delete_continue_hash(Process *p,
int did_erase = 0;
if (db_match_dbterm(&tb->common, p, mp, 0,
&(*current)->dbterm, NULL, 0) == am_true) {
+ HashDbTerm *del;
if (NFIXED(tb) > fixated_by_me) { /* fixated by others? */
if (slot_ix != last_pseudo_delete) {
- add_fixed_deletion(tb, slot_ix);
+ if (!add_fixed_deletion(tb, slot_ix, fixated_by_me))
+ goto do_erase;
last_pseudo_delete = slot_ix;
}
(*current)->hvalue = INVALID_HASH;
} else {
- HashDbTerm *del = *current;
+ do_erase:
+ del = *current;
*current = (*current)->next;
free_term(tb, del);
did_erase = 1;
@@ -2089,9 +2103,9 @@ static int db_take_hash(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
*ret = get_term_list(p, tb, key, hval, b, &bend);
while (b != bend) {
--nitems_diff;
- if (nitems_diff == -1 && IS_FIXED(tb)) {
+ if (nitems_diff == -1 && IS_FIXED(tb)
+ && add_fixed_deletion(tb, ix, 0)) {
/* Pseudo remove (no need to keep several of same key) */
- add_fixed_deletion(tb, ix);
bp = &b->next;
b->hvalue = INVALID_HASH;
b = b->next;
@@ -2131,7 +2145,7 @@ int db_mark_all_deleted_hash(DbTable *tbl)
for (i = 0; i < NACTIVE(tb); i++) {
if ((list = BUCKET(tb,i)) != NULL) {
- add_fixed_deletion(tb, i);
+ add_fixed_deletion(tb, i, 0);
do {
list->hvalue = INVALID_HASH;
list = list->next;
@@ -2908,8 +2922,8 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle)
ASSERT((&b->dbterm == handle->dbterm) == !(tb->common.compress && handle->flags & DB_MUST_RESIZE));
if (handle->flags & DB_NEW_OBJECT && cret != DB_ERROR_NONE) {
- if (IS_FIXED(tb)) {
- add_fixed_deletion(tb, hash_to_ix(tb, b->hvalue));
+ if (IS_FIXED(tb) && add_fixed_deletion(tb, hash_to_ix(tb, b->hvalue),
+ 0)) {
b->hvalue = INVALID_HASH;
} else {
*bp = b->next;
diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index 77a1e3d7cb..2dcfb79f00 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -189,6 +189,9 @@ pdisplay1(int to, void *to_arg, Process* p, Eterm obj)
case BINARY_DEF:
erts_print(to, to_arg, "#Bin");
break;
+ case MATCHSTATE_DEF:
+ erts_print(to, to_arg, "#Matchstate");
+ break;
default:
erts_print(to, to_arg, "unknown object %x", obj);
}
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index a91e36e3c5..ff2a355309 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -32,7 +32,9 @@
#include "global.h"
#include "erl_process.h"
#include "error.h"
+#define ERL_WANT_HIPE_BIF_WRAPPER__
#include "bif.h"
+#undef ERL_WANT_HIPE_BIF_WRAPPER__
#include "erl_binary.h"
#include "erl_map.h"
@@ -952,8 +954,11 @@ BIF_RETTYPE maps_keys_1(BIF_ALIST_1) {
BIF_P->fvalue = BIF_ARG_1;
BIF_ERROR(BIF_P, BADMAP);
}
+
/* maps:merge/2 */
+HIPE_WRAPPER_BIF_DISABLE_GC(maps_merge, 2)
+
BIF_RETTYPE maps_merge_2(BIF_ALIST_2) {
if (is_flatmap(BIF_ARG_1)) {
if (is_flatmap(BIF_ARG_2)) {
diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c
index 267c0b3ff4..2917d58932 100644
--- a/erts/emulator/beam/erl_printf_term.c
+++ b/erts/emulator/beam/erl_printf_term.c
@@ -467,10 +467,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
}
break;
case BINARY_DEF:
- if (header_is_bin_matchstate(*boxed_val(wobj))) {
- PRINT_STRING(res, fn, arg, "#MatchState");
- }
- else {
+ {
byte* bytep;
Uint bytesize = binary_size_rel(obj,obj_base);
Uint bitoffs;
@@ -633,6 +630,9 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
}
}
break;
+ case MATCHSTATE_DEF:
+ PRINT_STRING(res, fn, arg, "#MatchState");
+ break;
default:
PRINT_STRING(res, fn, arg, "<unknown:");
PRINT_POINTER(res, fn, arg, wobj);
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index ee1dd36d48..3b1b593d1c 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -7938,11 +7938,16 @@ sched_thread_func(void *vesdp)
ErtsThrPrgrCallbacks callbacks;
ErtsSchedulerData *esdp = vesdp;
Uint no = esdp->no;
+#ifdef ERTS_SMP
+ erts_tse_t *tse;
+#endif
erts_sched_init_time_sup(esdp);
#ifdef ERTS_SMP
- ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = erts_tse_fetch();
+ tse = erts_tse_fetch();
+ erts_tse_prepare_timed(tse);
+ ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = tse;
callbacks.arg = (void *) esdp->ssi;
callbacks.wakeup = thr_prgr_wakeup;
callbacks.prepare_wait = thr_prgr_prep_wait;
@@ -9177,6 +9182,10 @@ erts_set_process_priority(Process *p, Eterm value)
a = erts_smp_atomic32_cmpxchg_mb(&p->state, n, e);
} while (a != e);
+
+ if (slocked)
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+
}
switch (oprio) {
@@ -11522,10 +11531,14 @@ save_pending_exiter(Process *p)
{
ErtsProcList *plp;
ErtsRunQueue *rq;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
- rq = erts_get_runq_current(NULL);
+ if (!esdp)
+ rq = RUNQ_READ_RQ(&p->run_queue);
+ else
+ rq = esdp->run_queue;
plp = proclist_create(p);
@@ -11542,6 +11555,7 @@ save_pending_exiter(Process *p)
else
#endif
wake_scheduler(rq);
+
}
#endif
@@ -11730,23 +11744,21 @@ send_exit_signal(Process *c_p, /* current process if and only
if (need_locks
&& erts_smp_proc_trylock(rp, need_locks) == EBUSY) {
/* ... but we havn't got all locks on it ... */
- save_pending_exiter(rp);
+ save_pending_exiter(rp);
/*
* The pending exit will be discovered when next
* process is scheduled in
*/
- goto set_pending_exit;
- }
- else {
- /* ...and we have all locks on it... */
- *rp_locks = ERTS_PROC_LOCKS_ALL;
- set_proc_exiting(rp,
- state,
- (is_immed(rsn)
- ? rsn
- : copy_object(rsn, rp)),
- NULL);
+ goto set_pending_exit;
}
+ /* ...and we have all locks on it... */
+ *rp_locks = ERTS_PROC_LOCKS_ALL;
+ set_proc_exiting(rp,
+ state,
+ (is_immed(rsn)
+ ? rsn
+ : copy_object(rsn, rp)),
+ NULL);
}
else { /* Process running... */
@@ -12126,7 +12138,8 @@ erts_do_exit_process(Process* p, Eterm reason)
#endif
if (p->static_flags & ERTS_STC_FLG_SYSTEM_PROC)
- erl_exit(1, "System process %T terminated: %T\n", p->common.id, reason);
+ erl_exit(ERTS_DUMP_EXIT, "System process %T terminated: %T\n",
+ p->common.id, reason);
#ifdef ERTS_SMP
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c
index 89459fb278..e5050bfaa5 100644
--- a/erts/emulator/beam/erl_term.c
+++ b/erts/emulator/beam/erl_term.c
@@ -91,6 +91,7 @@ unsigned tag_val_def(Wterm x)
case (_TAG_HEADER_REFC_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
case (_TAG_HEADER_HEAP_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
case (_TAG_HEADER_SUB_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
+ case (_TAG_HEADER_BIN_MATCHSTATE >> _TAG_PRIMARY_SIZE): return MATCHSTATE_DEF;
}
break;
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index 90e35151b0..d5e91d80d9 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -1136,8 +1136,9 @@ _ET_DECLARE_CHECKED(Uint,y_reg_index,Uint)
#define FLOAT_DEF 0xe
#define BIG_DEF 0xf
#define SMALL_DEF 0x10
+#define MATCHSTATE_DEF 0x11 /* not a "real" term */
-#define FIRST_VACANT_TAG_DEF 0x11
+#define FIRST_VACANT_TAG_DEF 0x12
#if ET_DEBUG
extern unsigned tag_val_def_debug(Wterm, const char*, unsigned);
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index 5347979372..34f91e2ec8 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -649,6 +649,7 @@ ERTS_GLB_INLINE void erts_tsd_set(erts_tsd_key_t key, void *value);
ERTS_GLB_INLINE void * erts_tsd_get(erts_tsd_key_t key);
ERTS_GLB_INLINE erts_tse_t *erts_tse_fetch(void);
ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep);
+ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep);
ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep);
ERTS_GLB_INLINE void erts_tse_reset(erts_tse_t *ep);
ERTS_GLB_INLINE int erts_tse_wait(erts_tse_t *ep);
@@ -3461,6 +3462,15 @@ ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep)
#endif
}
+ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep)
+{
+#ifdef USE_THREADS
+ int res = ethr_event_prepare_timed(&((ethr_ts_event *) ep)->event);
+ if (res != 0)
+ erts_thr_fatal_error(res, "prepare timed");
+#endif
+}
+
ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep)
{
#ifdef USE_THREADS
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 342e91e983..e9d7c91ac9 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -844,7 +844,6 @@ Uint32 make_hash(Eterm term_arg)
Eterm hash = 0;
unsigned op;
- /* Must not collide with the real tag_val_def's: */
#define MAKE_HASH_TUPLE_OP (FIRST_VACANT_TAG_DEF)
#define MAKE_HASH_TERM_ARRAY_OP (FIRST_VACANT_TAG_DEF+1)
#define MAKE_HASH_CDR_PRE_OP (FIRST_VACANT_TAG_DEF+2)