Package erjang

Source Code of erjang.ERT$NullInputStream

/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

package erjang;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import erjang.codegen.EFunCG;
import kilim.Mailbox;
import kilim.Pausable;
import kilim.Task;
import erjang.driver.Drivers;
import erjang.driver.EAsync;
import erjang.driver.EDriver;
import erjang.driver.EDriverTask;
import erjang.driver.efile.Posix;
import erjang.m.java.JavaObject;
import erjang.m.re.ECompiledRE;

@Module(value = "erlang")
public class ERT {

  public static Logger log = Logger.getLogger("erjang");
  static Logger ipclog = Logger.getLogger("erjang.ipc");
  public static EAtom am_badsig = EAtom.intern("badsig");
  public static EAtom am_file = EAtom.intern("file");
  public static EAtom am_line = EAtom.intern("line");

  public static EObject raise(EObject trace, EObject value) throws ErlangException {
    // log.warning("raise "+trace);
    if (trace instanceof ErlangException.ExceptionAsObject) {
      ErlangException etrace = ((ErlangException.ExceptionAsObject) trace).getException();
      EAtom clazz = etrace.getExClass();
      ESeq traz = etrace.getLazyTrace();
      throw new ErlangRaise(clazz, value, traz);
    } else if (trace==am_exit || trace==am_error || trace==am_throw) {
      log.warning("Pre-R10-1 exception style is not supported.");
    }

    ESeq trz;
    if ((trz = trace.testSeq()) != null) {
      throw new ErlangRaise(am_error, value, trz);
    }

    Throwable error = new Throwable("bad argument to raise2 :: "+ trace.getClass().getName());
    log.log(Level.WARNING, "bad argument to raise2: ("+value+", "+trace+")", error);
    throw ERT.badarg(trace, value);
  }

  public static final EAtom am_badarg = EAtom.intern("badarg");
  public static final EAtom am_notsup = EAtom.intern("notsup");
  public static final EAtom AM_BADMATCH = EAtom.intern("badmatch");
  public static final EAtom AM_BADARITH = EAtom.intern("badarith");
  public static final EAtom am_module = EAtom.intern("module");

  public static ECons cons(EObject h, EObject t) {
    return t.cons(h);
  }

  public static ErlangError badarg() {
    throw new ErlangError(am_badarg);
  }

  public static ErlangError notsup() {
    throw new ErlangError(am_notsup);
  }

  public static ErlangError badarg(EObject... args) {
    throw new ErlangError(am_badarg, args);
  }

  /** Utility method throws <code>erlang:error('badarg', [o1, o2])</code>. */
  public static ErlangError badarg(EObject o1, EObject o2) throws ErlangError {
    throw new ErlangError(am_badarg, NIL.cons(o2).cons(o1));
  }

  public static ErlangError badarg(EObject o1) throws ErlangError {
    throw new ErlangError(am_badarg, NIL.cons(o1));
  }

  public static ErlangError badarith(EObject... args) {
    throw new ErlangError(AM_BADARITH, args);
  }

  public static ErlangError badarith(EObject o1, EObject o2) throws ErlangError {
    throw new ErlangError(AM_BADARITH, NIL.cons(o2).cons(o1));
  }

  public static ErlangError badarith(int o1, EObject o2) {
    throw new ErlangError(AM_BADARITH, NIL.cons(o2).cons(o1));
  }

  public static ErlangError badarith(EObject o1, int o2) {
    throw new ErlangError(AM_BADARITH, NIL.cons(o2).cons(o1));
  }

  public static ErlangError badarith(double o1, EObject o2) {
    throw new ErlangError(AM_BADARITH, NIL.cons(o2).cons(o1));
  }

  public static ErlangError badarith(EObject o1, double o2) {
    throw new ErlangError(AM_BADARITH, NIL.cons(o2).cons(o1));
  }

  public static ErlangError badarith(BigInteger o1, EObject o2) {
    throw new ErlangError(AM_BADARITH, NIL.cons(o2).cons(o1));
  }

