You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gs...@apache.org on 2007/05/23 23:14:45 UTC

svn commit: r541084 - in /harmony/enhanced/drlvm/trunk: src/test/regression/H3894/ src/test/regression/excludes/ vm/vmcore/src/jvmti/ vm/vmcore/src/kernel_classes/javasrc/java/lang/

Author: gshimansky
Date: Wed May 23 14:14:44 2007
New Revision: 541084

URL: http://svn.apache.org/viewvc?view=rev&rev=541084
Log:
Applied patch and regression test from HARMONY-3894 [drlvm][jvmti] JVMTI function GetThreadGroupChildren() return no more than 10 child threds and groups


Added:
    harmony/enhanced/drlvm/trunk/src/test/regression/H3894/
    harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.cpp   (with props)
    harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.java   (with props)
    harmony/enhanced/drlvm/trunk/src/test/regression/H3894/run.test.xml   (with props)
Modified:
    harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.linux.x86_64
    harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.windows.x86_64
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_thread_group.cpp
    harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java

Added: harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.cpp?view=auto&rev=541084
==============================================================================
--- harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.cpp (added)
+++ harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.cpp Wed May 23 14:14:44 2007
@@ -0,0 +1,253 @@
+/**
+ * Test case for GetThreadGroupChildren() jvmti function.
+ * Checks that the function may report more than 10 child theads.
+ * Checks that the function reports the same thread group children that were
+ * added by java application.
+ */
+
+#include <iostream>
+#include <jvmti.h>
+
+using namespace std;
+
+#define PACKAGE "org/apache/harmony/drlvm/tests/regression/h3894/"
+
+static const char* EXCEPTION_CLASS = "L" PACKAGE "InvokeAgentException;";
+
+#define TURN_EVENT(event, state) { \
+    jvmtiError err = turn_event(jvmti, event, state, #event); \
+    if (JVMTI_ERROR_NONE != err) return; \
+}
+
+#define CHECK_RESULT(func) \
+    if (JVMTI_ERROR_NONE != err) { \
+        cerr << "[JvmtiAgent] ERROR: " << #func << " failed with error: " << err << endl;  \
+        return; \
+    }
+
+#define CHECK_JNI3(result, func, error_code) { \
+    if (jni->ExceptionCheck()) { \
+        cerr << "[JvmtiAgent] ERROR: unexpected exception in " << #func << endl;  \
+        jni->ExceptionDescribe(); \
+        return error_code; \
+    } \
+    if (! (result)) { \
+        cerr << "[JvmtiAgent] ERROR: get NULL in " << #func << endl;  \
+        return error_code; \
+    } \
+}
+
+#define CHECK_JNI(result, func) CHECK_JNI3(result, func, )
+
+static void set_passed_state(JNIEnv* jni)
+{
+    cerr << endl << "TEST PASSED" << endl << endl;
+
+    jclass cl = jni->FindClass(PACKAGE "Status");
+    CHECK_JNI(cl, FindClass);
+
+    jfieldID testGroup_field = jni->GetStaticFieldID(cl, "status", "Z");
+    CHECK_JNI(testGroup_field, GetStaticFieldID);
+
+    jni->SetStaticBooleanField(cl, testGroup_field, JNI_TRUE);
+    CHECK_JNI(true, SetStaticBooleanField);
+}
+
+static jvmtiError turn_event(jvmtiEnv* jvmti, jvmtiEvent event, bool state,
+        const char* event_name)
+{
+    jvmtiError err;
+    err = jvmti->SetEventNotificationMode(state ? JVMTI_ENABLE : JVMTI_DISABLE,
+            event, NULL);
+    if (JVMTI_ERROR_NONE != err) {
+        cerr << "[JvmtiAgent] ERROR: unable to " << (state ? "en" : "dis")
+                << "able " << event_name
+                << endl;
+    }
+
+    return err;
+}
+
+static void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread)
+{
+    cerr << endl << "==> VM Init callback" << endl;
+
+    TURN_EVENT(JVMTI_EVENT_EXCEPTION, true);
+}
+
+static bool check_array(jvmtiEnv* jvmti,
+                              JNIEnv* jni,
+                              jobject* array,
+                              int array_length,
+                              jobject object,
+                              jclass clazz,
+                              const char* field_name,
+                              const char* field_sig)
+{
+    jfieldID field = jni->GetFieldID(clazz, field_name, field_sig);
+    CHECK_JNI3(field, GetFieldID, false);
+
+    jobjectArray expected = jni->GetObjectField(object, field);
+    CHECK_JNI3(expected, GetObjectField, false);
+
+    jint expected_length = jni->GetArrayLength(expected);
+    CHECK_JNI3(expected_length, GetArrayLength, false);
+
+    cerr << "Array length:   \t" << array_length << endl
+            << "Expected length:\t" << expected_length << endl;
+
+    if (array_length != expected_length) {
+        cerr << "Array length doesn't match expected" << endl;
+        return false;
+    }
+
+    for (jint j = 0; j < expected_length; j++) {
+        jobject entry = jni->GetObjectArrayElement(expected, j);
+        CHECK_JNI3(entry, GetObjectArrayElement, false);
+
+        bool found = false;
+        for (int i = 0; i < array_length; i++) {
+            jboolean is_same = jni->IsSameObject(entry, array[i]);
+            CHECK_JNI3(true, IsSameObject, false);
+
+            if (is_same)
+                found = ! found;
+        }
+
+        if (! found) {
+            cerr << "Expected element not found" << endl;
+            return false;
+        }
+
+    }
+
+    return true;
+
+}
+
+static void JNICALL
+Exception(jvmtiEnv *jvmti,
+            JNIEnv* jni,
+            jthread thread,
+            jmethodID method,
+            jlocation location,
+            jobject exception,
+            jmethodID catch_method,
+            jlocation catch_location)
+{
+    jvmtiError err;
+
+    jclass exn_class = jni->GetObjectClass(exception);
+    CHECK_JNI(exn_class, GetObjectClass);
+
+    char* class_name = NULL;
+    err = jvmti->GetClassSignature(exn_class, &class_name, NULL);
+    CHECK_RESULT(GetClassSignature);
+
+    if (0 != strcmp(EXCEPTION_CLASS, class_name))
+        return;
+
+    cerr << endl << "==> Exception callback" << endl;
+    cerr << "    for class: " << class_name << endl;
+
+    TURN_EVENT(JVMTI_EVENT_EXCEPTION, false);
+
+    jfieldID testGroup_field = jni->GetFieldID(exn_class, "testGroup",
+            "Ljava/lang/ThreadGroup;");
+    CHECK_JNI(testGroup_field, GetFieldID);
+
+    jthreadGroup group = jni->GetObjectField(exception, testGroup_field);
+    CHECK_JNI(group, GetObjectField);
+
+    jint thread_count;
+    jthread* threads;
+    jint group_count;
+    jthreadGroup* groups;
+
+    err = jvmti->GetThreadGroupChildren(group, &thread_count, &threads,
+            &group_count, &groups);
+    CHECK_RESULT(GetThreadGroupChildren);
+
+    cerr << endl << "Child threads:" << endl;
+    for (int i = 0; i < thread_count; i++) {
+        jvmtiThreadInfo info;
+
+        err = jvmti->GetThreadInfo(threads[i], &info);
+        CHECK_RESULT(GetThreadInfo);
+
+        cerr << i << ":\t" << info.name << endl;
+    }
+
+    cerr << endl << "Child groups:" << endl;
+    for (int i = 0; i < group_count; i++) {
+        jvmtiThreadGroupInfo info;
+
+        err = jvmti->GetThreadGroupInfo(groups[i], &info);
+        CHECK_RESULT(GetThreadDroupInfo);
+
+        cerr << i << ":\t" << info.name << endl;
+    }
+
+    cerr << endl << "Checking threads..." << endl;
+    if (! check_array(jvmti, jni, threads, thread_count, exception, exn_class,
+            "childThreads", "[Ljava/lang/Thread;")) {
+        return;
+    }
+
+    cerr << endl << "Checking groups..." << endl;
+    if (! check_array(jvmti, jni, groups, group_count, exception, exn_class,
+            "childGroups", "[Ljava/lang/ThreadGroup;")) {
+        return;
+    }
+
+
+    set_passed_state(jni);
+}
+
+JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+{
+    jvmtiEnv *jvmti = NULL;
+    jvmtiError err;
+
+    // Get JVMTI interface pointer
+    jint iRes = vm->GetEnv((void**)&jvmti, JVMTI_VERSION);
+    if (JNI_OK != iRes) {
+        cerr << "[JvmtiAgent] ERROR: unable to get JVMTI environment" << endl;
+        return -1;
+    }
+
+    // Set events callbacks
+    jvmtiEventCallbacks callbacks;
+    memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+
+    callbacks.VMInit = VMInit;
+    callbacks.Exception = Exception;
+
+    err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));
+    if (JVMTI_ERROR_NONE != err) {
+        cerr << "[JvmtiAgent] ERROR: unable to register event callbacks" << endl;
+        return -1;
+    }
+
+    err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
+            JVMTI_EVENT_VM_INIT, NULL);
+    if (JVMTI_ERROR_NONE != err) {
+        cerr << "[JvmtiAgent] ERROR: unable to enable VMInit event"
+                << endl;
+        return -1;
+    }
+
+    // Set capabilities
+    jvmtiCapabilities capabilities;
+    memset(&capabilities, 0, sizeof(jvmtiCapabilities));
+    capabilities.can_generate_exception_events = 1;
+
+    err = jvmti->AddCapabilities(&capabilities);
+    if (JVMTI_ERROR_NONE != err) {
+        cerr << "[JvmtiAgent] ERROR: unable to possess capabilities" << endl;
+        return -1;
+    }
+
+    // Agent initialized successfully
+    return 0;
+}

