aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_db.c
diff options
context:
space:
mode:
authorRickard Green <[email protected]>2010-12-17 10:39:37 +0100
committerRickard Green <[email protected]>2010-12-17 10:39:37 +0100
commitf4f3beb158352b23959c09f8b0dfc83013d5fdf2 (patch)
tree6684443f968a9442d26afb6346e992466fc07c11 /erts/emulator/beam/erl_db.c
parent3e219dd7c05762fae05815db2813e765fd3b3a8f (diff)
parent8b18824e2b13e60fb1a067f80dbb228172f6a3d2 (diff)
downloadotp-f4f3beb158352b23959c09f8b0dfc83013d5fdf2.tar.gz
otp-f4f3beb158352b23959c09f8b0dfc83013d5fdf2.tar.bz2
otp-f4f3beb158352b23959c09f8b0dfc83013d5fdf2.zip
Merge branch 'rickard/ets-tab-delete/OTP-8999' into dev
* rickard/ets-tab-delete/OTP-8999: Safe deallocation of ETS-table structures Fix rwlock resource leak when hitting system limit Conflicts: erts/emulator/beam/erl_process.h erts/emulator/beam/erl_process.c
Diffstat (limited to 'erts/emulator/beam/erl_db.c')
-rw-r--r--erts/emulator/beam/erl_db.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 65565cf3c7..8875780842 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -227,10 +227,10 @@ static ERTS_INLINE DbTable* db_ref(DbTable* tb, db_lock_kind_t kind)
}
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",
@@ -257,6 +257,36 @@ static ERTS_INLINE DbTable* db_unref(DbTable* tb, db_lock_kind_t kind)
ASSERT(is_immed(tb->common.heir_data));
erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable));
+}
+
+#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 ERTS_INLINE DbTable* db_unref(DbTable* tb, db_lock_kind_t kind)
+{
+ if (kind != LCK_READ && erts_refc_dectest(&tb->common.ref, 0) == 0) {
+#ifdef ERTS_SMP
+ int scheds = erts_get_max_no_executing_schedulers();
+ if (scheds == 1)
+ free_dbtable(tb);
+ else {
+ int refs = scheds - 1;
+ ASSERT(scheds > 1);
+ ERTS_THR_MEMORY_BARRIER;
+ erts_refc_add(&tb->common.ref, refs, refs);
+ erts_smp_schedule_misc_aux_work(1, scheds, chk_free_dbtable, tb);
+ }
+#else
+ free_dbtable(tb);
+#endif
return NULL;
}
return tb;
@@ -1436,8 +1466,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));
+ db_unref(tb, LCK_NONE);
BIF_ERROR(BIF_P, SYSTEM_LIMIT);
}