aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_db.c
diff options
context:
space:
mode:
authorRickard Green <[email protected]>2010-12-15 00:56:56 +0100
committerRickard Green <[email protected]>2010-12-16 12:12:25 +0100
commit8b18824e2b13e60fb1a067f80dbb228172f6a3d2 (patch)
tree1a1a5bd6f105eeee03cf38a35d2b9a24c7f20ba8 /erts/emulator/beam/erl_db.c
parent766c7cabb1545418bf59e8dcfcc1a5fae8b01d40 (diff)
downloadotp-8b18824e2b13e60fb1a067f80dbb228172f6a3d2.tar.gz
otp-8b18824e2b13e60fb1a067f80dbb228172f6a3d2.tar.bz2
otp-8b18824e2b13e60fb1a067f80dbb228172f6a3d2.zip
Safe deallocation of ETS-table structures
Ensure that all threads potentially accessing an ETS-table have dropped all references to the table before deallocating it.
Diffstat (limited to 'erts/emulator/beam/erl_db.c')
-rw-r--r--erts/emulator/beam/erl_db.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 0dfc0e721f..e662b17592 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;