Propchange: harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.java?view=auto&rev=541084
==============================================================================
--- harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.java (added)
+++ harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.java Wed May 23 14:14:44 2007
@@ -0,0 +1,139 @@
+package org.apache.harmony.drlvm.tests.regression.h3894;
+
+import junit.framework.TestCase;
+import java.util.HashSet;
+
+/**
+ * Test case for GetThreadGroupChildren() jvmti function.
+ * Checks that the function may report more than 10 child theads.
+ * Checks that the function reports the same thread group children that were
+ * added by java application.
+ * Checks that not started threads are not reported.
+ * Checks that grand children are not reported.
+ */
+public class ThreadGroupChildren extends TestCase {
+
+    static final int CHILD_THREADS = 15;
+    static final int NOT_STARTED_CHILD_THREADS = 2;
+    static final int CHILD_GROUPS = 15;
+    static final int EMPTY_CHILD_GROUPS = 2;
+    static final int GRAND_CHILD_THREADS = 2;
+    static final int GRAND_CHILD_GROUPS = 2;
+
+    public static void main(String args[]) {
+        (new ThreadGroupChildren()).test();
+    }
+
+    public void test() {
+        // this collection should hold references to created Thead and
+        // ThreadGroup objects to avoid their elimination by garbage collector
+        HashSet<Object> set = new HashSet<Object>();
+
+        ThreadGroup testGroup = new ThreadGroup("test group");
+
+        Thread[] childThreads = new Thread[CHILD_THREADS];
+
+        for (int i = 0; i < CHILD_THREADS; i++) {
+            Thread thread = new TestThread(testGroup, "child thread " + i);
+            childThreads[i] = thread;
+            set.add(thread);
+            thread.start();
+        }
+
+        for (int i = 0; i < NOT_STARTED_CHILD_THREADS; i++) {
+            Thread thread = new TestThread(testGroup,
+                    "not started child thread " + i);
+            set.add(thread);
+        }
+
+        ThreadGroup[] childGroups = new ThreadGroup[CHILD_GROUPS +
+                EMPTY_CHILD_GROUPS];
+        int childGroupsIndex = 0;
+
+        for (int i = 0; i < EMPTY_CHILD_GROUPS; i++) {
+            ThreadGroup group = new ThreadGroup(testGroup, "empty child group "
+                     + i);
+            childGroups[childGroupsIndex ++] = group;
+            set.add(group);
+        }
+
+        for (int i = 0; i < CHILD_GROUPS; i++) {
+            ThreadGroup group = new ThreadGroup(testGroup, "child group " + i);
+            childGroups[childGroupsIndex ++] = group;
+            set.add(group);
+
+            for (int j = 0; j < GRAND_CHILD_THREADS; j++) {
+                Thread thread = new TestThread(group, "grand child thread "
+                         + j);
+                set.add(thread);
+                thread.start();
+            }
+
+            for (int j = 0; j < GRAND_CHILD_GROUPS; j++) {
+                ThreadGroup subGroup = new ThreadGroup(group,
+                         "empty grand child group " + j);
+                set.add(subGroup);
+            }
+        }
+
+        try {
+            System.err.println("[Java]: Throwing an exception");
+            // pass execution to the agent
+            throw new InvokeAgentException(testGroup, childThreads,
+                     childGroups);
+        } catch (Exception e) {
+            System.err.println("[Java]: Exception caught");
+        }
+
+        synchronized (TestThread.class) {
+            try {
+                TestThread.class.notifyAll();
+            } catch (Throwable exc) {
+                exc.printStackTrace();
+            }
+        }
+
+        System.err.println("[Java]: test done");
+        assertTrue(Status.status);
+    }
+}
+
+class TestThread extends Thread {
+
+    public TestThread(ThreadGroup group, String name) {
+        super(group, name);
+    }
+
+    public void run() {
+        System.err.println("Thread started: " + getName());
+
+        synchronized (TestThread.class) {
+            try {
+                TestThread.class.wait();
+            } catch (Throwable exc) {
+                exc.printStackTrace();
+            }
+        }
+
+        System.err.println("Thread finished: " + getName());
+    }
+}
+
+class InvokeAgentException extends Exception {
+
+    ThreadGroup testGroup;
+    Thread[] childThreads;
+    ThreadGroup[] childGroups;
+
+    InvokeAgentException(ThreadGroup group, Thread[] threads,
+             ThreadGroup[] groups) {
+        testGroup = group;
+        childThreads = threads;
+        childGroups = groups;
+    }
+}
+
+class Status {
+    /** the field should be modified by jvmti agent to determine test result. */
+    public static boolean status = false;
+}

