You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2006/03/31 17:34:51 UTC
svn commit: r390443 [3/5] - in /incubator/harmony/enhanced/classlib/trunk:
make/ make/patternsets/ modules/kernel/ modules/luni-kernel/
modules/luni-kernel/META-INF/ modules/luni-kernel/src/
modules/luni-kernel/src/main/ modules/luni-kernel/src/main/ja...
Added: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/System.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/System.java?rev=390443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/System.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/System.java Fri Mar 31 07:34:47 2006
@@ -0,0 +1,824 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * 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 java.lang;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Properties;
+import java.util.PropertyPermission;
+
+
+/**
+ * Class System provides a standard place for programs to find system related
+ * information. All System API is static.
+ *
+ */
+public final class System {
+
+ // The standard input, output, and error streams.
+ // Typically, these are connected to the shell which
+ // ran the Java program.
+ /**
+ * Default input stream
+ */
+ public static final InputStream in;
+
+ /**
+ * Default output stream
+ */
+ public static final PrintStream out;
+
+ /**
+ * Default error output stream
+ */
+ public static final PrintStream err;
+
+ // Get a ref to the Runtime instance for faster lookup
+ private static final Runtime RUNTIME = Runtime.getRuntime();
+
+ // The System Properties table
+ private static Properties systemProperties;
+
+ // The System default SecurityManager
+ private static SecurityManager security;
+
+ // Initialize all the slots in System on first use.
+ static {
+ // Fill in the properties from the VM information.
+ ensureProperties();
+ // Set up standard in, out, and err.
+ err = new String.ConsolePrintStream(new BufferedOutputStream(
+ new FileOutputStream(FileDescriptor.err)));
+ out = new String.ConsolePrintStream(new BufferedOutputStream(
+ new FileOutputStream(FileDescriptor.out)));
+ in = new BufferedInputStream(new FileInputStream(FileDescriptor.in));
+ }
+
+ /**
+ * Sets the value of the static slot "in" in the receiver to the passed in
+ * argument.
+ *
+ * @param newIn
+ * the new value for in.
+ */
+ public static void setIn(InputStream newIn) {
+ SecurityManager secMgr = System.getSecurityManager();
+ setFieldImpl("in", newIn);
+ }
+
+ /**
+ * Sets the value of the static slot "out" in the receiver to the passed in
+ * argument.
+ *
+ * @param newOut
+ * the new value for out.
+ */
+ public static void setOut(java.io.PrintStream newOut) {
+ SecurityManager secMgr = System.getSecurityManager();
+
+ setFieldImpl("out", newOut);
+ }
+
+ /**
+ * Sets the value of the static slot "err" in the receiver to the passed in
+ * argument.
+ *
+ * @param newErr
+ * the new value for err.
+ */
+ public static void setErr(java.io.PrintStream newErr) {
+ SecurityManager secMgr = System.getSecurityManager();
+
+ }
+
+ /**
+ * Prevents this class from being instantiated.
+ */
+ private System() {
+ }
+
+ /**
+ * Copies the contents of <code>array1</code> starting at offset
+ * <code>start1</code> into <code>array2</code> starting at offset
+ * <code>start2</code> for <code>length</code> elements.
+ *
+ * @param array1
+ * the array to copy out of
+ * @param start1
+ * the starting index in array1
+ * @param array2
+ * the array to copy into
+ * @param start2
+ * the starting index in array2
+ * @param length
+ * the number of elements in the array to copy
+ */
+ public static void arraycopy(Object array1, int start1, Object array2,
+ int start2, int length) {
+ // sending getClass() to both arguments will check for null
+ Class type1 = array1.getClass();
+ Class type2 = array2.getClass();
+ if (!type1.isArray() || !type2.isArray())
+ throw new ArrayStoreException();
+ Class componentType1 = type1.getComponentType();
+ Class componentType2 = type2.getComponentType();
+ if (!componentType1.isPrimitive()) {
+ if (componentType2.isPrimitive())
+ throw new ArrayStoreException();
+ arraycopy((Object[]) array1, start1, (Object[]) array2, start2,
+ length);
+ } else {
+ if (componentType2 != componentType1)
+ throw new ArrayStoreException();
+ if (componentType1 == Integer.TYPE) {
+ arraycopy((int[]) array1, start1, (int[]) array2, start2,
+ length);
+ } else if (componentType1 == Byte.TYPE) {
+ arraycopy((byte[]) array1, start1, (byte[]) array2, start2,
+ length);
+ } else if (componentType1 == Long.TYPE) {
+ arraycopy((long[]) array1, start1, (long[]) array2, start2,
+ length);
+ } else if (componentType1 == Short.TYPE) {
+ arraycopy((short[]) array1, start1, (short[]) array2, start2,
+ length);
+ } else if (componentType1 == Character.TYPE) {
+ arraycopy((char[]) array1, start1, (char[]) array2, start2,
+ length);
+ } else if (componentType1 == Boolean.TYPE) {
+ arraycopy((boolean[]) array1, start1, (boolean[]) array2,
+ start2, length);
+ } else if (componentType1 == Double.TYPE) {
+ arraycopy((double[]) array1, start1, (double[]) array2, start2,
+ length);
+ } else if (componentType1 == Float.TYPE) {
+ arraycopy((float[]) array1, start1, (float[]) array2, start2,
+ length);
+ }
+ }
+ }
+
+ /**
+ * Private version of the arraycopy method (used by the jit for reference arraycopies)
+ */
+ private static void arraycopy(Object[] A1, int offset1, Object[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(int[] A1, int offset1, int[] A2, int offset2,
+ int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(byte[] A1, int offset1, byte[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(short[] A1, int offset1, short[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(long[] A1, int offset1, long[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(char[] A1, int offset1, char[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(boolean[] A1, int offset1, boolean[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(double[] A1, int offset1, double[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Copies the contents of <code>A1</code> starting at offset <code>offset1</code>
+ * into <code>A2</code> starting at offset <code>offset2</code> for
+ * <code>length</code> elements.
+ *
+ * @param A1 the array to copy out of
+ * @param offset1 the starting index in array1
+ * @param A2 the array to copy into
+ * @param offset2 the starting index in array2
+ * @param length the number of elements in the array to copy
+ */
+ private static void arraycopy(float[] A1, int offset1, float[] A2,
+ int offset2, int length) {
+ if (offset1 >= 0 && offset2 >= 0 && length >= 0
+ && length <= A1.length - offset1
+ && length <= A2.length - offset2) {
+ // Check if this is a forward or backwards arraycopy
+ if (A1 != A2 || offset1 > offset2 || offset1 + length <= offset2) {
+ for (int i = 0; i < length; ++i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ A2[offset2 + i] = A1[offset1 + i];
+ }
+ }
+ } else
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ /**
+ * Answers the current time expressed as milliseconds since the time
+ * 00:00:00 UTC on January 1, 1970.
+ *
+ * @return the time in milliseconds.
+ */
+ public static native long currentTimeMillis();
+
+ private static final int InitLocale = 0;
+
+ private static final int PlatformEncoding = 1;
+
+ private static final int FileEncoding = 2;
+
+ private static final int OSEncoding = 3;
+
+ /**
+ * If systemProperties is unset, then create a new one based on the values
+ * provided by the virtual machine.
+ */
+ private static void ensureProperties() {
+ systemProperties = new Properties();
+
+ String platformEncoding = null;
+ String fileEncoding, osEncoding = null;
+ String definedFileEncoding = getEncoding(FileEncoding);
+ String definedOSEncoding = getEncoding(OSEncoding);
+ if (definedFileEncoding != null) {
+ fileEncoding = definedFileEncoding;
+ // if file.encoding is defined, and os.encoding is not, use the
+ // detected
+ // platform encoding for os.encoding
+ if (definedOSEncoding == null) {
+ platformEncoding = getEncoding(PlatformEncoding);
+ osEncoding = platformEncoding;
+ } else {
+ getEncoding(InitLocale);
+ }
+ } else {
+ platformEncoding = getEncoding(PlatformEncoding);
+ fileEncoding = platformEncoding;
+ }
+ // if os.encoding is not defined, file.encoding will be used
+ if (osEncoding == null)
+ osEncoding = definedOSEncoding;
+ if (osEncoding != null)
+ systemProperties.put("os.encoding", osEncoding);
+
+ systemProperties.put("file.encoding", fileEncoding);
+
+ systemProperties.put("java.version", "1.4.2 subset");
+ systemProperties.put("java.specification.version", "1.4");
+
+ systemProperties.put("java.specification.vendor",
+ "Sun Microsystems Inc.");
+ systemProperties.put("java.specification.name",
+ "Java Platform API Specification");
+
+ systemProperties.put("com.ibm.oti.configuration", "clear");
+ systemProperties.put("com.ibm.oti.configuration.dir", "jclClear");
+
+ String[] list = getPropertyList();
+ for (int i = 0; i < list.length; i += 2) {
+ String key = list[i];
+ if (key == null)
+ break;
+ systemProperties.put(key, list[i + 1]);
+ }
+
+ String consoleEncoding = (String) systemProperties
+ .get("console.encoding");
+ if (consoleEncoding == null) {
+ if (platformEncoding == null)
+ platformEncoding = getEncoding(PlatformEncoding);
+ consoleEncoding = platformEncoding;
+ systemProperties.put("console.encoding", consoleEncoding);
+ }
+
+ systemProperties.put("com.ibm.oti.jcl.build", "plugin");
+ }
+
+ /**
+ * 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 code
+ * the return code.
+ *
+ * @throws SecurityException
+ * if the running thread is not allowed to cause the vm to exit.
+ *
+ * @see SecurityManager#checkExit
+ */
+ public static void exit(int code) {
+ RUNTIME.exit(code);
+ }
+
+ /**
+ * Indicate to the virtual machine that it would be a good time to collect
+ * available memory. Note that, this is a hint only.
+ */
+ public static void gc() {
+ RUNTIME.gc();
+ }
+
+ /**
+ * Returns an environment variable.
+ *
+ * @param var
+ * the name of the environment variable
+ * @return the value of the specified environment variable
+ * @deprecated Use System.getProperty()
+ */
+ public static String getenv(String var) {
+ if (var == null) {
+ throw new NullPointerException();
+ }
+ SecurityManager secMgr = System.getSecurityManager();
+ if (secMgr != null) {
+ secMgr.checkPermission(new RuntimePermission("getenv." + var));
+ }
+ throw new Error();
+ }
+
+ /**
+ * Answers the system properties. Note that this is not a copy, so that
+ * changes made to the returned Properties object will be reflected in
+ * subsequent calls to getProperty and getProperties.
+ * <p>
+ * Security managers should restrict access to this API if possible.
+ *
+ * @return the system properties
+ */
+ public static Properties getProperties() {
+ SecurityManager secMgr = System.getSecurityManager();
+ if (secMgr != null) {
+ secMgr.checkPropertiesAccess();
+ }
+ return systemProperties;
+ }
+
+ /**
+ * Answers the system properties without any security checks. This is used
+ * for access from within java.lang.
+ *
+ * @return the system properties
+ */
+ static Properties internalGetProperties() {
+ return systemProperties;
+ }
+
+ /**
+ * Answers the value of a particular system property. Answers null if no
+ * such property exists,
+ * <p>
+ * The properties currently provided by the virtual machine are:
+ *
+ * <pre>
+ * java.vendor.url
+ * java.class.path
+ * user.home
+ * java.class.version
+ * os.version
+ * java.vendor
+ * user.dir
+ * user.timezone
+ * path.separator
+ * os.name
+ * os.arch
+ * line.separator
+ * file.separator
+ * user.name
+ * java.version
+ * java.home
+ * </pre>
+ *
+ * @param prop
+ * the system property to look up
+ * @return the value of the specified system property, or null if the
+ * property doesn't exist
+ */
+ public static String getProperty(String prop) {
+ return getProperty(prop, null);
+ }
+
+ /**
+ * Answers the value of a particular system property. If no such property is
+ * found, answers the defaultValue.
+ *
+ * @param prop
+ * the system property to look up
+ * @param defaultValue
+ * return value if system property is not found
+ * @return the value of the specified system property, or defaultValue if
+ * the property doesn't exist
+ */
+ public static String getProperty(String prop, String defaultValue) {
+ if (prop.length() == 0)
+ throw new IllegalArgumentException();
+ SecurityManager secMgr = System.getSecurityManager();
+ if (secMgr != null) {
+ secMgr.checkPropertyAccess(prop);
+ }
+ return systemProperties.getProperty(prop, defaultValue);
+ }
+
+ /**
+ * Sets the value of a particular system property.
+ *
+ * @param prop
+ * the system property to change
+ * @param value
+ * the value to associate with prop
+ * @return the old value of the property, or null
+ */
+ public static String setProperty(String prop, String value) {
+ if (prop.length() == 0)
+ throw new IllegalArgumentException();
+ SecurityManager secMgr = System.getSecurityManager();
+ if (secMgr != null) {
+ secMgr.checkPermission(new PropertyPermission(prop, "write"));
+ }
+ return (String) systemProperties.setProperty(prop, value);
+ }
+
+ /**
+ * Answers an array of Strings containing key..value pairs (in consecutive
+ * array elements) which represent the starting values for the system
+ * properties as provided by the virtual machine.
+ *
+ * @return the default values for the system properties.
+ */
+ private static native String[] getPropertyList();
+
+ /**
+ * Return the requested encoding. 0 - initialize locale 1 - detected
+ * platform encoding 2 - command line defined file.encoding 3 - command line
+ * defined os.encoding
+ */
+ private static native String getEncoding(int type);
+
+ /**
+ * Answers the active security manager.
+ *
+ * @return the system security manager object.
+ */
+ public static SecurityManager getSecurityManager() {
+ return security;
+ }
+
+ /**
+ * Answers an integer hash code for the parameter. The hash code returned is
+ * the same one that would be returned by java.lang.Object.hashCode(),
+ * whether or not the object's class has overridden hashCode(). The hash
+ * code for null is 0.
+ *
+ * @param anObject
+ * the object
+ * @return the hash code for the object
+ *
+ * @see java.lang.Object#hashCode
+ */
+ public static native int identityHashCode(Object anObject);
+
+ /**
+ * Loads the specified file as a dynamic library.
+ *
+ * @param pathName
+ * the path of the file to be loaded
+ */
+ public static void load(String pathName) {
+ SecurityManager smngr = System.getSecurityManager();
+ if (smngr != null)
+ smngr.checkLink(pathName);
+ ClassLoader.loadLibraryWithPath(pathName, ClassLoader
+ .callerClassLoader(), null);
+ }
+
+ /**
+ * 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 static void loadLibrary(String libName) {
+ ClassLoader.loadLibraryWithClassLoader(libName, ClassLoader
+ .callerClassLoader());
+ }
+
+ /**
+ * Provides a hint to the virtual machine that it would be useful to attempt
+ * to perform any outstanding object finalizations.
+ */
+ public static void runFinalization() {
+ RUNTIME.runFinalization();
+ }
+
+ /**
+ * 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 flag
+ * true means finalize all on exit.
+ *
+ * @deprecated This method is unsafe.
+ */
+ public static void runFinalizersOnExit(boolean flag) {
+ Runtime.runFinalizersOnExit(flag);
+ }
+
+ /**
+ * Answers the system properties. Note that the object which is passed in
+ * not copied, so that subsequent changes made to the object will be
+ * reflected in calls to getProperty and getProperties.
+ * <p>
+ * Security managers should restrict access to this API if possible.
+ *
+ * @param p
+ * the property to set
+ */
+ public static void setProperties(Properties p) {
+ SecurityManager secMgr = System.getSecurityManager();
+ if (secMgr != null) {
+ secMgr.checkPropertiesAccess();
+ }
+ if (p == null) {
+ ensureProperties();
+ } else {
+ systemProperties = p;
+ }
+ }
+
+ /**
+ * Sets the active security manager. Note that once the security manager has
+ * been set, it can not be changed. Attempts to do so will cause a security
+ * exception.
+ *
+ * @param s
+ * the new security manager
+ *
+ * @throws SecurityException
+ * if the security manager has already been set.
+ */
+ public static void setSecurityManager(final SecurityManager s) {
+ final SecurityManager currentSecurity = security;
+ try {
+ // Preload classes used for checkPackageAccess(),
+ // otherwise we could go recursive
+ s.checkPackageAccess("java.lang");
+ } catch (Exception e) {
+ }
+
+ security = s;
+ }
+
+ /**
+ * Answers the platform specific file name format for the shared library
+ * named by the argument.
+ *
+ * @param userLibName
+ * the name of the library to look up.
+ * @return the platform specific filename for the library
+ */
+ public static native String mapLibraryName(String userLibName);
+
+ /**
+ * Sets the value of the named static field in the receiver to the passed in
+ * argument.
+ *
+ * @param fieldName
+ * the name of the field to set, one of in, out, or err
+ * @param stream
+ * the new value of the field
+ */
+ private static native void setFieldImpl(String fieldName, Object stream);
+
+}
Added: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Thread.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Thread.java?rev=390443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Thread.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Thread.java Fri Mar 31 07:34:47 2006
@@ -0,0 +1,694 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * 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 java.lang;
+
+/**
+ * This class must be implemented by the vm vendor. The documented methods must
+ * be implemented to support other provided class implementations in this
+ * package. A Thread is a unit of concurrent execution in Java. It has its own
+ * call stack for methods being called and their parameters. Threads in the same
+ * VM interact and synchronize by the use of shared Objects and monitors
+ * associated with these objects. Synchronized methods and part of the API in
+ * Object also allow Threads to cooperate. When a Java program starts executing
+ * there is an implicit Thread (called "main") which is automatically created by
+ * the VM. This Thread belongs to a ThreadGroup (also called "main") which is
+ * automatically created by the bootstrap sequence by the VM as well.
+ *
+ * @see java.lang.Object
+ * @see java.lang.ThreadGroup
+ */
+public class Thread implements Runnable {
+
+ public final static int MAX_PRIORITY = 10; // Maximum allowed priority for
+
+ // a thread
+ public final static int MIN_PRIORITY = 1; // Minimum allowed priority for
+
+ // a thread
+ public final static int NORM_PRIORITY = 5; // Normal priority for a thread
+
+ Object slot1;
+
+ Object slot2;
+
+ Object slot3;
+
+ /**
+ * Constructs a new Thread with no runnable object and a newly generated
+ * name. The new Thread will belong to the same ThreadGroup as the Thread
+ * calling this constructor.
+ *
+ * @see java.lang.ThreadGroup
+ */
+ public Thread() {
+ super();
+ }
+
+ /**
+ * Constructs a new Thread with a runnable object and a newly generated
+ * name. The new Thread will belong to the same ThreadGroup as the Thread
+ * calling this constructor.
+ *
+ * @param runnable
+ * a java.lang.Runnable whose method <code>run</code> will be
+ * executed by the new Thread
+ * @see java.lang.ThreadGroup
+ * @see java.lang.Runnable
+ */
+ public Thread(Runnable runnable) {
+ super();
+ }
+
+ /**
+ * Constructs a new Thread with a runnable object and name provided. The new
+ * Thread will belong to the same ThreadGroup as the Thread calling this
+ * constructor.
+ *
+ * @param runnable
+ * a java.lang.Runnable whose method <code>run</code> will be
+ * executed by the new Thread
+ * @param threadName
+ * Name for the Thread being created
+ * @see java.lang.ThreadGroup
+ * @see java.lang.Runnable
+ */
+ public Thread(Runnable runnable, String threadName) {
+ super();
+ }
+
+ /**
+ * Constructs a new Thread with no runnable object and the name provided.
+ * The new Thread will belong to the same ThreadGroup as the Thread calling
+ * this constructor.
+ *
+ * @param threadName
+ * Name for the Thread being created
+ * @see java.lang.ThreadGroup
+ * @see java.lang.Runnable
+ */
+ public Thread(String threadName) {
+ super();
+ }
+
+ /**
+ * Constructs a new Thread with a runnable object and a newly generated
+ * name. The new Thread will belong to the ThreadGroup passed as parameter.
+ *
+ * @param group
+ * ThreadGroup to which the new Thread will belong
+ * @param runnable
+ * a java.lang.Runnable whose method <code>run</code> will be
+ * executed by the new Thread
+ * @exception SecurityException
+ * if <code>group.checkAccess()</code> fails with a
+ * SecurityException
+ * @exception IllegalThreadStateException
+ * if <code>group.destroy()</code> has already been done
+ * @see java.lang.ThreadGroup
+ * @see java.lang.Runnable
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager
+ */
+ public Thread(ThreadGroup group, Runnable runnable) {
+ super();
+ }
+
+ /**
+ * Constructs a new Thread with a runnable object, the given name and
+ * belonging to the ThreadGroup passed as parameter.
+ *
+ * @param group
+ * ThreadGroup to which the new Thread will belong
+ * @param runnable
+ * a java.lang.Runnable whose method <code>run</code> will be
+ * executed by the new Thread
+ * @param threadName
+ * Name for the Thread being created
+ * @param stack
+ * Platform dependent stack size
+ * @exception SecurityException
+ * if <code>group.checkAccess()</code> fails with a
+ * SecurityException
+ * @exception IllegalThreadStateException
+ * if <code>group.destroy()</code> has already been done
+ * @see java.lang.ThreadGroup
+ * @see java.lang.Runnable
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager
+ */
+ public Thread(ThreadGroup group, Runnable runnable, String threadName,
+ long stack) {
+ super();
+ }
+
+ /**
+ * Constructs a new Thread with a runnable object, the given name and
+ * belonging to the ThreadGroup passed as parameter.
+ *
+ * @param group
+ * ThreadGroup to which the new Thread will belong
+ * @param runnable
+ * a java.lang.Runnable whose method <code>run</code> will be
+ * executed by the new Thread
+ * @param threadName
+ * Name for the Thread being created
+ * @exception SecurityException
+ * if <code>group.checkAccess()</code> fails with a
+ * SecurityException
+ * @exception IllegalThreadStateException
+ * if <code>group.destroy()</code> has already been done
+ * @see java.lang.ThreadGroup
+ * @see java.lang.Runnable
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager
+ */
+ public Thread(ThreadGroup group, Runnable runnable, String threadName) {
+ super();
+ }
+
+ /**
+ * Constructs a new Thread with no runnable object, the given name and
+ * belonging to the ThreadGroup passed as parameter.
+ *
+ * @param group
+ * ThreadGroup to which the new Thread will belong
+ * @param threadName
+ * Name for the Thread being created
+ * @exception SecurityException
+ * if <code>group.checkAccess()</code> fails with a
+ * SecurityException
+ * @exception IllegalThreadStateException
+ * if <code>group.destroy()</code> has already been done
+ * @see java.lang.ThreadGroup
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager
+ */
+ public Thread(ThreadGroup group, String threadName) {
+ super();
+ }
+
+ /**
+ * Returns the number of active threads in the running thread's ThreadGroup
+ *
+ * @return Number of Threads
+ */
+ public static int activeCount() {
+ return 0;
+ }
+
+ /**
+ * This method is used for operations that require approval from a
+ * SecurityManager. If there's none installed, this method is a no-op. If
+ * there's a SecurityManager installed ,
+ * <code>checkAccess(Ljava.lang.Thread;)</code> is called for that
+ * SecurityManager.
+ *
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager
+ */
+ public final void checkAccess() {
+ return;
+ }
+
+ /**
+ * Returns the number of stack frames in this thread.
+ *
+ * @return Number of stack frames
+ * @deprecated The results of this call were never well defined. To make
+ * things worse, it would depend if the Thread was suspended or
+ * not, and suspend was deprecated too.
+ */
+ public int countStackFrames() {
+ return 0;
+ }
+
+ /**
+ * Answers the instance of Thread that corresponds to the running Thread
+ * which calls this method.
+ *
+ * @return a java.lang.Thread corresponding to the code that called
+ * <code>currentThread()</code>
+ */
+ public static Thread currentThread() {
+ return null;
+ };
+
+ /**
+ * Destroys the receiver without any monitor cleanup. Not implemented.
+ *
+ * @deprecated Not implemented.
+ */
+ public void destroy() {
+ return;
+ }
+
+ /**
+ * Prints a text representation of the stack for this Thread.
+ *
+ */
+ public static void dumpStack() {
+ return;
+ }
+
+ /**
+ * Copies an array with all Threads which are in the same ThreadGroup as the
+ * receiver - and subgroups - into the array <code>threads</code> passed
+ * as parameter. If the array passed as parameter is too small no exception
+ * is thrown - the extra elements are simply not copied.
+ *
+ * @param threads
+ * array into which the Threads will be copied
+ * @return How many Threads were copied over
+ * @exception SecurityException
+ * if the installed SecurityManager fails
+ * <code>checkAccess(Ljava.lang.Thread;)</code>
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager
+ */
+ public static int enumerate(Thread[] threads) {
+ return 0;
+ }
+
+ /**
+ * Returns the context ClassLoader for the receiver.
+ *
+ * @return ClassLoader The context ClassLoader
+ * @see java.lang.ClassLoader
+ * @see #getContextClassLoader()
+ */
+ public ClassLoader getContextClassLoader() {
+ return null;
+ }
+
+ /**
+ * Answers the name of the receiver.
+ *
+ * @return the receiver's name (a java.lang.String)
+ */
+ public final String getName() {
+ return null;
+ }
+
+ /**
+ * Answers the priority of the receiver.
+ *
+ * @return the receiver's priority (an <code>int</code>)
+ * @see Thread#setPriority
+ */
+ public final int getPriority() {
+ return 0;
+ }
+
+ /**
+ * Answers the ThreadGroup to which the receiver belongs
+ *
+ * @return the receiver's ThreadGroup
+ */
+ public final ThreadGroup getThreadGroup() {
+ return null;
+ }
+
+ /**
+ * A sample implementation of this method is provided by the reference
+ * implementation. It must be included, as it is called by ThreadLocal.get()
+ * and InheritableThreadLocal.get(). Return the value associated with the
+ * ThreadLocal in the receiver
+ *
+ * @param local
+ * ThreadLocal to perform the lookup
+ * @return the value of the ThreadLocal
+ * @see #setThreadLocal
+ */
+ Object getThreadLocal(ThreadLocal local) {
+ return null;
+ }
+
+ /**
+ * Posts an interrupt request to the receiver
+ *
+ * @exception SecurityException
+ * if <code>group.checkAccess()</code> fails with a
+ * SecurityException
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager
+ * @see Thread#interrupted
+ * @see Thread#isInterrupted
+ */
+ public void interrupt() {
+ return;
+ }
+
+ /**
+ * Answers a <code>boolean</code> indicating whether the current Thread (
+ * <code>currentThread()</code>) has a pending interrupt request (
+ * <code>true</code>) or not (<code>false</code>). It also has the
+ * side-effect of clearing the flag.
+ *
+ * @return a <code>boolean</code>
+ * @see Thread#currentThread
+ * @see Thread#interrupt
+ * @see Thread#isInterrupted
+ */
+ public static boolean interrupted() {
+ return false;
+ };
+
+ /**
+ * Answers <code>true</code> if the receiver has already been started and
+ * still runs code (hasn't died yet). Answers <code>false</code> either if
+ * the receiver hasn't been started yet or if it has already started and run
+ * to completion and died.
+ *
+ * @return a <code>boolean</code>
+ * @see Thread#start
+ */
+ public final boolean isAlive() {
+ return false;
+ }
+
+ /**
+ * Answers a <code>boolean</code> indicating whether the receiver is a
+ * daemon Thread (<code>true</code>) or not (<code>false</code>) A
+ * daemon Thread only runs as long as there are non-daemon Threads running.
+ * When the last non-daemon Thread ends, the whole program ends no matter if
+ * it had daemon Threads still running or not.
+ *
+ * @return a <code>boolean</code>
+ * @see Thread#setDaemon
+ */
+ public final boolean isDaemon() {
+ return false;
+ }
+
+ /**
+ * Answers a <code>boolean</code> indicating whether the receiver has a
+ * pending interrupt request (<code>true</code>) or not (
+ * <code>false</code>)
+ *
+ * @return a <code>boolean</code>
+ * @see Thread#interrupt
+ * @see Thread#interrupted
+ */
+ public boolean isInterrupted() {
+ return false;
+ }
+
+ /**
+ * Blocks the current Thread (<code>Thread.currentThread()</code>) until
+ * the receiver finishes its execution and dies.
+ *
+ * @exception InterruptedException
+ * if <code>interrupt()</code> was called for the receiver
+ * while it was in the <code>join()</code> call
+ * @see Object#notifyAll
+ * @see java.lang.ThreadDeath
+ */
+ public final void join() throws InterruptedException {
+ return;
+ }
+
+ /**
+ * Blocks the current Thread (<code>Thread.currentThread()</code>) until
+ * the receiver finishes its execution and dies or the specified timeout
+ * expires, whatever happens first.
+ *
+ * @param timeoutInMilliseconds
+ * The maximum time to wait (in milliseconds).
+ * @exception InterruptedException
+ * if <code>interrupt()</code> was called for the receiver
+ * while it was in the <code>join()</code> call
+ * @see Object#notifyAll
+ * @see java.lang.ThreadDeath
+ */
+ public final void join(long timeoutInMilliseconds)
+ throws InterruptedException {
+ return;
+ }
+
+ /**
+ * Blocks the current Thread (<code>Thread.currentThread()</code>) until
+ * the receiver finishes its execution and dies or the specified timeout
+ * expires, whatever happens first.
+ *
+ * @param timeoutInMilliseconds
+ * The maximum time to wait (in milliseconds).
+ * @param nanos
+ * Extra nanosecond precision
+ * @exception InterruptedException
+ * if <code>interrupt()</code> was called for the receiver
+ * while it was in the <code>join()</code> call
+ * @see Object#notifyAll
+ * @see java.lang.ThreadDeath
+ */
+ public final void join(long timeoutInMilliseconds, int nanos)
+ throws InterruptedException {
+ return;
+ }
+
+ /**
+ * This is a no-op if the receiver was never suspended, or suspended and
+ * already resumed. If the receiver is suspended, however, makes it resume
+ * to the point where it was when it was suspended.
+ *
+ * @exception SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @see Thread#suspend()
+ * @deprecated Used with deprecated method Thread.suspend().
+ */
+ public final void resume() {
+ return;
+ }
+
+ /**
+ * Calls the <code>run()</code> method of the Runnable object the receiver
+ * holds. If no Runnable is set, does nothing.
+ *
+ * @see Thread#start
+ */
+ public void run() {
+ return;
+ }
+
+ /**
+ * Set the context ClassLoader for the receiver.
+ *
+ * @param cl
+ * The context ClassLoader
+ * @see java.lang.ClassLoader
+ * @see #getContextClassLoader()
+ */
+ public void setContextClassLoader(ClassLoader cl) {
+ return;
+ }
+
+ /**
+ * Set if the receiver is a daemon Thread or not. This can only be done
+ * before the Thread starts running.
+ *
+ * @param isDaemon
+ * A boolean indicating if the Thread should be daemon or not
+ * @exception SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @see Thread#isDaemon
+ */
+ public final void setDaemon(boolean isDaemon) {
+ return;
+ }
+
+ /**
+ * Sets the name of the receiver.
+ *
+ * @param threadName
+ * new name for the Thread
+ * @exception SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @see Thread#getName
+ */
+ public final void setName(String threadName) {
+ return;
+ }
+
+ /**
+ * Sets the priority of the receiver. Note that the final priority set may
+ * not be the parameter that was passed - it will depend on the receiver's
+ * ThreadGroup. The priority cannot be set to be higher than the receiver's
+ * ThreadGroup's maxPriority().
+ *
+ * @param priority
+ * new priority for the Thread
+ * @exception SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @exception IllegalArgumentException
+ * if the new priority is greater than Thread.MAX_PRIORITY or
+ * less than Thread.MIN_PRIORITY
+ * @see Thread#getPriority
+ */
+ public final void setPriority(int priority) {
+ return;
+ }
+
+ /**
+ * A sample implementation of this method is provided by the reference
+ * implementation. It must be included, as it is called by ThreadLocal.set()
+ * and InheritableThreadLocal.set(). Set the value associated with the
+ * ThreadLocal in the receiver to be <code>value</code>.
+ *
+ * @param local
+ * ThreadLocal to set
+ * @param value
+ * new value for the ThreadLocal
+ * @see #getThreadLocal
+ */
+ void setThreadLocal(ThreadLocal local, Object value) {
+ return;
+ }
+
+ /**
+ * Causes the thread which sent this message to sleep an interval of time
+ * (given in milliseconds). The precision is not guaranteed - the Thread may
+ * sleep more or less than requested.
+ *
+ * @param time
+ * The time to sleep in milliseconds.
+ * @exception InterruptedException
+ * if <code>interrupt()</code> was called for this Thread
+ * while it was sleeping
+ * @see Thread#interrupt()
+ */
+
+ public static void sleep(long time) throws InterruptedException {
+ return;
+ }
+
+ /**
+ * Causes the thread which sent this message to sleep an interval of time
+ * (given in milliseconds). The precision is not guaranteed - the Thread may
+ * sleep more or less than requested.
+ *
+ * @param time
+ * The time to sleep in milliseconds.
+ * @param nanos
+ * Extra nanosecond precision
+ * @exception InterruptedException
+ * if <code>interrupt()</code> was called for this Thread
+ * while it was sleeping
+ * @see Thread#interrupt()
+ */
+ public static void sleep(long time, int nanos) throws InterruptedException {
+ return;
+ };
+
+ /**
+ * Starts the new Thread of execution. The <code>run()</code> method of
+ * the receiver will be called by the receiver Thread itself (and not the
+ * Thread calling <code>start()</code>).
+ *
+ * @exception IllegalThreadStateException
+ * Unspecified in the Java language specification
+ * @see Thread#run
+ */
+ public void start() {
+ return;
+ }
+
+ /**
+ * Requests the receiver Thread to stop and throw ThreadDeath. The Thread is
+ * resumed if it was suspended and awakened if it was sleeping, so that it
+ * can proceed to throw ThreadDeath.
+ *
+ * @exception SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @deprecated
+ */
+ public final void stop() {
+ return;
+ }
+
+ /**
+ * Requests the receiver Thread to stop and throw the
+ * <code>throwable()</code>. The Thread is resumed if it was suspended
+ * and awakened if it was sleeping, so that it can proceed to throw the
+ * <code>throwable()</code>.
+ *
+ * @param throwable
+ * Throwable object to be thrown by the Thread
+ * @exception SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @exception NullPointerException
+ * if <code>throwable()</code> is <code>null</code>
+ * @deprecated
+ */
+ public final void stop(Throwable throwable) {
+ return;
+ }
+
+ /**
+ * This is a no-op if the receiver is suspended. If the receiver
+ * <code>isAlive()</code> however, suspended it until
+ * <code>resume()</code> is sent to it. Suspend requests are not queued,
+ * which means that N requests are equivalent to just one - only one resume
+ * request is needed in this case.
+ *
+ * @exception SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @see Thread#resume()
+ * @deprecated May cause deadlocks.
+ */
+ public final void suspend() {
+ return;
+ }
+
+ /**
+ * Answers a string containing a concise, human-readable description of the
+ * receiver.
+ *
+ * @return a printable representation for the receiver.
+ */
+ public String toString() {
+ return null;
+ }
+
+ /**
+ * Causes the thread which sent this message to yield execution to another
+ * Thread that is ready to run. The actual scheduling is
+ * implementation-dependent.
+ *
+ */
+ public static void yield() {
+ return;
+ };
+
+ /**
+ * Returns whether the current thread has a monitor lock on the specified
+ * object.
+ *
+ * @param object
+ * the object to test for the monitor lock
+ * @return true when the current thread has a monitor lock on the specified
+ * object
+ */
+ public static boolean holdsLock(Object object) {
+ return false;
+ };
+
+}
Added: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java?rev=390443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java Fri Mar 31 07:34:47 2006
@@ -0,0 +1,850 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * 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 java.lang;
+
+/**
+ * An implementation of this class is provided, but the documented constructors
+ * are used by the vm specific implementation to create the required "system"
+ * and "main" ThreadGroups. The documented methods are used by java.lang.Thread
+ * to add and remove Threads from their ThreadGroups.
+ *
+ * ThreadGroups are containers of Threads and ThreadGroups, therefore providing
+ * a tree-like structure to organize Threads. The root ThreadGroup name is
+ * "system" and it has no parent ThreadGroup. All other ThreadGroups have
+ * exactly one parent ThreadGroup. All Threads belong to exactly one
+ * ThreadGroup.
+ *
+ * @see Thread
+ * @see SecurityManager
+ */
+
+public class ThreadGroup {
+ // Name of this ThreadGroup
+ private String name;
+
+ // Maximum priority for Threads inside this ThreadGroup
+ private int maxPriority = Thread.MAX_PRIORITY;
+
+ // The ThreadGroup to which this ThreadGroup belongs
+ ThreadGroup parent = null;
+
+ int numThreads = 0;
+
+ // The Threads this ThreadGroup contains
+ private Thread[] childrenThreads = new Thread[5];
+
+ // The number of children groups
+ int numGroups = 0;
+
+ // The ThreadGroups this ThreadGroup contains
+ private ThreadGroup[] childrenGroups = new ThreadGroup[3];
+
+ // Locked when using the childrenGroups field
+ private Object childrenGroupsLock = new Object();
+
+ // Locked when using the childrenThreads field
+ private Object childrenThreadsLock = new Object();
+
+ // Whether this ThreadGroup is a daemon ThreadGroup or not
+ private boolean isDaemon = false;
+
+ // Whether this ThreadGroup has already been destroyed or not
+ private boolean isDestroyed = false;
+
+ // Memory space to associate all new threads with
+ private long memorySpace;
+
+ /**
+ * Used by the JVM to create the "system" ThreadGroup. Construct a
+ * ThreadGroup instance, and assign the name "system".
+ */
+ private ThreadGroup() {
+ name = "system";
+ }
+
+ /**
+ * Constructs a new ThreadGroup with the name provided. The new ThreadGroup
+ * will be child of the ThreadGroup to which the
+ * <code>Thread.currentThread()</code> belongs.
+ *
+ * @param name
+ * Name for the ThreadGroup being created
+ *
+ * @throws SecurityException
+ * if <code>checkAccess()</code> for the parent group fails
+ * with a SecurityException
+ *
+ * @see java.lang.Thread#currentThread
+ */
+
+ public ThreadGroup(String name) {
+ this(Thread.currentThread().getThreadGroup(), name);
+ }
+
+ /**
+ * Constructs a new ThreadGroup with the name provided, as child of the
+ * ThreadGroup <code>parent</code>
+ *
+ * @param parent
+ * Parent ThreadGroup
+ * @param name
+ * Name for the ThreadGroup being created
+ *
+ * @throws NullPointerException
+ * if <code>parent<code> is <code>null<code>
+ * @throws SecurityException if <code>checkAccess()</code> for the parent group fails with a SecurityException
+ * @throws IllegalThreadStateException if <code>parent<code> has been destroyed already
+ */
+ public ThreadGroup(ThreadGroup parent, String name) {
+ super();
+ if (Thread.currentThread() != null) {
+ // If parent is null we must throw NullPointerException, but that
+ // will be done "for free" with the message send below
+ parent.checkAccess();
+ }
+
+ this.name = name;
+ this.setParent(parent);
+ if (parent != null) {
+ this.setMaxPriority(parent.getMaxPriority());
+ if (parent.isDaemon())
+ this.setDaemon(true);
+ }
+ }
+
+ /**
+ * Initialize the "main" ThreadGroup
+ */
+ ThreadGroup(ThreadGroup parent) {
+ this.name = "main";
+ this.setParent(parent);
+ }
+
+ /**
+ * Returns the number of Threads which are children of the receiver,
+ * directly or indirectly.
+ *
+ * @return Number of children Threads
+ */
+
+ public int activeCount() {
+ int count = numThreads;
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++)
+ count += this.childrenGroups[i].activeCount();
+ }
+ return count;
+ }
+
+ /**
+ * Returns the number of ThreadGroups which are children of the receiver,
+ * directly or indirectly.
+ *
+ * @return Number of children ThreadGroups
+ */
+ public int activeGroupCount() {
+ int count = 0;
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++)
+ // One for this group & the subgroups
+ count += 1 + this.childrenGroups[i].activeGroupCount();
+ }
+ return count;
+ }
+
+ /**
+ * Adds a Thread to the receiver. This should only be visible to class
+ * java.lang.Thread, and should only be called when a new Thread is created
+ * and initialized by the constructor.
+ *
+ * @param thread
+ * Thread to add to the receiver
+ *
+ * @throws IllegalThreadStateException
+ * if the receiver has been destroyed already
+ *
+ * @see #remove(java.lang.Thread)
+ */
+ final void add(Thread thread) throws IllegalThreadStateException {
+ synchronized (this.childrenThreadsLock) {
+ if (!isDestroyed) {
+ if (childrenThreads.length == numThreads) {
+ Thread[] newThreads = new Thread[childrenThreads.length * 2];
+ System.arraycopy(childrenThreads, 0, newThreads, 0,
+ numThreads);
+ newThreads[numThreads++] = thread;
+ childrenThreads = newThreads;
+ } else
+ childrenThreads[numThreads++] = thread;
+ } else
+ throw new IllegalThreadStateException();
+ }
+ }
+
+ /**
+ * Adds a ThreadGroup to the receiver.
+ *
+ * @param g
+ * ThreadGroup to add to the receiver
+ *
+ * @throws IllegalThreadStateException
+ * if the receiver has been destroyed already
+ */
+ private void add(ThreadGroup g) throws IllegalThreadStateException {
+ synchronized (this.childrenGroupsLock) {
+ if (!isDestroyed) {
+ if (childrenGroups.length == numGroups) {
+ ThreadGroup[] newGroups = new ThreadGroup[childrenGroups.length * 2];
+ System
+ .arraycopy(childrenGroups, 0, newGroups, 0,
+ numGroups);
+ newGroups[numGroups++] = g;
+ childrenGroups = newGroups;
+ } else
+ childrenGroups[numGroups++] = g;
+ } else
+ throw new IllegalThreadStateException();
+ }
+ }
+
+ /**
+ * The definition of this method depends on the deprecated method
+ * <code>suspend()</code>. The behavior of this call was never specified.
+ *
+ * @param b
+ * Used to control low memory implicit suspension
+ *
+ * @deprecated Required deprecated method suspend().
+ */
+ public boolean allowThreadSuspension(boolean b) {
+ // Does not apply to this VM, no-op
+ return true;
+ }
+
+ /**
+ * If there is a SecurityManager installed, call <code>checkAccess</code>
+ * in it passing the receiver as parameter, otherwise do nothing.
+ */
+ public final void checkAccess() {
+ // Forwards the message to the SecurityManager (if there's one) passing
+ // the receiver as parameter
+ SecurityManager currentManager = System.getSecurityManager();
+ if (currentManager != null)
+ currentManager.checkAccess(this);
+ }
+
+ /**
+ * Destroys the receiver and recursively all its subgroups. It is only legal
+ * to destroy a ThreadGroup that has no Threads. Any daemon ThreadGroup is
+ * destroyed automatically when it becomes empty (no Threads and no
+ * ThreadGroups in it).
+ *
+ * @throws IllegalThreadStateException
+ * if the receiver or any of its subgroups has been destroyed
+ * already
+ * @throws SecurityException
+ * if <code>this.checkAccess()</code> fails with a
+ * SecurityException
+ */
+
+ public final void destroy() {
+ checkAccess();
+
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenThreadsLock) {
+ synchronized (this.childrenGroupsLock) {
+ int toDestroy = numGroups;
+ // Call recursively for subgroups
+ for (int i = 0; i < toDestroy; i++) {
+ // We always get the first element - remember, when the
+ // child dies it removes itself from our collection. See
+ // below.
+ this.childrenGroups[0].destroy();
+ }
+
+ if (parent != null)
+ parent.remove(this);
+
+ // Now that the ThreadGroup is really destroyed it can be tagged
+ // as so
+ this.isDestroyed = true;
+ }
+ }
+ }
+
+ /*
+ * Auxiliary method that destroys the receiver and recursively all its
+ * subgroups if the receiver is a daemon ThreadGroup.
+ *
+ * @see #destroy
+ * @see #setDaemon
+ * @see #isDaemon
+ */
+ private void destroyIfEmptyDaemon() {
+ // Has to be non-destroyed daemon to make sense
+ synchronized (this.childrenThreadsLock) {
+ if (isDaemon && !isDestroyed && numThreads == 0) {
+ synchronized (this.childrenGroupsLock) {
+ if (numGroups == 0)
+ destroy();
+ }
+ }
+ }
+ }
+
+ /**
+ * Copies an array with all Threads which are children of the receiver
+ * (directly or indirectly) into the array <code>threads</code> passed as
+ * parameters. If the array passed as parameter is too small no exception is
+ * thrown - the extra elements are simply not copied.
+ *
+ * @param threads
+ * Thread array into which the Threads will be copied
+ * @return How many Threads were copied over
+ *
+ */
+ public int enumerate(Thread[] threads) {
+ return enumerate(threads, true);
+ }
+
+ /**
+ * Copies an array with all Threads which are children of the receiver into
+ * the array <code>threads</code> passed as parameter. Children Threads of
+ * subgroups are recursively copied as well if parameter
+ * <code>recurse</code> is <code>true</code>.
+ *
+ * If the array passed as parameter is too small no exception is thrown -
+ * the extra elements are simply not copied.
+ *
+ * @param threads
+ * array into which the Threads will be copied
+ * @param recurse
+ * Indicates whether Threads in subgroups should be recursively
+ * copied as well or not
+ * @return How many Threads were copied over
+ *
+ */
+ public int enumerate(Thread[] threads, boolean recurse) {
+ return enumerateGeneric(threads, recurse, 0, true);
+ }
+
+ /**
+ * Copies an array with all ThreadGroups which are children of the receiver
+ * (directly or indirectly) into the array <code>groups</code> passed as
+ * parameters. If the array passed as parameter is too small no exception is
+ * thrown - the extra elements are simply not copied.
+ *
+ * @param groups
+ * array into which the ThreadGroups will be copied
+ * @return How many ThreadGroups were copied over
+ *
+ */
+ public int enumerate(ThreadGroup[] groups) {
+ return enumerate(groups, true);
+ }
+
+ /**
+ * Copies an array with all ThreadGroups which are children of the receiver
+ * into the array <code>groups</code> passed as parameter. Children
+ * ThreadGroups of subgroups are recursively copied as well if parameter
+ * <code>recurse</code> is <code>true</code>.
+ *
+ * If the array passed as parameter is too small no exception is thrown -
+ * the extra elements are simply not copied.
+ *
+ * @param groups
+ * array into which the ThreadGroups will be copied
+ * @param recurse
+ * Indicates whether ThreadGroups in subgroups should be
+ * recursively copied as well or not
+ * @return How many ThreadGroups were copied over
+ *
+ */
+ public int enumerate(ThreadGroup[] groups, boolean recurse) {
+ return enumerateGeneric(groups, recurse, 0, false);
+ }
+
+ /**
+ * Copies into <param>enumeration</param> starting at
+ * </param>enumerationIndex</param> all Threads or ThreadGroups in the
+ * receiver. If </param>recurse</param> is true, recursively enumerate the
+ * elements in subgroups.
+ *
+ * If the array passed as parameter is too small no exception is thrown -
+ * the extra elements are simply not copied.
+ *
+ * @param enumeration
+ * array into which the elements will be copied
+ * @param recurse
+ * Indicates whether </param>recurseCollection</param> should be
+ * enumerated or not
+ * @param enumerationIndex
+ * Indicates in which position of the enumeration array we are
+ * @param enumeratingThreads
+ * Indicates whether we are enumerating Threads or ThreadGroups
+ * @return How many elements were enumerated/copied over
+ */
+ private int enumerateGeneric(Object[] enumeration, boolean recurse,
+ int enumerationIndex, boolean enumeratingThreads) {
+ checkAccess();
+
+ Object[] immediateCollection = enumeratingThreads ? (Object[]) childrenThreads
+ : (Object[]) childrenGroups;
+ Object syncLock = enumeratingThreads ? childrenThreadsLock
+ : childrenGroupsLock;
+
+ synchronized (syncLock) { // Lock this subpart of the tree as we walk
+ for (int i = enumeratingThreads ? numThreads : numGroups; --i >= 0;) {
+ if (!enumeratingThreads
+ || ((Thread) immediateCollection[i]).isAlive()) {
+ if (enumerationIndex >= enumeration.length)
+ return enumerationIndex;
+ enumeration[enumerationIndex++] = immediateCollection[i];
+ }
+ }
+ }
+
+ if (recurse) { // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++) {
+ if (enumerationIndex >= enumeration.length)
+ return enumerationIndex;
+ enumerationIndex = childrenGroups[i].enumerateGeneric(
+ enumeration, recurse, enumerationIndex,
+ enumeratingThreads);
+ }
+ }
+ }
+ return enumerationIndex;
+ }
+
+ /**
+ * Answers the maximum allowed priority for a Thread in the receiver.
+ *
+ * @return the maximum priority (an <code>int</code>)
+ *
+ * @see #setMaxPriority
+ */
+ public final int getMaxPriority() {
+ return maxPriority;
+ }
+
+ /**
+ * Answers the name of the receiver.
+ *
+ * @return the receiver's name (a java.lang.String)
+ */
+ public final String getName() {
+ return name;
+ }
+
+ /**
+ * Answers the receiver's parent ThreadGroup. It can be null if the receiver
+ * is the the root ThreadGroup.
+ *
+ * @return the parent ThreadGroup
+ *
+ */
+ public final ThreadGroup getParent() {
+ if (parent != null)
+ parent.checkAccess();
+ return parent;
+ }
+
+ /**
+ * Interrupts every Thread in the receiver and recursively in all its
+ * subgroups.
+ *
+ * @throws SecurityException
+ * if <code>this.checkAccess()</code> fails with a
+ * SecurityException
+ *
+ * @see Thread#interrupt
+ */
+ public final void interrupt() {
+ checkAccess();
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenThreadsLock) {
+ for (int i = 0; i < numThreads; i++)
+ this.childrenThreads[i].interrupt();
+ }
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++)
+ this.childrenGroups[i].interrupt();
+ }
+ }
+
+ /**
+ * Answers true if the receiver is a daemon ThreadGroup, false otherwise.
+ *
+ * @return if the receiver is a daemon ThreadGroup
+ *
+ * @see #setDaemon
+ * @see #destroy
+ */
+ public final boolean isDaemon() {
+ return isDaemon;
+ }
+
+ /**
+ * Answers true if the receiver has been destroyed already, false otherwise.
+ *
+ * @return if the receiver has been destroyed already
+ *
+ * @see #destroy
+ */
+ public boolean isDestroyed() {
+ return isDestroyed;
+ }
+
+ /**
+ * Outputs to <code>System.out</code> a text representation of the
+ * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
+ * Proper identation is done to suggest the nesting of groups inside groups
+ * and threads inside groups.
+ */
+ public void list() {
+ // We start in a fresh line
+ System.out.println();
+ list(0);
+ }
+
+ /*
+ * Outputs to <code>System.out</code>a text representation of the
+ * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
+ * The identation will be four spaces per level of nesting.
+ *
+ * @param levels How many levels of nesting, so that proper identetion can
+ * be output.
+ */
+ private void list(int levels) {
+ for (int i = 0; i < levels; i++)
+ System.out.print(" "); // 4 spaces for each level
+
+ // Print the receiver
+ System.out.println(this.toString());
+
+ // Print the children threads, with 1 extra identation
+ synchronized (this.childrenThreadsLock) {
+ for (int i = 0; i < numThreads; i++) {
+ // children get an extra identation, 4 spaces for each level
+ for (int j = 0; j <= levels; j++)
+ System.out.print(" ");
+ System.out.println(this.childrenThreads[i]);
+ }
+ }
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++)
+ this.childrenGroups[i].list(levels + 1);
+ }
+ }
+
+ /**
+ * Answers true if the receiver is a direct or indirect parent group of
+ * ThreadGroup <code>g</code>, false otherwise.
+ *
+ * @param g
+ * ThreadGroup to test
+ *
+ * @return if the receiver is parent of the ThreadGroup passed as parameter
+ *
+ */
+ public final boolean parentOf(ThreadGroup g) {
+ while (g != null) {
+ if (this == g)
+ return true;
+ g = g.parent;
+ }
+ return false;
+ }
+
+ /**
+ * Removes a Thread from the receiver. This should only be visible to class
+ * java.lang.Thread, and should only be called when a Thread dies.
+ *
+ * @param thread
+ * Thread to remove from the receiver
+ *
+ * @see #add(Thread)
+ */
+ final void remove(java.lang.Thread thread) {
+ synchronized (this.childrenThreadsLock) {
+ for (int i = 0; i < numThreads; i++) {
+ if (childrenThreads[i].equals(thread)) {
+ numThreads--;
+ System.arraycopy(childrenThreads, i + 1, childrenThreads,
+ i, numThreads - i);
+ childrenThreads[numThreads] = null;
+ break;
+ }
+ }
+ }
+ destroyIfEmptyDaemon();
+ }
+
+ /**
+ * Removes an immediate subgroup from the receiver.
+ *
+ * @param g
+ * Threadgroup to remove from the receiver
+ *
+ * @see #add(Thread)
+ * @see #add(ThreadGroup)
+ */
+ private void remove(ThreadGroup g) {
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++) {
+ if (childrenGroups[i].equals(g)) {
+ numGroups--;
+ System.arraycopy(childrenGroups, i + 1, childrenGroups, i,
+ numGroups - i);
+ childrenGroups[numGroups] = null;
+ break;
+ }
+ }
+ }
+ destroyIfEmptyDaemon();
+ }
+
+ /**
+ * Resumes every Thread in the receiver and recursively in all its
+ * subgroups.
+ *
+ * @throws SecurityException
+ * if <code>this.checkAccess()</code> fails with a
+ * SecurityException
+ *
+ * @see Thread#resume
+ * @see #suspend
+ *
+ * @deprecated Requires deprecated method Thread.resume().
+ */
+ public final void resume() {
+ checkAccess();
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenThreadsLock) {
+ for (int i = 0; i < numThreads; i++)
+ this.childrenThreads[i].resume();
+ }
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++)
+ this.childrenGroups[i].resume();
+ }
+ }
+
+ /**
+ * Configures the receiver to be a daemon ThreadGroup or not. Daemon
+ * ThreadGroups are automatically destroyed when they become empty.
+ *
+ * @param isDaemon
+ * new value defining if receiver should be daemon or not
+ *
+ * @throws SecurityException
+ * if <code>checkAccess()</code> for the parent group fails
+ * with a SecurityException
+ *
+ * @see #isDaemon
+ * @see #destroy
+ */
+ public final void setDaemon(boolean isDaemon) {
+ checkAccess();
+ this.isDaemon = isDaemon;
+ }
+
+ /**
+ * Configures the maximum allowed priority for a Thread in the receiver and
+ * recursively in all its subgroups.
+ *
+ * One can never change the maximum priority of a ThreadGroup to be higher
+ * than it was. Such an attempt will not result in an exception, it will
+ * simply leave the ThreadGroup with its current maximum priority.
+ *
+ * @param newMax
+ * the new maximum priority to be set
+ *
+ * @throws SecurityException
+ * if <code>checkAccess()</code> fails with a
+ * SecurityException
+ * @throws IllegalArgumentException
+ * if the new priority is greater than Thread.MAX_PRIORITY or
+ * less than Thread.MIN_PRIORITY
+ *
+ * @see #getMaxPriority
+ */
+ public final void setMaxPriority(int newMax) {
+ checkAccess();
+
+ if (newMax <= this.maxPriority) {
+ if (newMax < Thread.MIN_PRIORITY)
+ newMax = Thread.MIN_PRIORITY;
+
+ int parentPriority = parent == null ? newMax : parent
+ .getMaxPriority();
+ this.maxPriority = parentPriority <= newMax ? parentPriority
+ : newMax;
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ // ??? why not maxPriority
+ for (int i = 0; i < numGroups; i++)
+ this.childrenGroups[i].setMaxPriority(newMax);
+ }
+ }
+ }
+
+ /**
+ * Sets the parent ThreadGroup of the receiver, and adds the receiver to the
+ * parent's collection of immediate children (if <code>parent</code> is
+ * not <code>null</code>).
+ *
+ * @param parent
+ * The parent ThreadGroup, or null if the receiver is to be the
+ * root ThreadGroup
+ *
+ * @see #getParent
+ * @see #parentOf
+ */
+ private void setParent(ThreadGroup parent) {
+ if (parent != null)
+ parent.add(this);
+ this.parent = parent;
+ }
+
+ /**
+ * Stops every Thread in the receiver and recursively in all its subgroups.
+ *
+ * @throws SecurityException
+ * if <code>this.checkAccess()</code> fails with a
+ * SecurityException
+ *
+ * @see Thread#stop()
+ * @see Thread#stop(Throwable)
+ * @see ThreadDeath
+ *
+ * @deprecated Requires deprecated method Thread.stop().
+ */
+ public final void stop() {
+ if (stopHelper())
+ Thread.currentThread().stop();
+ }
+
+ /**
+ * @deprecated Requires deprecated method Thread.suspend().
+ */
+ private final boolean stopHelper() {
+ checkAccess();
+
+ boolean stopCurrent = false;
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenThreadsLock) {
+ Thread current = Thread.currentThread();
+ for (int i = 0; i < numThreads; i++)
+ if (this.childrenThreads[i] == current) {
+ stopCurrent = true;
+ } else {
+ this.childrenThreads[i].stop();
+ }
+ }
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++)
+ stopCurrent |= this.childrenGroups[i].stopHelper();
+ }
+ return stopCurrent;
+ }
+
+ /**
+ * Suspends every Thread in the receiver and recursively in all its
+ * subgroups.
+ *
+ * @throws SecurityException
+ * if <code>this.checkAccess()</code> fails with a
+ * SecurityException
+ *
+ * @see Thread#suspend
+ * @see #resume
+ *
+ * @deprecated Requires deprecated method Thread.suspend().
+ */
+ public final void suspend() {
+ if (suspendHelper())
+ Thread.currentThread().suspend();
+ }
+
+ /**
+ * @deprecated Requires deprecated method Thread.suspend().
+ */
+ private final boolean suspendHelper() {
+ checkAccess();
+
+ boolean suspendCurrent = false;
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenThreadsLock) {
+ Thread current = Thread.currentThread();
+ for (int i = 0; i < numThreads; i++)
+ if (this.childrenThreads[i] == current) {
+ suspendCurrent = true;
+ } else {
+ this.childrenThreads[i].suspend();
+ }
+ }
+ // Lock this subpart of the tree as we walk
+ synchronized (this.childrenGroupsLock) {
+ for (int i = 0; i < numGroups; i++)
+ suspendCurrent |= this.childrenGroups[i].suspendHelper();
+ }
+ return suspendCurrent;
+ }
+
+ /**
+ * Answers a string containing a concise, human-readable description of the
+ * receiver.
+ *
+ * @return a printable representation for the receiver.
+ */
+ public String toString() {
+ return getClass().getName() + "[name=" + this.getName() + ",maxpri="
+ + this.getMaxPriority() + "]";
+ }
+
+ /**
+ * Any uncaught exception in any Thread has to be forwarded (by the VM) to
+ * the Thread's ThreadGroup by sending this message (uncaughtException).
+ * This allows users to define custom ThreadGroup classes and custom
+ * behavior for when a Thread has an uncaughtException or when it does
+ * (ThreadDeath).
+ *
+ * @param t
+ * Thread with an uncaught exception
+ * @param e
+ * The uncaught exception itself
+ *
+ * @see Thread#stop()
+ * @see Thread#stop(Throwable)
+ * @see ThreadDeath
+ */
+ public void uncaughtException(Thread t, Throwable e) {
+ if (parent != null) {
+ parent.uncaughtException(t, e);
+ } else if (!(e instanceof ThreadDeath)) {
+ // No parent group, has to be 'system' Thread Group
+ e.printStackTrace(System.err);
+ }
+ }
+}
Added: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java?rev=390443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java Fri Mar 31 07:34:47 2006
@@ -0,0 +1,350 @@
+/* Copyright 1998, 2005 The Apache Software Foundation or its licensors, as applicable
+ *
+ * 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 java.lang;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+
+/**
+ * This class must be implemented by the vm vendor, or the reference
+ * implementation can be used if the documented natives are implemented.
+ *
+ * This class is the superclass of all classes which can be thrown by the
+ * virtual machine. The two direct subclasses represent recoverable exceptions
+ * (Exception) and unrecoverable errors (Error). This class provides common
+ * methods for accessing a string message which provides extra information about
+ * the circumstances in which the throwable was created, and for filling in a
+ * walkback (i.e. a record of the call stack at a particular point in time)
+ * which can be printed later.
+ *
+ * @see Error
+ * @see Exception
+ * @see RuntimeException
+ */
+public class Throwable implements java.io.Serializable {
+ private static final long serialVersionUID = -3042686055658047285L;
+
+ /**
+ * The message provided when the exception was created.
+ */
+ private String detailMessage;
+
+ /**
+ * An object which describes the walkback. This field is stored by the
+ * fillInStackTrace() native, and used by the getStackTraceImpl() native.
+ */
+ private transient Object walkback;
+
+ /**
+ * The cause of this Throwable. Null when there is no cause.
+ */
+ private Throwable cause = this;
+
+ private StackTraceElement[] stackTrace = null;
+
+ /**
+ * Constructs a new instance of this class with its walkback filled in.
+ */
+ public Throwable() {
+ super();
+ fillInStackTrace();
+ }
+
+ /**
+ * Constructs a new instance of this class with its walkback and message
+ * filled in.
+ *
+ * @param detailMessage
+ * String The detail message for the exception.
+ */
+ public Throwable(String detailMessage) {
+ this();
+ this.detailMessage = detailMessage;
+ }
+
+ /**
+ * Constructs a new instance of this class with its walkback, message and
+ * cause filled in.
+ *
+ * @param detailMessage
+ * String The detail message for the exception.
+ * @param throwable
+ * The cause of this Throwable
+ */
+ public Throwable(String detailMessage, Throwable throwable) {
+ this();
+ this.detailMessage = detailMessage;
+ cause = throwable;
+ }
+
+ /**
+ * Constructs a new instance of this class with its walkback and cause
+ * filled in.
+ *
+ * @param throwable
+ * The cause of this Throwable
+ */
+ public Throwable(Throwable throwable) {
+ this();
+ this.detailMessage = throwable == null ? null : throwable.toString();
+ cause = throwable;
+ }
+
+ /**
+ * This native must be implemented to use the reference implementation of
+ * this class.
+ *
+ * Record in the receiver a walkback from the point where this message was
+ * sent. The message is public so that code which catches a throwable and
+ * then <em>re-throws</em> it can adjust the walkback to represent the
+ * location where the exception was re-thrown.
+ *
+ * @return the receiver
+ */
+ public native Throwable fillInStackTrace();
+
+ /**
+ * Answers the extra information message which was provided when the
+ * throwable was created. If no message was provided at creation time, then
+ * answer null.
+ *
+ * @return String The receiver's message.
+ */
+ public String getMessage() {
+ return detailMessage;
+ }
+
+ /**
+ * Answers the extra information message which was provided when the
+ * throwable was created. If no message was provided at creation time, then
+ * answer null. Subclasses may override this method to answer localized text
+ * for the message.
+ *
+ * @return String The receiver's message.
+ */
+ public String getLocalizedMessage() {
+ return getMessage();
+ }
+
+ /**
+ * This native must be implemented to use the reference implementation of
+ * this class. The result of this native is cloned, and returned from the
+ * public API getStackTrace().
+ *
+ * Answers an array of StackTraceElement. Each StackTraceElement represents
+ * a entry on the stack.
+ *
+ * @return an array of StackTraceElement representing the stack
+ */
+ private native StackTraceElement[] getStackTraceImpl();
+
+ /**
+ * Answers an array of StackTraceElement. Each StackTraceElement represents
+ * a entry on the stack.
+ *
+ * @return an array of StackTraceElement representing the stack
+ */
+ public StackTraceElement[] getStackTrace() {
+ return (StackTraceElement[]) getInternalStackTrace().clone();
+ }
+
+ /**
+ * Sets the array of StackTraceElements. Each StackTraceElement represents a
+ * entry on the stack. A copy of this array will be returned by
+ * getStackTrace() and printed by printStackTrace().
+ *
+ * @param trace
+ * The array of StackTraceElement
+ */
+ public void setStackTrace(StackTraceElement[] trace) {
+ StackTraceElement[] newTrace = (StackTraceElement[]) trace.clone();
+ for (int i = 0; i < newTrace.length; i++)
+ if (newTrace[i] == null)
+ throw new NullPointerException();
+ stackTrace = newTrace;
+ }
+
+ /**
+ * Outputs a printable representation of the receiver's walkback on the
+ * System.err stream.
+ */
+ public void printStackTrace() {
+ printStackTrace(System.err);
+ }
+
+ /**
+ * Count the number of duplicate stack frames, starting from
+ * the end of the stack.
+ *
+ * @param currentStack a stack to compare
+ * @param parentStack a stack to compare
+ *
+ * @return the number of duplicate stack frames.
+ */
+ private static int countDuplicates(StackTraceElement[] currentStack,
+ StackTraceElement[] parentStack) {
+ int duplicates = 0;
+ int parentIndex = parentStack.length;
+ for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
+ StackTraceElement parentFrame = parentStack[parentIndex];
+ if (parentFrame.equals(currentStack[i])) {
+ duplicates++;
+ } else {
+ break;
+ }
+ }
+ return duplicates;
+ }
+
+ /**
+ * Answers an array of StackTraceElement. Each StackTraceElement represents
+ * a entry on the stack. Cache the stack trace in the stackTrace field, returning
+ * the cached field when it has already been initialized.
+ *
+ * @return an array of StackTraceElement representing the stack
+ */
+ private StackTraceElement[] getInternalStackTrace() {
+ if (stackTrace == null)
+ stackTrace = getStackTraceImpl();
+ return stackTrace;
+ }
+
+ /**
+ * Outputs a printable representation of the receiver's walkback on the
+ * stream specified by the argument.
+ *
+ * @param err
+ * PrintStream The stream to write the walkback on.
+ */
+ public void printStackTrace(PrintStream err) {
+ err.println(toString());
+ // Don't use getStackTrace() as it calls clone()
+ // Get stackTrace, in case stackTrace is reassigned
+ StackTraceElement[] stack = getInternalStackTrace();
+ for (int i = 0; i < stack.length; i++)
+ err.println("\tat " + stack[i]);
+
+ StackTraceElement[] parentStack = stack;
+ Throwable throwable = getCause();
+ while (throwable != null) {
+ err.print("Caused by: ");
+ err.println(throwable);
+ StackTraceElement[] currentStack = throwable
+ .getInternalStackTrace();
+ int duplicates = countDuplicates(currentStack, parentStack);
+ for (int i = 0; i < currentStack.length - duplicates; i++)
+ err.println("\tat " + currentStack[i]);
+ if (duplicates > 0) {
+ err.println("\t... " + duplicates + " more");
+ }
+ parentStack = currentStack;
+ throwable = throwable.getCause();
+ }
+ }
+
+ /**
+ * Outputs a printable representation of the receiver's walkback on the
+ * writer specified by the argument.
+ *
+ * @param err
+ * PrintWriter The writer to write the walkback on.
+ */
+ public void printStackTrace(PrintWriter err) {
+ err.println(toString());
+ // Don't use getStackTrace() as it calls clone()
+ // Get stackTrace, in case stackTrace is reassigned
+ StackTraceElement[] stack = getInternalStackTrace();
+ for (int i = 0; i < stack.length; i++)
+ err.println("\tat " + stack[i]);
+
+ StackTraceElement[] parentStack = stack;
+ Throwable throwable = getCause();
+ while (throwable != null) {
+ err.print("Caused by: ");
+ err.println(throwable);
+ StackTraceElement[] currentStack = throwable
+ .getInternalStackTrace();
+ int duplicates = countDuplicates(currentStack, parentStack);
+ for (int i = 0; i < currentStack.length - duplicates; i++)
+ err.println("\tat " + currentStack[i]);
+ if (duplicates > 0) {
+ err.println("\t... " + duplicates + " more");
+ }
+ parentStack = currentStack;
+ throwable = throwable.getCause();
+ }
+ }
+
+ /**
+ * Answers a string containing a concise, human-readable description of the
+ * receiver.
+ *
+ * @return String a printable representation for the receiver.
+ */
+ public String toString() {
+ String msg = getLocalizedMessage();
+ String name = getClass().getName();
+ if (msg == null) {
+ return name;
+ }
+ return new StringBuffer(name.length() + 2 + msg.length()).append(name)
+ .append(": ").append(msg).toString();
+ }
+
+ /**
+ * Initialize the cause of the receiver. The cause cannot be reassigned.
+ *
+ * @param throwable
+ * The cause of this Throwable
+ *
+ * @exception IllegalArgumentException
+ * when the cause is the receiver
+ * @exception IllegalStateException
+ * when the cause has already been initialized
+ *
+ * @return the receiver.
+ */
+ public synchronized Throwable initCause(Throwable throwable) {
+ if (cause == this) {
+ if (throwable != this) {
+ cause = throwable;
+ return this;
+ }
+ throw new IllegalArgumentException("Cause cannot be the receiver");
+ }
+ throw new IllegalStateException("Cause already initialized");
+ }
+
+ /**
+ * Answers the cause of this Throwable, or null if there is no cause.
+ *
+ * @return Throwable The receiver's cause.
+ */
+ public Throwable getCause() {
+ if (cause == this)
+ return null;
+ return cause;
+ }
+
+ private void writeObject(ObjectOutputStream s) throws IOException {
+ // ensure the stackTrace field is initialized
+ getInternalStackTrace();
+ s.defaultWriteObject();
+ }
+}