aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam')
-rw-r--r--erts/emulator/beam/bif.c5
-rw-r--r--erts/emulator/beam/dist.c159
-rw-r--r--erts/emulator/beam/dist.h3
-rw-r--r--erts/emulator/beam/erl_alloc.c2
-rw-r--r--erts/emulator/beam/erl_alloc.types2
-rw-r--r--erts/emulator/beam/erl_bits.c14
-rw-r--r--erts/emulator/beam/erl_db.c147
-rw-r--r--erts/emulator/beam/erl_db_util.h5
-rw-r--r--erts/emulator/beam/erl_lock_check.c2
-rw-r--r--erts/emulator/beam/erl_process.c137
-rw-r--r--erts/emulator/beam/erl_process.h14
-rw-r--r--erts/emulator/beam/erl_term.h12
12 files changed, 355 insertions, 147 deletions
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index d4a43f6e5f..bb237e378a 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1351,9 +1351,10 @@ BIF_RETTYPE exit_2(BIF_ALIST_2)
#ifdef ERTS_SMP
if (rp == BIF_P)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
- else
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ if (rp != BIF_P)
erts_smp_proc_dec_refc(rp);
- erts_smp_proc_unlock(rp, rp_locks);
#endif
/*
* We may have exited ourselves and may have to take action.
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 694460d702..02910fad90 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -917,6 +917,7 @@ int erts_net_message(Port *prt,
Eterm token_size;
ErtsMonitor *mon;
ErtsLink *lnk;
+ Uint tuple_arity;
int res;
#ifdef ERTS_DIST_MSG_DBG
int orig_len = len;
@@ -1003,29 +1004,23 @@ int erts_net_message(Port *prt,
#endif
if (is_not_tuple(arg) ||
- (tuple = tuple_val(arg), arityval(*tuple) < 1) ||
+ (tuple = tuple_val(arg), (tuple_arity = arityval(*tuple)) < 1) ||
is_not_small(tuple[1])) {
- erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "Invalid distribution message: %.200T", arg);
- erts_send_error_to_logger_nogl(dsbufp);
- goto data_error;
+ goto invalid_message;
}
token_size = 0;
switch (type = unsigned_val(tuple[1])) {
case DOP_LINK:
+ if (tuple_arity != 3) {
+ goto invalid_message;
+ }
from = tuple[2];
to = tuple[3]; /* local proc to link to */
if (is_not_pid(from) || is_not_pid(to)) {
- erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- PURIFY_MSG("data error");
- erts_dsprintf(dsbufp,
- "Invalid DOP_LINK distribution message: %.200T",
- arg);
- erts_send_error_to_logger_nogl(dsbufp);
- goto data_error;
+ goto invalid_message;
}
rp = erts_pid2proc_opt(NULL, 0,
@@ -1064,8 +1059,14 @@ int erts_net_message(Port *prt,
case DOP_UNLINK: {
ErtsDistLinkData dld;
+ if (tuple_arity != 3) {
+ goto invalid_message;
+ }
from = tuple[2];
to = tuple[3];
+ if (is_not_pid(from) || is_not_pid(to)) {
+ goto invalid_message;
+ }
rp = erts_pid2proc_opt(NULL, 0,
to, ERTS_PROC_LOCK_LINK,
@@ -1092,11 +1093,19 @@ int erts_net_message(Port *prt,
/* A remote process wants to monitor us, we get:
{DOP_MONITOR_P, Remote pid, local pid or name, ref} */
Eterm name;
+
+ if (tuple_arity != 4) {
+ goto invalid_message;
+ }
watcher = tuple[2];
watched = tuple[3]; /* local proc to monitor */
ref = tuple[4];
+ if (is_not_ref(ref)) {
+ goto invalid_message;
+ }
+
if (is_atom(watched)) {
name = watched;
rp = erts_whereis_process(NULL, 0,
@@ -1138,10 +1147,17 @@ int erts_net_message(Port *prt,
We get {DOP_DEMONITOR_P, Remote pid, Local pid or name, ref},
We need only the ref of course */
+ if (tuple_arity != 4) {
+ goto invalid_message;
+ }
/* watcher = tuple[2]; */
/* watched = tuple[3]; May be an atom in case of monitor name */
ref = tuple[4];
+ if(is_not_ref(ref)) {
+ goto invalid_message;
+ }
+
erts_smp_de_links_lock(dep);
mon = erts_remove_monitor(&(dep->monitors),ref);
erts_smp_de_links_unlock(dep);
@@ -1166,10 +1182,11 @@ int erts_net_message(Port *prt,
erts_destroy_monitor(mon);
break;
- case DOP_NODE_LINK: /* XXX never sent ?? */
- break;
-
case DOP_REG_SEND_TT:
+ if (tuple_arity != 5) {
+ goto invalid_message;
+ }
+
token_size = size_object(tuple[5]);
/* Fall through ... */
case DOP_REG_SEND:
@@ -1180,12 +1197,19 @@ int erts_net_message(Port *prt,
* There is intentionally no testing of the cookie (it is always '')
* from R9B and onwards.
*/
+ if (type != DOP_REG_SEND_TT && tuple_arity != 4) {
+ goto invalid_message;
+ }
+
#ifdef ERTS_DIST_MSG_DBG
dist_msg_dbg(&ede, "MSG", buf, orig_len);
#endif
from = tuple[2];
to = tuple[4];
+ if (is_not_pid(from) || is_not_atom(to)){
+ goto invalid_message;
+ }
rp = erts_whereis_process(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC);
if (rp) {
Uint xsize = (type == DOP_REG_SEND
@@ -1217,6 +1241,10 @@ int erts_net_message(Port *prt,
break;
case DOP_SEND_TT:
+ if (tuple_arity != 4) {
+ goto invalid_message;
+ }
+
token_size = size_object(tuple[4]);
/* Fall through ... */
case DOP_SEND:
@@ -1227,8 +1255,13 @@ int erts_net_message(Port *prt,
#ifdef ERTS_DIST_MSG_DBG
dist_msg_dbg(&ede, "MSG", buf, orig_len);
#endif
-
+ if (type != DOP_SEND_TT && tuple_arity != 3) {
+ goto invalid_message;
+ }
to = tuple[3];
+ if (is_not_pid(to)) {
+ goto invalid_message;
+ }
rp = erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_SMP_INC_REFC);
if (rp) {
Uint xsize = type == DOP_SEND ? 0 : ERTS_HEAP_FRAG_SIZE(token_size);
@@ -1266,11 +1299,19 @@ int erts_net_message(Port *prt,
Eterm sysname;
ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_MSG_SEND|ERTS_PROC_LOCK_LINK;
+ if (tuple_arity != 5) {
+ goto invalid_message;
+ }
+
/* watched = tuple[2]; */ /* remote proc which died */
/* watcher = tuple[3]; */
ref = tuple[4];
reason = tuple[5];
+ if(is_not_ref(ref)) {
+ goto invalid_message;
+ }
+
erts_smp_de_links_lock(dep);
sysname = dep->sysname;
mon = erts_remove_monitor(&(dep->monitors), ref);
@@ -1317,24 +1358,25 @@ int erts_net_message(Port *prt,
ErtsProcLocks rp_locks = ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCKS_XSIG_SEND;
/* 'from', which 'to' is linked to, died */
if (type == DOP_EXIT) {
- from = tuple[2];
- to = tuple[3];
- reason = tuple[4];
- token = NIL;
+ if (tuple_arity != 4) {
+ goto invalid_message;
+ }
+
+ from = tuple[2];
+ to = tuple[3];
+ reason = tuple[4];
+ token = NIL;
} else {
- from = tuple[2];
- to = tuple[3];
- token = tuple[4];
- reason = tuple[5];
+ if (tuple_arity != 5) {
+ goto invalid_message;
+ }
+ from = tuple[2];
+ to = tuple[3];
+ token = tuple[4];
+ reason = tuple[5];
}
- if (is_not_internal_pid(to)) {
- erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- PURIFY_MSG("data error");
- erts_dsprintf(dsbufp,
- "Invalid DOP_EXIT distribution message: %.200T",
- arg);
- erts_send_error_to_logger_nogl(dsbufp);
- goto data_error;
+ if (is_not_pid(from) || is_not_internal_pid(to)) {
+ goto invalid_message;
}
rp = erts_pid2proc(NULL, 0, to, rp_locks);
@@ -1381,15 +1423,24 @@ int erts_net_message(Port *prt,
ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND;
/* 'from' is send an exit signal to 'to' */
if (type == DOP_EXIT2) {
- from = tuple[2];
- to = tuple[3];
- reason = tuple[4];
- token = NIL;
+ if (tuple_arity != 4) {
+ goto invalid_message;
+ }
+ from = tuple[2];
+ to = tuple[3];
+ reason = tuple[4];
+ token = NIL;
} else {
- from = tuple[2];
- to = tuple[3];
- token = tuple[4];
- reason = tuple[5];
+ if (tuple_arity != 5) {
+ goto invalid_message;
+ }
+ from = tuple[2];
+ to = tuple[3];
+ token = tuple[4];
+ reason = tuple[5];
+ }
+ if (is_not_pid(from) || is_not_internal_pid(to)) {
+ goto invalid_message;
}
rp = erts_pid2proc_opt(NULL, 0, to, rp_locks,
ERTS_P2P_FLG_SMP_INC_REFC);
@@ -1408,10 +1459,14 @@ int erts_net_message(Port *prt,
break;
}
case DOP_GROUP_LEADER:
+ if (tuple_arity != 3) {
+ goto invalid_message;
+ }
from = tuple[2]; /* Group leader */
to = tuple[3]; /* new member */
- if (is_not_pid(from))
- break;
+ if (is_not_pid(from) || is_not_pid(to)) {
+ goto invalid_message;
+ }
rp = erts_pid2proc(NULL, 0, to, ERTS_PROC_LOCK_MAIN);
if (!rp)
@@ -1420,16 +1475,8 @@ int erts_net_message(Port *prt,
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
break;
- default: {
- erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp,
- "Illegal value in distribution dispatch switch: "
- "%.200T",
- arg);
- erts_send_error_to_logger_nogl(dsbufp);
- PURIFY_MSG("data error");
- goto data_error;
- }
+ default:
+ goto invalid_message;
}
erts_cleanup_offheap(&off_heap);
@@ -1441,8 +1488,14 @@ int erts_net_message(Port *prt,
UnUseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE);
ERTS_SMP_CHK_NO_PROC_LOCKS;
return 0;
-
+ invalid_message:
+ {
+ erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
+ erts_dsprintf(dsbufp, "Invalid distribution message: %.200T", arg);
+ erts_send_error_to_logger_nogl(dsbufp);
+ }
data_error:
+ PURIFY_MSG("data error");
erts_cleanup_offheap(&off_heap);
#ifndef HYBRID /* FIND ME! */
if (ctl != ctl_default) {
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index 9ccc3e5ba9..695a4fc3fe 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -52,7 +52,7 @@
#define DOP_SEND 2
#define DOP_EXIT 3
#define DOP_UNLINK 4
-#define DOP_NODE_LINK 5
+/* Ancient DOP_NODE_LINK (5) was here, can be reused */
#define DOP_REG_SEND 6
#define DOP_GROUP_LEADER 7
#define DOP_EXIT2 8
@@ -69,7 +69,6 @@
/* distribution trap functions */
extern Export* dsend2_trap;
extern Export* dsend3_trap;
-/*extern Export* dsend_nosuspend_trap;*/
extern Export* dlink_trap;
extern Export* dunlink_trap;
extern Export* dmonitor_node_trap;
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 7793f60f4f..e85e2d7e3f 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -1568,7 +1568,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
Eterm atoms[sizeof(size)/sizeof(Uint)];
Uint *uintps[sizeof(size)/sizeof(Uint)];
Eterm euints[sizeof(size)/sizeof(Uint)];
- int need_atom;
int want_tot_or_sys;
int length;
Eterm res = THE_NON_VALUE;
@@ -1756,7 +1755,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
/* Calculate values needed... */
want_tot_or_sys = want.total || want.system;
- need_atom = ERTS_MEM_NEED_ALL_ALCU || want.atom;
if (ERTS_MEM_NEED_ALL_ALCU) {
size.total = 0;
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 408ffd12f7..b7b9c6a133 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -263,6 +263,8 @@ type XPORTS_LIST SHORT_LIVED SYSTEM extra_port_list
type PROC_LCK_WTR LONG_LIVED SYSTEM proc_lock_waiter
type PROC_LCK_QS LONG_LIVED SYSTEM proc_lock_queues
type RUNQ_BLNS LONG_LIVED SYSTEM run_queue_balancing
+type MISC_AUX_WORK_Q LONG_LIVED SYSTEM misc_aux_work_q
+type MISC_AUX_WORK SHORT_LIVED SYSTEM misc_aux_work
+endif
#
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 88d2c06246..6f8a7436d5 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -555,10 +555,11 @@ fmt_int(byte *buf, Uint sz, Eterm val, Uint size, Uint flags)
{
unsigned long offs;
- ASSERT(size != 0);
offs = BIT_OFFSET(size);
if (is_small(val)) {
Sint v = signed_val(val);
+
+ ASSERT(size != 0); /* Tested by caller */
if (flags & BSF_LITTLE) { /* Little endian */
sz--;
COPY_VAL(buf,1,v,sz);
@@ -578,6 +579,9 @@ fmt_int(byte *buf, Uint sz, Eterm val, Uint size, Uint flags)
ErtsDigit* dp = big_v(val);
int n = MIN(sz,ds);
+ if (size == 0) {
+ return 0;
+ }
if (flags & BSF_LITTLE) {
sz -= n; /* pad with this amount */
if (sign) {
@@ -729,15 +733,13 @@ erts_new_bs_put_integer(ERL_BITS_PROTO_3(Eterm arg, Uint num_bits, unsigned flag
Uint b;
byte *iptr;
- if (num_bits == 0) {
- return 1;
- }
-
bit_offset = BIT_OFFSET(bin_offset);
if (is_small(arg)) {
Uint rbits = 8 - bit_offset;
- if (bit_offset + num_bits <= 8) {
+ if (num_bits == 0) {
+ return 1;
+ } else if (bit_offset + num_bits <= 8) {
/*
* All bits are in the same byte.
*/
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 65565cf3c7..3173d3510e 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -219,47 +219,68 @@ Export ets_select_continue_exp;
* Static traps
*/
static Export ets_delete_continue_exp;
-
-static ERTS_INLINE DbTable* db_ref(DbTable* tb, db_lock_kind_t kind)
-{
- if (tb != NULL && kind != LCK_READ) {
- erts_refc_inc(&tb->common.ref, 2);
- }
- return tb;
-}
-
-static ERTS_INLINE DbTable* db_unref(DbTable* tb, db_lock_kind_t kind)
+
+static void
+free_dbtable(DbTable* tb)
{
- if (kind != LCK_READ && !erts_refc_dectest(&tb->common.ref, 0)) {
#ifdef HARDDEBUG
if (erts_smp_atomic_read(&tb->common.memory_size) != sizeof(DbTable)) {
- erts_fprintf(stderr, "ets: db_unref memory remain=%ld fix=%x\n",
- erts_smp_atomic_read(&tb->common.memory_size)-sizeof(DbTable),
+ erts_fprintf(stderr, "ets: free_dbtable memory remain=%ld fix=%x\n",
+ erts_smp_atomic_read(&tb->common.memory_size)-sizeof(DbTable),
tb->common.fixations);
}
- erts_fprintf(stderr, "ets: db_unref(%T) deleted!!!\r\n",
+ erts_fprintf(stderr, "ets: free_dbtable(%T) deleted!!!\r\n",
tb->common.id);
- erts_fprintf(stderr, "ets: db_unref: meta_pid_to_tab common.memory_size = %ld\n",
+ erts_fprintf(stderr, "ets: free_dbtable: meta_pid_to_tab common.memory_size = %ld\n",
erts_smp_atomic_read(&meta_pid_to_tab->common.memory_size));
print_table(ERTS_PRINT_STDOUT, NULL, 1, meta_pid_to_tab);
- erts_fprintf(stderr, "ets: db_unref: meta_pid_to_fixed_tab common.memory_size = %ld\n",
+ erts_fprintf(stderr, "ets: free_dbtable: meta_pid_to_fixed_tab common.memory_size = %ld\n",
erts_smp_atomic_read(&meta_pid_to_fixed_tab->common.memory_size));
print_table(ERTS_PRINT_STDOUT, NULL, 1, meta_pid_to_fixed_tab);
-
#endif
#ifdef ERTS_SMP
erts_smp_rwmtx_destroy(&tb->common.rwlock);
erts_smp_mtx_destroy(&tb->common.fixlock);
#endif
ASSERT(is_immed(tb->common.heir_data));
- erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
+ erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable));
- return NULL;
- }
- return tb;
+}
+
+#ifdef ERTS_SMP
+static void
+chk_free_dbtable(void *vtb)
+{
+ DbTable * tb = (DbTable *) vtb;
+ ERTS_THR_MEMORY_BARRIER;
+ if (erts_refc_dectest(&tb->common.ref, 0) == 0)
+ free_dbtable(tb);
+}
+#endif
+
+static void schedule_free_dbtable(DbTable* tb)
+{
+ /*
+ * NON-SMP case: Caller is *not* allowed to access the *tb
+ * structure after this function has returned!
+ * SMP case: Caller is allowed to access the *tb structure
+ * until the bif has returned (we typically
+ * need to unlock the table lock after this
+ * function has returned).
+ */
+#ifdef ERTS_SMP
+ int scheds = erts_get_max_no_executing_schedulers();
+ ASSERT(scheds >= 1);
+ ASSERT(erts_refc_read(&tb->common.ref, 0) == 0);
+ erts_refc_init(&tb->common.ref, scheds);
+ ERTS_THR_MEMORY_BARRIER;
+ erts_smp_schedule_misc_aux_work(0, scheds, chk_free_dbtable, tb);
+#else
+ free_dbtable(tb);
+#endif
}
static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock,
@@ -270,8 +291,6 @@ static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock,
if (use_frequent_read_lock)
rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
#endif
- erts_refc_init(&tb->common.ref, 1);
- erts_refc_init(&tb->common.fixref, 0);
#ifdef ERTS_SMP
erts_smp_rwmtx_init_opt_x(&tb->common.rwlock, &rwmtx_opt,
rwname, tb->common.the_name);
@@ -280,7 +299,7 @@ static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock,
#endif
}
-static ERTS_INLINE void db_lock_take_over_ref(DbTable* tb, db_lock_kind_t kind)
+static ERTS_INLINE void db_lock(DbTable* tb, db_lock_kind_t kind)
{
#ifdef ERTS_SMP
ASSERT(tb != meta_pid_to_tab && tb != meta_pid_to_fixed_tab);
@@ -308,16 +327,13 @@ static ERTS_INLINE void db_lock_take_over_ref(DbTable* tb, db_lock_kind_t kind)
#endif
}
-static ERTS_INLINE void db_lock(DbTable* tb, db_lock_kind_t kind)
-{
- (void) db_ref(tb, kind);
-#ifdef ERTS_SMP
- db_lock_take_over_ref(tb, kind);
-#endif
-}
-
static ERTS_INLINE void db_unlock(DbTable* tb, db_lock_kind_t kind)
{
+ /*
+ * In NON-SMP case tb may refer to an already deallocated
+ * DbTable structure. That is, ONLY the SMP case is allowed
+ * to follow the tb pointer!
+ */
#ifdef ERTS_SMP
ASSERT(tb != meta_pid_to_tab && tb != meta_pid_to_fixed_tab);
@@ -344,7 +360,6 @@ static ERTS_INLINE void db_unlock(DbTable* tb, db_lock_kind_t kind)
}
}
#endif
- (void) db_unref(tb, kind); /* May delete table... */
}
@@ -371,6 +386,13 @@ DbTable* db_get_table_aux(Process *p,
DbTable *tb = NULL;
erts_smp_rwmtx_t *mtl = NULL;
+ /*
+ * IMPORTANT: Only scheduler threads are allowed
+ * to access tables. Memory management
+ * depend on it.
+ */
+ ASSERT(erts_get_scheduler_data());
+
if (is_small(id)) {
Uint slot = unsigned_val(id) & meta_main_tab_slot_mask;
if (!meta_already_locked) {
@@ -384,12 +406,8 @@ DbTable* db_get_table_aux(Process *p,
|| erts_lc_rwmtx_is_rwlocked(test_mtl));
}
#endif
- if (slot < db_max_tabs && IS_SLOT_ALIVE(slot)) {
- /* SMP: inc to prevent race, between unlock of meta_main_tab_lock
- * and the table locking outside the meta_main_tab_lock
- */
- tb = db_ref(meta_main_tab[slot].u.tb, kind);
- }
+ if (slot < db_max_tabs && IS_SLOT_ALIVE(slot))
+ tb = meta_main_tab[slot].u.tb;
}
else if (is_atom(id)) {
struct meta_name_tab_entry* bucket = meta_name_tab_bucket(id,&mtl);
@@ -403,16 +421,15 @@ DbTable* db_get_table_aux(Process *p,
if (bucket->pu.tb != NULL) {
if (is_atom(bucket->u.name_atom)) { /* single */
- if (bucket->u.name_atom == id) {
- tb = db_ref(bucket->pu.tb, kind);
- }
+ if (bucket->u.name_atom == id)
+ tb = bucket->pu.tb;
}
else { /* multi */
Uint cnt = unsigned_val(bucket->u.mcnt);
Uint i;
for (i=0; i<cnt; i++) {
if (bucket->pu.mvec[i].u.name_atom == id) {
- tb = db_ref(bucket->pu.mvec[i].pu.tb, kind);
+ tb = bucket->pu.mvec[i].pu.tb;
break;
}
}
@@ -420,7 +437,7 @@ DbTable* db_get_table_aux(Process *p,
}
}
if (tb) {
- db_lock_take_over_ref(tb, kind);
+ db_lock(tb, kind);
if (tb->common.id != id
|| ((tb->common.status & what) == 0 && p->id != tb->common.owner)) {
db_unlock(tb, kind);
@@ -594,11 +611,11 @@ done:
*/
static ERTS_INLINE void local_fix_table(DbTable* tb)
{
- erts_refc_inc(&tb->common.fixref, 1);
+ erts_refc_inc(&tb->common.ref, 1);
}
static ERTS_INLINE void local_unfix_table(DbTable* tb)
{
- if (erts_refc_dectest(&tb->common.fixref, 0) == 0) {
+ if (erts_refc_dectest(&tb->common.ref, 0) == 0) {
ASSERT(IS_HASH_TABLE(tb->common.status));
db_unfix_table_hash(&(tb->hash));
}
@@ -1414,6 +1431,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
tb->common.type = status & ERTS_ETS_TABLE_TYPES;
/* Note, 'type' is *read only* from now on... */
#endif
+ erts_refc_init(&tb->common.ref, 0);
db_init_lock(tb, status & (DB_FINE_LOCKED|DB_FREQ_READ),
"db_tab", "db_tab_fix");
tb->common.keypos = keypos;
@@ -1436,8 +1454,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
"** Too many db tables **\n");
free_heir_data(tb);
tb->common.meth->db_free_table(tb);
- erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
- ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable));
+ free_dbtable(tb);
BIF_ERROR(BIF_P, SYSTEM_LIMIT);
}
@@ -1471,9 +1488,10 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
free_slot(slot);
erts_smp_rwmtx_rwunlock(mmtl);
- db_lock_take_over_ref(tb,LCK_WRITE);
+ db_lock(tb,LCK_WRITE);
free_heir_data(tb);
tb->common.meth->db_free_table(tb);
+ schedule_free_dbtable(tb);
db_unlock(tb,LCK_WRITE);
BIF_ERROR(BIF_P, BADARG);
}
@@ -2845,8 +2863,7 @@ void init_db(void)
meta_pid_to_tab->common.meth = &db_hash;
meta_pid_to_tab->common.compress = 0;
- erts_refc_init(&meta_pid_to_tab->common.ref, 1);
- erts_refc_init(&meta_pid_to_tab->common.fixref, 0);
+ erts_refc_init(&meta_pid_to_tab->common.ref, 0);
/* Neither rwlock or fixlock used
db_init_lock(meta_pid_to_tab, "meta_pid_to_tab", "meta_pid_to_tab_FIX");*/
@@ -2878,8 +2895,7 @@ void init_db(void)
meta_pid_to_fixed_tab->common.meth = &db_hash;
meta_pid_to_fixed_tab->common.compress = 0;
- erts_refc_init(&meta_pid_to_fixed_tab->common.ref, 1);
- erts_refc_init(&meta_pid_to_fixed_tab->common.fixref, 0);
+ erts_refc_init(&meta_pid_to_fixed_tab->common.ref, 0);
/* Neither rwlock or fixlock used
db_init_lock(meta_pid_to_fixed_tab, "meta_pid_to_fixed_tab", "meta_pid_to_fixed_tab_FIX");*/
@@ -3037,12 +3053,10 @@ retry:
to_pid, to_locks,
ERTS_P2P_FLG_TRY_LOCK);
if (to_proc == ERTS_PROC_LOCK_BUSY) {
- db_ref(tb, LCK_NONE); /* while unlocked */
db_unlock(tb,LCK_WRITE);
to_proc = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
to_pid, to_locks);
db_lock(tb,LCK_WRITE);
- tb = db_unref(tb, LCK_NONE);
ASSERT(tb != NULL);
if (tb->common.owner != p->id) {
@@ -3153,13 +3167,13 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
erts_smp_rwmtx_t *mmtl = get_meta_main_tab_lock(ix);
erts_smp_rwmtx_rlock(mmtl);
if (!IS_SLOT_FREE(ix)) {
- tb = db_ref(GET_ANY_SLOT_TAB(ix), LCK_WRITE);
+ tb = GET_ANY_SLOT_TAB(ix);
ASSERT(tb);
}
erts_smp_rwmtx_runlock(mmtl);
if (tb) {
int do_yield;
- db_lock_take_over_ref(tb, LCK_WRITE);
+ db_lock(tb, LCK_WRITE);
/* Ownership may have changed since
we looked up the table. */
if (tb->common.owner != pid) {
@@ -3241,7 +3255,7 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
erts_smp_rwmtx_t *mmtl = get_meta_main_tab_lock(ix);
erts_smp_rwmtx_rlock(mmtl);
if (IS_SLOT_ALIVE(ix)) {
- tb = db_ref(meta_main_tab[ix].u.tb, LCK_WRITE_REC);
+ tb = meta_main_tab[ix].u.tb;
ASSERT(tb);
}
erts_smp_rwmtx_runlock(mmtl);
@@ -3249,7 +3263,7 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
int reds;
DbFixation** pp;
- db_lock_take_over_ref(tb, LCK_WRITE_REC);
+ db_lock(tb, LCK_WRITE_REC);
#ifdef ERTS_SMP
erts_smp_mtx_lock(&tb->common.fixlock);
#endif
@@ -3260,7 +3274,7 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
if ((*pp)->pid == pid) {
DbFixation* fix = *pp;
erts_aint_t diff = -((erts_aint_t) fix->counter);
- erts_refc_add(&tb->common.fixref,diff,0);
+ erts_refc_add(&tb->common.ref,diff,0);
*pp = fix->next;
erts_db_free(ERTS_ALC_T_DB_FIXATION,
tb, fix, sizeof(DbFixation));
@@ -3335,7 +3349,7 @@ static void fix_table_locked(Process* p, DbTable* tb)
#ifdef ERTS_SMP
erts_smp_mtx_lock(&tb->common.fixlock);
#endif
- erts_refc_inc(&tb->common.fixref,1);
+ erts_refc_inc(&tb->common.ref,1);
fix = tb->common.fixations;
if (fix == NULL) {
get_now(&(tb->common.megasec),
@@ -3389,7 +3403,7 @@ static void unfix_table_locked(Process* p, DbTable* tb,
for (pp = &tb->common.fixations; *pp != NULL; pp = &(*pp)->next) {
if ((*pp)->pid == p->id) {
DbFixation* fix = *pp;
- erts_refc_dec(&tb->common.fixref,0);
+ erts_refc_dec(&tb->common.ref,0);
--(fix->counter);
ASSERT(fix->counter >= 0);
if (fix->counter > 0) {
@@ -3419,7 +3433,6 @@ unlocked:
#ifdef ERTS_SMP
if (*kind_p == LCK_READ && tb->common.is_thread_safe) {
/* Must have write lock while purging pseudo-deleted (OTP-8166) */
- db_ref(tb, LCK_WRITE); /* LCK_WRITE need it, but not LCK_READ */
erts_smp_rwmtx_runlock(&tb->common.rwlock);
erts_smp_rwmtx_rwlock(&tb->common.rwlock);
*kind_p = LCK_WRITE;
@@ -3438,6 +3451,8 @@ static void free_fixations_locked(DbTable *tb)
fix = tb->common.fixations;
while (fix != NULL) {
+ erts_aint_t diff = -((erts_aint_t) fix->counter);
+ erts_refc_add(&tb->common.ref,diff,0);
next_fix = fix->next;
db_meta_lock(meta_pid_to_fixed_tab, LCK_WRITE_REC);
db_erase_bag_exact2(meta_pid_to_fixed_tab,
@@ -3561,10 +3576,6 @@ static int free_table_cont(Process *p,
mmtl = get_meta_main_tab_lock(tb->common.slot);
#ifdef ERTS_SMP
if (erts_smp_rwmtx_tryrwlock(mmtl) == EBUSY) {
- /*
- * We keep our increased refc over this op in order to
- * prevent the table from disapearing.
- */
erts_smp_rwmtx_rwunlock(&tb->common.rwlock);
erts_smp_rwmtx_rwlock(mmtl);
erts_smp_rwmtx_rwlock(&tb->common.rwlock);
@@ -3579,7 +3590,7 @@ static int free_table_cont(Process *p,
make_small(tb->common.slot));
db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC);
}
- db_unref(tb, LCK_NONE);
+ schedule_free_dbtable(tb);
BUMP_REDS(p, 100);
return 0;
}
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 10ba755e80..58ad39d772 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -206,8 +206,7 @@ typedef struct db_fixation {
*/
typedef struct db_table_common {
- erts_refc_t ref;
- erts_refc_t fixref; /* fixation counter */
+ erts_refc_t ref; /* fixation counter and delete counter */
#ifdef ERTS_SMP
erts_smp_rwmtx_t rwlock; /* rw lock on table */
erts_smp_mtx_t fixlock; /* Protects fixations,megasec,sec,microsec */
@@ -253,7 +252,7 @@ typedef struct db_table_common {
(DB_BAG | DB_SET | DB_DUPLICATE_BAG)))
#define IS_TREE_TABLE(Status) (!!((Status) & \
DB_ORDERED_SET))
-#define NFIXED(T) (erts_refc_read(&(T)->common.fixref,0))
+#define NFIXED(T) (erts_refc_read(&(T)->common.ref,0))
#define IS_FIXED(T) (NFIXED(T) != 0)
Eterm erts_ets_copy_object(Eterm, Process*);
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 7a6aaa6bbe..0185baee6b 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -177,6 +177,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "async_id", NULL },
{ "pix_lock", "address" },
{ "run_queues_lists", NULL },
+ { "misc_aux_work_queue", "index" },
+ { "misc_aux_work_pre_alloc_lock", "address" },
{ "sched_stat", NULL },
{ "run_queue_sleep_list", "address" },
#endif
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index bf553ae88a..ddfc27a93f 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -590,6 +590,122 @@ erts_sched_finish_poke(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flags)
}
}
+typedef struct erts_misc_aux_work_t_ erts_misc_aux_work_t;
+struct erts_misc_aux_work_t_ {
+ erts_misc_aux_work_t *next;
+ void (*func)(void *);
+ void *arg;
+};
+
+typedef struct {
+ erts_smp_mtx_t mtx;
+ erts_misc_aux_work_t *first;
+ erts_misc_aux_work_t *last;
+} erts_misc_aux_work_q_t;
+
+typedef union {
+ erts_misc_aux_work_q_t data;
+ char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_misc_aux_work_q_t))];
+} erts_algnd_misc_aux_work_q_t;
+
+static erts_algnd_misc_aux_work_q_t *misc_aux_work_queues;
+
+ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_aux_work,
+ erts_misc_aux_work_t,
+ 200,
+ ERTS_ALC_T_MISC_AUX_WORK)
+
+static void
+init_misc_aux_work(void)
+{
+ int ix;
+
+ init_misc_aux_work_alloc();
+
+ misc_aux_work_queues = erts_alloc(ERTS_ALC_T_MISC_AUX_WORK_Q,
+ (sizeof(erts_algnd_misc_aux_work_q_t)
+ *(erts_no_schedulers+1)));
+ if ((((UWord) misc_aux_work_queues) & ERTS_CACHE_LINE_MASK) != 0)
+ misc_aux_work_queues = ((erts_algnd_misc_aux_work_q_t *)
+ ((((UWord) misc_aux_work_queues)
+ & ~ERTS_CACHE_LINE_MASK)
+ + ERTS_CACHE_LINE_SIZE));
+
+ for (ix = 0; ix < erts_no_schedulers; ix++) {
+ erts_smp_mtx_init_x(&misc_aux_work_queues[ix].data.mtx,
+ "misc_aux_work_queue",
+ make_small(ix + 1));
+ misc_aux_work_queues[ix].data.first = NULL;
+ misc_aux_work_queues[ix].data.last = NULL;
+ }
+}
+
+static void
+handle_misc_aux_work(ErtsSchedulerData *esdp)
+{
+ int ix = (int) esdp->no - 1;
+ erts_misc_aux_work_t *mawp;
+
+ erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
+ mawp = misc_aux_work_queues[ix].data.first;
+ misc_aux_work_queues[ix].data.first = NULL;
+ misc_aux_work_queues[ix].data.last = NULL;
+ erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
+
+ while (mawp) {
+ erts_misc_aux_work_t *free_mawp;
+ mawp->func(mawp->arg);
+ free_mawp = mawp;
+ mawp = mawp->next;
+ misc_aux_work_free(free_mawp);
+ }
+}
+
+void
+erts_smp_schedule_misc_aux_work(int ignore_self,
+ int max_sched,
+ void (*func)(void *),
+ void *arg)
+{
+ int ix, ignore_ix = -1;
+
+ if (ignore_self) {
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ if (esdp)
+ ignore_ix = (int) esdp->no - 1;
+ }
+
+ ASSERT(0 <= max_sched && max_sched <= erts_no_schedulers);
+
+ for (ix = 0; ix < max_sched; ix++) {
+ erts_aint32_t aux_work;
+ erts_misc_aux_work_t *mawp;
+ ErtsSchedulerSleepInfo *ssi;
+ if (ix == ignore_ix)
+ continue;
+
+ mawp = misc_aux_work_alloc();
+
+ mawp->func = func;
+ mawp->arg = arg;
+ mawp->next = NULL;
+
+ erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
+ if (!misc_aux_work_queues[ix].data.last)
+ misc_aux_work_queues[ix].data.first = mawp;
+ else
+ misc_aux_work_queues[ix].data.last->next = mawp;
+ misc_aux_work_queues[ix].data.last = mawp;
+ erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
+
+ ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
+ aux_work = erts_smp_atomic32_bor(&ssi->aux_work,
+ ERTS_SSI_AUX_WORK_MISC);
+ if ((aux_work & ERTS_SSI_AUX_WORK_MISC) == 0)
+ erts_sched_poke(ssi);
+ }
+}
+
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
void
erts_smp_notify_check_children_needed(void)
@@ -615,6 +731,12 @@ blockable_aux_work(ErtsSchedulerData *esdp,
erts_aint32_t aux_work)
{
if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
+ if (aux_work & ERTS_SSI_AUX_WORK_MISC) {
+ aux_work = erts_smp_atomic32_band(&ssi->aux_work,
+ ~ERTS_SSI_AUX_WORK_MISC);
+ aux_work &= ~ERTS_SSI_AUX_WORK_MISC;
+ handle_misc_aux_work(esdp);
+ }
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
if (aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN) {
aux_work = erts_smp_atomic32_band(&ssi->aux_work,
@@ -2612,6 +2734,8 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
erts_smp_atomic32_init(&doing_sys_schedule, 0);
+ init_misc_aux_work();
+
#else /* !ERTS_SMP */
{
ErtsSchedulerData *esdp;
@@ -2739,6 +2863,19 @@ resume_process(Process *p)
p->rstatus = P_FREE;
}
+int
+erts_get_max_no_executing_schedulers(void)
+{
+#ifdef ERTS_SMP
+ if (erts_smp_atomic32_read(&schdlr_sspnd.changing))
+ return (int) erts_no_schedulers;
+ ERTS_THR_MEMORY_BARRIER;
+ return (int) erts_smp_atomic32_read(&schdlr_sspnd.active);
+#else
+ return 1;
+#endif
+}
+
#ifdef ERTS_SMP
static void
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 8e32121a68..d927415f37 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -236,16 +236,14 @@ typedef enum {
| ERTS_SSI_FLG_WAITING \
| ERTS_SSI_FLG_SUSPENDED)
-
-#if !defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK) \
- && defined(ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN)
#define ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
-#endif
#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 0)
+#define ERTS_SSI_AUX_WORK_MISC (((erts_aint32_t) 1) << 1)
#define ERTS_SSI_BLOCKABLE_AUX_WORK_MASK \
- (ERTS_SSI_AUX_WORK_CHECK_CHILDREN)
+ (ERTS_SSI_AUX_WORK_CHECK_CHILDREN \
+ | ERTS_SSI_AUX_WORK_MISC)
#define ERTS_SSI_NONBLOCKABLE_AUX_WORK_MASK \
(0)
@@ -1034,6 +1032,7 @@ int erts_sched_set_wakeup_limit(char *str);
#ifdef DEBUG
void erts_dbg_multi_scheduling_return_trap(Process *, Eterm);
#endif
+int erts_get_max_no_executing_schedulers(void);
#ifdef ERTS_SMP
ErtsSchedSuspendResult
erts_schedulers_state(Uint *, Uint *, Uint *, int);
@@ -1048,6 +1047,11 @@ int erts_is_multi_scheduling_blocked(void);
Eterm erts_multi_scheduling_blockers(Process *);
void erts_start_schedulers(void);
void erts_smp_notify_check_children_needed(void);
+void
+erts_smp_schedule_misc_aux_work(int ignore_self,
+ int max_sched,
+ void (*func)(void *),
+ void *arg);
#endif
void erts_sched_notify_check_cpu_bind(void);
Uint erts_active_schedulers(void);
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index b8e4473141..815cc1beae 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -193,7 +193,7 @@ struct erl_node_; /* Declared in erl_node_tables.h */
#endif
#define _is_aligned(x) (((Uint)(x) & 0x3) == 0)
#define _unchecked_make_boxed(x) ((Uint) COMPRESS_POINTER(x) + TAG_PRIMARY_BOXED)
-_ET_DECLARE_CHECKED(Eterm,make_boxed,Eterm*);
+_ET_DECLARE_CHECKED(Eterm,make_boxed,Eterm*)
#define make_boxed(x) _ET_APPLY(make_boxed,(x))
#if 1
#define _is_not_boxed(x) ((x) & (_TAG_PRIMARY_MASK-TAG_PRIMARY_BOXED))
@@ -204,12 +204,12 @@ _ET_DECLARE_CHECKED(int,is_boxed,Eterm)
#define is_boxed(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_BOXED)
#endif
#define _unchecked_boxed_val(x) ((Eterm*) EXPAND_POINTER(((x) - TAG_PRIMARY_BOXED)))
-_ET_DECLARE_CHECKED(Eterm*,boxed_val,Eterm);
+_ET_DECLARE_CHECKED(Eterm*,boxed_val,Eterm)
#define boxed_val(x) _ET_APPLY(boxed_val,(x))
/* cons cell ("list") access methods */
#define _unchecked_make_list(x) ((Uint) COMPRESS_POINTER(x) + TAG_PRIMARY_LIST)
-_ET_DECLARE_CHECKED(Eterm,make_list,Eterm*);
+_ET_DECLARE_CHECKED(Eterm,make_list,Eterm*)
#define make_list(x) _ET_APPLY(make_list,(x))
#if 1
#define _unchecked_is_not_list(x) ((x) & (_TAG_PRIMARY_MASK-TAG_PRIMARY_LIST))
@@ -226,7 +226,7 @@ _ET_DECLARE_CHECKED(int,is_not_list,Eterm)
#define _list_precond(x) (is_list(x))
#endif
#define _unchecked_list_val(x) ((Eterm*) EXPAND_POINTER((x) - TAG_PRIMARY_LIST))
-_ET_DECLARE_CHECKED(Eterm*,list_val,Eterm);
+_ET_DECLARE_CHECKED(Eterm*,list_val,Eterm)
#define list_val(x) _ET_APPLY(list_val,(x))
#define CONS(hp, car, cdr) \
@@ -995,14 +995,14 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm)
#endif
#define _unchecked_make_cp(x) ((Eterm) COMPRESS_POINTER(x))
-_ET_DECLARE_CHECKED(Eterm,make_cp,BeamInstr*);
+_ET_DECLARE_CHECKED(Eterm,make_cp,BeamInstr*)
#define make_cp(x) _ET_APPLY(make_cp,(x))
#define is_not_CP(x) ((x) & _CPMASK)
#define is_CP(x) (!is_not_CP(x))
#define _unchecked_cp_val(x) ((BeamInstr*) EXPAND_POINTER(x))
-_ET_DECLARE_CHECKED(BeamInstr*,cp_val,Eterm);
+_ET_DECLARE_CHECKED(BeamInstr*,cp_val,Eterm)
#define cp_val(x) _ET_APPLY(cp_val,(x))
#define make_catch(x) (((x) << _TAG_IMMED2_SIZE) | _TAG_IMMED2_CATCH)