/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.cldc.isolate;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.IOException;
import com.sun.cldchi.jvm.JVM;
/**
* <blockquote>
* <hr>
* Last modified: 05/03/31 13:22:49. <p>
* Note: this document is still a draft. Details in the API are
* subject to change. <p>
* <hr>
* </blockquote>
* The <code>Isolate</code> class provides the means of creating and managing
* isolated computations and arranging for their communication with each
* other.
* <p>
* <h3>Terminology</h3>
*
* Each isolated computation is called a <b>Task</b>. An <b>Isolate
* object</b> is a Java representation of the task. Multiple
* Isolate objects may be created to represent the same task. Where
* the context is clear, the words "task", "isolate" and "isolate
* object" may be used interchangeably. When a distinction needs to be
* made, the word "task" is used to describe the underlying
* computation, and the word "isolate" is used to describe the Java
* object(s) that represent the computation. <p>
*
* When two Isolate objects represent the same task, they are said to
* be <b>equivalent</b> to each other. Equivalent Isolate objects are
* created to avoid the sharing of Isolate objects across task
* boundaries. For example, in the following program, task A launches
* task B using the object <code>b1</code>, and task B gets a
* reference to itself using the object
* <code>b2</code>. <code>b1</code> and <code>b2</code> are two
* distinct objects: <p>
*
*<blockquote><pre>
*class TaskA {
* void launchB() {
* Isolate <b>b1</b> = new Isolate("TaskB", ....);
* b1.start();
* }
*}
*class TaskB {
* public static void main(String args[]) {
* Isolate <b>b2</b> = Isolate.currentIsolate();
* }
*}</pre></blockquote>
*
* <h3>Degree of Isolation</h3>
*
* Tasks in the CLDC environment are isolated in the following sense:
* <ul>
* <li> Each task has a separate namespace for loading Java classes.
* <li> Each task has a separate set of static variables for Java classes
* <li> A <code>synchronized static</code> method uses a different
* monitor object inside each task.
* <li> Typically no Java objects are shared across task boundaries.
* (see <a href=#classdoc_sharing>Object Sharing</a> below for
* exceptions).
* <li> Resource quotas are controlled by the runtime environment to
* prevent tasks to use excessive amount of resources. The
* implementation currently supports resource control for
* memory or CPU cycles.
* </ul>
*
* <a name="classdoc_class_path"><h3>Class path</h3></a>
*
* <p>Part of the definition of an isolate is its
* classpath, where the basic classes for the isolate are found.
* The CLDC runtime searches for classes in three sets of
* locations:
* <ul>
* <li>The romized system classes.
* <li>The isolate system class path.
* <li>The isolate application class path.
* </ul>
*
* <p><i>System</i> and <i>application</i> class paths are specified separately
* for an isolate when it is created. Classes on system and application class
* paths have different access rights:
* <ul>
* <li>Only classes loaded from the system class path can access
* hidden classes.
* <li>Only classes on the system class path can be loaded to restricted
* packages.
* </ul>
* For the definition of hidden and restricted packages, see
* doc/misc/Romizer.html.
*
* <p>When an isolate requests a class, the class is first looked up the
* romized system classes, then searched in the isolate system class path,
* and then searched in the isolate application class path.
*
* <p>User application classes should be put on the application class path,
* system class path can contain only trusted system classes.
*
* <p>WARNING: UNTRUSTED USER APPLICATION CLASSES MUST NEVER BE PUT ON THE
* SYSTEM CLASS PATH, AS IT GRANTS THEM ACCESS TO SYSTEM INTERNALS AND BREAKS
* SYSTEM SECURITY.
*
* <a name="classdoc_sharing"><h3>Object Sharing</h3></a>
*
* The Isolate API in CLDC does not support the sharing of arbitrary
* Java object across Isolate boundaries. The only exception is String
* objects: String objects may be passed as arguments from a parent
* isolate to a child isolate's <code>main()</code> method. Such
* Strings are passed by reference instead of by value in order to
* conserve resource. Also, interned Strings (such as literal Strings
* that appear inside Java source code) may be shared across Isolate
* boundaries. <p>
*
* Even though String objects may be shared across isolates, different
* isolates should not attempt to coordinate their activities by
* synchronizing on these Strings. Specifically, an interned Strings cannot
* be synchronized across isolate boundaries because it uses a different
* monitor object in each Isolate. <p>
*
* <h3>Inter-Isolate Communication</h3>
*
* Isolates may need to communicate with each to coordinate their
* activities. The recommended method of inter-isolate communication
* is a <b>native event queue</b>. On many CLDC/MIDP environments a native
* event queue already exists. Such event queues can be extended for
* one isolate to send events to another isolate. <p>
*
* Some CLDC/MIDP implementors may be tempted to use native code to
* pass shared objects from one isolate to another, and use
* traditional Java object-level synchronization to perform
* inter-isolate communication. In our experience this could easily
* lead to inter-isolate deadlock that could be exploited by
* downloaded malicious Midlets. For example, if a shared object is
* used to synchronize screen painting, a malicious Midlet may stop
* other Midlets from painting by not returning from its
* <code>paint()</code> method. <p>
*
* In our experience, with shared objects, it would take significant
* effort to design a system that can prevent such attacks. In
* contrast, event queues are much more easily understood to design
* a safe environment. Thus, we strongly recommend against using
* shared objects for inter-isolate communication.<p>
*
* The following code is an example of how an isolate can create other
* isolates:
*
*<blockquote><pre>import com.sun.cldc.isolate.*;
*
*class HelloWorld {
*
* // Usage: cldc_vm -classpath <XX> HelloWorld HelloWorld2 <classpath>
* public static void main(String [] argv) {
* System.out.println("HelloWorld");
* for (int i = 0; i < 6; i++) {
* try {
* // pass i as an argument to the isolate just for fun
* String[] isoArgs = {Integer.toString(i)};
* Isolate iso = new Isolate(argv[0], isoArgs);
* iso.start();
* } catch (Exception e) {
* System.out.println("caught exception " + e);
* e.printStackTrace();
* }
* System.out.println("HelloWorld: Iso " + i + " started.");
*
* }
* }
*}
*
*
*class HelloWorld2 {
* static String st = "HelloWorld2[";
*
* public static void main(String [] argv) {
* st = st.concat(argv[0]);
* st = st.concat("]");
* System.out.println("st is " + st);
* System.exit(42);
* }
*} </pre></blockquote>
*
* @see javax.isolate.IsolateStartupException
**/
public final class Isolate {
/**
* Controls access to each public API entry point. The
* isolate creator can grant API access to the child.
* Note this is a static so it is private to each Isolate
*/
private static int _API_access_ok = 1;
/**
* Priority level of this Isolate that was set using setPriority before
* the isolate has started.
*/
private int _priority;
/**
* Links to the next Isolate in a task's _seen_isolates list. See
* Task.cpp for more information.
*/
private Isolate _next;
/**
* A small integer ID that uniquely identifies this Isolate
* among the current set of active Isolates.
*/
private int _id = -1;
/**
* A number that uniquely identifies the task represented by this
* Isolate object.
*/
private long _uniqueId;
/**
* Called by native code when the task corresponding to this Isolate
* has terminated
*/
private int _terminated;
/**
* If this isolate has terminated, this variable saves the exit code --
* Normally the exitCode() method would retrieve the exit code from
* the Task. _saved_exit_code is used only if this Isolate object
* has been dis-associated from the Task (i.e., the Task has
* exited).
*/
private int _saved_exit_code;
/**
* Saves the mainClass parameter passed to Isolate() constructor.
*/
private String _mainClass;
/**
* Saves the mainArgs parameter passed to Isolate() constructor.
*/
private String[] _mainArgs;
/**
* Saves app_classpath[] parameter passed to Isolate() constructor.
*/
private String[] _app_classpath;
/**
* Saves sys_classpath[] parameter passed to Isolate() constructor.
*/
private String[] _sys_classpath;
/**
* Packages we want to be hidden in this Isolate. See definition of hidden package in
* doc/misc/Romizer.html
*/
private String[] _hidden_packages;
/**
* Packages we want to be restricted in this Isolate. See definition of restricted package in
* doc/misc/Romizer.html
*/
private String[] _restricted_packages;
/**
* Amount of memory reserved for this isolate
* The isolate cannot get OutOfMemory exception until it
* allocates at least memoryReserve bytes.
* If the system cannot reserve the requested amount,
* the isolate will not start.
*/
private int _memoryReserve = 0;
/**
* Memory allocation limit for this isolate
* OutOfMemoryError exception is thrown if
* - the isolate exceeds its memory allocation limit
* - excess over the reserved amount for this isolate
* cannot be allocated in the heap or
* conflicts with reserves of other isolates
*/
private int _memoryLimit = Integer.MAX_VALUE;
/**
* Used during bootstrap of new Isolate to store API access value
*/
private int _APIAccess = 0;
private int _ConnectDebugger = 0;
private int _UseVerifier = 1;
private int _profileId = DEFAULT_PROFILE_ID;
private int _UseProfiler = 1;
/**
* ID of default profile.
*/
private final static int DEFAULT_PROFILE_ID = -1;
/**
* A special priority level to indicate that an Isolate is suspended.
*/
private final static int SUSPEND = 0;
/**
* The minimum priority that an Isolate can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to an Isolate.
*/
public final static int NORM_PRIORITY = 2;
/**
* The maximum priority that an Isolate can have.
*/
public final static int MAX_PRIORITY = 3;
/**
* Creates a new isolated java application with a default configuration.
*
* <p>This constructor has the same effect as invoking
* {@link #Isolate(String,String[],String[])}
* and passing <code>null</code> for the <code>app_classpath</code>
* and <code>sys_classpath</code> parameters.
* See the long constructor documentation for more details.
*
* @param mainClass fully qualified name of the main method class
* @param mainArgs the arguments of the main method in the new isolate
* @throws IsolateStartupException if an error occurs in the configuration
* or startup of the new isolate before any application code is invoked
**/
public Isolate(String mainClass, String[] mainArgs)
throws IsolateStartupException {
this(mainClass, mainArgs, (String[])null);
}
/**
* Creates a new isolated java application with a default configuration.
*
* <p>This constructor has the same effect as invoking
* {@link #Isolate(String,String[],String[], String[])}
* and passing <code>null</code> for the <code>sys_classpath</code>
* parameter.
* See the long constructor documentation for more details.
*
* @param mainClass fully qualified name of the main method class
* @param mainArgs the arguments of the main method in the new isolate
* @param app_classpath the application classpath(s) for the isolate
* (see <a href=#classdoc_class_path>Class path</a>)
* @throws IsolateStartupException if an error occurs in the configuration
* or startup of the new isolate before any application code is invoked
**/
public Isolate(String mainClass, String[] mainArgs, String[] app_classpath)
throws IsolateStartupException {
this(mainClass, mainArgs, app_classpath, (String[])null);
}
/**
* Creates a new Isolate with the specified arguments and
* classpath. <p>
*
* The new isolate will execute the <code>main</code> method of
* class <code>mainClass</code> with arguments
* <code>mainArgs</code>. The <code>mainClass</code> parameter
* must reference a class present in the romized system classes,
* or in one of the classpath elements specified by the
* <code>sys_classpath</code> and <code>app_classpath</code> parameters.
*
* <p>When the constructor returns, the new isolate is not yet
* running. The new isolate does not start execution until the
* {@link #start start} method is invoked. The {@link #halt halt}
* and {@link #exit exit} methods will fail if before
* {@link #start start} is invoked.
*
* <p>Class resolution and loading are performed in the new task
* represented by this new isolate. Any loading exceptions (such as
* <code>ClassNotFoundException</code>), including the loading
* exception of the specified <code>mainClass</code>, will occur
* inside the new task when it is started, not the creator task.
*
* <p>Changes made to any of the constructor's parameters after
* control returns from this constructor will have no effect on the
* newly created isolate.
*
* <p>If <code>mainArgs</code> is <code>null</code>, a zero-length
* <code>String</code> array will be provided to the main method
* of <code>mainClass</code>.
*
* <p>User application classes should be put on <code>app_classpath</code>,
* while <code>sys_classpath</code> can contain only trusted system
* classes.
*
* <p>WARNING: UNTRUSTED USER APPLICATION CLASSES MUST NEVER BE PUT ON THE
* SYSTEM CLASS PATH, AS IT GRANTS THEM ACCESS TO SYSTEM INTERNALS AND
* BREAKS SYSTEM SECURITY.
*
* @param mainClass fully qualified name of the main method class
* @param mainArgs the arguments of the main method in the new isolate
* @param app_classpath the application classpath(s) for the isolate
* @param sys_classpath the system classpath(s) for the isolate
* (see <a href=#classdoc_class_path>Class path</a>)
* @throws IsolateStartupException if an error occurs in the configuration
* of the new isolate before any application code is invoked
* @throws IllegalArgumentException if any parameters are found to be
* invalid.
**/
public Isolate(String mainClass, String[] mainArgs,
String[] app_classpath, String[] sys_classpath)
throws IsolateStartupException
{
securityCheck();
if (mainClass == null) {
throw new IllegalArgumentException("specified class name is null");
}
registerNewIsolate();
_priority = NORM_PRIORITY;
_mainClass = mainClass;
_mainArgs = argCopy(mainArgs);
_app_classpath = argCopy(app_classpath);
_sys_classpath = argCopy(sys_classpath);
/*
* <p>WARNING: DO NOT REMOVE THIS MESSAGE UNLESS YOU HAVE READ AND
* UNDERSTOOD THE SECURITY IMPLICATIONS: HAVING UNTRUSTED USER
* APPLICATION CLASSES ON THE SYSTEM CLASS PATH GRANTS THEM ACCESS TO
* SYSTEM INTERNALS AND BREAKS SYSTEM SECURITY.
*/
if (_sys_classpath.length != 0) {
System.err.println();
System.err.println("****warning****");
System.err.println("****Untrusted user classes must never be put");
System.err.println("****on the system class path");
System.err.println("****warning****");
System.err.println();
}
}
/**
* Start execution of this <code>Isolate</code>. Any code that belongs
* to this <code>Isolate</code> (including static initializers)
* is executed only after this method is called.
* <p>
* Control will return from this method when the new isolate's
* first user level thread starts executing, or if an error occurs
* during the initialization of the new isolate.
*
* <p>If any exception is thrown by this method, no code in the
* <code>Isolate</code> will have executed.
*
* <p>Errors such as the main class being invalid or not visible in
* the classpath will occur handled within the new isolate.
*
* @throws IsolateStartupException if an error occurs in the
* initialization or configuration of the new isolate
* before any application code is invoked, or if this
* Isolate was already started or is terminated.
* @throws IsolateResourceError if systems exceeds maximum Isolate count
* @throws OutOfMemoryError if the reserved memory cannot be allocated
*/
public synchronized void start() throws IsolateStartupException
{
if (getStatus() > NEW) {
throw new IsolateStartupException("Isolate has already started");
}
try {
nativeStart();
} catch (IsolateResourceError e) {
throw e;
} catch (OutOfMemoryError e) {
throw e;
} catch (Throwable t) {
// To be somewhat compilant to JSR-121, we do not pass any
// other errors back to the caller of start(). Instead,
// the caller can use Isolate.exitCode() to discover that
// the isolate has exited. See CR 6270554.
}
// Wait till the fate of the started isolate is known
// (STARTED or STOPPED...)
while (getStatus() <= NEW) {
try {
// Note: do NOT use wait(). See comments inside waitForExit().
waitStatus(NEW);
} catch (InterruptedException e) {
throw new IsolateStartupException(
"Exception was thrown while Isolate was starting");
}
}
}
/**
* Requests normal termination of this <code>Isolate</code>.
* Invocation of this method is equivalent to causing the isolate
* to invoke {@link java.lang.Runtime#exit(int)}. If this method
* invocation is, in fact, the cause of the isolate's termination,
* the <code>status</code> supplied will be the isolate's
* termination status.
*
* <p>No exception is thrown if this isolate is already
* terminated. Even if {@link #isTerminated()} returns false prior
* to invoking <code>exit</code>, an invocation of <code>exit</code> may
* occur after the isolate exits on its own or is terminated by
* another isolate. In these cases, the actual exit code reported by
* the isolate may be different from <code>status</code>.
*
* <p>If this isolate is not yet started, it will be marked as
* already terminated. A subsequent invocation to {@link #start()} would
* result in an IsolateStartupException.
*
* <p>If this isolate is suspended, it will be terminated without
* being resumed.
*
* @param status Termination status. By convention, a nonzero status
* code indicates abnormal termination.
**/
public void exit(int status) {
try {
stop(status, this == currentIsolate() ?
EXIT_REASON_SELF_EXIT :
EXIT_REASON_OTHER_EXIT);
} catch (SecurityException se) {
stop(status, EXIT_REASON_SELF_EXIT);
}
}
/**
* Forces termination of this <code>Isolate</code>.
*
* If this method invocation is in fact the cause of the isolate's
* termination, the <code>status</code> supplied will be the
* isolate's termination status.
*
* <p>No exception is thrown if this isolate is already
* terminated. Even if {@link #isTerminated()} returns false prior
* to invoking <code>halt</code>, an invocation of <code>halt</code> may
* occur after the isolate exits on its own or is terminated by
* another isolate. In these cases, the actual exit code reported by
* the isolate may be different from <code>status</code>.
*
* <p>If this isolate is not yet started, it will be marked as
* already terminated. A subsequent invocation to {@link #start()} would
* result in an IsolateStartupException.
*
* <p>If this isolate is suspended, it will be terminated without
* being resumed.
*
* <h3>Implementation Note</h3>
*
* Implementations should strive to implement "quick" termination
* with as little coordination with the target isolate as possible.
* The only information required of a terminated isolate is the exit
* code it was terminated with.
*
* @param status Termination status. By convention, a nonzero status code
* indicates abnormal termination.
**/
public void halt(int status) {
try {
stop(status, this == currentIsolate() ?
EXIT_REASON_SELF_HALT :
EXIT_REASON_OTHER_HALT);
} catch (SecurityException se) {
stop(status, EXIT_REASON_SELF_HALT);
}
}
/**
* Returns true if this <code>Isolate</code> is terminated.
*/
public boolean isTerminated() {
int state = getStatus();
return (state >= STOPPED);
}
/**
* Returns the Isolate object corresponding to the currently executing
* task.
*
* <p>This method never returns <code>null</code>.
*
* @return the <code>Isolate</code> object for the current task
**/
public static Isolate currentIsolate() {
securityCheck();
return currentIsolate0();
}
private native static Isolate currentIsolate0();
/**
* Returns an array of <code>Isolate</code> objects representing
* all tasks that have been started but have not terminated.
* New tasks may have been constructed or existing ones
* terminated by the time this method returns.
*
* @return the active <code>Isolate</code> objects at the time
* of the call
**/
public static Isolate[] getIsolates() {
securityCheck();
return getIsolates0();
}
private native static Isolate[] getIsolates0();
///////////////////////////////////////////////////////////////////////////
// Valid state transitions are:
// NEW -> { STARTED, STOPPED }
// STARTED -> { STOPPING, STOPPED }
// STOPPING -> { STOPPED }
// { STOPPED } : final states.
// { NEW} : initial states.
//
//
// Note: only Isolate created by the current isolate can be in the NEW
// state.
// Hence, knowing if an isolate is started only consists of testing if
// its state is > NEW.
static final int INVALID_TASK_ID = -1; // invalid task id.
static final int NEW = 1; // created by the current isolate
static final int STARTED = 2; // start() method has been called.
static final int STOPPING = 3; // isolate is stopping --
// see IsolateEvent.STOPPING
static final int STOPPED = 4; // isolate was terminated --
// see IsolateEvent.TERMINATED
/**
* Returns a small integer ID that uniquely identifies this
* Isolate among the current set of active Isolates. The returned
* ID will remain unchanged and reserved for this Isolate during its
* entire lifetime. However, after this Isolate is terminated, the ID may
* be resumed for a new Isolate.
*
* @return -1 if the task has not been started or it has been terminated,
*
*/
public int id() {
return _id;
}
/**
* Returns a 64-bit ID that uniquely identifies this Isolate.
* The ID is assigned when the Isolate is created and will remain
* unchanged and reserved for this Isolate during the entire
* lifetime of the VM.
*/
public long uniqueId() {
return _uniqueId;
}
/**
* @return the amount of object heap memory reserved for this Isolate.
*/
public int reservedMemory() {
return _memoryReserve;
}
/**
* @return the maximum amount of object heap memory that can be
* allocated by this Isolate.
*/
public int totalMemory() {
return _memoryLimit;
}
/**
* This function returns the approximate amount of object heap
* memory currently used by this Isolate. The approximate value
* may not be accurate: it may not include recent allocations
* made by the Isolate, and it may count objects allocated by the
* Isolate that have since become unreachable. <p>
*
* @return the approximate amount of object heap memory currently
* used by this Isolate.
*/
public int usedMemory() {
return usedMemory0();
}
private native int usedMemory0();
/**
* Sets the object heap memory reserved and maximum limits to the
* same value. Note that if the system does not have sufficient
* resources to guaranteed the reserved amount, the start() method
* of this Isolate would fail. This method should only be called
* before the Isolate is started. Calling it after the isolate
* has started will cause undetermined behavior. <p>
*
* @param reserved The minimum amount of memory guaranteed to be
* available to the isolate at any time. Also the total
* amount of memory that the isolate can reserve.
*/
public void setMemoryQuota(int reserved) {
setMemoryQuota(reserved, reserved);
}
/**
* Sets the object heap memory quota for this Isolate. Note that
* if the system does not have sufficient resources to guaranteed
* the reserved amount, the start() method of this Isolate would
* fail.
* This method should only be called before the Isolate is
* started. Calling it after the isolate has started will cause
* undetermined behavior. <p>
*
* @param reserved The minimum amount of memory guaranteed to be
* available to the isolate at any time.
* @param total The total amount of memory that the isolate can
* reserve.
*/
public void setMemoryQuota(int reserved, int total) {
if (reserved < 0 || reserved > total) {
throw new IllegalArgumentException();
}
_memoryReserve = reserved;
_memoryLimit = total;
}
/* Return true if isolate has been started.
*/
synchronized boolean isStarted() {
return getStatus() <= NEW;
}
private String[] argCopy(String[] args) {
if (args == null) {
return new String[0];
}
String[] result = new String[args.length];
JVM.unchecked_obj_arraycopy(args, 0, result, 0, args.length);
return result;
}
/**
* Add this Isolate to the TaskDesc::_seen_isolates list of the
* current task and return the globally unique isolate identifier.
*/
private native void registerNewIsolate();
/**
* Stopping execution of an Isolate. Used by implementation of exit
* and halt.
*
* <p>If this isolate is not yet started, it will be marked as
* already terminated. A subsequent invocation to {@link #start()} would
* result in an IsolateStartupException.
*
* <p>If this isolate is suspended, it will be terminated without
* being resumed.
*/
private native void stop(int exit_code, int exit_reason);
/**
* Adjust the priority of this Isolate. The priority controls the
* amount of CPU time that VM allocates to execute threads in this
* Isolate.
*
* Note: thread scheduling and task scheduling use separate mechanisms.
* In the current imeplentation, each task is guaranteed execution time
* relative to its priority.
*
*
* @param new_priority must be between <code>MIN_PRIORITY</code>
* and <code>MAX_PRIORITY</code>, or else this method call will
* have no effect.
*/
public void setPriority(int new_priority) {
if (new_priority >= MIN_PRIORITY && new_priority <= MAX_PRIORITY) {
_priority = new_priority;
setPriority0(new_priority);
}
}
private native void setPriority0(int new_priority);
/**
* Returns the priority of this isolate.
*
* @return the priority of this isolate. If the isolate has already
* terminated, the returned value is undefined.
*/
public int getPriority() {
return _priority;
}
/**
* Returns if this isolate has been suspended.
* @return true iff the isolate has been suspended.
*/
public boolean isSuspended() {
return (isSuspended0() != 0 ? true : false);
}
private native int isSuspended0();
/**
* Suspends all threads in this isolate from execution. This
* method should be used carefully if objects shared between isolates
* (passed via native methods) are used for synchornization. A
* suspended isolate holding a lock on such an object will stop other
* tasks from ever receiving that lock.
* See introduction for better ways of communicating between isolates.
*
* This method will suspend the isolate only if the isolate is currently
* started, not suspended and not terminated. Otherwise this method
* has no effect.
*/
public void suspend() {
suspend0();
}
private native void suspend0();
/**
* The opposite of the <code>suspend</code> method.
*
* This method will resume the isolate only if the isolate is
* currently started, suspended and not terminated. Otherwise this
* method has no effect.
*/
public void resume() {
resume0();
}
private native void resume0();
/**
* Returns the exit code of the isolate. If this Isolate has terminated,
* this method returns the exit code parameter to the first invocation of
* System.exit(), Isolate.exit() or Isolate.halt() that caused the Isolate
* to terminate. If this Isolate has terminated without calling
* System.exit(), Isolate.exit() or Isolate.halt(), then 0 is returned.
*
* If this Isolate has not started or has not terminated, 0 is returned.
*
* @return the exit code of the isolate.
*/
public int exitCode() {
return exitCode0();
}
private native int exitCode0();
/**
* Blocks the execution of the calling thread until this Isolate
* has exited. If <code>waitForExit()</code> is called on the
* current Isolate, the result is undefined.
*
* @throws InterruptedException (unimplemented yet): if CLDC
* Specification 1.1 is enabled, when a thread is blocked
* inside this method, it may be interrupted by an
* invocation of Thread.interrupt, in which case an
* InterruptedException is thrown regardless of the
* termination status of this Isolate.
*/
public synchronized void waitForExit() /* throws InterruptedException */ {
while (getStatus() <= STOPPING) {
try {
// Note: do NOT use wait(): When notifyStatus() is
// called, the calling thread may not hold the monitor
// of this object, so if we wrote the code like this
// we may get into a race condition
// while (getStatus() <= STOPPING) {
// <thread switch/race condition may happen here>
// wait();
// }
// waitStatus() performs the getStatus() <= STOPPING check in
// native code again, where thread switch is guaranteed to
// not happen. Hence we won't have a race condition.
waitStatus(STOPPED);
} catch (InterruptedException e) {
// IMPL_NOTE: this method should throw InterruptedException!
throw new Error();
}
}
}
/**
* Returns the classpath the Isolate was started with.
*
* @return String[] that is equal to classpath argument passed to
* Isolate constructor
*/
public String[] getClassPath() {
return argCopy(_app_classpath);
}
/**
* Determine if this isolate has permission to access the API
* If not, throw runtime exception
*/
private static void securityCheck() {
if (_API_access_ok == 0) {
throw new SecurityException("Access to Isolate API not allowed");
}
}
/**
* Sets the access to Isolate API for this Isolate. This method
* should be used by the AMS, before the Isolate is started, to
* control whether or not a created Isolate is able to call the
* Isolate API. The default for all but the first Isolate is
* <code>false</code>. If the AMS calls this method after the Isolate
* has started, it has no effect.<p>
*
* In additional, after an Isolate has started, if it has access
* to the Isolate API, it can call this method to disable
* it. However, once it loses the access, attempts to call this
* method would result in a SecurityException.
*/
public void setAPIAccess(boolean access) {
_APIAccess = (access == true ? 1 : 0);
// Only allow access to be degraded after starting.
if (!access && equals(currentIsolate())) {
_API_access_ok = 0;
}
}
public void setDebug(boolean mode) {
_ConnectDebugger = (mode == true ? 1 : 0);
}
public void attachDebugger() {
securityCheck();
attachDebugger0(this);
}
/**
* Indicates if debugger connection is established with the VM.
*
* @return true if debugger is connected, otherwise returns false.
*/
public native boolean isDebuggerConnected();
/**
* Controls whether or not classes for this isolate need to be
* verified. When creating a new Isolate, the AMS may waive
* verification for classes that have already been verified. The
* default is <code>false</code>. This method should be called
* before the Isolate is started.
*/
public void setUseVerifier(boolean verify) {
_UseVerifier = (verify == true ? 1 : 0);
}
/**
* Returns the current status of the task represented by this Isolate.
*
* @return one of NEW, STARTED, STOPPING or STOPPED
*/
private native int getStatus();
/**
* Notify all threads that are waiting on the status of any Isolate object
* that represent the same task as this Isolate object.
*
* To simplify VM design, this method does NOT need to be called
* while holding a lock of such Isolate objects. To avert race conditions,
* the waiting threads must be blocked using waitStatus() instead
* of wait(). See comments inside waitForExit() for details.
*/
private native void notifyStatus();
/**
* Blocks the current thread until getStatus() would return a value
* greater than maxStatus, or (CLDC Spec 1.1 only) until this
* thread is interrupted. <p>
*
* See comments inside waitForExit() to see why this method method
* must be used instead of wait() to avert race conditions.
*/
private native void waitStatus(int maxStatus) throws InterruptedException;
/* For now, ignore the links argument.
* Native method will use the JNI invocation API to start a new in-process
* JVM to execute the new Isolate.
*/
private native void nativeStart() throws IsolateStartupException;
/**
* The last non-daemon thread returned from main.
*/
private static final int EXIT_REASON_IMPLICIT_EXIT = 1;
/**
* The last non-daemon thread exited due to an uncaught exception.
*
* <p>Note that if a daemon thread dies with an uncaught exception,
* that will not cause the containing isolate to die. Additionally,
* only if the <emph>last</emph> non-daemon thread dies with
* an uncaught exception will this reason be noted. Uncaught exceptions
* in shutdown hooks do not count, either.
*/
private static final int EXIT_REASON_UNCAUGHT_EXCEPT = 6;
/**
* The isolate invoked {@link System#exit System.exit},
* {@link Runtime#exit Runtime.exit}, or
* {@link Isolate#exit Isolate.exit} on itself.
*/
private static final int EXIT_REASON_SELF_EXIT = 2;
/**
* The isolate invoked
* {@link Runtime#halt Runtime.halt} or
* {@link Isolate#halt Isolate.halt} on itself.
*/
private static final int EXIT_REASON_SELF_HALT = 3;
/**
* Some other isolate invoked {@link Isolate#exit Isolate.exit}
* on the isolate.
*/
private static final int EXIT_REASON_OTHER_EXIT = 4;
/**
* Some other isolate invoked {@link Isolate#halt Isolate.halt}
* on the isolate.
*/
private static final int EXIT_REASON_OTHER_HALT = 5;
/**
* Sets active profile name for isolate. This method must be
* called before the isolate is started.
*
* If isolate is already started the method throws an
* <code>IllegalIsolateStateException</code>.
*
* The method also determines if <code>profile</code>
* is a name of existing profile which is defined in ROM
* configuration file. If not, throws runtime
* <code>IllegalArgumentException</code>.
*
* @param profile The new active profile name.
*/
public native void setProfile(String profile) throws
IllegalArgumentException,
IllegalIsolateStateException;
/**
* Sets the packages which will be hidden. See definition of hidden package in
* doc/misc/Romizer.html. Note, that this function call overrides previous settings.
*
* If isolate is already started the method throws an
* <code>IllegalIsolateStateException</code>.
*
* @param package_name. The name of package for marking.
*/
public void setHiddenPackages(String[] package_names) throws
IllegalIsolateStateException {
if (getStatus() > NEW) {
throw new IllegalIsolateStateException("Can only set hidden packages before Isolate starts");
}
_hidden_packages = package_names;
}
/**
* Sets the packages which will be restricted. See definition of restricted package in
* doc/misc/Romizer.html. Note, that this function call overrides previous settings.
*
* If isolate is already started the method throws an
* <code>IllegalIsolateStateException</code>.
*
* @param package_name The name of package for marking.
*/
public void setRestrictedPackages(String[] package_names) throws
IllegalIsolateStateException {
if (getStatus() > NEW) {
throw new IllegalIsolateStateException("Can only set restricted packages before Isolate starts");
}
_restricted_packages = package_names;
}
/**
* Sets whether isolate should be profiled or not. By default all isolates are profiled.
* Should be set before task for isolate is created.
*
*/
public void setUseProfiler(boolean useProfiler) {
_UseProfiler = (useProfiler == true ? 1 : 0);
}
private native void attachDebugger0(Isolate obj);
}