  public static ErlangError badfun(EObject o) {
    throw new ErlangError(new ETuple2(am_badfun, o));
  }


  public static final EAtom TRUE = EAtom.intern("true");
  public static final EAtom FALSE = EAtom.intern("false");

  public static boolean eq(EObject o1, EObject o2) {
    return o1 == null ? o2 == null : o1.equals(o2);
  }

  public static boolean eq(EAtom o1, EAtom o2) {
    return o1 == o2;
  }

  public static EAtom as_atom_or_null(EObject o) {
    return o == null ? null : o.testAtom();
  }

  public static ECons as_nonempty_list_or_null(EObject o) {
    return o == null ? null : o.testNonEmptyList();
  }

  public static ENil as_nil_or_null(EObject o) {
    return o == null ? ERT.NIL : o.testNil();
  }

  public static EDouble as_float_or_null(EObject o) {
    return o == null ? null : o.testFloat();
  }

  /**
   * @param s
   * @return
   */
  public static EPID loopkup_pid(ESeq name) {
    throw new NotImplemented();
  }

  // "definer" holds a reference to ClassLoader#defineClass
  static private final Method definer;
  static {
    try {
      definer = ClassLoader.class.getDeclaredMethod("defineClass",
          new Class[] { String.class, byte[].class, int.class,
              int.class });
      definer.setAccessible(true);
    } catch (Exception e) {
      throw new ErlangError(e);
    }
  }

  /**
   * @param classLoader
   * @param name
   * @param data
   * @param i
   * @param length
   * @return
   */
  @SuppressWarnings("unchecked")
  public static <T> Class<? extends T> defineClass(ClassLoader classLoader,
      String name, byte[] data) {
    /*
     * Class<? extends ETuple> res = (Class<? extends ETuple>)
     * loader2.define(name, data);
     */
    Class<? extends T> res;
    try {
      res = (Class<? extends T>) definer.invoke(classLoader, name.replace('/', '.'), data, 0,
          data.length);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    if (!name.equals(res.getName())) {
      throw new Error();
    }

    return res;
  }

  public static ESmall box(int v) {
    return ESmall.make(v);
  }

  /**
   * Boxes a <code>long</code> value to an EInteger (EBig or ESmall)
   *
   * @param longValue
   * @return
   */
  public static EInteger box2(long longVal) {

    // very simple: see if the longValue can be converted
    // to an int and back again without loosing it's value

    int intVal = (int) longVal;
    if (longVal == (long) intVal) {
      return ESmall.make(intVal);
    } else {
      return new EBig(longVal);
    }
  }

  public static EInteger box(long longVal) {

    int intVal = (int)longVal;
   
    if (intVal == longVal) {
      return ESmall.make(intVal);
    } else {
      return new EBig(longVal);
    }

  }

  /**
   * @param doubleVal
   * @return
   */
  public static EDouble box(double doubleVal) {
    return new EDouble(doubleVal);
  }

  static BigInteger INT_MIN_AS_BIG = BigInteger.valueOf(Integer.MIN_VALUE);
  static BigInteger INT_MAX_AS_BIG = BigInteger.valueOf(Integer.MAX_VALUE);
  private static final ENode localNode = new ENode();

  /**
   * @param add
   * @return
   */
  public static EInteger box(BigInteger res) {

    if (res.compareTo(INT_MIN_AS_BIG) < 0)
      return new EBig(res);

    if (res.compareTo(INT_MAX_AS_BIG) > 0)
      return new EBig(res);

    return ESmall.make(res.intValue());
  }

  public static EInteger box_parse(String str) {
    return box(new BigInteger(str));
  }
 
  /**
   * @param b
   * @return
   */
  public static EAtom box(boolean bool) {
    return bool ? TRUE : FALSE;
  }

  /**
   * @param b
   * @return
   */
  public static EAtom guard(boolean bool) {
    return bool ? TRUE : FALSE;
  }

  public static final ENil NIL = new ENil();
  public static final EAtom am_EXIT = EAtom.intern("EXIT");
  public static final EAtom IGNORED = EAtom.intern("ignored");
  private static final EAtom am_badmatch = EAtom.intern("badmatch");
  private static final EAtom am_case_clause = EAtom.intern("case_clause");
  public static final EAtom am_undefined = EAtom.intern("undefined");
  public static final EObject am_receive_clause = EAtom
      .intern("receive_clause");
  public static final EObject AM_NOT_IMPLEMENTED = EAtom
      .intern("not_implemented");
  public static final EAtom AM_TIMEOUT = EAtom.intern("timeout");
  public static final EAtom am_try_case_clause = EAtom
      .intern("try_case_clause");
  public static final EAtom am_if_clause = EAtom.intern("if_clause");
  public static final EBinary EMPTY_BINARY = new EBinary(new byte[0]);
  public static final ByteBuffer[] EMPTY_BYTEBUFFER_ARR = new ByteBuffer[0];
  public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
  public static final EAtom am_infinity = EAtom.intern("infinity");
  public static final EAtom am_noproc = EAtom.intern("noproc");
  public static final EAtom am_error = EAtom.intern("error");
  public static final EAtom am_exit = EAtom.intern("exit");
  public static final EAtom am_throw = EAtom.intern("throw");
  public static final EAtom am_badfile = EAtom.intern("badfile");
  public static final EAtom am_value = EAtom.intern("value");
  public static final EAtom am_timeout = EAtom.intern("timeout");
  public static final EAtom am_function_clause = EAtom
      .intern("function_clause");
  public static final EAtom am_ok = EAtom.intern("ok");
  public static final EAtom am_noconnect = EAtom.intern("noconnect");
  public static final EAtom am_latin1 = EAtom.intern("latin1");
  public static final EAtom am_utf8 = EAtom.intern("utf8");
  public static final EAtom am_unicode = EAtom.intern("unicode");
  private static final EAtom am_init = EAtom.intern("init");
  private static final EAtom am_stop = EAtom.intern("stop");
  protected static final EAtom am_new = EAtom.intern("new");

  public static EBitStringBuilder bs_init(int size, int flags) {
    if (size<0) throw ERT.badarg();
    return new EBitStringBuilder(size, flags);
  }

  public static EBitStringBuilder bs_initBits(int size, int flags) {
    if (size<0) throw ERT.badarg();
    return new EBitStringBuilder(size/8, size%8, flags);
  }

  /**
   * @param e
   * @return
   */
  public static String describe_exception(Throwable e) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    pw.print("java trace: ");
    e.printStackTrace(pw);
    pw.close();
    return sw.toString();
  }

