/*
* 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.
*/
package java.lang;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.apache.harmony.luni.util.DeleteOnExit;
import org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection;
import org.apache.harmony.luni.internal.process.SystemProcess;
import org.apache.harmony.lang.RuntimePermissionCollection;
import org.apache.harmony.kernel.vm.VM;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.mm.mminterface.MemoryManager;
import org.jikesrvm.runtime.DynamicLibrary;
import org.jikesrvm.scheduler.RVMThread;
/**
* This class, with the exception of the exec() APIs, must be implemented by the
* VM vendor. The exec() APIs must first do any required security checks, and
* then call org.apache.harmony.luni.internal.process.SystemProcess.create().
* The Runtime interface.
*/
public class Runtime {
private static final Runtime singleton = new Runtime();
/** Shutdown hooks */
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;
/**
* Prevent this class from being instantiated
*/
private Runtime(){
//do nothing
}
/**
* Execute progArray[0] in a separate platform process The new process
* inherits the environment of the caller.
*
* @param progArray the array containing the program to execute as well as
* any arguments to the program.
* @throws java.io.IOException if the program cannot be executed
* @throws SecurityException if the current SecurityManager disallows
* program execution
* @see SecurityManager#checkExec
*/
public Process exec(String[] progArray) throws java.io.IOException {
return exec(progArray, null, null);
}
/**
* Execute progArray[0] in a separate platform process The new process uses
* the environment provided in envp
*
* @param progArray the array containing the program to execute a well as
* any arguments to the program.
* @param envp the array containing the environment to start the new process
* in.
* @throws java.io.IOException if the program cannot be executed
* @throws SecurityException if the current SecurityManager disallows
* program execution
* @see SecurityManager#checkExec
*/
public Process exec(String[] progArray, String[] envp) throws java.io.IOException {
return exec(progArray, envp, null);
}
/**
* Execute progArray[0] in a separate platform process. The new process uses
* the environment provided in envp
*
* @param progArray the array containing the program to execute a well as
* any arguments to the program.
* @param envp the array containing the environment to start the new process
* in.
* @param directory the directory in which to execute progArray[0]. If null,
* execute in same directory as parent process.
* @throws java.io.IOException if the program cannot be executed
* @throws SecurityException if the current SecurityManager disallows
* program execution
* @see SecurityManager#checkExec
*/
public Process exec(String[] progArray, String[] envp, File directory)
throws java.io.IOException {
SecurityManager currentSecurity = System.getSecurityManager();
if (currentSecurity != null) {
currentSecurity.checkExec(progArray[0]);
}
if (progArray == null) {
throw new NullPointerException("Command argument shouldn't be empty.");
}
if (progArray.length == 0) {
throw new IndexOutOfBoundsException();
}
for (int i = 0; i < progArray.length; i++) {
if (progArray[i] == null) {
throw new NullPointerException("An element of progArray shouldn't be empty.");
}
}
if (envp == null) {
envp = new String[0];
} else 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.");
}
}
}
return SystemProcess.create(progArray, envp, directory);
}
/**
* Execute program in a separate platform process The new process inherits
* the environment of the caller.
*
* @param prog the name of the program to execute
* @throws java.io.IOException if the program cannot be executed
* @throws SecurityException if the current SecurityManager disallows
* program execution
* @see SecurityManager#checkExec
*/
public Process exec(String prog) throws java.io.IOException {
return exec(prog, null, null);
}
/**
* Execute prog in a separate platform process The new process uses the
* environment provided in envp
*
* @param prog the name of the program to execute
* @param envp the array containing the environment to start the new process
* in.
* @throws java.io.IOException if the program cannot be executed
* @throws SecurityException if the current SecurityManager disallows
* program execution
* @see SecurityManager#checkExec
*/
public Process exec(String prog, String[] envp) throws java.io.IOException {
return exec(prog, envp, null);
}
/**
* Execute prog in a separate platform process The new process uses the
* environment provided in envp
*
* @param prog the name of the program to execute
* @param envp the array containing the environment to start the new process
* in.
* @param directory the initial directory for the subprocess, or null to use
* the directory of the current process
* @throws java.io.IOException if the program cannot be executed
* @throws SecurityException if the current SecurityManager disallows
* program execution
* @see SecurityManager#checkExec
*/
public Process exec(String prog, String[] envp, File directory) throws java.io.IOException {
if (prog == null) {
throw new NullPointerException();
}
if (prog.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(prog);
String[] progArray = new String[st.countTokens()];
int i = 0;
while (st.hasMoreTokens()) {
progArray[i++] = st.nextToken();
}
return exec(progArray, envp, directory);
}
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;
// TODO
//FinalizerThread.shutdown(finalizeOnExit);
// Close connections.
if (VM.closeJars) {
JarURLConnection.closeCachedFiles();
}
// Delete files.
if (VM.deleteOnExit) {
DeleteOnExit.deleteOnExit();
}
} catch (Throwable e) {
// just catch all exceptions
}
}
}
/**
* Causes the virtual machine to stop running, and the program to exit. If
* runFinalizersOnExit(true) has been invoked, then all finalizers will be
* run first.
*
* @param status the return code.
* @throws SecurityException if the running thread is not allowed to cause
* the vm to exit.
* @see SecurityManager#checkExit
*/
public void exit(int status) {
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();
org.jikesrvm.VM.sysExit(status);
}
/**
* Answers the amount of free memory resources which are available to the
* running program.
*
*/
public long freeMemory() {
return MemoryManager.freeMemory().toLong();
}
/**
* Indicates to the virtual machine that it would be a good time to collect
* available memory. Note that, this is a hint only.
*
*/
public void gc() {
VMCommonLibrarySupport.gc();
}
/**
* Return the single Runtime instance
*
*/
public static Runtime getRuntime() {
return singleton;
}
/**
* Loads and links the library specified by the argument.
*
* @param pathName the absolute (ie: platform dependent) path to the library
* to load
* @throws UnsatisfiedLinkError if the library could not be loaded
* @throws SecurityException if the library was not allowed to be loaded
*/
public void load(String pathName) {
load0(pathName, RVMClass.getClassLoaderFromStackFrame(1), 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);
}
}
if (DynamicLibrary.load(filename) == 0) {
// TODO: make use of cL
throw new UnsatisfiedLinkError("Can not find the library: " +
filename);
}
}
/**
* Loads and links the library specified by the argument.
*
* @param libName the name of the library to load
* @throws UnsatisfiedLinkError if the library could not be loaded
* @throws SecurityException if the library was not allowed to be loaded
*/
public void loadLibrary(String libName) {
loadLibrary0(libName, RVMClass.getClassLoaderFromStackFrame(1), 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);
}
/**
* Provides a hint to the virtual machine that it would be useful to attempt
* to perform any outstanding object finalizations.
*
*/
public void runFinalization() {
return;
}
/**
* Ensure that, when the virtual machine is about to exit, all objects are
* finalized. Note that all finalization which occurs when the system is
* exiting is performed after all running threads have been terminated.
*
* @param run true means finalize all on exit.
* @deprecated This method is unsafe.
*/
@Deprecated
public static void runFinalizersOnExit(boolean run) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkExit(0);
}
synchronized(hooksList) {
finalizeOnExit = run;
}
}
/**
* Answers the total amount of memory resources which is available to (or in
* use by) the running program.
*
*/
public long totalMemory() {
return MemoryManager.totalMemory().toLong();
}
/**
* Turns the output of debug information for instructions on or off.
*
* @param enable if true, turn trace on. false turns trace off.
*/
public void traceInstructions(boolean enable) {
return;
}
/**
* Turns the output of debug information for methods on or off.
*
* @param enable if true, turn trace on. false turns trace off.
*/
public void traceMethodCalls(boolean enable) {
return;
}
/**
* @deprecated Use InputStreamReader
*/
@Deprecated
public InputStream getLocalizedInputStream(InputStream stream) {
return stream;
}
/**
* @deprecated Use OutputStreamWriter
*/
@Deprecated
public OutputStream getLocalizedOutputStream(OutputStream stream) {
return stream;
}
/**
* Registers a new virtual-machine shutdown hook.
*
* @param hook the hook (a Thread) to register
*/
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);
}
}
/**
* De-registers a previously-registered virtual-machine shutdown hook.
*
* @param hook the hook (a Thread) to de-register
* @return true if the hook could be de-registered
*/
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);
}
}
/**
* Causes the virtual machine to stop running, and the program to exit.
* Finalizers will not be run first. Shutdown hooks will not be run.
*
* @param code
* the return code.
* @throws SecurityException
* if the running thread is not allowed to cause the vm to
* exit.
* @see SecurityManager#checkExit
*/
public void halt(int code) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkExit(code);
}
org.jikesrvm.VM.sysExit(code);
}
/**
* Return the number of processors, always at least one.
*/
public int availableProcessors() {
return RVMThread.availableProcessors;
}
/**
* Return the maximum memory that will be used by the virtual machine, or
* Long.MAX_VALUE.
*/
public long maxMemory() {
return MemoryManager.maxMemory().toLong();
}
}