Propchange: harmony/enhanced/drlvm/trunk/src/test/regression/H3894/ThreadGroupChildren.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: harmony/enhanced/drlvm/trunk/src/test/regression/H3894/run.test.xml
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/src/test/regression/H3894/run.test.xml?view=auto&rev=541084
==============================================================================
--- harmony/enhanced/drlvm/trunk/src/test/regression/H3894/run.test.xml (added)
+++ harmony/enhanced/drlvm/trunk/src/test/regression/H3894/run.test.xml Wed May 23 14:14:44 2007
@@ -0,0 +1,9 @@
+<project name="RUN HARMONY-3894 Regression Test">
+    <target name="run-test">
+        <!-- use special launcher for JVMTI tests -->
+        <run-jvmti-test
+            test="org.apache.harmony.drlvm.tests.regression.h3894.ThreadGroupChildren"
+            agent="ThreadGroupChildren"/>
+    </target>
+</project>
+

Propchange: harmony/enhanced/drlvm/trunk/src/test/regression/H3894/run.test.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.linux.x86_64
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.linux.x86_64?view=diff&rev=541084&r1=541083&r2=541084
==============================================================================
--- harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.linux.x86_64 (original)
+++ harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.linux.x86_64 Wed May 23 14:14:44 2007
@@ -7,4 +7,6 @@
 H3730
 # Exclude this test because JVMTI is not implemented for x86_64 in JIT mode yet
 H3698