  public static void test_fun(EObject orig, EFun fun) {
    if (fun == null) {
      if ((orig.testFunction()) != null) {
        throw new ErlangError(new ETuple2(am_badarity, new ETuple2(orig, NIL)));
      } else {
        throw badfun(orig);
      }
    }
  }
 
  static EInteger max_send_time = ERT.box(4294967295L);
  static ESmall zero = ERT.box(0);
 
  public static final boolean gt(EInteger v1, EInteger v2) {
    return v1.erlangCompareTo(v2) > 0;
  }
 
  public static final boolean lt(EInteger v1, EInteger v2) {
    return v1.erlangCompareTo(v2) < 0;
  }
 
/*
  public static final <T> boolean le(Comparable<T> v1, T v2) {
    return v1.erlangCompareTo(v2) <= 0;
  }
  */
 
  @BIF
  public static EObject cancel_timer(EObject ref)
  {
    // check arguments
    ERef timer_ref = ref.testReference();
    if (timer_ref == null) throw ERT.badarg();
   
    long time_left = ETimerTask.cancel(timer_ref);
   
    if (time_left > 0) {
      return ERT.box(time_left);
    } else {
      return ERT.FALSE;
    }
  }
 
  @BIF
  public static EObject read_timer(EObject ref)
  {
    // check arguments
    ERef timer_ref = ref.testReference();
    if (timer_ref == null) throw ERT.badarg();
   
    long time_left = ETimerTask.read_timer(timer_ref);
   
    if (time_left > 0) {
      return ERT.box(time_left);
    } else {
      return ERT.FALSE;
    }
  }
 
