1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 1996-2018. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 /*
22  * Manage registered processes.
23  */
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27 
28 #include "sys.h"
29 #include "erl_vm.h"
30 #include "global.h"
31 #include "hash.h"
32 #include "atom.h"
33 #include "register.h"
34 
35 static Hash process_reg;
36 
37 #define PREG_HASH_SIZE 10
38 
39 #define REG_HASH(term) ((HashValue) atom_val(term))
40 
41 static erts_rwmtx_t regtab_rwmtx;
42 
43 #define reg_try_read_lock()		erts_rwmtx_tryrlock(&regtab_rwmtx)
44 #define reg_try_write_lock()		erts_rwmtx_tryrwlock(&regtab_rwmtx)
45 #define reg_read_lock()			erts_rwmtx_rlock(&regtab_rwmtx)
46 #define reg_write_lock()		erts_rwmtx_rwlock(&regtab_rwmtx)
47 #define reg_read_unlock()		erts_rwmtx_runlock(&regtab_rwmtx)
48 #define reg_write_unlock()		erts_rwmtx_rwunlock(&regtab_rwmtx)
49 
50 static ERTS_INLINE void
reg_safe_read_lock(Process * c_p,ErtsProcLocks * c_p_locks)51 reg_safe_read_lock(Process *c_p, ErtsProcLocks *c_p_locks)
52 {
53     if (*c_p_locks) {
54 	ASSERT(c_p);
55 	ASSERT(c_p_locks);
56 	ASSERT(*c_p_locks);
57 
58 	if (reg_try_read_lock() != EBUSY) {
59 #ifdef ERTS_ENABLE_LOCK_CHECK
60 	    erts_proc_lc_might_unlock(c_p, *c_p_locks);
61 #endif
62 	    return;
63 	}
64 
65 	/* Release process locks in order to avoid deadlock */
66 	erts_proc_unlock(c_p, *c_p_locks);
67 	*c_p_locks = 0;
68     }
69 
70     reg_read_lock();
71 }
72 
73 static ERTS_INLINE void
reg_safe_write_lock(Process * c_p,ErtsProcLocks * c_p_locks)74 reg_safe_write_lock(Process *c_p, ErtsProcLocks *c_p_locks)
75 {
76     if (*c_p_locks) {
77 	ASSERT(c_p);
78 	ASSERT(c_p_locks);
79 	ASSERT(*c_p_locks);
80 
81 	if (reg_try_write_lock() != EBUSY) {
82 #ifdef ERTS_ENABLE_LOCK_CHECK
83 	    erts_proc_lc_might_unlock(c_p, *c_p_locks);
84 #endif
85 	    return;
86 	}
87 
88 	/* Release process locks in order to avoid deadlock */
89 	erts_proc_unlock(c_p, *c_p_locks);
90 	*c_p_locks = 0;
91     }
92 
93     reg_write_lock();
94 }
95 
96 
97 static ERTS_INLINE int
is_proc_alive(Process * p)98 is_proc_alive(Process *p)
99 {
100     return !ERTS_PROC_IS_EXITING(p);
101 }
102 
register_info(fmtfn_t to,void * to_arg)103 void register_info(fmtfn_t to, void *to_arg)
104 {
105     int lock = !ERTS_IS_CRASH_DUMPING;
106     if (lock)
107 	reg_read_lock();
108     hash_info(to, to_arg, &process_reg);
109     if (lock)
110 	reg_read_unlock();
111 }
112 
reg_hash(RegProc * obj)113 static HashValue reg_hash(RegProc* obj)
114 {
115     return REG_HASH(obj->name);
116 }
117 
reg_cmp(RegProc * tmpl,RegProc * obj)118 static int reg_cmp(RegProc *tmpl, RegProc *obj) {
119     return tmpl->name != obj->name;
120 }
121 
reg_alloc(RegProc * tmpl)122 static RegProc* reg_alloc(RegProc *tmpl)
123 {
124     RegProc* obj = (RegProc*) erts_alloc(ERTS_ALC_T_REG_PROC, sizeof(RegProc));
125     if (!obj) {
126 	erts_exit(ERTS_ERROR_EXIT, "Can't allocate %d bytes of memory\n", sizeof(RegProc));
127     }
128     obj->name = tmpl->name;
129     obj->p = tmpl->p;
130     obj->pt = tmpl->pt;
131     return obj;
132 }
133 
reg_free(RegProc * obj)134 static void reg_free(RegProc *obj)
135 {
136     erts_free(ERTS_ALC_T_REG_PROC, (void*) obj);
137 }
138 
init_register_table(void)139 void init_register_table(void)
140 {
141     HashFunctions f;
142     erts_rwmtx_opt_t rwmtx_opt = ERTS_RWMTX_OPT_DEFAULT_INITER;
143     rwmtx_opt.type = ERTS_RWMTX_TYPE_FREQUENT_READ;
144     rwmtx_opt.lived = ERTS_RWMTX_LONG_LIVED;
145 
146     erts_rwmtx_init_opt(&regtab_rwmtx, &rwmtx_opt, "reg_tab", NIL,
147         ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
148 
149     f.hash = (H_FUN) reg_hash;
150     f.cmp  = (HCMP_FUN) reg_cmp;
151     f.alloc = (HALLOC_FUN) reg_alloc;
152     f.free = (HFREE_FUN) reg_free;
153     f.meta_alloc = (HMALLOC_FUN) erts_alloc;
154     f.meta_free = (HMFREE_FUN) erts_free;
155     f.meta_print = (HMPRINT_FUN) erts_print;
156 
157     hash_init(ERTS_ALC_T_REG_TABLE, &process_reg, "process_reg",
158 	      PREG_HASH_SIZE, f);
159 }
160 
161 /*
162  * Register a process or port (can't be registered twice).
163  * Returns 0 if name, process or port is already registered.
164  *
165  * When smp support is enabled:
166  *   * Assumes that main lock is locked (and only main lock)
167  *     on c_p.
168  *
169  */
erts_register_name(Process * c_p,Eterm name,Eterm id)170 int erts_register_name(Process *c_p, Eterm name, Eterm id)
171 {
172     int res = 0;
173     Process *proc = NULL;
174     Port *port = NULL;
175     RegProc r, *rp;
176     ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(c_p);
177 
178     if (is_not_atom(name) || name == am_undefined)
179 	return res;
180 
181     if (c_p->common.id == id) /* A very common case I think... */
182 	proc = c_p;
183     else {
184 	if (is_not_internal_pid(id) && is_not_internal_port(id))
185 	    return res;
186 	erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
187 	if (is_internal_port(id)) {
188 	    port = erts_id2port(id);
189 	    if (!port)
190 		goto done;
191 	}
192     }
193 
194     {
195 	ErtsProcLocks proc_locks = proc ? ERTS_PROC_LOCK_MAIN : 0;
196 	reg_safe_write_lock(proc, &proc_locks);
197 
198 	if (proc && !proc_locks)
199 	    erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
200     }
201 
202     if (is_internal_pid(id)) {
203 	if (!proc)
204 	    proc = erts_pid2proc(NULL, 0, id, ERTS_PROC_LOCK_MAIN);
205 	r.p = proc;
206 	if (!proc)
207 	    goto done;
208 	if (proc->common.u.alive.reg)
209 	    goto done;
210 	r.pt = NULL;
211     }
212     else {
213 	ASSERT(!INVALID_PORT(port, id));
214 	ERTS_LC_ASSERT(erts_lc_is_port_locked(port));
215 	r.pt = port;
216 	if (r.pt->common.u.alive.reg)
217 	    goto done;
218 	r.p = NULL;
219     }
220 
221     r.name = name;
222 
223     rp = (RegProc*) hash_put(&process_reg, (void*) &r);
224     if (proc && rp->p == proc) {
225 	if (IS_TRACED_FL(proc, F_TRACE_PROCS)) {
226 	    trace_proc(proc, ERTS_PROC_LOCK_MAIN,
227                        proc, am_register, name);
228 	}
229 	proc->common.u.alive.reg = rp;
230     }
231     else if (port && rp->pt == port) {
232     	if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
233 		trace_port(port, am_register, name);
234 	}
235 	port->common.u.alive.reg = rp;
236     }
237 
238     if ((rp->p && rp->p->common.id == id)
239 	|| (rp->pt && rp->pt->common.id == id)) {
240 	res = 1;
241     }
242 
243  done:
244     reg_write_unlock();
245     if (port)
246 	erts_port_release(port);
247     if (c_p != proc) {
248 	if (proc)
249 	    erts_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
250 	erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
251     }
252     return res;
253 }
254 
255 /*
256  *
257  * When smp support is enabled:
258  *   * Assumes that main lock is locked (and only main lock)
259  *     on c_p.
260  *
261  *   * am_undefined is returned if c_p became exiting.
262  */
263 
264 Eterm
erts_whereis_name_to_id(Process * c_p,Eterm name)265 erts_whereis_name_to_id(Process *c_p, Eterm name)
266 {
267     Eterm res = am_undefined;
268     HashValue hval;
269     int ix;
270     HashBucket* b;
271     ErtsProcLocks c_p_locks = 0;
272     if (c_p) {
273         c_p_locks = ERTS_PROC_LOCK_MAIN;
274         ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(c_p);
275     }
276     reg_safe_read_lock(c_p, &c_p_locks);
277 
278     if (c_p && !c_p_locks)
279         erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
280 
281     hval = REG_HASH(name);
282     ix = hval % process_reg.size;
283     b = process_reg.bucket[ix];
284 
285     /*
286      * Note: We have inlined the code from hash.c for speed.
287      */
288 
289     while (b) {
290 	RegProc* rp = (RegProc *) b;
291 	if (rp->name == name) {
292 	    /*
293 	     * SMP NOTE: No need to lock registered entity since it cannot
294 	     * be removed without acquiring write reg lock and id on entity
295 	     * is read only.
296 	     */
297 	    if (rp->p)
298 		res = rp->p->common.id;
299 	    else if (rp->pt)
300 		res = rp->pt->common.id;
301 	    break;
302 	}
303 	b = b->next;
304     }
305 
306     reg_read_unlock();
307 
308     ASSERT(is_internal_pid(res) || is_internal_port(res) || res==am_undefined);
309 
310     return res;
311 }
312 
313 
314 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)315 erts_whereis_name(Process *c_p,
316 		  ErtsProcLocks c_p_locks,
317 		  Eterm name,
318 		  Process** proc,
319 		  ErtsProcLocks need_locks,
320 		  int flags,
321 		  Port** port,
322                   int lock_port)
323 {
324     RegProc* rp = NULL;
325     HashValue hval;
326     int ix;
327     HashBucket* b;
328     ErtsProcLocks current_c_p_locks;
329     Port *pending_port = NULL;
330 
331     if (!c_p)
332 	c_p_locks = 0;
333     current_c_p_locks = c_p_locks;
334 
335  restart:
336 
337     reg_safe_read_lock(c_p, &current_c_p_locks);
338 
339     /* Locked locks:
340      * - port lock on pending_port if pending_port != NULL
341      * - read reg lock
342      * - current_c_p_locks (either c_p_locks or 0) on c_p
343      */
344 
345     hval = REG_HASH(name);
346     ix = hval % process_reg.size;
347     b = process_reg.bucket[ix];
348 
349     /*
350      * Note: We have inlined the code from hash.c for speed.
351      */
352 
353     while (b) {
354 	if (((RegProc *) b)->name == name) {
355 	    rp = (RegProc *) b;
356 	    break;
357 	}
358 	b = b->next;
359     }
360 
361     if (proc) {
362 	if (!rp)
363 	    *proc = NULL;
364 	else {
365 	    if (!rp->p)
366 		*proc = NULL;
367 	    else {
368 		if (need_locks) {
369 		    erts_proc_safelock(c_p,
370 				       current_c_p_locks,
371 				       c_p_locks,
372 				       rp->p,
373 				       0,
374 				       need_locks);
375 		    current_c_p_locks = c_p_locks;
376 		}
377 		if ((flags & ERTS_P2P_FLG_ALLOW_OTHER_X) || is_proc_alive(rp->p))
378 		    *proc = rp->p;
379 		else {
380 		    if (need_locks)
381 			erts_proc_unlock(rp->p, need_locks);
382 		    *proc = NULL;
383 		}
384 	    }
385 	    if (*proc && (flags & ERTS_P2P_FLG_INC_REFC))
386 		erts_proc_inc_refc(*proc);
387 	}
388     }
389 
390     if (port) {
391 	if (!rp || !rp->pt)
392 	    *port = NULL;
393 	else {
394             if (lock_port) {
395                 if (pending_port == rp->pt)
396                     pending_port = NULL;
397                 else {
398                     if (pending_port) {
399                         /* Ahh! Registered port changed while reg lock
400                            was unlocked... */
401                         erts_port_release(pending_port);
402                         pending_port = NULL;
403                     }
404 
405                     if (erts_port_trylock(rp->pt) == EBUSY) {
406                         Eterm id = rp->pt->common.id; /* id read only... */
407                         /* Unlock all locks, acquire port lock, and restart... */
408                         if (current_c_p_locks) {
409                             erts_proc_unlock(c_p, current_c_p_locks);
410                             current_c_p_locks = 0;
411                         }
412                         reg_read_unlock();
413                         pending_port = erts_id2port(id);
414                         goto restart;
415                     }
416                 }
417                 ERTS_LC_ASSERT(erts_lc_is_port_locked(rp->pt));
418             }
419 	    *port = rp->pt;
420 	}
421     }
422 
423     if (c_p && !current_c_p_locks)
424 	erts_proc_lock(c_p, c_p_locks);
425     if (pending_port)
426 	erts_port_release(pending_port);
427 
428     reg_read_unlock();
429 }
430 
431 Process *
erts_whereis_process(Process * c_p,ErtsProcLocks c_p_locks,Eterm name,ErtsProcLocks need_locks,int flags)432 erts_whereis_process(Process *c_p,
433 		     ErtsProcLocks c_p_locks,
434 		     Eterm name,
435 		     ErtsProcLocks need_locks,
436 		     int flags)
437 {
438     Process *proc;
439     erts_whereis_name(c_p, c_p_locks, name, &proc, need_locks, flags, NULL, 0);
440     return proc;
441 }
442 
443 
444 /*
445  * Unregister a name
446  * Return 0 if not registered
447  * Otherwise returns 1
448  *
449  */
erts_unregister_name(Process * c_p,ErtsProcLocks c_p_locks,Port * c_prt,Eterm name)450 int erts_unregister_name(Process *c_p,
451 			 ErtsProcLocks c_p_locks,
452 			 Port *c_prt,
453 			 Eterm name)
454 {
455     int res = 0;
456     RegProc r, *rp;
457     Port *port = c_prt;
458     ErtsProcLocks current_c_p_locks = 0;
459 
460     /*
461      * SMP note: If 'c_prt != NULL' and 'c_prt->reg->name == name',
462      *           we are *not* allowed to temporarily release the lock
463      *           on c_prt.
464      */
465 
466     if (!c_p) {
467 	c_p_locks = 0;
468     }
469     current_c_p_locks = c_p_locks;
470 
471  restart:
472 
473     reg_safe_write_lock(c_p, &current_c_p_locks);
474 
475     r.name = name;
476     if (is_non_value(name)) {
477 	/* Unregister current process name */
478 	ASSERT(c_p);
479 	if (current_c_p_locks != c_p_locks) {
480 	    erts_proc_lock(c_p, c_p_locks);
481 	    current_c_p_locks = c_p_locks;
482 	}
483 	if (c_p->common.u.alive.reg) {
484 	    r.name = c_p->common.u.alive.reg->name;
485 	} else {
486 	    /* Name got unregistered while main lock was released */
487 	    res = 0;
488 	    goto done;
489 	}
490     }
491 
492     if ((rp = (RegProc*) hash_get(&process_reg, (void*) &r)) != NULL) {
493 	if (rp->pt) {
494 	    if (port != rp->pt) {
495 		if (port) {
496 		    ASSERT(port != c_prt);
497 		    erts_port_release(port);
498 		    port = NULL;
499 		}
500 
501 		if (erts_port_trylock(rp->pt) == EBUSY) {
502 		    Eterm id = rp->pt->common.id; /* id read only... */
503 		    /* Unlock all locks, acquire port lock, and restart... */
504 		    if (current_c_p_locks) {
505 			erts_proc_unlock(c_p, current_c_p_locks);
506 			current_c_p_locks = 0;
507 		    }
508 		    reg_write_unlock();
509 		    port = erts_id2port(id);
510 		    goto restart;
511 		}
512 		port = rp->pt;
513 	    }
514 
515 	    ASSERT(rp->pt == port);
516 	    ERTS_LC_ASSERT(erts_lc_is_port_locked(port));
517 
518 	    rp->pt->common.u.alive.reg = NULL;
519 
520 	    if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
521                 if (current_c_p_locks) {
522                     erts_proc_unlock(c_p, current_c_p_locks);
523                     current_c_p_locks = 0;
524                 }
525 		trace_port(port, am_unregister, r.name);
526 	    }
527 
528 	} else if (rp->p) {
529 
530 	    erts_proc_safelock(c_p,
531 			       current_c_p_locks,
532 			       c_p_locks,
533 			       rp->p,
534 			       (c_p == rp->p) ?  current_c_p_locks : 0,
535 			       ERTS_PROC_LOCK_MAIN);
536 	    current_c_p_locks = c_p_locks;
537 	    rp->p->common.u.alive.reg = NULL;
538 	    if (IS_TRACED_FL(rp->p, F_TRACE_PROCS)) {
539                 trace_proc(rp->p, (c_p == rp->p) ? c_p_locks : ERTS_PROC_LOCK_MAIN,
540                            rp->p, am_unregister, r.name);
541 	    }
542 	    if (rp->p != c_p) {
543 		erts_proc_unlock(rp->p, ERTS_PROC_LOCK_MAIN);
544 	    }
545 	}
546 	hash_erase(&process_reg, (void*) &r);
547 	res = 1;
548     }
549 
550  done:
551 
552     reg_write_unlock();
553     if (c_prt != port) {
554 	if (port) {
555 	    erts_port_release(port);
556 	}
557 	if (c_prt) {
558 	    erts_port_lock(c_prt);
559 	}
560     }
561     if (c_p && !current_c_p_locks) {
562 	erts_proc_lock(c_p, c_p_locks);
563     }
564     return res;
565 }
566 
process_reg_size(void)567 int process_reg_size(void)
568 {
569     int size;
570     int lock = !ERTS_IS_CRASH_DUMPING;
571     if (lock)
572 	reg_read_lock();
573     size = process_reg.size;
574     if (lock)
575 	reg_read_unlock();
576     return size;
577 }
578 
process_reg_sz(void)579 int process_reg_sz(void)
580 {
581     int sz;
582     int lock = !ERTS_IS_CRASH_DUMPING;
583     if (lock)
584 	reg_read_lock();
585     sz = hash_table_sz(&process_reg);
586     if (lock)
587 	reg_read_unlock();
588     return sz;
589 }
590 
591 /**********************************************************************/
592 
593 #include "bif.h"
594 
595 /* return a list of the registered processes */
596 
registered_0(BIF_ALIST_0)597 BIF_RETTYPE registered_0(BIF_ALIST_0)
598 {
599     int i;
600     Eterm res;
601     Uint need;
602     Eterm* hp;
603     HashBucket **bucket;
604     ErtsProcLocks proc_locks = ERTS_PROC_LOCK_MAIN;
605 
606     ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(BIF_P);
607     reg_safe_read_lock(BIF_P, &proc_locks);
608     if (!proc_locks)
609 	erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
610 
611     bucket = process_reg.bucket;
612 
613     /* work out how much heap we need & maybe garb, by scanning through
614        the registered process table */
615     need = 0;
616     for (i = 0; i < process_reg.size; i++) {
617 	HashBucket *b = bucket[i];
618 	while (b != NULL) {
619 	    need += 2;
620 	    b = b->next;
621 	}
622     }
623 
624     if (need == 0) {
625 	reg_read_unlock();
626 	BIF_RET(NIL);
627     }
628 
629     hp = HAlloc(BIF_P, need);
630 
631      /* scan through again and make the list */
632     res = NIL;
633 
634     for (i = 0; i < process_reg.size; i++) {
635 	HashBucket *b = bucket[i];
636 	while (b != NULL) {
637 	    RegProc *reg = (RegProc *) b;
638 
639 	    res = CONS(hp, reg->name, res);
640 	    hp += 2;
641 	    b = b->next;
642 	}
643     }
644 
645     reg_read_unlock();
646 
647     BIF_RET(res);
648 }
649