void erts_whereis_name(Process *c_p, ErtsProcLocks c_p_locks, Eterm name, Process** proc, ErtsProcLocks need_locks, int flags, Port** port, int lock_port) { RegProc* rp = NULL; HashValue hval; int ix; HashBucket* b; #ifdef ERTS_SMP ErtsProcLocks current_c_p_locks; Port *pending_port = NULL; if (!c_p) c_p_locks = 0; current_c_p_locks = c_p_locks; restart: reg_safe_read_lock(c_p, ¤t_c_p_locks); /* Locked locks: * - port lock on pending_port if pending_port != NULL * - read reg lock * - current_c_p_locks (either c_p_locks or 0) on c_p */ #endif hval = REG_HASH(name); ix = hval % process_reg.size; b = process_reg.bucket[ix]; /* * Note: We have inlined the code from hash.c for speed. */ while (b) { if (((RegProc *) b)->name == name) { rp = (RegProc *) b; break; } b = b->next; } if (proc) { if (!rp) *proc = NULL; else { #ifdef ERTS_SMP if (!rp->p) *proc = NULL; else { if (need_locks) { erts_proc_safelock(c_p, current_c_p_locks, c_p_locks, rp->p, 0, need_locks); current_c_p_locks = c_p_locks; } if ((flags & ERTS_P2P_FLG_ALLOW_OTHER_X) || is_proc_alive(rp->p)) *proc = rp->p; else { if (need_locks) erts_smp_proc_unlock(rp->p, need_locks); *proc = NULL; } } #else if (rp->p && ((flags & ERTS_P2P_FLG_ALLOW_OTHER_X) || is_proc_alive(rp->p))) *proc = rp->p; else *proc = NULL; #endif if (*proc && (flags & ERTS_P2P_FLG_INC_REFC)) erts_proc_inc_refc(*proc); } } if (port) { if (!rp || !rp->pt) *port = NULL; else { #ifdef ERTS_SMP if (lock_port) { if (pending_port == rp->pt) pending_port = NULL; else { if (pending_port) { /* Ahh! Registered port changed while reg lock was unlocked... */ erts_port_release(pending_port); pending_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_read_unlock(); pending_port = erts_id2port(id); goto restart; } } ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(rp->pt)); } #endif *port = rp->pt; } } #ifdef ERTS_SMP if (c_p && !current_c_p_locks) erts_smp_proc_lock(c_p, c_p_locks); if (pending_port) erts_port_release(pending_port); #endif reg_read_unlock(); }
/* * 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; }