  @BIF
  public static EObject send_after(final EProc proc, EObject time, final EObject rcv, final EObject msg)
  {
    // check arguments
    EInteger when = time.testInteger();
    final EInternalPID rcv_pid = rcv.testInternalPID();
    EAtom rcv_atom = rcv.testAtom();
   
    if (when == null
      || gt(when, max_send_time)
      || lt(when, zero)
      || (rcv_pid == null && rcv_atom == null)) {
      throw ERT.badarg(time, rcv, msg);
    }
     
    ETimerTask send_task = new ETimerTask(rcv_pid) {
      @Override
      public void on_timeout()  throws Pausable {
       
        EHandle p;
        if ((p = rcv.testHandle()) != null) {
          p.send(proc.self_handle(), msg);
          return;
        }

        p = register.get(rcv);
        if (p != null) {
          p.send(proc.self_handle(), msg);
        }
      }
    };
   
    send_task.schedule(when.longValue());

    return send_task.ref;
  }

  @BIF
  public static EObject start_timer(EObject time, final EObject rcv, final EObject msg)
  {
    // check arguments
    EInteger when = time.testInteger();
    final EInternalPID rcv_pid = rcv.testInternalPID();
    EAtom rcv_atom = rcv.testAtom();
   
    if (when == null
      || gt(when, max_send_time)
      || lt(when, zero)
      || (rcv_pid == null && rcv_atom == null)) {
      throw ERT.badarg(time, rcv, msg);
    }
     
    ETimerTask send_task = new ETimerTask(rcv_pid) {
      @Override
      public void on_timeout() throws Pausable {
       
        ETuple3 timeout_msg = new ETuple3();
        timeout_msg.elem1 = am_timeout;
        timeout_msg.elem2 = this.ref;
        timeout_msg.elem3 = msg;
       
        EHandle p;
        if ((p = rcv.testHandle()) != null) {
          p.sendb(timeout_msg);
          return;
        }

        p = register.get(rcv);
        if (p != null) {
          p.sendb(timeout_msg);
        }
      }
    };
   
    send_task.schedule(when.longValue());

    return send_task.ref;
  }
 
  @Import(module="erlang", fun="dsend", arity=2)
  static EFun erlang__dsend__2;
 
  @Import(module="erlang", fun="dsend", arity=3)
  static EFun erlang__dsend__3;
 
  /**
   * @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;
  }

  @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);
      }
    }
  }

  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;
      }
    }
  }

  private static boolean send_to_locally_registered(EProc proc, EAtom name, EObject msg) throws Pausable {
    EHandle handle;
    if ((handle = register.get(name)) != null) {
      send_to_handle(proc, handle, msg);
      return true;
    } else return 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);
  }

  /**
   * @return
   */
  public static ENode getLocalNode() {
    return localNode;
  }

  static EAtom am_undef = EAtom.intern("undef");

  /**
   * @param fun
   * @return
   */
  public static ErlangException undef(FunID fun, EObject... args) {
    throw new ErlangError(am_undef, args);
  }

  public static EFun resolve_fun(EObject mod, EObject fun, int arity) {
    EAtom f = fun.testAtom();
    if (f == null) {
      throw ERT.badarg(mod, fun, ESmall.make(arity));
    }

    JavaObject jo;
    if ((jo = mod.testJavaObject()) != null) {
      return jo.resolve_fun(f, arity);
    }
   
    EAtom m = mod.testAtom();
   
    if (m == null)
    {
      final ETuple tup;
      EAtom pmod;
      if ((tup = mod.testTuple()) != null
          && tup.arity() > 0
          && (pmod=tup.elm(1).testAtom()) != null) {
       
        final EFun pfun = EModuleManager.resolve(new FunID(pmod, f, arity+1));
       
        return EFunCG.get_fun_with_handler(pmod.getName(), f.getName(), arity, new EFunHandler() {
                    @Override
                    public EObject invoke(EProc proc, EObject[] args) throws Pausable {
                        EObject[] real_args = new EObject[args.length + 1];
                        System.arraycopy(args, 0, real_args, 0, args.length);
                        real_args[args.length] = tup;
                        return pfun.invoke(proc, real_args);
                    }
                }, ERT.class.getClassLoader());
       
      }
     
      throw ERT.badarg(mod, fun, ESmall.make(arity));
    }
    EFun efun = EModuleManager.resolve(new FunID(m, f, arity));

    return efun;
  }

