public static void do_trace(EProc proc, EAtom what, EObject info) throws Pausable { EPID pid = proc.get_trace_flags().tracer; EObject msg = ETuple4.make_tuple(am_trace, proc.self_handle(), what, info); pid.send(proc.self_handle(), msg); }
/** * @param s * @return */ public static EPID loopkup_pid(ESeq name) { String str = name.stringValue(); for (EProc p : EProc.all_tasks.values()) { if (p.self_handle().toString().equals(str)) { return p.self_handle(); } } throw ERT.badarg(name); }
public static EObject apply_list_last(EProc proc, EObject mod, EObject fun, ESeq seq, int len) throws Pausable { EAtom f = fun.testAtom(); ESeq a = seq.testSeq(); if (f == null || a == null) throw ERT.badarg(mod, fun, seq); EFun found = resolve_fun(mod, fun, len); if (len > 9) { // TODO: make it real tail recursion in stead return found.invoke(proc, a.toArray()); } proc.tail = found; a = a.reverse(); switch (len) { default: throw new NotImplemented(); case 9: proc.arg8 = a.head(); a = a.tail(); case 8: proc.arg7 = a.head(); a = a.tail(); case 7: proc.arg6 = a.head(); a = a.tail(); case 6: proc.arg5 = a.head(); a = a.tail(); case 5: proc.arg4 = a.head(); a = a.tail(); case 4: proc.arg3 = a.head(); a = a.tail(); case 3: proc.arg2 = a.head(); a = a.tail(); case 2: proc.arg1 = a.head(); a = a.tail(); case 1: proc.arg0 = a.head(); a = a.tail(); case 0: } return EProc.TAIL_MARKER; }
/** wait for howlong, for one more message to be available */ public static boolean wait_timeout(EProc proc, EObject howlong) throws Pausable { try { proc.check_exit(); if (ipclog.isLoggable(Level.FINE)) ipclog.fine("WAIT| " + proc + " waits for messages for " + howlong + " ms"); if (howlong == am_infinity) { proc.mbox.untilHasMessages(proc.midx + 1); proc.check_exit(); if (ipclog.isLoggable(Level.FINE)) ipclog.fine("WAIT| " + proc + " wakes up on message"); return true; } else { long now = System.currentTimeMillis(); if (proc.midx == 0 || proc.timeout_start == 0L) { proc.timeout_start = now; } EInteger ei; if ((ei = howlong.testInteger()) == null) throw new ErlangError(EAtom.intern("timeout_value")); long end = proc.timeout_start + ei.longValue(); long left = end - now; if (left < 0) { return false; } if (!proc.in_receive) { Task.sleep(left); return false; } else { if (ipclog.isLoggable(Level.FINE)) ipclog.fine( "WAIT| " + proc + " waiting for " + left + "ms for msg #" + (proc.midx + 1)); boolean res = proc.mbox.untilHasMessages(proc.midx + 1, left); proc.check_exit(); if (ipclog.isLoggable(Level.FINE)) ipclog.fine("WAIT| " + proc + " wakes up " + (res ? "on message" : "after timeout")); return res; } } } finally { proc.in_receive = false; } }
private static EObject send_to_remote( EProc proc, ETuple dest, EAtom node_name, EAtom reg_name, EObject msg, EObject options) throws Pausable { // INVARIANT: t == ETuple.make(node_name, reg_name) if (node_name == getLocalNode().node) { // We're talking to ourselves send_to_locally_registered(proc, reg_name, msg); return am_ok; // Even if the process does not exist. // TODO: Return 'noconnect' if options contain noconnect?... } else { // We're talking to another node if (ipclog.isLoggable(Level.FINE)) { ipclog.fine("sending msg " + dest + " ! " + msg); } EAbstractNode node = EPeer.get(node_name); if (node == null) { EObject[] args = (options != null ? new EObject[] {dest, msg, options} : new EObject[] {dest, msg, ERT.NIL}); return erlang__dsend__3.invoke(proc, args); } else { node.dsig_reg_send(proc.self_handle(), reg_name, msg); return am_ok; } } }
@BIF public static EObject send(EProc proc, final EObject pid, final EObject msg, EObject options) throws Pausable { // TODO handle ports also? proc.check_exit(); // log.log(Level.FINER, "ignored options to send: " + options); EHandle handle; EAtom reg_name; if ((handle = pid.testHandle()) != null) { send_to_handle(proc, handle, msg); return am_ok; } else if ((reg_name = pid.testAtom()) != null) { boolean ok = send_to_locally_registered(proc, reg_name, msg); if (ok) return am_ok; else throw badarg(pid, msg); } else { ETuple t; EAtom node_name; if ((t = pid.testTuple()) != null && t.arity() == 2 && (reg_name = t.elm(1).testAtom()) != null && (node_name = t.elm(2).testAtom()) != null) { return send_to_remote(proc, t, node_name, reg_name, msg, options); } else { // PID was of a bad type. ipclog.info("trying to send message to " + pid + " failed."); throw badarg(pid, msg); } } }
/** * @param owner * @param make * @throws Pausable */ @BIF(name = "!") public static EObject send(EProc proc, EObject pid, EObject msg) throws Pausable { // TODO handle ports also? proc.check_exit(); // log.log(Level.FINER, "ignored options to send: " + options); EHandle p; EAtom reg_name; if ((p = pid.testHandle()) != null) { send_to_handle(proc, p, msg); } else if ((reg_name = pid.testAtom()) != null) { send_to_locally_registered(proc, reg_name, msg); } else { ETuple t; EAtom node_name; if ((t = pid.testTuple()) != null && t.arity() == 2 && (reg_name = t.elm(1).testAtom()) != null && (node_name = t.elm(2).testAtom()) != null) { send_to_remote(proc, t, node_name, reg_name, msg, null); } else { // PID was of a bad type. ipclog.info("trying to send message to " + pid + " failed."); throw badarg(pid, msg); } } // Arguments were of valid types; return the message: return msg; }
/** peek mbox at current index (proc.midx), which is 0 upon entry to the loop. */ public static EObject loop_rec(EProc proc) { int idx = proc.midx; proc.in_receive = true; EObject msg = proc.mbox.peek(idx); if (ipclog.isLoggable(Level.FINE)) ipclog.fine("WAIT| entered loop #" + idx + " message=" + msg); return msg; }
@BIF public static EInteger trace(EProc self_proc, EObject arg0, EObject arg1, EObject arg2) { EInternalPID pid = arg0.testInternalPID(); EAtom all = arg0.testAtom(); EObject how = arg1.testBoolean(); ESeq flags = arg2.testSeq(); if ((pid == null && all != am_all) || how == null || flags == null) { throw ERT.badarg(arg0, arg1, arg2); } EInternalPID self = self_proc.self_handle(); if (all == am_all) { ESeq allprocs = EProc.processes(); int result = allprocs.length(); global_trace_flags.update(how == ERT.TRUE, flags, self); while (!allprocs.isNil()) { EProc proc = allprocs.head().testInternalPID().task(); allprocs = allprocs.tail(); if (proc.trace_flags != null) { proc.trace_flags.update(how == ERT.TRUE, flags, self); } } return ERT.box(result); } else { EProc proc = pid.task(); if (!proc.is_alive_dirtyread()) { return ESmall.ZERO; } if (proc.trace_flags == null) { proc.trace_flags = global_trace_flags.clone(); } proc.trace_flags.update(how == ERT.TRUE, flags, self); return ESmall.ONE; } }
/** wait forever, for one more message to be available */ public static void wait(EProc proc) throws Pausable { try { int idx = proc.midx + 1; if (ipclog.isLoggable(Level.FINE)) ipclog.fine("WAIT| " + proc + " waits for " + idx + " messages"); proc.mbox.untilHasMessages(idx); if (ipclog.isLoggable(Level.FINE)) ipclog.fine("WAIT| " + proc + " wakes up after timeout; now has " + (idx)); } finally { proc.in_receive = false; } }
@BIF public static EInteger trace_pattern(EProc proc, EObject arg0, EObject arg1, EObject arg2) { ETuple3 mfa = ETuple3.cast(arg0); EAtom mod, fun; if (mfa == null || (mod = mfa.elem1.testAtom()) == null || (fun = mfa.elem2.testAtom()) == null) { throw ERT.badarg(arg0, arg1, arg2); } int count = EModuleManager.trace_pattern(proc.self_handle(), mod, fun, mfa.elem3, arg1, arg2); return ERT.box(count); }
/** message did not match incoming, goto next message (will be followed by goto top-of-loop) */ public static void loop_rec_end(EProc proc) { proc.midx += 1; }
/** remove current message, and reset message index */ public static void remove_message(EProc proc) { proc.mbox.remove(proc.midx); proc.midx = 0; proc.timeout_start = 0L; proc.in_receive = false; }
/** message reception timed out, reset message index */ public static void timeout(EProc proc) { if (ipclog.isLoggable(Level.FINE)) ipclog.fine("WAIT| " + proc + " timed out"); proc.midx = 0; proc.timeout_start = 0L; proc.in_receive = false; }
private static void send_to_handle(EProc proc, EHandle handle, EObject msg) throws Pausable { int penalty = handle.send(proc.self_handle(), msg); proc.bump_reductions(penalty); }
public static void check_exit(EProc p) { p.check_exit(); }
public static void print_all_stack_traces() { System.err.println("== Trace =="); Mailbox<EObject> mbox = new Mailbox<>(EProc.process_count()); ESeq all = EProc.processes(); for (EObject o : all) { EInternalPID pid = (EInternalPID) o; pid.task().printStackTrace(mbox); } while (true) { EObject o = mbox.getb(1000); if (o == null) break; ETuple2 tup = ETuple2.cast(o); EHandle handle = tup.elm(1).testHandle(); ESeq stack = tup.elm(2).testSeq(); System.err.println("\n == " + handle + " : " + handle.name); for (EObject elm : stack) { ETuple4 tup4 = ETuple4.cast(elm); if (tup4 != null) { ESeq args = tup4.elem3.testSeq(); ESmall arity = tup4.elem3.testSmall(); if (arity == null && args != null) { arity = ERT.box(args.length()); } StringBuffer file_line = new StringBuffer(); ESeq info = tup4.elem4.testSeq(); if (info != null) { String file = "?"; int line = -1; for (EObject inf : info) { ETuple2 t; if ((t = ETuple2.cast(inf)) != null) { ESmall n; EString f; if (t.elem1 == ErlangException.am_line && ((n = t.elem2.testSmall()) != null)) { line = n.value; } else if (t.elem1 == ErlangException.am_file && ((f = t.elem2.testString()) != null)) { file = f.stringValue(); } } } if (line != -1) { file_line.append('(').append(file).append(':').append(line).append(')'); } } String module = tup4.elem1.toString(); String mfa; System.err.print(mfa = make_width(20, module) + ":" + tup4.elem2 + "/" + arity); System.err.println(" " + make_width(65 - mfa.length(), file_line.toString())); } else { System.err.println(elm); } } } }