+# Exclude this test because JVMTI is not implemented for x86_64 in JIT mode yet
+H3894
 

Modified: harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.windows.x86_64
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.windows.x86_64?view=diff&rev=541084&r1=541083&r2=541084
==============================================================================
--- harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.windows.x86_64 (original)
+++ harmony/enhanced/drlvm/trunk/src/test/regression/excludes/exclude.windows.x86_64 Wed May 23 14:14:44 2007
@@ -4,4 +4,6 @@
 H3730
 # Exclude this test because JVMTI is not implemented for x86_64 in JIT mode yet
 H3698
+# Exclude this test because JVMTI is not implemented for x86_64 in JIT mode yet
+H3894
 

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_thread_group.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_thread_group.cpp?view=diff&rev=541084&r1=541083&r2=541084
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_thread_group.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/jvmti/jvmti_thread_group.cpp Wed May 23 14:14:44 2007
@@ -14,10 +14,10 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-/** 
+/**
  * @author Gregory Shimansky
  * @version $Revision: 1.1.2.1.4.4 $
- */  
+ */
 /*
  * JVMTI thread group APIO
  */
@@ -29,6 +29,7 @@
 #include "cxxlog.h"
 #include "suspend_checker.h"
 #include "environment.h"
+#include "exceptions.h"
 #include "Class.h"
 
 #define jvmti_test_jenv (p_TLS_vmthread->jni_env)