    public static EObject apply_last(EProc proc, EObject mod, EObject fun, EObject args) throws Pausable {
    ESeq seq = args.testSeq();
    if (seq == null) { throw ERT.badarg(mod, fun, args); }
    return apply_list_last(proc, mod, fun, seq, seq.length());
  }
 
  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;
  }

  static Map<EAtom, EHandle> register = new ConcurrentHashMap<EAtom, EHandle>();

  /**
   * @param aname
   * @param handle
   */
  public static void register(EAtom aname, EHandle handle) {
    register.put(aname, handle);
    handle.setName(aname);
  }

  public static boolean unregister(EAtom aname) {
    EHandle val = register.remove(aname);
    if (val != null) {
      val.setName(ERT.am_undefined);
      return true;
    } else {
      return false;
    }   
  }

  /**
   * @param regname
   * @return
   */
  public static EObject whereis(EObject regname) {
    EObject result = register.get(regname);
    if (result == null) {
      // System.out.println(regname + " => " + am_undefined);
      return am_undefined;
    } else {
      // System.out.println(regname + " => " + result);
      return result;
    }
  }

  public static EObject badmatch(EObject val) {
    throw new ErlangError(new ETuple2(am_badmatch, val));
  }

  public static void paranoiaCheck(final EObject e, String details) {
    if (e == null) throw new Error("Bif returned null: "+details);
  }

  public static EObject decode_exception2(final ErlangException e) {
    return e.getCatchValue();
  }

  public static ETuple3 decode_exception3(final ErlangException e) {
    return e.getTryValue();
  }

  public static EObject case_end(EObject val) {
    throw new ErlangError(ETuple.make(am_case_clause, val));
  }

  public static EObject if_end() {
    throw new ErlangError(am_if_clause);
  }

  public static EObject try_case_end(EObject val) {
    throw new ErlangError(ETuple.make(am_try_case_clause, val));
  }

  static kilim.Scheduler scheduler = new kilim.Scheduler(threadPoolSize());
  static kilim.Scheduler async_scheduler = new kilim.Scheduler(asyncThreadPoolSize());
  public static EAtom am_io = EAtom.intern("io");
  public static EAtom am_attributes = EAtom.intern("attributes");
  public static EAtom am_compile = EAtom.intern("compile");
  public static EAtom am_exports = EAtom.intern("exports");
  public static EAtom am_badfun = EAtom.intern("badfun");
  public static EAtom am_badarity = EAtom.intern("badarity");

  public static EAtom am_name = EAtom.intern("name");
  public static EAtom am_arity = EAtom.intern("arity");
  public static EAtom am_env = EAtom.intern("env");

  public static EAtom am_index = EAtom.intern("index");
  public static EAtom am_new_index = EAtom.intern("new_index");
  public static EAtom am_new_uniq = EAtom.intern("new_uniq");
  public static EAtom am_uniq = EAtom.intern("uniq");
  public static EAtom am_pid = EAtom.intern("pid");
  public static EAtom am_type = EAtom.intern("type");
  public static EAtom am_local = EAtom.intern("local");
  public static EAtom am_external = EAtom.intern("external");
  public static EAtom am_DOWN = EAtom.intern("DOWN");
  public static EAtom am_killed = EAtom.intern("killed");

  public static void run(Task task) {
    task.setScheduler(scheduler);
    task.start();
  }
 
  public static void run_async(Task task) {
    task.setScheduler(async_scheduler);
    task.start();
  }
 
   /*
    * Skeleton for receive statement:
    *
    *      L1:          <-------------------+
    *                   <-----------+       |
    *                             |       |
    *             loop_rec L2 ------+---+   |
    *             ...               |   |   |
    *             remove_message     |   |    |
    *             jump L3           |   |   |
    *            ...                |   |   |
    *    loop_rec_end L1         --+   |   |
    *      L2:          <---------------+   |
    *       wait L1          -----------------+      or wait_timeout
    *    timeout
    *
    *   L3:    Code after receive...
    *
    */

  /** 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;
  }

  /** 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 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;
  }

  /** 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;
    }
  }

  /** 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;
    }   
  }

  /** 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;
  }

  public static int unboxToInt(EInteger i) {
    return i.intValue();
  }

  public static int unboxToInt(EObject i) {
    ESmall ii;
    if ((ii = i.testSmall()) == null)
      throw ERT.badarg(i);
    return ii.value;
  }

  public static int unboxToInt(ENumber i) {
    return i.intValue();
  }

  public static double unboxToDouble(EInteger i) {
    return i.doubleValue();
  }

  public static double unboxToDouble(ENumber i) {
    return i.doubleValue();
  }

  public static double unboxToDouble(EObject i) {
    ENumber num;
    if ((num = i.testNumber()) == null)
      throw ERT.badarg(i);
    return num.doubleValue();
  }

  public static double unboxToDouble(int i) {
    return i;
  }

  public static Boolean asBoolean(EObject obj) {
    if (obj == ERT.TRUE) return true;
    if (obj == ERT.FALSE) return false;
    return null;
  }

  public static void check_exit(EProc p) {
    p.check_exit();
  }

  public static EObject func_info(EAtom mod, EAtom fun, int arity) {
    throw new ErlangError(am_function_clause);
  }

  public static EObject func_info(EAtom mod, EAtom fun, ESeq args) {
    throw new ErlangError(am_function_clause, args);
  }

  public static ERef make_ref() {
    return getLocalNode().createRef();
  }
 
  /**
   * @param command
   * @return
   */
  public static EDriver find_driver(EString command) {
    String name = command.stringValue();
    int idx = name.indexOf(' ');
    if (idx != -1) {
      name = name.substring(0, idx);
    }
    return Drivers.getDriver(name);
  }

  /**
   * @param job
   */
  public static void run_async(final EAsync job, final EDriverTask dt) {
    run_async(new Task() {
      @Override
      public void execute() throws Pausable, Exception {
        job.async();
        dt.async_done(job);
      }
    });
  }

  /**
   * @return
   */
  public static int threadPoolSize() {
    String threads = ErjangConfig.getString("erjang.beam.option.S");
    if (threads != null)
      return Integer.parseInt(threads);
    else
      return Math.max(1, Runtime.getRuntime().availableProcessors()/2);
  }

  public static int asyncThreadPoolSize() {
    String threads = ErjangConfig.getString("erjang.beam.option.A");
    if (threads != null)
      return Integer.parseInt(threads);
    else
      return 10;
  }

  public static int processLimit() {
    String threads = ErjangConfig.getString("erjang.beam.option.P");
    if (threads != null)
      return Integer.parseInt(threads);
    else
      return 500000;
  }

  public static ESeq registered() {
    ESeq res = ERT.NIL;
    for (EAtom reg : register.keySet()) {
      res = res.cons(reg);
    }
    return res;
  }

  /** Shuts down currently running OTP */
  public static void shutdown() {
    EObject init_proc = whereis(am_init);
    ETuple tup = ETuple.make(am_stop, am_stop);
    EPID init_pid;
    if ((init_pid = init_proc.testPID()) != null) {
      init_pid.sendb(tup);
    }
  }
 
  /**
   * Shutdown Kilim schedulers.
   */
  /*package*/ static void shutdownSchedulers() {
    scheduler.shutdown();
    async_scheduler.shutdown();
  }

  static protected volatile InputStream in = System.in;
  static protected volatile PrintStream out = System.out;
  static protected volatile PrintStream err = System.err;
 
  public static void set_stdio(InputStream in,
      PrintStream out, PrintStream err) {
    // avoid null
    ERT.in = (in != null ? in : new NullInputStream());
    ERT.out = (out != null ? out : new PrintStream(new NullOutputStream()));
    ERT.err = (err != null ? err : new PrintStream(new NullOutputStream()));
  }

  public static void set_stdio(InputStream in,
      OutputStream out, OutputStream err) {
    // avoid null
    ERT.in = (in != null ? in : new NullInputStream());
    ERT.out = (out != null ? new PrintStream(out) : new PrintStream(new NullOutputStream()));
    ERT.err = (err != null ? new PrintStream(err) : new PrintStream(new NullOutputStream()));
  }

  public static void setInputStream(InputStream in) {
    ERT.in = (in != null ? in : new NullInputStream());
  }

  public static InputStream getInputStream() {
    return in;
  }

  public static void setOutputStream(PrintStream out) {
    ERT.out = (out != null ? out : new PrintStream(new NullOutputStream()));
  }

  public static void setOutputStream(OutputStream out) {
    ERT.out = (out != null ? new PrintStream(out) : new PrintStream(new NullOutputStream()));
  }

  public static PrintStream getOutputStream() {
    return out;
  }

  public static void setErrorStream(PrintStream err) {
    ERT.err = (err != null ? err : new PrintStream(new NullOutputStream()));
  }

  public static void setErrorStream(OutputStream err) {
    ERT.err = (err != null ? new PrintStream(err) : new PrintStream(new NullOutputStream()));
  }

  public static PrintStream getErrorStream() {
    return err;
  }

  public static File newFile(String file_name) {
    File file = new File(file_name);
    if (file.isAbsolute())
      return file;
    return new File(Posix.getCWD(), file_name);
  }

  public static void debug(String text) {
    log.fine(text);
  }
 
  public static void debug(boolean condition, String text) {
    if (condition) {
      debug(text);
    }
  }
 
  static class NullInputStream extends InputStream {
    @Override
    public int read() throws IOException {
      return -1;
    }
  }
  static class NullOutputStream extends OutputStream {
    @Override
    public void write(int arg0) throws IOException {
      // ignore
    }
    @Override
    public void write(byte[] b) throws IOException {
      // ignore
    }
    @Override
    public void write(byte[] b, int off, int len) throws IOException {
      // ignore
    }
  }

  /**
   * contains versions, paths and other information.
   * use {@link ERT#setRuntimeInfo(RuntimeInfo)} to set this field.
   */
  public static RuntimeInfo runtime_info = null;
 
  public static void setRuntimeInfo(RuntimeInfo info) {
    // TODO perform synchronization? We usually set this
    // field only once from Main before ERT is started
    runtime_info = info;
    if (runtime_info != null) {
      System.setProperty("erjang.path", runtime_info.erl_bootstrap_ebindir);
    }
  }
 
  public static EObject compile_elixir_regex(EObject patt, EObject opts) {
    byte[] ops = opts.testBinary().getByteArray();
    ECons l = ECompiledRE.decode_options(ops);
    EObject tup = erjang.m.re.Native.compile(patt, l);
    return tup.testTuple().elm(2);
  }

  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);
        }
      }
    }
  }
 
  private static String make_width(int n, String s) {
    if (s.length() > n) return s;
    StringBuilder sb = new StringBuilder();
    while ((sb.length()+s.length()) < n) {
      sb.append(' ');
    }
    sb.append(s);
    return sb.toString();
  }
 
  /*
   *
    async_scheduler.schedule(new Task() {
      @Override
      public void execute() throws Pausable, Exception {
        try {
        execute0();
        } catch (Throwable e) {
          e.printStackTrace();
        }
      }
       
      public void execute0() throws Pausable, Exception {
       
        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 (mbox.untilHasMessages(1, 1000L)) {
          ETuple2 tup = (ETuple2) mbox.get();
          EHandle handle = tup.elm(1).testHandle();
          ESeq stack = tup.elm(2).testSeq();
         
          System.err.println(" == "+handle+" : "+handle.name);
          for (EObject o : stack) {
            System.err.println(o);
          }
        }
       
      }
    }); */
TOP

Related Classes of erjang.ERT$NullInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.