Package erjang.driver

Source Code of erjang.driver.ExecDriverInstance

/**
* 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.driver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import kilim.Pausable;
import kilim.Task;
import erjang.EAtom;
import erjang.EBinary;
import erjang.ECons;
import erjang.EHandle;
import erjang.EObject;
import erjang.EPID;
import erjang.ERT;
import erjang.ERef;
import erjang.ESeq;
import erjang.EString;
import erjang.ETuple2;
import erjang.ErlangError;
import erjang.NotImplemented;
import erjang.driver.EDriverTask.Mode;
import erjang.m.erlang.ErlPort;

/**
*
*/
public class ExecDriverInstance extends EDriverInstance {

  private ETuple2 name;
  private Process process;
  private DataOutputStream out;
  private DataInputStream in;
  private DataInputStream err;
  protected Thread stdin_thread;
  protected Thread stderr_thread;
  private boolean is_closing;

  /**
   * @param name
   */
  public ExecDriverInstance(ETuple2 name) {
    super(new ExecDriver(name));
    this.name = name;

  }

  @Override
  public void setup() {

    HashMap<String, String> env = task.env;
    String[] cmd = task.cmd;
    String cwd = task.cwd;

    String[] envp = new String[env.size()];
    int pos = 0;
    for (Map.Entry<String, String> e : env.entrySet()) {
      envp[pos++] = e.getKey() + "=" + e.getValue();
    }

    try {
      this.process = Runtime.getRuntime().exec(cmd, envp, ERT.newFile(cwd));
    } catch (IOException e1) {
      throw new ErlangError(e1);
    }

    List<String> al = new ArrayList<String>();
    Collections.addAll(al, cmd);

    // System.err.println("EXEC " + al);

    this.out = new DataOutputStream(this.process.getOutputStream());
    this.in = new DataInputStream(this.process.getInputStream());
    this.err = new DataInputStream(this.process.getErrorStream());

    if (!task.is_out_only) {

      start_input_reader(in, true);

      // also read stderr
      if (task.stderr_to_stdout) {
        start_input_reader(err, false);
      }

    }

  }
 
  synchronized void do_close() {
   
    //System.err.println("closing: "+name);

    this.is_closing = true;
   
    Thread th = stderr_thread;
    if (th != null) {
      th.interrupt();
    }
   
    th = stdin_thread;
    if (th != null) {
      th.interrupt();
    }
   
    Process p = this.process;
    if (p != null) {
      p.destroy();
    }
   
  }
 
  synchronized boolean is_closing() {
    return this.is_closing;
  }