@@ -148,6 +149,45 @@
     return JVMTI_ERROR_NONE;
 }
 
+/**
+ * This function extracts element specified by 'index' from 'pair' array.
+ * Extracted element assumed to be an jobjectArray and is converted to native
+ * array of jobject that is returned via 'array_ptr' ant 'count_ptr' args.
+ */
+static jvmtiError read_array(jvmtiEnv* env,
+                                  jobjectArray pair,
+                                  jint index,
+                                  jint* count_ptr,
+                                  jobject** array_ptr)
+{
+    jint count = 0;
+    jobjectArray object_array = NULL;
+
+    if (NULL != pair) {
+        object_array = jvmti_test_jenv->GetObjectArrayElement(pair, index);
+
+        if (NULL != object_array)
+            count = jvmti_test_jenv->GetArrayLength(object_array);
+    }
+
+    jvmtiError err;
+
+    jobject* native_array = NULL;
+    err = _allocate(sizeof(jobject) * count, (unsigned char**) &native_array);
+
+    if (JVMTI_ERROR_NONE != err)
+        return err;
+
+    for (int i = 0; i < count; i++)
+        native_array[i] = jvmti_test_jenv->
+                GetObjectArrayElement(object_array, i);
+
+    *count_ptr = count;
+    *array_ptr = native_array;
+
+    return JVMTI_ERROR_NONE;
+}
+
 /*
  * Get Thread Group Children
  *
@@ -183,57 +223,38 @@
         return JVMTI_ERROR_NULL_POINTER;
     }
 
-    ti->setLocallyDisabled();//-----------------------------------V
-
-    jclass cl = GetObjectClass(jvmti_test_jenv, group);
-    jobjectArray jg = jvmti_test_jenv -> NewObjectArray(10, cl, 0);
-    jmethodID id = jvmti_test_jenv -> GetMethodID(cl, "enumerate","([Ljava/lang/ThreadGroup;)I");
-    int cc = jvmti_test_jenv -> CallIntMethod (group, id, jg);
-    jthreadGroup* groups = NULL;
-    jvmtiError jvmti_error = _allocate(sizeof(jthreadGroup) * cc,
-            (unsigned char **)&groups);
+    jclass thread_group_class = GetObjectClass(jvmti_test_jenv, group);
+    jmethodID method = jvmti_test_jenv -> GetMethodID(thread_group_class,
+            "getActiveChildren","()[Ljava/lang/Object;");
+    assert(method);
 
-    if (JVMTI_ERROR_NONE != jvmti_error)
-    {
-        
-        ti->setLocallyEnabled();//-----------------------------------^
-        return jvmti_error;
-    }
+    ti->setLocallyDisabled();//-----------------------------------V
 
-    int i; // Visual C++ 6.0 does not treat "for" as C++ scope
+    // by contract this method returns Object[2] array.
+    // First element is Object[] array of child Thread objects.
+    // Second element is Object[] array of child ThreadGroup objects.
+    jobjectArray result = jvmti_test_jenv->CallObjectMethod(group, method);
 
-    for (i = 0; i < cc; i++)
-    {
-        groups[i] = jvmti_test_jenv -> GetObjectArrayElement(jg, i);
-    }
+    ti->setLocallyEnabled();//-----------------------------------^
 
-    *group_count_ptr = cc;
-    *groups_ptr = groups;
+    if (exn_raised())
+        return JVMTI_ERROR_INTERNAL;
 
-    jclass cll = struct_Class_to_java_lang_Class_Handle(VM_Global_State::loader_env->java_lang_Thread_Class);
-    jobjectArray jt = jvmti_test_jenv -> NewObjectArray(10, cll, 0);
-    id = jvmti_test_jenv -> GetMethodID(cl, "enumerate","([Ljava/lang/Thread;Z)I");
-    cc = jvmti_test_jenv -> CallIntMethod (group, id, jt, JNI_FALSE);
+    jvmtiError err;
 
-    ti->setLocallyEnabled();//-----------------------------------^
+    // extract child threads array
+    err = read_array(env, result, 0, thread_count_ptr, threads_ptr);
 
-    jthread * threads = NULL;
-    jvmti_error = _allocate(sizeof(jthread) * cc, (unsigned char **)&threads);
+    if (JVMTI_ERROR_NONE != err)
+        return err;
 
-    if (JVMTI_ERROR_NONE != jvmti_error)
-    {
-        return jvmti_error;
-    }
+    // extract child groups array
+    err = read_array(env, result, 1, group_count_ptr, groups_ptr);
 
-    for (i = 0; i < cc; i++)
-    {
-        threads[i] = jvmti_test_jenv -> GetObjectArrayElement(jt, i);
+    if (JVMTI_ERROR_NONE != err) {
+        _deallocate((unsigned char*) *threads_ptr);
+        return err;
     }
 
-    *thread_count_ptr = cc;
-    *threads_ptr = threads;
-
     return JVMTI_ERROR_NONE;
-}
-
-
+} // jvmtiGetThreadGroupChildren

Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java?view=diff&rev=541084&r1=541083&r2=541084
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/javasrc/java/lang/ThreadGroup.java Wed May 23 14:14:44 2007
@@ -22,13 +22,14 @@
 package java.lang;
 
 import java.util.List;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.Iterator;
 import java.util.WeakHashMap;
 import java.util.ConcurrentModificationException;
 
 /**
- * @com.intel.drl.spec_ref 
+ * @com.intel.drl.spec_ref
  */
 
 public class ThreadGroup implements Thread.UncaughtExceptionHandler{
@@ -66,7 +67,7 @@
     /**
      * Parent thread group of this thread group.
      *
-     * FIXME: this field must be private. It is changed to package-private 
+     * FIXME: this field must be private. It is changed to package-private
      * to be accessible from FT SecurityManager class. Both SecurityManager
      * and ThreadGroup are considered as non-Kernel by FT, but ThreadGroup
      * is Kernel now in DRL.
@@ -125,13 +126,13 @@
             threadsCopy = copyThreads();
             groupsListCopy = (List)groups.clone();
         }
-        
+
         for (int i = 0; i < threadsCopy.length; i++) {
             if (((Thread) threadsCopy[i]).isAlive()) {
                 count++;
             }
         }
-        
+
         for (Iterator it = groupsListCopy.iterator(); it.hasNext();) {
             count += ((ThreadGroup)it.next()).activeCount();
         }
@@ -185,7 +186,7 @@
 					"The thread group " + name + " is already destroyed!");
 		}
         if (!nonsecureDestroy()) {
-            throw new IllegalThreadStateException("The thread group " + name + 
+            throw new IllegalThreadStateException("The thread group " + name +
                     " is not empty");
         } else {
             if (parent != null) {
@@ -314,7 +315,7 @@
      */
     public synchronized final void setMaxPriority(int priority) {
         checkAccess();
-        
+
         /*
          *  GMJ : note that this is to match a known bug in the RI
          *  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708197
@@ -364,7 +365,7 @@
         if(parent != null){
            parent.uncaughtException(thread, throwable);
            return;
-        } 
+        }
         Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
         if(defaultHandler != null){
             defaultHandler.uncaughtException(thread, throwable);
@@ -416,7 +417,7 @@
         }
         groups.add(group);
     }
-    
+
     /**
      * Copies this ThreadGroup's threads to an array which is used in iteration
      * over threads because iteration over a WeakHashMap object can lead to
@@ -433,11 +434,46 @@
     }
 
     /**
+     * Used by GetThreadGroupChildren() jvmti function.
+     * @return Object[] array of 2 elements: first - Object[] array of active
+     * child threads; second - Object[] array of child groups.
+     */
+    private Object[] getActiveChildren() {
+        ArrayList<Thread> threadsCopy = new ArrayList<Thread>(threads.size());
+        ArrayList<ThreadGroup> groupsCopy = new ArrayList<ThreadGroup>(groups.size());
+
+        synchronized (this) {
+            if (destroyed) {
+                return new Object[] {null, null};
+            }
+
+            for (Thread thread : threads.keySet()) {
+                threadsCopy.add(thread);
+            }
+
+            for (ThreadGroup group : groups) {
+                groupsCopy.add(group);
+            }
+        }
+
+        ArrayList<Thread> activeThreads = new ArrayList<Thread>(threadsCopy.size());
+
+        // filter out alive threads
+        for (Thread thread : threadsCopy) {
+            if (thread.isAlive()) {
+                activeThreads.add(thread);
+            }
+        }
+
+        return new Object[] {activeThreads.toArray(), groupsCopy.toArray()};
+    }
+
+    /**
      * Copies all the threads contained in the snapshot of this thread group to
      * the array specified starting from the specified position. <br>
      * If the specified array is not long enough to take all the threads of this
      * thread group, the exta threads are silently ignored. <br>
-     * 
+     *
      * @param list an array to copy threads to
      * @param offset position in this array to start copying from
      * @param recurse indicates if the threads contained in the subgroups of
@@ -480,7 +516,7 @@
      * to the array specified starting from the specified position. <br>
      * If the specified array is not long enough to take all the subgroups of
      * this thread group, the exta subgroups are silently ignored. <br>
-     * 
+     *
      * @param list an array to copy subgroups to
      * @param offset position in this array to start copying from
      * @param recurse indicates if the subgroups contained in the subgroups of
@@ -537,7 +573,7 @@
      * Destroys this thread group without any security checks. We add this
      * method to avoid calls to the checkAccess() method on subgroups.
      * All non-empty subgroups are removed recursievely.
-     * If at least one subgroup is not empty, IllegalThreadStateException 
+     * If at least one subgroup is not empty, IllegalThreadStateException
      * will be thrown.
      * @return false if this ThreadGroup is not empty
      */
@@ -628,7 +664,7 @@
 
     /**
      * Removes the specified thread group from this group.
-     * 
+     *
      * @param group group to be removed from this one
      */
     private synchronized void remove(ThreadGroup group) {