term_t cbif_monitor2(proc_t *proc, term_t *regs) { term_t Type = regs[0]; term_t Item = regs[1]; if (Type != A_PROCESS) badarg(Type); if (!is_short_pid(Item) && !is_atom(Item)) badarg(Item); term_t ref = heap_make_ref(&proc->hp); proc_t *target = (is_short_pid(Item)) ?scheduler_lookup(Item) :scheduler_process_by_name(Item); if (target == 0) { // the process is gone already - send notification immediately // {'DOWN',#Ref<0.0.0.38>,process,<0.34.0>,noproc} term_t msg = heap_tuple5(&proc->hp, ADOWN__, ref, A_PROCESS, Item, A_NOPROC); int x = scheduler_new_local_mail_N(proc, msg); if (x < 0) fail(A_NO_MEMORY); } else { uint64_t ref_id = local_ref_id(ref); if (monitor(ref_id, proc->pid, target->pid) < 0) fail(A_NO_MEMORY); } return ref; }
static int erlang_fire(etimer_t *tm) { proc_t *to_proc = (is_atom(tm->dst)) ?scheduler_process_by_name(tm->dst) :scheduler_lookup(tm->dst); int rc = 0; if (to_proc != 0) { term_t marsh_msg = tm->msg; if (tm->sender != to_proc) // tm->sender may be zero { rc = heap_copy_terms_N(&to_proc->hp, &marsh_msg, 1); if (rc < 0) goto error; } term_t env_msg = marsh_msg; // {timeout,TRef,Msg} or Msg if (tm->enveloped) { term_t tref = heap_remake_local_ref_N(&to_proc->hp, tm->ref_id); if (tref == noval) { rc = -NO_MEMORY; goto error; } uint32_t *htop = heap_alloc_N(&to_proc->hp, 1 +3); if (htop == 0) { rc = -NO_MEMORY; goto error; } heap_set_top(&to_proc->hp, htop +1 +3); env_msg = tag_tuple(htop); htop[0] = 3; htop[1] = A_TIMEOUT; htop[2] = tref; htop[3] = marsh_msg; } rc = scheduler_new_local_mail_N(to_proc, env_msg); } error: if (tm->sender != 0) { assert(tm->sender->pending_timers > 0); tm->sender->pending_timers--; if (tm->sender->pending_timers == 0 && tm->sender->my_queue == MY_QUEUE_PENDING_TIMERS) proc_destroy(tm->sender); // destroy a zombie process } return rc; }