  private void start_input_reader(final DataInputStream stream,
      final boolean is_stdin) {
    new Thread() {
     
      { setDaemon(true); start(); }
     
      public void run() {
        try {
          run0();
        } catch (ThreadDeath e) {
          throw e;
        } catch (Throwable e) {
          // this should not happen //
          e.printStackTrace();
        }
      }
       
      public void run0() {

       
        if (is_stdin) {
          stdin_thread = Thread.currentThread();

          try {
           
            boolean cont = false;
            do {
              try {
                cont = do_read();
              } catch (InterruptedIOException e) {
                cont = !is_closing();
              } catch (IOException e) {
                cont = false;
              }
            } while (cont);

          } finally {
            stdin_thread = null;
           
            while(stderr_thread != null) {
              Thread t = stderr_thread;
              if (t != null && !t.isAlive())
                break;
             
              try {
                Thread.sleep(1);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
           
            if (task.send_eof) {
              task.eof_from_driver_b();
            }
           
            if (task.send_exit_status) {
              int code;
              while (true) {
                try {
                  code = process.waitFor();
                  break;
                } catch (InterruptedException e) {
                  continue;
                }
              }
              task.exit_status_from_driver_b(code);
            }
          }

        } else {
          stderr_thread = Thread.currentThread();

          try {
           
            boolean cont = false;
            do {
              try {
                cont = do_read();
              } catch (InterruptedIOException e) {
                cont = !is_closing();
              } catch (IOException e) {
                cont = false;
              }
            } while (cont);

          } finally {
            stderr_thread = null;
          }
        }
      }

      private boolean do_read() throws IOException {

        byte[] data;

        int nbytes;

        if (task.mode == Mode.STREAM) {
          data = new byte[Math.max(stream.available(), 512)];
          try {
            nbytes = stream.read(data);
          } catch (IOException e) {
            nbytes = 0;
          }

        } else if (task.mode == Mode.PACKET) {

          switch (task.packet) {
          case 1:
            nbytes = stream.read();
            break;
          case 2:
            nbytes = stream.readUnsignedShort();
            break;
          case 4:
            nbytes = stream.readInt() & 0x7fffffff;
            break;
          default:
            throw new InternalError();
          }

          if (nbytes <= 0) {
            return false;
          }

          data = new byte[nbytes];

          try {
            stream.readFully(data);
          } catch (IOException e) {
            nbytes = 0;
          }

        } else {
          throw new NotImplemented("mode=" + task.mode);
        }

        if (nbytes <= 0) {
          return false;
        }

        if (task.send_binary_data) {
          task.output_from_driver_b(new EBinary(data, 0, nbytes));
        } else {
          task.output_from_driver_b(EString.make(data, 0, nbytes));
        }

        return true;
      }

    };
  }

  /*
   * (non-Javadoc)
   *
   * @see erjang.driver.EDriverInstance#call(int, erjang.EObject)
   */
  @Override
  protected EObject call(EPID pid, int command, EObject data) throws Pausable {
    throw ERT.badarg(ERT.box(command), data);
  }

  /*
   * (non-Javadoc)
   *
   * @see erjang.driver.EDriverInstance#flush()
   */
  @Override
  protected void flush() throws Pausable {
    // TODO Auto-generated method stub

  }

  @Override
  protected void stop(EObject reason) throws Pausable {

    this.do_close();

  }

  /*
   * (non-Javadoc)
   *
   * @see erjang.driver.EDriverInstance#output(java.nio.ByteBuffer)
   */
  @Override
  protected void output(EHandle caller, ByteBuffer buf) throws IOException,
      Pausable {

    byte[] data = buf.array();
    int data_off = buf.position() + buf.arrayOffset();
    int data_len = buf.remaining();

    //System.err.println("out: " + data_len + "; "
    //    + EString.make(data, data_off, data_len));

    switch (task.mode) {
    case STREAM:
      this.out.write(data, data_off, data_len);
      this.out.flush();
      return;

    case PACKET:
      switch (task.packet) {
      case 1:
        for (int off = 0; off < data_len; off += 256) {
          int rest = Math.min(256, data_len - off);
          out.writeByte(rest);
          out.write(data, data_off + off, rest);
        }
        this.out.flush();
        return;

      case 2:
        for (int off = 0; off < data_len; off += (1 << 16)) {
          int rest = Math.min((1 << 16), data_len - off);
          out.writeShort(rest);
          out.write(data, data_off + off, rest);
        }
        this.out.flush();
        return;

      case 4:
        out.writeInt(data_len);
        out.write(data, data_off, data_len);
        this.out.flush();
        return;

      default:
        throw new Error("should not happen");
      }

    case LINE:
      throw new NotImplemented();

    }

    this.out.flush();
  }

  /*
   * (non-Javadoc)
   *
   * @see erjang.driver.EDriverInstance#processExit(erjang.ERef)
   */
  @Override
  public void processExit(ERef monitor) throws Pausable {
    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   *
   * @see erjang.driver.EDriverInstance#readyAsync(erjang.driver.EAsync)
   */
  @Override
  protected void readyAsync(EAsync data) throws Pausable {
    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   *
   * @see
   * erjang.driver.EDriverInstance#readyInput(java.nio.channels.SelectableChannel
   * )
   */
  @Override
  protected void readyInput(SelectableChannel ch) throws Pausable {
    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   *
   * @see
   * erjang.driver.EDriverInstance#readyOutput(java.nio.channels.SelectableChannel
   * )
   */
  @Override
  protected void readyOutput(SelectableChannel evt) throws Pausable {
    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   *
   * @see erjang.driver.EDriverInstance#timeout()
   */
  @Override
  protected void timeout() throws Pausable {
    // TODO Auto-generated method stub

  }

}
TOP

Related Classes of erjang.driver.ExecDriverInstance

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.