static void try_delete_node(void *venp) { ErlNode *enp = (ErlNode *) venp; erts_aint_t refc; erts_smp_rwmtx_rwlock(&erts_node_table_rwmtx); /* * Another thread might have looked up this node after we * decided to delete it (refc became zero). If so, the other * thread incremented refc twice. Once for the new reference * and once for this thread. * * If refc reach -1, noone has used the entry since we * set up the timer. Delete the entry. * * If refc reach 0, the entry is currently not in use * but has been used since we set up the timer. Set up a * new timer. * * If refc > 0, the entry is in use. Keep the entry. */ refc = erts_refc_dectest(&enp->refc, -1); if (refc == -1) (void) hash_erase(&erts_node_table, (void *) enp); erts_smp_rwmtx_rwunlock(&erts_node_table_rwmtx); if (refc == 0) erts_schedule_delete_node(enp); }
void erts_set_this_node(Eterm sysname, Uint creation) { erts_smp_mtx_lock(&erts_node_table_mtx); erts_smp_mtx_lock(&erts_dist_table_mtx); (void) hash_erase(&erts_dist_table, (void *) erts_this_dist_entry); erts_this_dist_entry->sysname = sysname; erts_this_dist_entry->creation = creation; (void) hash_put(&erts_dist_table, (void *) erts_this_dist_entry); (void) hash_erase(&erts_node_table, (void *) erts_this_node); erts_this_node->sysname = sysname; erts_this_node->creation = creation; (void) hash_put(&erts_node_table, (void *) erts_this_node); erts_smp_mtx_unlock(&erts_dist_table_mtx); erts_smp_mtx_unlock(&erts_node_table_mtx); }
void erts_set_this_node(Eterm sysname, Uint creation) { erts_smp_rwmtx_rwlock(&erts_node_table_rwmtx); erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx); (void) hash_erase(&erts_dist_table, (void *) erts_this_dist_entry); erts_this_dist_entry->sysname = sysname; erts_this_dist_entry->creation = creation; (void) hash_put(&erts_dist_table, (void *) erts_this_dist_entry); (void) hash_erase(&erts_node_table, (void *) erts_this_node); erts_this_node->sysname = sysname; erts_this_node->creation = creation; erts_this_node_sysname = erts_this_node_sysname_BUFFER; erts_snprintf(erts_this_node_sysname, sizeof(erts_this_node_sysname_BUFFER), "%T", sysname); (void) hash_put(&erts_node_table, (void *) erts_this_node); erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx); erts_smp_rwmtx_rwunlock(&erts_node_table_rwmtx); }
void erts_delete_node(ErlNode *enp) { ASSERT(enp != erts_this_node); if(enp != erts_this_node) { erts_smp_mtx_lock(&erts_node_table_mtx); /* * Another thread might have looked up this node after we * decided to delete it (refc became zero). If so, the other * thread incremented refc twice. Once for the new reference * and once for this thread. Therefore, delete node if refc * is 0 or -1 after a decrement. */ if (erts_refc_dectest(&enp->refc, -1) <= 0) (void) hash_erase(&erts_node_table, (void *) enp); erts_smp_mtx_unlock(&erts_node_table_mtx); } }
void erts_delete_dist_entry(DistEntry *dep) { ASSERT(dep != erts_this_dist_entry); if(dep != erts_this_dist_entry) { erts_smp_mtx_lock(&erts_dist_table_mtx); /* * Another thread might have looked up this dist entry after * we decided to delete it (refc became zero). If so, the other * thread incremented refc twice. Once for the new reference * and once for this thread. Therefore, delete dist entry if * refc is 0 or -1 after a decrement. */ if (erts_refc_dectest(&dep->refc, -1) <= 0) (void) hash_erase(&erts_dist_table, (void *) dep); erts_smp_mtx_unlock(&erts_dist_table_mtx); } }
/* Test that we can erase a key from the table */ int test_erase() { build_hash(); /* The key should no longer be found */ if(!hash_get(hash, (void*)"k1", (void**)&value)) { printf("Key k1 missing from initial hash.\n"); return 1; } /* make sure that unset values actually fail */ hash_erase(hash, (void*)"k1"); value = ""; /* The key should no longer be found */ if(hash_get(hash, (void*)"k1", (void**)&value)) { printf("Found: '%s'\n", value); return 1; } return 0; }
/* * Unregister a name * Return 0 if not registered * Otherwise returns 1 * */ int erts_unregister_name(Process *c_p, ErtsProcLocks c_p_locks, Port *c_prt, Eterm name) { int res = 0; RegProc r, *rp; Port *port = c_prt; ErtsProcLocks current_c_p_locks = 0; #ifdef ERTS_SMP /* * SMP note: If 'c_prt != NULL' and 'c_prt->reg->name == name', * we are *not* allowed to temporarily release the lock * on c_prt. */ if (!c_p) { c_p_locks = 0; } current_c_p_locks = c_p_locks; restart: reg_safe_write_lock(c_p, ¤t_c_p_locks); #endif r.name = name; if (is_non_value(name)) { /* Unregister current process name */ ASSERT(c_p); #ifdef ERTS_SMP if (current_c_p_locks != c_p_locks) { erts_smp_proc_lock(c_p, c_p_locks); current_c_p_locks = c_p_locks; } #endif if (c_p->common.u.alive.reg) { r.name = c_p->common.u.alive.reg->name; } else { /* Name got unregistered while main lock was released */ res = 0; goto done; } } if ((rp = (RegProc*) hash_get(&process_reg, (void*) &r)) != NULL) { if (rp->pt) { if (port != rp->pt) { #ifdef ERTS_SMP if (port) { ASSERT(port != c_prt); erts_port_release(port); port = NULL; } if (erts_smp_port_trylock(rp->pt) == EBUSY) { Eterm id = rp->pt->common.id; /* id read only... */ /* Unlock all locks, acquire port lock, and restart... */ if (current_c_p_locks) { erts_smp_proc_unlock(c_p, current_c_p_locks); current_c_p_locks = 0; } reg_write_unlock(); port = erts_id2port(id); goto restart; } #endif port = rp->pt; } ASSERT(rp->pt == port); ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(port)); rp->pt->common.u.alive.reg = NULL; if (IS_TRACED_FL(port, F_TRACE_PORTS)) { if (current_c_p_locks) { erts_smp_proc_unlock(c_p, current_c_p_locks); current_c_p_locks = 0; } trace_port(port, am_unregister, r.name); } } else if (rp->p) { #ifdef ERTS_SMP erts_proc_safelock(c_p, current_c_p_locks, c_p_locks, rp->p, (c_p == rp->p) ? current_c_p_locks : 0, ERTS_PROC_LOCK_MAIN); current_c_p_locks = c_p_locks; #endif rp->p->common.u.alive.reg = NULL; if (IS_TRACED_FL(rp->p, F_TRACE_PROCS)) { trace_proc(rp->p, (c_p == rp->p) ? c_p_locks : ERTS_PROC_LOCK_MAIN, rp->p, am_unregister, r.name); } #ifdef ERTS_SMP if (rp->p != c_p) { erts_smp_proc_unlock(rp->p, ERTS_PROC_LOCK_MAIN); } #endif } hash_erase(&process_reg, (void*) &r); res = 1; } done: reg_write_unlock(); if (c_prt != port) { if (port) { erts_port_release(port); } if (c_prt) { erts_smp_port_lock(c_prt); } } #ifdef ERTS_SMP if (c_p && !current_c_p_locks) { erts_smp_proc_lock(c_p, c_p_locks); } #endif return res; }
/* * Unregister a name * Return 0 if not registered * Otherwise returns 1 * */ int erts_unregister_name(Process *c_p, ErtsProcLocks c_p_locks, Port *c_prt, Eterm name) { int res = 0; RegProc r, *rp; Port *port = c_prt; #ifdef ERTS_SMP ErtsProcLocks current_c_p_locks; /* * SMP note: If 'c_prt != NULL' and 'c_prt->reg->name == name', * we are *not* allowed to temporarily release the lock * on c_prt. */ if (!c_p) c_p_locks = 0; current_c_p_locks = c_p_locks; restart: reg_safe_write_lock(c_p, ¤t_c_p_locks); #endif r.name = name; if ((rp = (RegProc*) hash_get(&process_reg, (void*) &r)) != NULL) { if (rp->pt) { #ifdef ERTS_SMP if (port != rp->pt) { if (port) { ERTS_SMP_LC_ASSERT(port != c_prt); erts_smp_port_unlock(port); port = NULL; } if (erts_smp_port_trylock(rp->pt) == EBUSY) { Eterm id = rp->pt->id; /* id read only... */ /* Unlock all locks, acquire port lock, and restart... */ if (current_c_p_locks) { erts_smp_proc_unlock(c_p, current_c_p_locks); current_c_p_locks = 0; } reg_read_unlock(); port = erts_id2port(id, NULL, 0); goto restart; } port = rp->pt; } #endif ERTS_SMP_LC_ASSERT(rp->pt == port && erts_lc_is_port_locked(port)); rp->pt->reg = NULL; if (IS_TRACED_FL(port, F_TRACE_PORTS)) { trace_port(port, am_unregister, name); } } else if (rp->p) { Process* p = rp->p; #ifdef ERTS_SMP erts_proc_safelock(c_p, current_c_p_locks, c_p_locks, rp->p, 0, ERTS_PROC_LOCK_MAIN); current_c_p_locks = c_p_locks; #endif p->reg = NULL; #ifdef ERTS_SMP if (rp->p != c_p) erts_smp_proc_unlock(rp->p, ERTS_PROC_LOCK_MAIN); #endif if (IS_TRACED_FL(p, F_TRACE_PROCS)) { trace_proc(c_p, p, am_unregister, name); } } hash_erase(&process_reg, (void*) &r); res = 1; } reg_write_unlock(); if (c_prt != port) { if (port) erts_smp_port_unlock(port); if (c_prt) erts_smp_port_lock(c_prt); } #ifdef ERTS_SMP if (c_p && !current_c_p_locks) erts_smp_proc_lock(c_p, c_p_locks); #endif return res; }