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  * Assumes that main lock is locked (and only the main lock) on c_p.
166  *
167  * On return, c_p->value is set to one of the following values:
168  *
169  *   am_registered_name   The process or port already has a name.
170  *   am_notalive          The process is no longer alive.
171  *   am_none              Success or other error reason.
172  */
erts_register_name(Process * c_p,Eterm name,Eterm id)173 int erts_register_name(Process *c_p, Eterm name, Eterm id)
174 {
175     int res = 0;
176     Process *proc = NULL;
177     Port *port = NULL;
178     RegProc r, *rp;
179     ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(c_p);
180 
181     c_p->fvalue = am_none;
182     if (is_not_atom(name) || name == am_undefined)
183 	return res;
184 
185     if (c_p->common.id == id) /* A very common case I think... */
186 	proc = c_p;
187     else {
188 	if (is_not_internal_pid(id) && is_not_internal_port(id))
189 	    return res;
190 	erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
191 	if (is_internal_port(id)) {
192 	    port = erts_id2port(id);
193 	    if (!port)
194 		goto done;
195 	}
196     }
197 
198     {
199 	ErtsProcLocks proc_locks = proc ? ERTS_PROC_LOCK_MAIN : 0;
200 	reg_safe_write_lock(proc, &proc_locks);
201 
202 	if (proc && !proc_locks)
203 	    erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
204     }
205 
206     if (is_internal_pid(id)) {
207 	if (!proc)
208 	    proc = erts_pid2proc(NULL, 0, id, ERTS_PROC_LOCK_MAIN);
209 	r.p = proc;
210         if (!proc) {
211             c_p->fvalue = am_notalive;
212 	    goto done;
213 	}
214         if (proc->common.u.alive.reg) {
215             c_p->fvalue = am_registered_name;
216 	    goto done;
217         }
218 	r.pt = NULL;
219     }
220     else {
221 	ASSERT(!INVALID_PORT(port, id));
222 	ERTS_LC_ASSERT(erts_lc_is_port_locked(port));
223 	r.pt = port;
224         if (r.pt->common.u.alive.reg) {
225             c_p->fvalue = am_registered_name;
226 	    goto done;
227         }
228 	r.p = NULL;
229     }
230 
231     r.name = name;
232 
233     rp = (RegProc*) hash_put(&process_reg, (void*) &r);
234     if (proc && rp->p == proc) {
235 	if (IS_TRACED_FL(proc, F_TRACE_PROCS)) {
236 	    trace_proc(proc, ERTS_PROC_LOCK_MAIN,
237                        proc, am_register, name);
238 	}
239 	proc->common.u.alive.reg = rp;
240     }
241     else if (port && rp->pt == port) {
242     	if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
243 		trace_port(port, am_register, name);
244 	}
245 	port->common.u.alive.reg = rp;
246     }
247 
248     if ((rp->p && rp->p->common.id == id)
249 	|| (rp->pt && rp->pt->common.id == id)) {
250 	res = 1;
251     }
252 
253  done:
254     reg_write_unlock();
255     if (port)
256 	erts_port_release(port);
257     if (c_p != proc) {
258 	if (proc)
259 	    erts_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
260 	erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
261     }
262     return res;
263 }
264 
265 /*
266  *
267  * When smp support is enabled:
268  *   * Assumes that main lock is locked (and only main lock)
269  *     on c_p.
270  *
271  *   * am_undefined is returned if c_p became exiting.
272  */
273 
274 Eterm
erts_whereis_name_to_id(Process * c_p,Eterm name)275 erts_whereis_name_to_id(Process *c_p, Eterm name)
276 {
277     Eterm res = am_undefined;
278     ErtsProcLocks c_p_locks = 0;
279     RegProc *rp, tmpl;
280     if (c_p) {
281         c_p_locks = ERTS_PROC_LOCK_MAIN;
282         ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(c_p);
283     }
284     reg_safe_read_lock(c_p, &c_p_locks);
285 
286     if (c_p && !c_p_locks)
287         erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
288 
289     tmpl.name = name;
290     rp = hash_fetch(&process_reg, &tmpl, (H_FUN)reg_hash, (HCMP_FUN)reg_cmp);
291 
292     if (rp) {
293         if (rp->p)
294             res = rp->p->common.id;
295         else if (rp->pt)
296             res = rp->pt->common.id;
297     }
298 
299     reg_read_unlock();
300 
301     ASSERT(is_internal_pid(res) || is_internal_port(res) || res==am_undefined);
302 
303     return res;
304 }
305 
306 
307 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)308 erts_whereis_name(Process *c_p,
309 		  ErtsProcLocks c_p_locks,
310 		  Eterm name,
311 		  Process** proc,
312 		  ErtsProcLocks need_locks,
313 		  int flags,
314 		  Port** port,
315                   int lock_port)
316 {
317     RegProc* rp = NULL, tmpl;
318     ErtsProcLocks current_c_p_locks;
319     Port *pending_port = NULL;
320 
321     if (!c_p)
322 	c_p_locks = 0;
323     current_c_p_locks = c_p_locks;
324 
325  restart:
326 
327     reg_safe_read_lock(c_p, &current_c_p_locks);
328 
329     /* Locked locks:
330      * - port lock on pending_port if pending_port != NULL
331      * - read reg lock
332      * - current_c_p_locks (either c_p_locks or 0) on c_p
333      */
334 
335     tmpl.name = name;
336     rp = hash_fetch(&process_reg, &tmpl, (H_FUN)reg_hash, (HCMP_FUN)reg_cmp);
337 
338     if (proc) {
339 	if (!rp)
340 	    *proc = NULL;
341 	else {
342 	    if (!rp->p)
343 		*proc = NULL;
344 	    else {
345 		if (need_locks) {
346 		    erts_proc_safelock(c_p,
347 				       current_c_p_locks,
348 				       c_p_locks,
349 				       rp->p,
350 				       0,
351 				       need_locks);
352 		    current_c_p_locks = c_p_locks;
353 		}
354 		if ((flags & ERTS_P2P_FLG_ALLOW_OTHER_X) || is_proc_alive(rp->p))
355 		    *proc = rp->p;
356 		else {
357 		    if (need_locks)
358 			erts_proc_unlock(rp->p, need_locks);
359 		    *proc = NULL;
360 		}
361 	    }
362 	    if (*proc && (flags & ERTS_P2P_FLG_INC_REFC))
363 		erts_proc_inc_refc(*proc);
364 	}
365     }
366 
367     if (port) {
368 	if (!rp || !rp->pt)
369 	    *port = NULL;
370 	else {
371             if (lock_port) {
372                 if (pending_port == rp->pt)
373                     pending_port = NULL;
374                 else {
375                     if (pending_port) {
376                         /* Ahh! Registered port changed while reg lock
377                            was unlocked... */
378                         erts_port_release(pending_port);
379                         pending_port = NULL;
380                     }
381 
382                     if (erts_port_trylock(rp->pt) == EBUSY) {
383                         Eterm id = rp->pt->common.id; /* id read only... */
384                         /* Unlock all locks, acquire port lock, and restart... */
385                         if (current_c_p_locks) {
386                             erts_proc_unlock(c_p, current_c_p_locks);
387                             current_c_p_locks = 0;
388                         }
389                         reg_read_unlock();
390                         pending_port = erts_id2port(id);
391                         goto restart;
392                     }
393                 }
394                 ERTS_LC_ASSERT(erts_lc_is_port_locked(rp->pt));
395             }
396 	    *port = rp->pt;
397 	}
398     }
399 
400     if (c_p && !current_c_p_locks)
401 	erts_proc_lock(c_p, c_p_locks);
402     if (pending_port)
403 	erts_port_release(pending_port);
404 
405     reg_read_unlock();
406 }
407 
408 Process *
erts_whereis_process(Process * c_p,ErtsProcLocks c_p_locks,Eterm name,ErtsProcLocks need_locks,int flags)409 erts_whereis_process(Process *c_p,
410 		     ErtsProcLocks c_p_locks,
411 		     Eterm name,
412 		     ErtsProcLocks need_locks,
413 		     int flags)
414 {
415     Process *proc;
416     erts_whereis_name(c_p, c_p_locks, name, &proc, need_locks, flags, NULL, 0);
417     return proc;
418 }
419 
420 
421 /*
422  * Unregister a name
423  * Return 0 if not registered
424  * Otherwise returns 1
425  *
426  */
erts_unregister_name(Process * c_p,ErtsProcLocks c_p_locks,Port * c_prt,Eterm name)427 int erts_unregister_name(Process *c_p,
428 			 ErtsProcLocks c_p_locks,
429 			 Port *c_prt,
430 			 Eterm name)
431 {
432     int res = 0;
433     RegProc r, *rp;
434     Port *port = c_prt;
435     ErtsProcLocks current_c_p_locks = 0;
436 
437     /*
438      * SMP note: If 'c_prt != NULL' and 'c_prt->reg->name == name',
439      *           we are *not* allowed to temporarily release the lock
440      *           on c_prt.
441      */
442 
443     if (!c_p) {
444 	c_p_locks = 0;
445     }
446     current_c_p_locks = c_p_locks;
447 
448  restart:
449 
450     reg_safe_write_lock(c_p, &current_c_p_locks);
451 
452     r.name = name;
453     if (is_non_value(name)) {
454 	/* Unregister current process name */
455 	ASSERT(c_p);
456 	if (current_c_p_locks != c_p_locks) {
457 	    erts_proc_lock(c_p, c_p_locks);
458 	    current_c_p_locks = c_p_locks;
459 	}
460 	if (c_p->common.u.alive.reg) {
461 	    r.name = c_p->common.u.alive.reg->name;
462 	} else {
463 	    /* Name got unregistered while main lock was released */
464 	    res = 0;
465 	    goto done;
466 	}
467     }
468 
469     if ((rp = (RegProc*) hash_get(&process_reg, (void*) &r)) != NULL) {
470 	if (rp->pt) {
471 	    if (port != rp->pt) {
472 		if (port) {
473 		    ASSERT(port != c_prt);
474 		    erts_port_release(port);
475 		    port = NULL;
476 		}
477 
478 		if (erts_port_trylock(rp->pt) == EBUSY) {
479 		    Eterm id = rp->pt->common.id; /* id read only... */
480 		    /* Unlock all locks, acquire port lock, and restart... */
481 		    if (current_c_p_locks) {
482 			erts_proc_unlock(c_p, current_c_p_locks);
483 			current_c_p_locks = 0;
484 		    }
485 		    reg_write_unlock();
486 		    port = erts_id2port(id);
487 		    goto restart;
488 		}
489 		port = rp->pt;
490 	    }
491 
492 	    ASSERT(rp->pt == port);
493 	    ERTS_LC_ASSERT(erts_lc_is_port_locked(port));
494 
495 	    rp->pt->common.u.alive.reg = NULL;
496 
497 	    if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
498                 if (current_c_p_locks) {
499                     erts_proc_unlock(c_p, current_c_p_locks);
500                     current_c_p_locks = 0;
501                 }
502 		trace_port(port, am_unregister, r.name);
503 	    }
504 
505 	} else if (rp->p) {
506 
507 	    erts_proc_safelock(c_p,
508 			       current_c_p_locks,
509 			       c_p_locks,
510 			       rp->p,
511 			       (c_p == rp->p) ?  current_c_p_locks : 0,
512 			       ERTS_PROC_LOCK_MAIN);
513 	    current_c_p_locks = c_p_locks;
514 	    rp->p->common.u.alive.reg = NULL;
515 	    if (IS_TRACED_FL(rp->p, F_TRACE_PROCS)) {
516                 trace_proc(rp->p, (c_p == rp->p) ? c_p_locks : ERTS_PROC_LOCK_MAIN,
517                            rp->p, am_unregister, r.name);
518 	    }
519 	    if (rp->p != c_p) {
520 		erts_proc_unlock(rp->p, ERTS_PROC_LOCK_MAIN);
521 	    }
522 	}
523 	hash_erase(&process_reg, (void*) &r);
524 	res = 1;
525     }
526 
527  done:
528 
529     reg_write_unlock();
530     if (c_prt != port) {
531 	if (port) {
532 	    erts_port_release(port);
533 	}
534 	if (c_prt) {
535 	    erts_port_lock(c_prt);
536 	}
537     }
538     if (c_p && !current_c_p_locks) {
539 	erts_proc_lock(c_p, c_p_locks);
540     }
541     return res;
542 }
543 
process_reg_sz(void)544 int process_reg_sz(void)
545 {
546     int sz;
547     int lock = !ERTS_IS_CRASH_DUMPING;
548     if (lock)
549 	reg_read_lock();
550     sz = hash_table_sz(&process_reg);
551     if (lock)
552 	reg_read_unlock();
553     return sz;
554 }
555 
556 /**********************************************************************/
557 
558 #include "bif.h"
559 
560 struct registered_foreach_arg {
561     Eterm res;
562     Eterm *hp;
563 };
564 
565 static void
registered_foreach(RegProc * reg,struct registered_foreach_arg * arg)566 registered_foreach(RegProc *reg, struct registered_foreach_arg *arg)
567 {
568     arg->res = CONS(arg->hp, reg->name, arg->res);
569     arg->hp += 2;
570 }
571 
572 /* return a list of the registered processes */
573 
registered_0(BIF_ALIST_0)574 BIF_RETTYPE registered_0(BIF_ALIST_0)
575 {
576     struct registered_foreach_arg arg;
577     Uint need;
578     ErtsProcLocks proc_locks = ERTS_PROC_LOCK_MAIN;
579 
580     ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(BIF_P);
581     reg_safe_read_lock(BIF_P, &proc_locks);
582     if (!proc_locks)
583 	erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
584 
585     /* work out how much heap we need */
586     need = process_reg.nobjs * 2;
587 
588     if (need == 0) {
589 	reg_read_unlock();
590 	BIF_RET(NIL);
591     }
592 
593     /* scan through again and make the list */
594     arg.hp = HAlloc(BIF_P, need);
595     arg.res = NIL;
596 
597     hash_foreach(&process_reg, (HFOREACH_FUN)registered_foreach, &arg);
598 
599     reg_read_unlock();
600 
601     BIF_RET(arg.res);
602 }
603