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; }
int scheduler_signal_exit_N(proc_t *proc, term_t source, term_t reason) { //printk("scheduler_signal_exit_N: pid %pt src %pt reason %pt\n", T(proc->pid), T(source), T(reason)); if (reason == A_KILL) { scheduler_dequeue_process(proc); scheduler_exit_process(proc, A_KILLED); return 0; } if (proc->trap_exit == A_TRUE) { term_t marshalled_reason = reason; int x = heap_copy_terms_N(&proc->hp, &marshalled_reason, 1); if (x < 0) { printk("Cannot marshal the exit reason, replacing with 'undefined'\n"); marshalled_reason = A_UNDEFINED; } // build {'EXIT',Pid,Reason} uint32_t *htop = heap_alloc_N(&proc->hp, 1 +3); if (htop == 0) return -NO_MEMORY; term_t msg = tag_tuple(htop); *htop++ = 3; *htop++ = AEXIT__; *htop++ = source; *htop++ = marshalled_reason; heap_set_top(&proc->hp, htop); x = scheduler_new_local_mail_N(proc, msg); if (x < 0) return x; } else { if (reason != A_NORMAL) { scheduler_dequeue_process(proc); scheduler_exit_process(proc, reason); return 0; } } return 0; }
int notify_monitors_N(term_t late, term_t reason) { monitor_t **p = &active_monitors; while ((*p) != 0) { if ((*p)->pid1 == late || (*p)->pid2 == late) { monitor_t *m = *p; *p = (*p)->next; if (m->pid2 == late) { // notify the watcher proc_t *watcher = scheduler_lookup(m->pid1); assert(watcher != 0); term_t ref = heap_remake_local_ref_N(&watcher->hp, m->ref_id); if (ref == noval) return -NO_MEMORY; term_t marshalled_reason = reason; int x = heap_copy_terms_N(&watcher->hp, &marshalled_reason, 1); if (x < 0) return x; uint32_t *htop = heap_alloc_N(&watcher->hp, 1 +5); if (htop == 0) return -NO_MEMORY; heap_set_top(&watcher->hp, htop +1 +5); htop[0] = 5; htop[1] = ADOWN__; htop[2] = ref; htop[3] = A_PROCESS; htop[4] = late; htop[5] = marshalled_reason; x = scheduler_new_local_mail_N(watcher, tag_tuple(htop)); if (x < 0) return x; } } else p = &(*p)->next; } return 0; }
term_t cbif_process_info2(proc_t *proc, term_t *regs) { term_t Pid = regs[0]; term_t What = regs[1]; if (!is_short_pid(Pid)) badarg(Pid); if (!is_atom(What)) badarg(What); proc_t *probe = scheduler_lookup(Pid); if (probe == 0) return A_UNDEFINED; term_t val; if (What == A_BACKTRACE) { //TODO: current stack trace is not enough val = A_UNDEFINED; } else if (What == A_BINARY) { //NB: BinInfo is documented to be a list, yet its contents is unspesfied val = int_to_term(probe->hp.total_pb_size, &probe->hp); } else if (What == A_CATCHLEVEL) { assert(fits_int(probe->catch_level)); val = tag_int(probe->catch_level); } else if (What == A_CURRENT_FUNCTION) { // NB: probe->cap.ip is valid even if proc == probe uint32_t *fi = backstep_to_func_info(probe->cap.ip); val = heap_tuple3(&proc->hp, fi[1], fi[2], tag_int(fi[3])); } else if (What == A_CURRENT_LOCATION) { // NB: probe->cap.ip is valid even if proc == probe uint32_t *fi = backstep_to_func_info(probe->cap.ip); term_t loc = nil; char fname[256]; uint32_t line = code_base_source_line(probe->cap.ip, fname, sizeof(fname)); if (line != 0) { term_t f = heap_strz(&proc->hp, fname); term_t t1 = heap_tuple2(&proc->hp, A_FILE, f); term_t t2 = heap_tuple2(&proc->hp, A_LINE, tag_int(line)); loc = heap_cons(&proc->hp, t2, nil); loc = heap_cons(&proc->hp, t1, loc); } val = heap_tuple4(&proc->hp, fi[1], fi[2], tag_int(fi[3]), loc); } else if (What == A_CURRENT_STACKTRACE) { val = probe->stack_trace; if (probe != proc) { int x = heap_copy_terms_N(&proc->hp, &val, 1); if (x < 0) fail(err_to_term(x)); } } else if (What == A_DICTIONARY) { val = probe->dictionary; if (probe != proc) { int x = heap_copy_terms_N(&proc->hp, &val, 1); if (x < 0) fail(err_to_term(x)); } } else if (What == A_ERROR_HANDLER) val = A_ERROR_HANDLER; else if (What == A_GARBAGE_COLLECTION) { //TODO val = A_UNDEFINED; } else if (What == A_GROUP_LEADER) val = probe->group_leader; else if (What == A_HEAP_SIZE) val = int_to_term(probe->hp.total_size, &proc->hp); else if (What == A_INITIAL_CALL) { val = (probe->init_call_mod == noval) ?A_UNDEFINED :heap_tuple3(&proc->hp, probe->init_call_mod, probe->init_call_func, tag_int(probe->init_call_arity)); } else if (What == A_LINKS) { term_t ids = nil; plink_t *pl = probe->links.active; while (pl != 0) { ids = heap_cons(&proc->hp, pl->id, ids); pl = pl->next; } val = ids; } else if (What == A_LAST_CALLS) { //TODO val = A_FALSE; } else if (What == A_MEMORY) { int pages = 0; pages += probe->home_node->index; pages += probe->stack_node->index; memnode_t *node = probe->hp.nodes; while (node != 0) { pages += node->index; node = node->next; } node = probe->mailbox.nodes; while (node != 0) { pages += node->index; node = node->next; } node = probe->links.nodes; while (node != 0) { pages += node->index; node = node->next; } int bytes = pages * PAGE_SIZE; val = int_to_term(bytes, &proc->hp); } else if (What == A_MESSAGE_BINARY) { //TODO val = A_UNDEFINED; } else if (What == A_MESSAGE_QUEUE_LEN) { int len = msg_queue_len(&probe->mailbox); assert(fits_int(len)); val = tag_int(len); } else if (What == A_MESSAGES) { int messages = nil; message_t *msg = probe->mailbox.head; while (msg != 0) { term_t marsh_body = msg->body; if (probe != proc) { int x = heap_copy_terms_N(&proc->hp, &marsh_body, 1); if (x < 0) fail(err_to_term(x)); } messages = heap_cons(&proc->hp, marsh_body, messages); msg = msg->next; } val = list_rev(messages, &proc->hp); } else if (What == A_MIN_HEAP_SIZE) val = tag_int(INIT_HEAP_SIZE); else if (What == A_MIN_BIN_VHEAP_SIZE) { //TODO val = A_UNDEFINED; } else if (What == A_MONITORED_BY) val = list_monitored_by(probe->pid, &proc->hp); else if (What == A_MONITORS) val = list_monitors(probe->pid, &proc->hp); else if (What == A_PRIORITY) val = probe->priority; else if (What == A_REDUCTIONS) val = int_to_term(probe->total_reds, &proc->hp); else if (What == A_REGISTERED_NAME) { val = probe->name; if (val == noval) return nil; // be backward compatible } else if (What == A_SEQUENTIAL_TRACE_TOKEN) { //TODO val = A_UNDEFINED; } else if (What == A_STACK_SIZE) { int ss = proc_stack_bottom(probe) - proc_stack_top(probe); assert(fits_int(ss)); val = tag_int(ss); } else if (What == A_STATUS) { if (probe->my_queue == MY_QUEUE_NORMAL || probe->my_queue == MY_QUEUE_HIGH || probe->my_queue == MY_QUEUE_LOW) val = A_RUNNABLE; else if (probe->my_queue == MY_QUEUE_INF_WAIT || probe->my_queue == MY_QUEUE_TIMED_WAIT) val = A_WAITING; else { assert(probe->my_queue == MY_QUEUE_NONE); val = A_RUNNING; } } else if (What == A_SUSPENDING) { //TODO val = nil; } else if (What == A_TOTAL_HEAP_SIZE) { int ss = proc_stack_bottom(probe) - proc_stack_top(probe); int ths = probe->hp.total_size + ss; assert(fits_int(ths)); val = tag_int(ths); } else if (What == A_TRACE) { //TODO val = A_UNDEFINED; } else if (What == A_TRAP_EXIT) val = probe->trap_exit; else badarg(What); return heap_tuple2(&proc->hp, What, val); }