blob: 010893c6a4f9be66e47495f7a6e2b808f204d7aa [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/**
* @author Serguei S.Zapreyev
* @version $Revision: 1.1.2.2.4.5 $
*
*/
/**
* ###############################################################################
* ###############################################################################
* TODO LIST:
* 1. Provide correct processing the case if process isn't started because of some
* reason
* 2. Clean and develop the native support
* 3. Think of the default/undefault buffering
* 3. Runtime.SubProcess.SubInputStream.read(b, off, len) and
* Runtime.SubProcess.SubErrorStream.read(b, off, len) should be effectively
* reimplemented on the native side.
* ###############################################################################
* ###############################################################################
*/
package java.lang;
import java.util.StringTokenizer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.lang.UnsatisfiedLinkError;
import java.lang.VMExecutionEngine;
import java.lang.VMMemoryManager;
import java.util.ArrayList;
import org.apache.harmony.vm.VMStack;
import org.apache.harmony.kernel.vm.VM;
import org.apache.harmony.luni.util.DeleteOnExit;
import org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnectionImpl;
import org.apache.harmony.lang.RuntimePermissionCollection;
/**
* @com.intel.drl.spec_ref
*/
public class Runtime
{
//--------------------------------------------------------------------------------
// Nested protected Runtime.SubProcess class:
//--------------------------------------------------------------------------------
static final class SubProcess extends Process {
final static class SubInputStream extends InputStream {
long streamHandle;
/**
* Constructs a new SubInputStream instance.
*/
SubInputStream() {
this.streamHandle = -1;
}
/**
* Reads the next byte of data from the input stream....
*
* @see int read() from InputStream
*/
private final native int readInputByte0(long handle) throws IOException;
public final int read() throws IOException {
return readInputByte0(this.streamHandle);
}
/**
* Returns the number of bytes that can be read (or skipped over) from
* this input stream without blocking by the next caller
* of a method for this input stream...
*
* @see int available() from InputStream
*/
private final native int available0(long handle);
public final int available() throws IOException {
return available0(this.streamHandle);
}
/**
* Reads len bytes from input stream ...
*
* @see void read(byte[], int, int) from InputStream
*/
public int read(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
}
if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException();
}
if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte) c;
int i = 1;
for(; i < len; i++) {
try {
if (available() != 0) {
int r = read();
if (r != -1) {
b[off + i] = (byte) r;
continue;
}
return i;
}
} catch(IOException e) {
break; //If any subsequent call to read() results in a IOException
}
break; //but a smaller number may be read, possibly zero.
}
return i;
}
/**
* Closes this input stream and releases any system resources associated
* with the stream.
*
* @see void close() from InputStream
*/
private final native void close0(long handle) throws IOException;
public final synchronized void close() throws IOException {
if (streamHandle == -1) return;
close0(streamHandle);
streamHandle = -1;
}
protected void finalize() throws Throwable {
close();
}
}
//--------------------------------------------------------------------------------
// Nested Class Runtime.SubProcess.SubOutputStream :
//--------------------------------------------------------------------------------
/**
* Extends OutputStream class.
*/
final static class SubOutputStream extends OutputStream {
long streamHandle;
/**
* Constructs a new SubOutputStream instance.
*/
SubOutputStream() {
this.streamHandle = -1;
}
/**
* Writes the specified byte to this output stream ...
*
* @see void write(int) from OutputStream
*/
private final native void writeOutputByte0(long handle, int bt);
public final void write(int b) throws IOException {
writeOutputByte0(this.streamHandle, b);
}
/**
* Writes len bytes from the specified byte array starting at
* offset off to this output stream ...
*
* @see void write(byte[], int, int) from OutputStream
*/
private final native void writeOutputBytes0(long handle, byte[] b, int off, int len);
public final void write(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
}
if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException();
}
writeOutputBytes0(this.streamHandle, b, off, len);
}
/**
* Writes b.length bytes from the specified byte array to this output stream...
*
* @see void write(byte[]) from OutputStream
*/
public final void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
/**
* Flushes this output stream and forces any buffered output
* bytes to be written out ...
*
* @see void flush() from OutputStream
*/
private final native void flush0(long handle);
public final void flush() throws IOException {
flush0(this.streamHandle);
}
/**
* Closes this output stream and releases any system resources
* associated with this stream ...
*
* @see void close() from OutputStream
*/
private final native void close0(long handle);
public final synchronized void close() throws IOException {
if (streamHandle == -1) return;
close0(streamHandle);
streamHandle = -1;
}
protected void finalize() throws Throwable {
close();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// Runtime.SubProcess BODY //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
private int processHandle;
private int processExitCode;
private OutputStream os;
private InputStream is;
private InputStream es;
/**
* An application cannot create its own instance of this class.
*/
protected SubProcess() {
this.processHandle = -1;
this.processExitCode = 0;
this.os = null;
this.is = null;
this.es = null;
}
private final native void close0(int handle);
protected void finalize() throws Throwable {
if (processHandle != -1)
close0(this.processHandle);
}
/**
* @see OutputStream.getOutputStream() from Process
*/
public final OutputStream getOutputStream() {
return os;
}
/**
* @see InputStream.getInputStream() from Process
*/
public final InputStream getInputStream() {
return is;
}
/**
* @see InputStream getErrorStream() from Process
*/
public final InputStream getErrorStream() {
return es;
}
private final native boolean getState0(int thisProcessHandle);
private final native void createProcess0(Object[] cmdarray, Object[] envp, String dir, long[] ia);
protected final void execVM(String[] cmdarray, String[] envp, String dir) throws IOException {
// Do all java heap allocation first, in order to throw OutOfMemory
// exception early, before we have actually executed the process.
// Otherwise we should do somewhat complicated cleanup.
SubProcess.SubOutputStream os1 = new SubProcess.SubOutputStream();
SubProcess.SubInputStream is1 = new SubProcess.SubInputStream();
SubProcess.SubInputStream es1 = new SubProcess.SubInputStream();
long[] la = new long[4];
createProcess0(cmdarray, envp, dir, la);
if (la[0] == 0) {
String cmd = null;
for(int i = 0; i < cmdarray.length; i++) {
if (i == 0) {
cmd = "\"" + cmdarray[i] + "\"";
} else {
cmd = cmd + " " + cmdarray[i];
}
}
throw new IOException("The creation of the Process has just failed: " + cmd);
}
this.processHandle = (int)la[0];
os1.streamHandle = la[1];
is1.streamHandle = la[2];
es1.streamHandle = la[3];
os = new BufferedOutputStream(os1);
is = new BufferedInputStream(is1);
es = new BufferedInputStream(es1);
}
/**
* @seeint waitFor() from Process
*/
public int waitFor() throws InterruptedException {
while (true) {
synchronized (this) {
if (getState0(processHandle)) break;
}
Thread.sleep(50);
}
return processExitCode;
}
/**
* @see int exitValue() from Process
*/
public synchronized int exitValue() throws IllegalThreadStateException {
if (!getState0(processHandle)) {
throw new IllegalThreadStateException("process has not exited");
}
return processExitCode;
}
/**
* @see void destroy() from Process
*/
private final native void destroy0(int thisProcessHandle);
public synchronized final void destroy() {
destroy0(processHandle);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////// RUNTIME BODY ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* "Every Java application has a single instance of class Runtime ..."
*/
private static Runtime thisApplicationRuntime = new Runtime();
private static ArrayList<Thread> hooksList = new ArrayList<Thread>();
/**
* 0 - normal work
* 1 - being shutdown sequence running
* 2 - being finalizing
*/
private static int VMState = 0;
static boolean finalizeOnExit = false;
/**
* An application cannot create its own instance of this class.
*/
private Runtime() {
}
/**
* @com.intel.drl.spec_ref
*/
public static Runtime getRuntime() {
return thisApplicationRuntime;
}
void execShutdownSequence() {
synchronized (hooksList) {
if (VMState > 0) {
return;
}
try {
// Phase1: Execute all registered hooks.
VMState = 1;
for (Thread hook : hooksList) {
hook.start();
}
for (Thread hook : hooksList) {
while (true){
try {
hook.join();
break;
} catch (InterruptedException e) {
continue;
}
}
}
// Phase2: Execute all finalizers if nessesary.
VMState = 2;
FinalizerThread.shutdown(finalizeOnExit);
// Close connections.
if (VM.closeJars) {
JarURLConnectionImpl.closeCachedFiles();
}
// Delete files.
if (VM.deleteOnExit) {
DeleteOnExit.deleteOnExit();
}
} catch (Throwable e) {
// just catch all exceptions
}
}
}
/**
* @com.intel.drl.spec_ref
*/
public void exit(int status) throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkExit(status);
}
// Halt the VM if it is running finalizers.
if (VMState == 2 && finalizeOnExit == true && status != 0) {
halt(status);
}
execShutdownSequence();
// No need to invoke finalizers one more time.
// vvvvv
VMExecutionEngine.exit(status, false);
}
/**
* @com.intel.drl.spec_ref
*/
public void addShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(RuntimePermissionCollection.SHUTDOWN_HOOKS_PERMISSION);
}
// Check hook for null
if (hook == null)
throw new NullPointerException("null is not allowed here");
if (hook.getState() != Thread.State.NEW) {
throw new IllegalArgumentException();
}
if (VMState > 0) {
throw new IllegalStateException();
}
synchronized (hooksList) {
if (hooksList.contains(hook)) {
throw new IllegalArgumentException();
}
hooksList.add(hook);
}
}
/**
* @com.intel.drl.spec_ref
*/
public boolean removeShutdownHook(Thread hook) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(RuntimePermissionCollection.SHUTDOWN_HOOKS_PERMISSION);
}
// Check hook for null
if (hook == null)
throw new NullPointerException("null is not allowed here");
if (VMState > 0) {
throw new IllegalStateException();
}
synchronized (hooksList) {
return hooksList.remove(hook);
}
}
/**
* @com.intel.drl.spec_ref
*/
public void halt(int status) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkExit(status);
}
VMExecutionEngine.exit(status, false);
}
/**
* @com.intel.drl.spec_ref
* @deprecated
*/
public static void runFinalizersOnExit(boolean value) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkExit(0);
}
synchronized(hooksList) {
finalizeOnExit = value;
}
}
/**
* @com.intel.drl.spec_ref
*/
public Process exec(String command) throws IOException {
return exec(command, null, null);
}
/**
* @com.intel.drl.spec_ref
*/
public Process exec(String cmd, String[] envp) throws IOException {
return exec(cmd, envp, null);
}
/**
* @com.intel.drl.spec_ref
*/
public Process exec(String command, String[] envp, File dir) throws IOException {
if (command == null) {
throw new NullPointerException();
}
if (command.length() == 0) {
throw new IllegalArgumentException();
}
if (envp != null) {
if (envp.length != 0) {
for (int i = 0; i < envp.length; i++) {
if (envp[i] == null) {
throw new NullPointerException("An element of envp shouldn't be empty.");
}
}
} else {
envp = null;
}
}
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
int i = 0;
while (st.hasMoreTokens()) {
cmdarray[i++] = st.nextToken();
}
return exec(cmdarray, envp, dir);
}
/**
* @com.intel.drl.spec_ref
*/
public Process exec(String[] cmdarray) throws IOException {
return exec(cmdarray, null, null);
}
/**
* @com.intel.drl.spec_ref
*/
public Process exec(String[] cmdarray, String[] envp) throws IOException, NullPointerException, IndexOutOfBoundsException, SecurityException {
return exec(cmdarray, envp, null);
}
/**
* @com.intel.drl.spec_ref
*/
public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException {
SecurityManager currentSecurity = System.getSecurityManager();
if (currentSecurity != null) {
currentSecurity.checkExec(cmdarray[0]);
}
if (cmdarray == null) {
throw new NullPointerException("Command argument shouldn't be empty.");
}
if (cmdarray.length == 0) {
throw new IndexOutOfBoundsException();
}
for (int i = 0; i < cmdarray.length; i++) {
if (cmdarray[i] == null) {
throw new NullPointerException("An element of cmdarray shouldn't be empty.");
}
}
if (envp != null) {
if (envp.length != 0) {
for (int i = 0; i < envp.length; i++) {
if (envp[i] == null) {
throw new NullPointerException("An element of envp shouldn't be empty.");
}
}
} else {
envp = null;
}
}
String dirPathName = (dir != null ? dir.getPath() : null);
SubProcess sp = new SubProcess();
sp.execVM(cmdarray, envp, dirPathName);
return sp;
}
/**
* @com.intel.drl.spec_ref
*/
public int availableProcessors() {
return VMExecutionEngine.getAvailableProcessors();
}
/**
* @com.intel.drl.spec_ref
*/
public long freeMemory() {
return VMMemoryManager.getFreeMemory();
}
/**
* @com.intel.drl.spec_ref
*/
public long totalMemory() {
return VMMemoryManager.getTotalMemory();
}
/**
* @com.intel.drl.spec_ref
*/
public long maxMemory() {
return VMMemoryManager.getMaxMemory();
}
/**
* @com.intel.drl.spec_ref
*/
public void gc() {
VMMemoryManager.runGC();
}
/**
* @com.intel.drl.spec_ref
*/
public void runFinalization() {
VMMemoryManager.runFinalization();
}
/**
* @com.intel.drl.spec_ref
*/
public void traceInstructions(boolean on) {
VMExecutionEngine.traceInstructions(on);
}
/**
* @com.intel.drl.spec_ref
*/
public void traceMethodCalls(boolean on) {
VMExecutionEngine.traceMethodCalls(on);
}
/**
* @com.intel.drl.spec_ref
*/
public void load(String filename) throws SecurityException, UnsatisfiedLinkError {
load0(filename, VMClassRegistry.getClassLoader(VMStack.getCallerClass(0)), true);
}
void load0(String filename, ClassLoader cL, boolean check) throws SecurityException, UnsatisfiedLinkError {
if (check) {
if (filename == null) {
throw new NullPointerException();
}
SecurityManager currentSecurity = System.getSecurityManager();
if (currentSecurity != null) {
currentSecurity.checkLink(filename);
}
}
VMClassRegistry.loadLibrary(filename, cL); // Should throw UnsatisfiedLinkError if needs.
}
/**
* @com.intel.drl.spec_ref
*/
public void loadLibrary(String libname) throws SecurityException, UnsatisfiedLinkError {
loadLibrary0(libname, VMClassRegistry.getClassLoader(VMStack.getCallerClass(0)), true);
}
void loadLibrary0(String libname, ClassLoader cL, boolean check) throws SecurityException, UnsatisfiedLinkError {
if (check) {
if (libname == null) {
throw new NullPointerException();
}
SecurityManager currentSecurity = System.getSecurityManager();
if (currentSecurity != null) {
currentSecurity.checkLink(libname);
}
}
String libFullName = null;
if (cL!=null) {
libFullName = cL.findLibrary(libname);
}
if (libFullName == null) {
String allPaths = null;
//XXX: should we think hard about security policy for this block?:
String jlp = System.getProperty("java.library.path");
String vblp = System.getProperty("vm.boot.library.path");
String udp = System.getProperty("user.dir");
String pathSeparator = System.getProperty("path.separator");
String fileSeparator = System.getProperty("file.separator");
allPaths = (jlp!=null?jlp:"")+(vblp!=null?pathSeparator+vblp:"")+(udp!=null?pathSeparator+udp:"");
if (allPaths.length()==0) {
throw new UnsatisfiedLinkError("Can not find the library: " +
libname);
}
//String[] paths = allPaths.split(pathSeparator);
String[] paths;
{
ArrayList<String> res = new ArrayList<String>();
int curPos = 0;
int l = pathSeparator.length();
int i = allPaths.indexOf(pathSeparator);
int in = 0;
while (i != -1) {
String s = allPaths.substring(curPos, i);
res.add(s);
in++;
curPos = i + l;
i = allPaths.indexOf(pathSeparator, curPos);
}
if (curPos <= allPaths.length()) {
String s = allPaths.substring(curPos, allPaths.length());
in++;
res.add(s);
}
paths = (String[]) res.toArray(new String[in]);
}
libname = System.mapLibraryName(libname);
for (int i=0; i<paths.length; i++) {
if (paths[i]==null) {
continue;
}
libFullName = paths[i] + fileSeparator + libname;
try {
this.load0(libFullName, cL, false);
return;
} catch (UnsatisfiedLinkError e) {
}
}
} else {
this.load0(libFullName, cL, false);
return;
}
throw new UnsatisfiedLinkError("Can not find the library: " +
libname);
}
/**
* @com.intel.drl.spec_ref
* @deprecated
*/
public InputStream getLocalizedInputStream(InputStream in) {
//XXX: return new BufferedInputStream( (InputStream) (Object) new InputStreamReader( in ) );
return in;
}
/**
* @com.intel.drl.spec_ref
* @deprecated
*/
public OutputStream getLocalizedOutputStream(OutputStream out) {
//XXX: return new BufferedOutputStream( (OutputStream) (Object) new OutputStreamWriter( out ) );
return out;
}
}