harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ge...@apache.org
Subject svn commit: r480141 [14/38] - in /harmony/enhanced/jdktools/trunk/modules/jpda: ./ doc/ doc/images/ make/ src/ src/common/ src/common/other/ src/common/other/jpda/ src/common/other/jpda/jdwp/ src/common/other/jpda/jdwp/agent/ src/common/other/jpda/jdwp...
Date Tue, 28 Nov 2006 17:49:31 GMT
Added: harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/RequestModifier.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/RequestModifier.h?view=auto&rev=480141
==============================================================================
--- harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/RequestModifier.h (added)
+++ harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/RequestModifier.h Tue Nov 28 09:49:08 2006
@@ -0,0 +1,905 @@
+/*
+ * Copyright 2005-2006 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.
+ */
+
+/**
+ * @author Pavel N. Vyssotski
+ * @version $Revision: 1.10.2.1 $
+ */
+
+/**
+ * @file
+ * RequestModifier.h
+ *
+ */
+
+#ifndef _REQUEST_MODIFIER_H_
+#define _REQUEST_MODIFIER_H_
+
+#include "AgentBase.h"
+
+namespace jdwp {
+
+    /**
+     * The event description structure used in <code>RequestManager</code>.
+     */
+    struct EventInfo {
+
+        /**
+         * The JDWP kind of the request event.
+         */
+        jdwpEventKind kind;
+
+        /**
+         * The Java thread where the event occurred.
+         */
+        jthread thread;
+
+        /**
+         * The Java class in which the method event occurred.
+         */
+        jclass cls;
+
+        /**
+         * The signature of the Java class in which the method event occurred.
+         */
+        char* signature;
+
+        /**
+         * The method ID where the event occurred.
+         */
+        jmethodID method;
+
+        /**
+         * The Java location where the event occurred.
+         */
+        jlocation location;
+
+        /**
+         * The field ID accessed or modified on the corresponding
+         * event, such as <code>FieldAccess</code> and 
+         * <code>FieldModification</code>.
+         */
+        jfieldID field;
+
+        /**
+         * The Java object which field was accessed or modified on the corresponding
+         * event, such as <code>FieldAccess</code> and 
+         * <code>FieldModification</code>.
+         */
+        jobject instance;
+
+        /**
+         * The aux class corresponding to the exception in the Exception event or
+         * to the field reference type in <code>FieldAccess</code> and 
+         * <code>FieldModification</code> events.
+         */
+        jclass auxClass;
+
+        /**
+         * The flag indicating that the exception thrown in the Exception event
+         * was caught.
+         */
+        bool caught;
+    };
+
+    /**
+     * The base class for event request modifiers used to filter the events
+     * generated by the target VM.
+     */
+    class RequestModifier : public AgentBase {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param kind - the JDWP request modifier kind
+         */
+        RequestModifier(jdwpRequestModifier kind) : m_kind(kind) {}
+
+        /**
+         * A destructor.
+         */
+        virtual ~RequestModifier() {};
+
+        /**
+         * Applies filtering for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return <code>TRUE</code>.
+         */
+        virtual bool Apply(JNIEnv* jni, EventInfo &eInfo) throw() {
+            return true;
+        }
+
+        /**
+         * Gets the JDWP request modifier kind.
+         *
+         * @return The JDWP request modifier kind.
+         */
+        jdwpRequestModifier GetKind() const throw() { return m_kind; }
+
+    protected:
+
+        bool MatchPattern(const char *signature, const char *pattern)
+            const throw();
+
+        jdwpRequestModifier m_kind;
+
+    };
+
+    /**
+     * The class implements the Count modifier enabling the requested events
+     * to be reported only once after specified number of occurrences.
+     * 
+     */
+    class CountModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param n - the initial count value
+         */
+        CountModifier(jint n) :
+            RequestModifier(JDWP_MODIFIER_COUNT),
+            m_count(n)
+        {}
+
+        /**
+         * Gets the current count value.
+         *
+         * @return The current value of the event counter.
+         */
+        jint GetCount() const throw() { return m_count; }
+
+        /**
+         * Applies count filtering for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return Returns <code>TRUE</code> if count is zero, otherwise 
+         * <code>FALSE</code>.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            if (m_count > 0) {
+                m_count--;
+                if (m_count == 0) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+    private:
+
+        jint m_count;
+
+    };
+
+    /**
+     * The class implements the Conditional modifier enabling the requested events
+     * to be reported depending on the specified expression. Currently, not 
+     * implemented.
+     */
+    class ConditionalModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param id - the expression ID
+         */
+        ConditionalModifier(jint id) :
+            RequestModifier(JDWP_MODIFIER_CONDITIONAL),
+            m_exprID(id)
+        {}
+
+        /**
+         * Gets the expression ID.
+         *
+         * @return The expression ID.
+         */
+        jint GetExprID() const throw() { return m_exprID; }
+
+        /**
+         * Applies filtering by the expression result for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return <code>TRUE</code> (not implemented).
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw() {
+            return true;
+        }
+
+    private:
+
+        jint m_exprID;
+
+    };
+
+    /**
+     * The class implements the <code>ThreadOnly</code> modifier enabling 
+     * the requested events to be reported only for the specified thread.
+     */
+    class ThreadOnlyModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param jni     - the JNI interface pointer
+         * @param thread  - the Java thread
+         *
+         * @throws OutOfMemoryException.
+         */
+        ThreadOnlyModifier(JNIEnv *jni, jthread thread) throw(AgentException) :
+            RequestModifier(JDWP_MODIFIER_THREAD_ONLY)
+        {
+            m_thread = jni->NewGlobalRef(thread);
+            if (m_thread == 0) {
+                throw OutOfMemoryException();
+            }
+        }
+
+        /**
+         * A destructor.
+         */
+        ~ThreadOnlyModifier() {
+            GetJniEnv()->DeleteGlobalRef(m_thread);
+        }
+
+        /**
+         * Gets the Java thread.
+         *
+         * @return The Java thread.
+         */
+        jthread GetThread() const throw() {
+            return m_thread;
+        }
+
+        /**
+         * Applies filtering by belonging to the only thread for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return Returns <code>TRUE</code>, if the event occurs in the 
+         *         thread of interest.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw() 
+        {
+            JDWP_ASSERT(eInfo.thread != 0);
+            return (JNI_TRUE == jni->IsSameObject(eInfo.thread, m_thread));
+        }
+
+    private:
+
+        jthread m_thread;
+
+    };
+
+    /**
+     * The class implements the <code>ClassOnly</code> modifier enabling the 
+     * requested events to be reported only for a specified or derived class.
+     */
+    class ClassOnlyModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param jni - the JNI interface pointer
+         * @param cls - the Java class
+         *
+         * @throws OutOfMemoryException.
+         */
+        ClassOnlyModifier(JNIEnv *jni, jclass cls) throw(AgentException) :
+            RequestModifier(JDWP_MODIFIER_CLASS_ONLY)
+        {
+            m_class = static_cast<jclass>(jni->NewGlobalRef(cls));
+            if (m_class == 0) {
+                throw OutOfMemoryException();
+            }
+        }
+
+        /**
+         * A destructor.
+         */
+        ~ClassOnlyModifier() {
+            GetJniEnv()->DeleteGlobalRef(m_class);
+        }
+
+        /**
+         * Gets the Java class.
+         *
+         * @return The Java class.
+         */
+        jclass GetClass() const throw() {
+            return m_class;
+        }
+
+        /**
+         * Applies filtering by belonging to the only class for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return Returns <code>TRUE</code>, if event occurs in the class of interest.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            JDWP_ASSERT(eInfo.cls != 0);
+            return (JNI_TRUE == jni->IsAssignableFrom(eInfo.cls, m_class));
+        }
+
+    private:
+
+        jclass m_class;
+
+    };
+
+    /**
+     * The class implements the <code>ClassMatch</code> modifier enabling the 
+     * requested events to be reported only for the classes with the name 
+     * corresponding to the given pattern.
+     */
+    class ClassMatchModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param str - the class match pattern
+         */
+        ClassMatchModifier(char* str)
+            : RequestModifier(JDWP_MODIFIER_CLASS_MATCH)
+            , m_pattern(str)
+        {}
+
+        /**
+         * A destructor.
+         */
+        ~ClassMatchModifier() {
+            GetMemoryManager().Free(m_pattern JDWP_FILE_LINE);
+        }
+
+        /**
+         * Gets the class-match pattern.
+         *
+         * @return Zero-terminated string.
+         */
+        const char* GetPattern() const throw() {
+            return m_pattern;
+        }
+
+        /**
+         * Applies the class match filtering for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return Returns <code>TRUE</code>, if the class signature matches the given pattern.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            JDWP_ASSERT(eInfo.signature != 0);
+            return (MatchPattern(eInfo.signature, m_pattern));
+        }
+
+    private:
+
+        char* m_pattern;
+
+    };
+
+    /**
+     * The class implements the <code>ClassExclude</code> modifier enabling the 
+     * requested events to be reported only for the classes with the name not 
+     * corresponding to the given pattern.
+     */
+    class ClassExcludeModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param str - the class exclude pattern
+         */
+        ClassExcludeModifier(char* str) :
+            RequestModifier(JDWP_MODIFIER_CLASS_EXCLUDE),
+            m_pattern(str)
+        {}
+
+        /**
+         * A destructor.
+         */
+        ~ClassExcludeModifier() {
+            GetMemoryManager().Free(m_pattern JDWP_FILE_LINE);
+        }
+
+        /**
+         * Gets the class exclude pattern.
+         *
+         * @return Zero-terminated string.
+         */
+        const char* GetPattern() const throw() {
+            return m_pattern;
+        }
+
+        /**
+         * Applies the class exclude filtering for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request event information
+         *
+         * @return Returns <code>TRUE</code>, if the class signature does not match 
+         * the given pattern.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            JDWP_ASSERT(eInfo.signature != 0);
+            return (!MatchPattern(eInfo.signature, m_pattern));
+        }
+
+    private:
+
+        char* m_pattern;
+
+    };
+
+    /**
+     * The class implements the <code>LocationOnly</code> modifier enabling 
+     * the requested events to be reported only at the specified location.
+     */
+    class LocationOnlyModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param jni     - the JNI interface pointer
+         * @param cls     - the Java class
+         * @param method  - the class method
+         * @param loc     - the Java location
+         *
+         * @throws OutOfMemoryException.
+         */
+        LocationOnlyModifier(JNIEnv *jni, jclass cls, jmethodID method,
+                jlocation loc) throw(AgentException) :
+            RequestModifier(JDWP_MODIFIER_LOCATION_ONLY),
+            m_method(method),
+            m_location(loc)
+        {
+            m_class = static_cast<jclass>(jni->NewGlobalRef(cls));
+            if (m_class == 0) {
+                throw OutOfMemoryException();
+            }
+        }
+
+        /**
+         * A destructor.
+         */
+        ~LocationOnlyModifier() {
+            GetJniEnv()->DeleteGlobalRef(m_class);
+        }
+
+        /**
+         * Gets the Java class.
+         *
+         * @return The Java class.
+         */
+        jclass GetClass() const throw() {
+            return m_class;
+        }
+
+        /**
+         * Gets the Java class method ID.
+         *
+         * @return The method ID.
+         */
+        jmethodID GetMethod() const throw() { 
+            return m_method;
+        }
+
+        /**
+         * Gets the Java location.
+         *
+         * @return The Java location.
+         */
+        jlocation GetLocation() const throw() {
+            return m_location;
+        }
+
+        /**
+         * Applies filtering by belonging to the given location for the given event.
+         *
+         * @param jni - the JNI interface pointer
+         * @param eInfo - the request-event information
+         *
+         * @return Returns <code>TRUE</code>, if event location is equal to the given one.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            JDWP_ASSERT(eInfo.cls != 0);
+            return (eInfo.method == m_method && eInfo.location == m_location &&
+                JNI_TRUE == jni->IsSameObject(eInfo.cls, m_class));
+        }
+
+    private:
+
+        jclass m_class;
+        jmethodID m_method;
+        jlocation m_location;
+
+    };
+
+    /**
+     * The class implements the <code>ExceptionOnly</code> modifier enabling the 
+     * requested events caused by exception to be reported only for a specified 
+     * exception reference type or for all exceptions if the specified type is null.
+     */
+    class ExceptionOnlyModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param jni      - the JNI interface pointer
+         * @param cls      - the Java class
+         * @param caught   - the caught exception 
+         * @param uncaught - the uncaught exception 
+         *
+         * @throws <code>OutOfMemoryException</code>.
+         */
+        ExceptionOnlyModifier(JNIEnv *jni, jclass cls, bool caught,
+                bool uncaught) throw(AgentException) :
+            RequestModifier(JDWP_MODIFIER_EXCEPTION_ONLY),
+            m_caught(caught),
+            m_uncaught(uncaught)
+        {
+            if (cls == 0) {
+                m_class = 0;
+            } else {
+                m_class = static_cast<jclass>(jni->NewGlobalRef(cls));
+                if (m_class == 0) {
+                    throw OutOfMemoryException();
+                }
+            }
+        }
+
+        /**
+         * A destructor.
+         */
+        ~ExceptionOnlyModifier() {
+            GetJniEnv()->DeleteGlobalRef(m_class);
+        }
+
+        /**
+         * Gets the Java class.
+         *
+         * @return The Java class.
+         */
+        jclass GetClass() const throw() {
+            return m_class;
+        }
+
+        /**
+         * Tells whether exception is caught.
+         *
+         * @return Boolean.
+         */
+        bool IsCaught() const throw() {
+            return m_caught;
+        }
+
+        /**
+         * Tells whether the exception is uncaught.
+         *
+         * @return Boolean.
+         */
+        bool IsUncaught() const throw() {
+            return m_uncaught;
+        }
+
+        /**
+         * Applies filtering by exception to the given location for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return Returns <code>TRUE</code>, if the event location is equal to the given one.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            return ((eInfo.caught ? m_caught : m_uncaught) &&
+                (m_class == 0 || (eInfo.cls != 0 &&
+                    JNI_TRUE == jni->IsAssignableFrom(eInfo.auxClass, m_class))));
+        }
+
+    private:
+
+        jclass m_class;
+        bool m_caught;
+        bool m_uncaught;
+
+    };
+
+    /**
+     * The class implements the <code>FieldOnly</code> modifier enabling the 
+     * requested field to access/modify events to be reported only for a 
+     * specified field in the given class.
+     */
+    class FieldOnlyModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param jni   - the JNI interface pointer
+         * @param cls   - the Java class
+         * @param field - the field ID
+         *
+         * @throws <code>OutOfMemoryException</code>.
+         */
+        FieldOnlyModifier(JNIEnv *jni, jclass cls,
+                jfieldID field) throw(AgentException) :
+            RequestModifier(JDWP_MODIFIER_FIELD_ONLY),
+            m_field(field)
+        {
+            m_class = static_cast<jclass>(jni->NewGlobalRef(cls));
+            if (m_class == 0) {
+                throw OutOfMemoryException();
+            }
+        }
+
+        /**
+         * A destructor.
+         */
+        ~FieldOnlyModifier() {
+            GetJniEnv()->DeleteGlobalRef(m_class);
+        }
+
+        /**
+         * Gets the Java class.
+         *
+         * @return The Java class.
+         */
+        jclass GetClass() const throw() {
+            return m_class;
+        }
+
+        /**
+         * Gets the field ID.
+         *
+         * @return The field ID.
+         */
+        jfieldID GetField() const throw() {
+            return m_field;
+        }
+
+        /**
+         * Applies filtering by field to the given location for the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request event information
+         *
+         * @return Returns <code>TRUE</code>, if the event field is equal to the given one.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            JDWP_ASSERT(eInfo.cls != 0);
+            return (eInfo.field == m_field &&
+                JNI_TRUE == jni->IsSameObject(eInfo.cls, m_class));
+        }
+
+    private:
+
+        jclass m_class;
+        jfieldID m_field;
+
+    };
+
+    /**
+     * The class implements the Step modifier enabling the requested 
+     * step events to be reported only if they occur within specified depth
+     * and size boundaries.
+     */
+    class StepModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param jni     - the JNI interface pointer
+         * @param thread  - the Java thread
+         * @param size    - the step size
+         * @param depth   - the step depth
+         *
+         * @throws OutOfMemoryException.
+         */
+        StepModifier(JNIEnv *jni, jthread thread, jint size,
+                jint depth) throw(AgentException) :
+            RequestModifier(JDWP_MODIFIER_STEP),
+            m_size(size),
+            m_depth(depth)
+        {
+            m_thread = jni->NewGlobalRef(thread);
+            if (m_thread == 0) {
+                throw OutOfMemoryException();
+            }
+        }
+
+        /**
+         * A destructor.
+         */
+        ~StepModifier() {
+            GetJniEnv()->DeleteGlobalRef(m_thread);
+        }
+
+        /**
+         * Gets the Java thread.
+         *
+         * @return The Java thread.
+         */
+        jthread GetThread() const throw() {
+            return m_thread;
+        }
+
+        /**
+         * Gets the step size.
+         *
+         * @return The int step size.
+         */
+        jint GetSize() const throw() {
+            return m_size;
+        }
+
+        /**
+         * Gets the step depth.
+         *
+         * @return The int step depth.
+         */
+        jint GetDepth() const throw() {
+            return m_depth;
+        }
+
+        /**
+         * Applies filtering by step depth and size to the given location for 
+         * the given event.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param eInfo  - the request-event information
+         *
+         * @return <code>TRUE</code>.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw() {
+            return true;
+        }
+
+    private:
+
+        jthread m_thread;
+        jint m_size;
+        jint m_depth;
+
+    };
+
+    /**
+     * The class implements <code>InstanceOnly</code> modifier that allows 
+     * the requested events to be reported only for specified object instance.
+     */
+    class InstanceOnlyModifier : public RequestModifier {
+
+    public:
+
+        /**
+         * A constructor.
+         *
+         * @param jni - the JNI interface pointer
+         * @param obj - the Java object instance
+         *
+         * @throws OutOfMemoryException.
+         */
+        InstanceOnlyModifier(JNIEnv *jni, jobject obj) throw(AgentException) :
+            RequestModifier(JDWP_MODIFIER_INSTANCE_ONLY)
+        {
+            if (obj == 0) {
+                m_instance = 0;
+            } else {
+                m_instance = jni->NewGlobalRef(obj);
+                if (m_instance == 0) {
+                    throw OutOfMemoryException();
+                }
+            }
+        }
+
+        /**
+         * A destructor.
+         */
+        ~InstanceOnlyModifier() {
+            GetJniEnv()->DeleteGlobalRef(m_instance);
+        }
+
+        /**
+         * Gets the Java object instance.
+         *
+         * @return The Java object.
+         */
+        jobject GetInstance() const throw() {
+            return m_instance;
+        }
+
+        /**
+         * Applies filtering by object instance to the given location for 
+         * the given event.
+         *
+         * @param jni   - the JNI interface pointer
+         * @param eInfo - the request event information
+         *
+         * @return <code>TRUE</code>.
+         */
+        bool Apply(JNIEnv* jni, EventInfo &eInfo) throw()
+        {
+            if (eInfo.instance == 0 &&
+                (eInfo.kind == JDWP_EVENT_SINGLE_STEP  ||
+                 eInfo.kind == JDWP_EVENT_BREAKPOINT   ||
+                 eInfo.kind == JDWP_EVENT_EXCEPTION    ||
+                 eInfo.kind == JDWP_EVENT_METHOD_ENTRY ||
+                 eInfo.kind == JDWP_EVENT_METHOD_EXIT))
+            {
+                jint modifiers;
+                jvmtiError err;
+                JVMTI_TRACE(err, GetJvmtiEnv()->GetMethodModifiers(
+                    eInfo.method, &modifiers));
+                if (err == JVMTI_ERROR_NONE && (modifiers & ACC_STATIC) == 0) {
+                    // get "this" object from slot 0 (stated in JVM spec)
+                    JVMTI_TRACE(err, GetJvmtiEnv()->GetLocalObject(
+                        eInfo.thread, 0, 0, &eInfo.instance));
+                }
+            }
+            return ((eInfo.instance == 0 && m_instance == 0) ||
+                ((eInfo.instance != 0 && m_instance != 0) &&
+                 JNI_TRUE == jni->IsSameObject(eInfo.instance, m_instance)));
+        }
+
+    private:
+
+        jobject m_instance;
+
+    };
+
+}
+
+#endif // _REQUEST_MODIFIER_H_

Propchange: harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/RequestModifier.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.cpp?view=auto&rev=480141
==============================================================================
--- harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.cpp (added)
+++ harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.cpp Tue Nov 28 09:49:08 2006
@@ -0,0 +1,1031 @@
+/*
+ * Copyright 2005-2006 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.
+ */
+
+/**
+ * @author Vitaly A. Provodin, Pavel N. Vyssotski
+ * @version $Revision: 1.32.2.1 $
+ */
+#include <algorithm>
+
+#include "Log.h"
+#include "ThreadManager.h"
+#include "ClassManager.h"
+#include "ObjectManager.h"
+#include "EventDispatcher.h"
+#include "RequestManager.h"
+
+using namespace jdwp;
+
+namespace jdwp {
+
+    /**
+     * The structure containing thread information about
+     * internal agent threads and suspended java threads.
+     */
+    class ThreadInfo : public AgentBase {
+
+    public:
+
+        /**
+         * Thread suspend count.
+         */
+        jint    m_suspendCount;
+
+        /**
+         * Java thread.
+         */
+        jthread m_thread;
+
+        /**
+         * Thread name.
+         */
+        char*   m_threadName;
+
+        /**
+         * Whether internal agent is working thread.
+         */
+        bool    m_isAgentThread;
+
+        /**
+         * Whether thread was suspended on event.
+         */
+        bool    m_isOnEvent;
+
+        /**
+         * A constructor.
+         * Creates new instance.
+         * @param jni the JNI interface pointer.
+         * @param thrd java thread.
+         * @param isAgentThrd indicates whether thread is internal agent's or traget VM's.
+         * @param isOnEvent on event thread suspension.
+         */
+        ThreadInfo(JNIEnv *jni, jthread thrd, bool isAgentThrd = false, bool isOnEvent = false)
+            throw (OutOfMemoryException)
+        {
+            m_thread = jni->NewGlobalRef(thrd);
+            if (m_thread == 0) throw OutOfMemoryException();
+            m_isAgentThread = isAgentThrd;
+            m_isOnEvent = isOnEvent;
+            m_suspendCount = 0;
+            m_threadName = 0;
+        }
+
+        /**
+         * Cleanups global reference to java thread.
+         * @param jni the JNI interface pointer.
+         */
+        void Clean(JNIEnv *jni)
+        {
+            jni->DeleteGlobalRef(m_thread);
+        }
+
+    }; //ThreadInfo
+
+    //-------------------------------------------------------------------------
+
+    /**
+     * Looks for corresponding thread info in the thread info list.
+     * @param jni the JNI interface pointer.
+     * @param thrdInfoList pointer to the thread info list.
+     * @param thread the given java thread.
+     * @param result found position in the thread info list.
+     */
+    void FindThreadInfo(JNIEnv *jni, ThreadInfoList *thrdInfoList, jthread thread,
+        ThreadInfoList::iterator &result)
+    {
+        for (result = thrdInfoList->begin(); result != thrdInfoList->end(); result++) {
+            if (*result != 0 && 
+                    jni->IsSameObject((*result)->m_thread, thread) == JNI_TRUE)
+                break;
+        }
+    }
+
+}// namespace jdwp
+
+//-----------------------------------------------------------------------------
+//ThreadManager----------------------------------------------------------------
+
+ThreadManager::~ThreadManager()
+{
+    JDWP_ASSERT(m_thrdmgrMonitor == 0);
+    JDWP_ASSERT(m_execMonitor == 0);
+}
+        
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::Init(JNIEnv *jni) throw()
+{
+    JDWP_TRACE_ENTRY("Init(" << jni << ')');
+
+    JDWP_ASSERT(m_thrdmgrMonitor == 0);
+
+    m_execMonitor = new AgentMonitor("_jdwp_ThreadManager_execMonitor");
+    m_thrdmgrMonitor = new AgentMonitor("_jdwp_ThreadManager_thrdmgrMonitor");
+    
+    m_stepMonitor = new AgentMonitor("_jdwp_ThreadManager_stepMonitor");
+    m_popFramesMonitor = new AgentMonitor("_jdwp_ThreadManager_popFramesMonitor");
+    m_stepMonitorReleased = false;
+    m_popFramesMonitorReleased = false;
+
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::Clean(JNIEnv *jni) throw()
+{
+    JDWP_TRACE_ENTRY("Clean(" << jni << ')');
+
+    if(m_execMonitor !=0) {
+        delete m_execMonitor;
+        m_execMonitor = 0;
+    }
+
+    if(m_thrdmgrMonitor != 0) {
+        delete m_thrdmgrMonitor;
+        m_thrdmgrMonitor = 0;
+    }
+
+    if (m_stepMonitor != 0) {
+        delete m_stepMonitor;
+        m_stepMonitor = 0;
+    }
+
+    if (m_popFramesMonitor != 0) {
+        delete m_popFramesMonitor;
+        m_popFramesMonitor = 0;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::Reset(JNIEnv *jni) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("Reset(" << jni << ')');
+
+    // delete not yet started but registered handlers for method invoke
+    if (m_execMonitor != 0) {
+        MonitorAutoLock lock(m_execMonitor JDWP_FILE_LINE);
+        ClearExecList(jni);
+    }
+
+    // resume all not internal threads and remove them from list
+    if (m_thrdmgrMonitor != 0) {
+        MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+        ClearThreadList(jni);
+    }
+
+    // reset flags and thread variable that are used in PopFrames process
+    {
+        m_stepMonitorReleased = false;
+        m_popFramesMonitorReleased = false;
+        m_popFramesThread = 0;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::ClearThreadList(JNIEnv *jni)
+{
+    JDWP_TRACE_ENTRY("ClearThreadList(" << jni << ')');
+
+    for (ThreadInfoList::iterator iter = m_threadInfoList.begin(); iter != m_threadInfoList.end(); iter++) {
+        if (*iter == 0) continue;
+        if (!(*iter)->m_isAgentThread) {
+            JDWP_TRACE_THREAD("Reset: resume thread=" << (*iter)->m_thread 
+                << ", name=" << JDWP_CHECK_NULL((*iter)->m_threadName));
+            // resume thread
+            GetObjectManager().DeleteFrameIDs(jni, (*iter)->m_thread);
+            jvmtiError err;
+            JVMTI_TRACE(err, GetJvmtiEnv()->ResumeThread((*iter)->m_thread));
+            // remove from list and destroy
+            (*iter)->Clean(jni);
+            delete *iter;
+            *iter = 0;
+        }
+    }
+    m_threadInfoList.clear();
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::ClearExecList(JNIEnv* jni) throw()
+{
+    JDWP_TRACE_ENTRY("ClearExecList(" << jni << ')');
+
+    while (!m_execList.empty()) {
+        SpecialAsyncCommandHandler* handler = m_execList.back();
+        m_execList.pop_back();
+        delete handler;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+jthread
+ThreadManager::RunAgentThread(JNIEnv *jni, jvmtiStartFunction proc,
+                                const void *arg, jint priority,
+                                const char *name) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("RunAgentThread(" << jni << ',' << proc 
+            << ',' << arg << ',' << priority 
+                        << ',' << JDWP_CHECK_NULL(name) << ')');
+
+    jthread thread = CreateAgentThread(jni, name);
+    jvmtiError err;
+    JVMTI_TRACE(err, GetJvmtiEnv()->RunAgentThread(thread, proc, arg, priority));
+
+    if (err != JVMTI_ERROR_NONE)
+        throw AgentException(err);
+
+    return thread;
+}
+
+//-----------------------------------------------------------------------------
+
+jthread
+ThreadManager::CreateAgentThread(JNIEnv *jni, const char *name) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("CreateAgentThread(" << jni 
+                        << ',' << JDWP_CHECK_NULL(name) << ')');
+
+    jthread thrd;
+    ClassManager &clsMgr = GetClassManager();
+
+    jclass klass = clsMgr.GetThreadClass();
+
+    jmethodID methodID;
+    if (name == 0)
+        methodID = jni->GetMethodID(klass, "<init>", "()V");
+    else
+        methodID = jni->GetMethodID(klass, "<init>", "(Ljava/lang/String;)V");
+
+    clsMgr.CheckOnException(jni);
+
+    if (name == 0)
+        thrd = jni->NewObject(klass, methodID);
+    else
+    {
+        jstring threadName = jni->NewStringUTF(name);
+        clsMgr.CheckOnException(jni);
+        thrd = jni->NewObject(klass, methodID, threadName);
+    }
+
+    clsMgr.CheckOnException(jni);
+
+    AddThread(jni, thrd, true);
+
+    return thrd;
+}
+
+//-----------------------------------------------------------------------------
+
+ThreadInfo* 
+ThreadManager::AddThread(JNIEnv *jni, jthread thread, bool isAgentThread, bool isOnEvent)
+    throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("AddThread(" << jni << ',' << thread 
+        << ',' << isAgentThread << ',' << isOnEvent << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    ThreadInfoList::iterator place = m_threadInfoList.end();
+    ThreadInfoList::iterator result;
+    for (result = m_threadInfoList.begin(); 
+                               result != m_threadInfoList.end(); result++) {
+        if (*result == 0) {
+            // save pointer to empty slot
+            place = result;
+        } else if (jni->IsSameObject((*result)->m_thread, thread) == JNI_TRUE) {
+            // thread found
+            break;
+        }
+    }
+
+    // not found
+    if  (result == m_threadInfoList.end())
+    {
+        ThreadInfo *thrdinf = new ThreadInfo(jni, thread, isAgentThread, isOnEvent);
+
+#ifndef NDEBUG
+        // save thread name for debugging purpose
+        if (JDWP_TRACE_ENABLED(LOG_KIND_THREAD)) {
+            jvmtiError err;
+            jvmtiThreadInfo info;
+
+            JVMTI_TRACE(err, GetJvmtiEnv()->GetThreadInfo(thread, &info));
+            if (err != JVMTI_ERROR_NONE)
+                throw AgentException(err);
+
+            thrdinf->m_threadName = info.name;
+        }
+#endif // NDEBUG
+
+        JDWP_TRACE_THREAD("AddThread: add thread=" << thread 
+            << ", name=" << JDWP_CHECK_NULL(thrdinf->m_threadName));
+
+        if (place != m_threadInfoList.end()) {
+            *place = thrdinf;
+        } else {
+            m_threadInfoList.push_back(thrdinf);
+        }
+
+        return thrdinf;
+    }
+
+    return *result;
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::InternalSuspend(JNIEnv *jni, jthread thread, bool ignoreInternal, bool isOnEvent) 
+    throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("InternalSuspend(" << jni << ',' << thread 
+        << ',' << ignoreInternal << ',' << isOnEvent << ')');
+
+    // find thread
+    ThreadInfoList::iterator place = m_threadInfoList.end();
+    ThreadInfoList::iterator result;
+    for (result = m_threadInfoList.begin(); 
+                               result != m_threadInfoList.end(); result++) {
+        if (*result == 0) {
+            // save pointer to empty slot
+            place = result;
+        } else if (jni->IsSameObject((*result)->m_thread, thread) == JNI_TRUE) {
+            // thread found
+            break;
+        }
+    }
+    
+    if  (result == m_threadInfoList.end())
+    {
+        // not in list -> suspend and add to list
+        jvmtiError err;
+
+        JVMTI_TRACE(err, GetJvmtiEnv()->SuspendThread(thread));
+
+        JDWP_ASSERT(err != JVMTI_ERROR_THREAD_SUSPENDED);
+
+        if (err != JVMTI_ERROR_NONE)
+            throw AgentException(err);
+
+        // add thread
+        ThreadInfo *thrdinf = new ThreadInfo(jni, thread, false, isOnEvent);
+        thrdinf->m_suspendCount = 1 ;
+        if (place != m_threadInfoList.end()) {
+            *place = thrdinf;
+        } else {
+            m_threadInfoList.push_back(thrdinf);
+        }
+
+#ifndef NDEBUG
+        // save thread name for debugging purpose
+        if (JDWP_TRACE_ENABLED(LOG_KIND_THREAD)) {
+            jvmtiError err;
+            jvmtiThreadInfo info;
+
+            JVMTI_TRACE(err, GetJvmtiEnv()->GetThreadInfo(thread, &info));
+            if (err != JVMTI_ERROR_NONE)
+                throw AgentException(err);
+
+            thrdinf->m_threadName = info.name;
+        }
+#endif // NDEBUG
+
+        JDWP_TRACE_THREAD("InternalSuspend: suspend thread=" << thread 
+            << ", name=" << JDWP_CHECK_NULL(thrdinf->m_threadName)
+            << ", oldCount=" << thrdinf->m_suspendCount
+            << ", isOnEvent=" << thrdinf->m_isOnEvent);
+
+    } else if ((*result)->m_isAgentThread) {
+        // agent thread -> error (if not ignored)
+        JDWP_TRACE_THREAD("InternalSuspend: ignore agent thread=" << thread 
+            << ", name=" << JDWP_CHECK_NULL((*result)->m_threadName)
+            << ", oldCount=" << (*result)->m_suspendCount
+            << ", isOnEvent=" << (*result)->m_isOnEvent);
+        if (!ignoreInternal) {
+            throw AgentException(JVMTI_ERROR_INVALID_THREAD);
+        }
+    } else {
+        // already in list -> just increase suspend count
+        JDWP_TRACE_THREAD("InternalSuspend: increase count thread=" << thread 
+            << ", name=" << JDWP_CHECK_NULL((*result)->m_threadName)
+            << ", oldCount=" << (*result)->m_suspendCount
+            << ", isOnEvent=" << (*result)->m_isOnEvent);
+        JDWP_ASSERT((*result)->m_suspendCount > 0);
+        (*result)->m_suspendCount++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::Suspend(JNIEnv *jni, jthread thread, bool isOnEvent) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("Suspend(" << jni << ',' << thread << '.' << isOnEvent << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+    InternalSuspend(jni, thread, false, isOnEvent);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::InternalResume(JNIEnv *jni, jthread thread, bool ignoreInternal) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("InternalResume(" << jni << ',' << thread << ')');
+
+    ThreadInfoList::iterator result;
+    FindThreadInfo(jni, &m_threadInfoList, thread, result);
+    
+    if  (result == m_threadInfoList.end()) {
+        // thread not yet suspended -> ignore
+    } else if ((*result)->m_isAgentThread) {
+        // agent thread -> error (if not ignored)
+        JDWP_TRACE_THREAD("InternalResume: ignore agent thread=" << thread 
+            << ", name=" << JDWP_CHECK_NULL((*result)->m_threadName)
+            << ", oldCount=" << (*result)->m_suspendCount
+            << ", isOnEvent=" << (*result)->m_isOnEvent);
+        if (!ignoreInternal) {
+            throw AgentException(JVMTI_ERROR_INVALID_THREAD);
+        }
+    } else if ((*result)->m_suspendCount == 1) {
+        // count == 1 -> resume thread
+        GetObjectManager().DeleteFrameIDs(jni, thread);
+
+        jvmtiError err;
+        JVMTI_TRACE(err, GetJvmtiEnv()->ResumeThread(thread));
+
+        JDWP_ASSERT(err != JVMTI_ERROR_THREAD_NOT_SUSPENDED);
+
+        if (err != JVMTI_ERROR_NONE)
+            throw AgentException(err);
+
+        JDWP_TRACE_THREAD("InternalResume: resume thread=" << thread 
+            << ", name=" << JDWP_CHECK_NULL((*result)->m_threadName)
+            << ", oldCount=" << (*result)->m_suspendCount
+            << ", isOnEvent=" << (*result)->m_isOnEvent);
+
+        // remove from list and destroy
+        (*result)->Clean(jni);
+        delete *result;
+        *result = 0;
+    } else {
+        // count > 1 -> just decrease count
+        JDWP_TRACE_THREAD("InternalResume: decrease count thread=" << thread 
+            << ", name=" << JDWP_CHECK_NULL((*result)->m_threadName)
+            << ", oldCount=" << (*result)->m_suspendCount
+            << ", isOnEvent=" << (*result)->m_isOnEvent);
+        (*result)->m_suspendCount--;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::Resume(JNIEnv *jni, jthread thread) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("Resume(" << jni << ',' << thread << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+    InternalResume(jni, thread, false);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::SuspendAll(JNIEnv *jni, jthread threadOnEvent) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("SuspendAll(" << jni << ',' << threadOnEvent << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    jint count;
+    jthread *threads = 0;
+
+    jvmtiError err;
+    JVMTI_TRACE(err, GetJvmtiEnv()->GetAllThreads(&count, &threads));
+    if (err != JVMTI_ERROR_NONE)
+        throw AgentException(err);
+    JvmtiAutoFree dobj(threads);
+
+    for (jint i = 0; i < count; i++)
+    {
+        JDWP_ASSERT(threads[i] != 0);
+        try
+        {
+            // suspend thread (ignoring internal)
+            bool isOnEvent = (threadOnEvent != 0 && jni->IsSameObject(threadOnEvent, threads[i]));
+            InternalSuspend(jni, threads[i], true, isOnEvent);
+        }
+        catch (const AgentException &e)
+        {
+            jvmtiError errTemp = (jvmtiError)e.ErrCode();
+
+            JDWP_ASSERT(errTemp != JVMTI_ERROR_THREAD_NOT_SUSPENDED);
+
+            if (errTemp != JVMTI_ERROR_NONE &&
+                errTemp != JVMTI_ERROR_THREAD_NOT_ALIVE &&
+                errTemp != JVMTI_ERROR_INVALID_THREAD)
+            {
+                err = errTemp;
+            }
+        }
+    }
+
+    if (err != JVMTI_ERROR_NONE)
+        throw AgentException(err);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::ResumeAll(JNIEnv *jni) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("ResumeAll(" << jni << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    // resume all not internal threads and remove from list
+    for (ThreadInfoList::iterator iter = m_threadInfoList.begin(); iter != m_threadInfoList.end(); iter++) {
+
+        if (*iter == 0) continue;
+
+        if (!(*iter)->m_isAgentThread) {
+            // check suspend count
+            JDWP_ASSERT((*iter)->m_suspendCount > 0);
+            if ((*iter)->m_suspendCount == 1) {
+
+                // resume application thread
+                JDWP_TRACE_THREAD("ResumeAll: resume thread=" << (*iter)->m_thread 
+                    << ", name=" << JDWP_CHECK_NULL((*iter)->m_threadName)
+                    << ", oldCount=" << (*iter)->m_suspendCount
+                    << ", isOnEvent=" << (*iter)->m_isOnEvent);
+
+                // destroy stack frame IDs
+                GetObjectManager().DeleteFrameIDs(jni, (*iter)->m_thread);
+
+                // resume thread
+                jvmtiError err;
+                JVMTI_TRACE(err, GetJvmtiEnv()->ResumeThread((*iter)->m_thread));
+
+                JDWP_ASSERT(err != JVMTI_ERROR_THREAD_NOT_SUSPENDED);
+                JDWP_ASSERT(err != JVMTI_ERROR_INVALID_TYPESTATE);
+                JDWP_ASSERT(err != JVMTI_ERROR_INVALID_THREAD);
+                JDWP_ASSERT(err != JVMTI_ERROR_THREAD_NOT_ALIVE);
+
+                if (err != JVMTI_ERROR_NONE)
+                    throw AgentException(err);
+
+                // remove from list and destroy
+                (*iter)->Clean(jni);
+                delete *iter;
+                *iter = 0;
+            } else {
+                // just decrease suspend count
+                JDWP_TRACE_THREAD("ResumeAll: decrease count thread=" << (*iter)->m_thread 
+                    << ", name=" << JDWP_CHECK_NULL((*iter)->m_threadName)
+                    << ", oldCount=" << (*iter)->m_suspendCount
+                    << ", isOnEvent=" << (*iter)->m_isOnEvent);
+                (*iter)->m_suspendCount--;
+            }
+        } else {
+            // ignore agent thread
+            JDWP_TRACE_THREAD("ResumeAll: ignore agent thread=" << (*iter)->m_thread 
+                << ", name=" << JDWP_CHECK_NULL((*iter)->m_threadName)
+                << ", oldCount=" << (*iter)->m_suspendCount
+                << ", isOnEvent=" << (*iter)->m_isOnEvent);
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::Interrupt(JNIEnv *jni, jthread thread) throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("Interrupt(" << jni << ',' << thread << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    jvmtiError err;
+    JVMTI_TRACE(err, GetJvmtiEnv()->InterruptThread(thread));
+
+    if (err != JVMTI_ERROR_NONE)
+        throw AgentException(err);
+}
+
+//-----------------------------------------------------------------------------
+
+void
+ThreadManager::Stop(JNIEnv *jni, jthread thread, jobject throwable)
+                        throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("Stop(" << jni << ',' << thread << ',' << throwable << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    jvmtiError err;
+    JVMTI_TRACE(err, GetJvmtiEnv()->StopThread(thread, throwable));
+    
+    if (err != JVMTI_ERROR_NONE)
+        throw AgentException(err);
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+ThreadManager::IsAgentThread(JNIEnv *jni, jthread thread)
+{
+    //JDWP_TRACE_ENTRY("IsAgentThread(" << jni << ',' << thread << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    bool ret_value = false;
+
+    ThreadInfoList::iterator result;
+    FindThreadInfo(jni, &m_threadInfoList, thread, result);
+    
+    // found
+    if  (result != m_threadInfoList.end())
+        ret_value = (*result)->m_isAgentThread;
+
+    return ret_value;
+}
+
+//-----------------------------------------------------------------------------
+
+jint
+ThreadManager::GetSuspendCount(JNIEnv *jni, jthread thread)
+{
+    //JDWP_TRACE_ENTRY("GetSuspendCount(" << jni << ',' << thread << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    jint ret_value = 0;
+
+    ThreadInfoList::iterator result;
+    FindThreadInfo(jni, &m_threadInfoList, thread, result);
+    
+    // found
+    if  (result != m_threadInfoList.end())
+        ret_value = (*result)->m_suspendCount;
+
+    return ret_value;
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+ThreadManager::IsSuspendedOnEvent(JNIEnv *jni, jthread thrd) throw (AgentException)
+{
+    //JDWP_TRACE_ENTRY("IsSuspendedOnEvent(" << thrd << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    bool ret_value = false;
+
+    ThreadInfoList::iterator result;
+    FindThreadInfo(jni, &m_threadInfoList, thrd, result);
+    
+    // found
+    if  (result != m_threadInfoList.end())
+        ret_value = (*result)->m_isOnEvent;
+
+    return ret_value;
+}
+
+//-----------------------------------------------------------------------------
+
+bool
+ThreadManager::IsSuspended(jthread thrd) throw (AgentException)
+{
+    //JDWP_TRACE_ENTRY("IsSuspended(" << thrd << ')');
+
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    jint thread_state;
+    jvmtiError err;
+    JVMTI_TRACE(err, GetJvmtiEnv()->GetThreadState(thrd, &thread_state));
+
+    JDWP_ASSERT(err != JVMTI_ERROR_NULL_POINTER);
+    if (err != JVMTI_ERROR_NONE)
+        throw AgentException(err);
+
+    return (thread_state & JVMTI_THREAD_STATE_SUSPENDED) != 0;
+}
+
+//-----------------------------------------------------------------------------
+
+void 
+ThreadManager::RegisterInvokeHandler(JNIEnv *jni, SpecialAsyncCommandHandler* handler)
+    throw (AgentException)
+{
+    JDWP_TRACE_ENTRY("RegisterInvokeHandler(" << jni << ',' << handler << ')');
+
+    JDWP_ASSERT(handler->GetThread() != 0);
+
+    // check if thread is suspended on event
+    MonitorAutoLock lock(m_thrdmgrMonitor JDWP_FILE_LINE);
+
+    ThreadInfoList::iterator result;
+    FindThreadInfo(jni, &m_threadInfoList, handler->GetThread(), result);
+
+    if  (result == m_threadInfoList.end() || !(*result)->m_isOnEvent)
+        throw AgentException(JDWP_ERROR_THREAD_NOT_SUSPENDED);
+
+    JDWP_TRACE_THREAD("RegisterInvokeHandler: handler=" << handler
+        << ", thread=" << (*result)->m_thread 
+        << ", name=" << JDWP_CHECK_NULL((*result)->m_threadName)
+        << ", options=" << handler->GetOptions());
+
+    {
+        MonitorAutoLock lock(m_execMonitor JDWP_FILE_LINE);
+        m_execList.push_back(handler);
+    }
+
+    if ((handler->GetOptions() & JDWP_INVOKE_SINGLE_THREADED) == 0) {
+        JDWP_TRACE_THREAD("RegisterInvokeHandler -- resume all before method invoke: thread=" 
+            << handler->GetThread());
+        ResumeAll(jni);
+    } else {
+        JDWP_TRACE_THREAD("RegisterInvokeHandler -- resume before method invoke: thread=" 
+            << handler->GetThread());
+        Resume(jni, handler->GetThread());
+    }
+}
+
+SpecialAsyncCommandHandler*
+ThreadManager::FindInvokeHandler(JNIEnv* jni, jthread thread)
+    throw (AgentException)
+{
+    JDWP_TRACE_ENTRY("FindInvokeHandler(" << jni << ',' << thread << ')');
+
+    MonitorAutoLock lock(m_execMonitor JDWP_FILE_LINE);
+    for (ExecListIterator i = m_execList.begin(); i != m_execList.end(); i++) {
+        SpecialAsyncCommandHandler* handler = *i;
+        if (jni->IsSameObject(thread, handler->GetThread())) {
+            m_execList.erase(i);
+            return handler;
+        }
+    }
+    return 0;
+}
+
+jboolean ThreadManager::IsPopFramesProcess(JNIEnv* jni, jthread thread)
+{
+    if (m_popFramesThread == 0) {
+        return false;
+    } else {
+        return (jni->IsSameObject(thread, m_popFramesThread));
+    }
+}
+
+void ThreadManager::HandleInternalSingleStep(JNIEnv* jni, jthread thread, 
+    jmethodID method, jlocation location) 
+    throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("HandleInternalSingleStep(" << jni << ',' << thread << ',' 
+        << method << ',' << location << ')');
+
+    char* threadName = 0;
+    char* methodName = 0;
+#ifndef NDEBUG
+    if (JDWP_TRACE_ENABLED(LOG_KIND_THREAD)) {
+        jvmtiError err;
+        JVMTI_TRACE(err, GetJvmtiEnv()->GetMethodName(method, &methodName, 0, 0));
+        
+        jvmtiThreadInfo threadInfo;
+        JVMTI_TRACE(err, GetJvmtiEnv()->GetThreadInfo(thread, &threadInfo));
+        threadName = threadInfo.name;
+    }
+#endif // NDEBUG
+    JvmtiAutoFree threadNameAutoFree(threadName);
+    JvmtiAutoFree methodNameAutoFree(methodName);
+
+    {
+        MonitorAutoLock stepMonitorLock(m_stepMonitor JDWP_FILE_LINE);
+        {
+            MonitorAutoLock popFramesMonitorLock(m_popFramesMonitor JDWP_FILE_LINE);
+            // notify that thread is waiting on suspension point
+            m_popFramesMonitorReleased = true;
+            m_popFramesMonitor->NotifyAll();
+
+            JDWP_TRACE_THREAD("HandleInternalSingleStep: thread on suspention point: thread=" 
+                << JDWP_CHECK_NULL(threadName) 
+                << ",method=" << JDWP_CHECK_NULL(methodName) 
+                << ",location=" << location);    
+        }
+        // wait for suspend on suspention point
+        m_stepMonitorReleased = false;
+        while (!m_stepMonitorReleased) {
+            m_stepMonitor->Wait();
+        }
+        JDWP_TRACE_THREAD("HandleInternalSingleStep: thread resumed: thread=" 
+            << JDWP_CHECK_NULL(threadName) 
+            << ",method=" << JDWP_CHECK_NULL(methodName) 
+            << ",location=" << location);    
+    }
+
+    // execute registered MethodInvoke hadlers if needed
+    GetEventDispatcher().ExecuteInvokeMethodHandlers(jni, thread);
+}
+
+void ThreadManager::PerformPopFrames(JNIEnv* jni, jint framesToPop, jthread thread) 
+    throw(AgentException)
+{
+    JDWP_TRACE_ENTRY("PerformPopFrames(" << jni << ',' << framesToPop << ',' << thread << ')');
+
+    MonitorAutoLock thrdmgrMonitorLock(m_thrdmgrMonitor JDWP_FILE_LINE);
+    
+    // thread should be suspended
+    if (!GetThreadManager().IsSuspended(thread)) {
+        throw AgentException(JDWP_ERROR_THREAD_NOT_SUSPENDED);
+    }
+
+    // The following check is disabled, because JVMTI and JDWP specifications 
+    // are unclear if PopFrames should be invoked only for thread on an event.
+    // Current algorithm supports PopFrames command for any suspended thread.
+    /*
+    if (!GetThreadManager().IsSuspendedOnEvent(jni, thread)) {
+        throw AgentException(JDWP_ERROR_THREAD_NOT_SUSPENDED);
+    }
+    */
+
+    jvmtiError err;
+    char* threadName = 0;
+#ifndef NDEBUG
+        if (JDWP_TRACE_ENABLED(LOG_KIND_THREAD)) {
+            jvmtiThreadInfo threadInfo;
+            JVMTI_TRACE(err, GetJvmtiEnv()->GetThreadInfo(thread, &threadInfo));
+            threadName = threadInfo.name;
+        }
+#endif // NDEBUG
+    JvmtiAutoFree af(threadName);
+    
+    // The following check is just for sure.
+    // This algorithm supposes that there are no invoke method handlers registered.
+    // Otherwise, active invoke handlers could break popFrame process.
+    {
+        MonitorAutoLock lockExecList(m_execMonitor JDWP_FILE_LINE);
+        if (!m_execList.empty()) {
+            throw AgentException(JDWP_ERROR_THREAD_NOT_SUSPENDED);
+        }
+    }
+
+    jint frameCount;
+    JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(thread, &frameCount));
+    if (err != JVMTI_ERROR_NONE) {
+        throw AgentException(err);
+    }
+    if (frameCount <= framesToPop) {
+        throw AgentException(JDWP_ERROR_INVALID_FRAMEID);
+    }
+
+    // if there is native frame, pop frame can't be performed
+    CheckNativeFrameExistence(thread, framesToPop);
+
+    MonitorAutoLock popFramesMonitorLock(m_popFramesMonitor JDWP_FILE_LINE);
+    try {
+        m_popFramesThread = thread;
+
+        // enabling step request on thread where PopFrame command is performed
+        JDWP_TRACE_THREAD("PerformPopFrames: enable internal step: thread=" 
+            << JDWP_CHECK_NULL(threadName));
+        GetRequestManager().EnableInternalStepRequest(jni, m_popFramesThread);
+
+        // cycle where topmost frames are popped one after one
+        for (int i = 0; i < framesToPop; i++) {
+            // pop topmost frame, thread is already suspended on event
+            JDWP_TRACE_THREAD("PerformPopFrames: pop: frame#=" << i 
+                << ", thread=" << JDWP_CHECK_NULL(threadName));
+            JVMTI_TRACE(err, GetJvmtiEnv()->PopFrame(m_popFramesThread));
+            if (err != JVMTI_ERROR_NONE) {
+                throw AgentException(err);
+            }
+
+            // resume thread
+            JDWP_TRACE_THREAD("PerformPopFrames: resume: thread=" 
+                << JDWP_CHECK_NULL(threadName));
+            JVMTI_TRACE(err, GetJvmtiEnv()->ResumeThread(m_popFramesThread));
+            JDWP_ASSERT(err != JVMTI_ERROR_THREAD_NOT_SUSPENDED);
+            if (err != JVMTI_ERROR_NONE)
+                throw AgentException(err);
+            
+            // wait for thread to achieve suspention point in InternalSingleStep handler
+            JDWP_TRACE_THREAD("PerformPopFrames: wait for step: thread=" 
+                << JDWP_CHECK_NULL(threadName));
+            m_popFramesMonitorReleased = false;
+            while (!m_popFramesMonitorReleased) {
+                m_popFramesMonitor->Wait();
+            }
+            
+            {
+                // suspend thread on suspention point
+                MonitorAutoLock stepMonitorLock(m_stepMonitor JDWP_FILE_LINE);
+                JDWP_TRACE_THREAD("PerformPopFrames: suspend: thread=" 
+                    << JDWP_CHECK_NULL(threadName));
+                JVMTI_TRACE(err, GetJvmtiEnv()->SuspendThread(m_popFramesThread));
+                JDWP_ASSERT(err != JVMTI_ERROR_THREAD_SUSPENDED);
+                if (err != JVMTI_ERROR_NONE)
+                    throw AgentException(err);
+
+                // notify suspended thread on suspention point
+                m_stepMonitorReleased = true;
+                m_stepMonitor->NotifyAll();
+                JDWP_TRACE_THREAD("PerformPopFrames: notify: thread=" 
+                    << JDWP_CHECK_NULL(threadName));
+            }
+        }
+        GetObjectManager().DeleteFrameIDs(jni, m_popFramesThread);
+        
+        JDWP_TRACE_THREAD("PerformPopFrames: disable internal step: thread=" 
+            << JDWP_CHECK_NULL(threadName));
+        GetRequestManager().DisableInternalStepRequest(jni, m_popFramesThread);
+        
+        m_popFramesThread = 0;
+    } catch (AgentException& e) {
+        JDWP_INFO("JDWP error: " << e.what() << " [" << e.ErrCode() << "]");
+        JDWP_TRACE_THREAD("PerformPopFrames: disable internal step: thread=" 
+            << JDWP_CHECK_NULL(threadName));
+        GetRequestManager().DisableInternalStepRequest(jni, m_popFramesThread);
+        m_popFramesThread = 0;
+        throw(e);
+    }
+}
+
+void ThreadManager::CheckNativeFrameExistence(jthread thread, jint framesToPop) 
+    throw(AgentException)
+{
+    jvmtiFrameInfo* frames = static_cast<jvmtiFrameInfo*>
+        (GetMemoryManager().Allocate((framesToPop+1) 
+            * sizeof(jvmtiFrameInfo) JDWP_FILE_LINE));
+    AgentAutoFree af(frames JDWP_FILE_LINE);
+    
+    jint count;
+    jvmtiError err;
+    // check (framesToPop+1) frames, because both the called 
+    // and calling methods must be non-native
+    JVMTI_TRACE(err, GetJvmtiEnv()->GetStackTrace(thread, 0, 
+        (framesToPop+1), frames, &count));
+    if (err != JVMTI_ERROR_NONE) {
+        throw AgentException(err);
+    }
+    JDWP_TRACE_THREAD("CheckNativeFrameExistence: FramesToCheck=" << count);
+    
+    jboolean isNative = false;
+    for (int i = 0; i < count; i++) {
+        jmethodID methodID = frames[i].method;
+        
+        jvmtiError err;
+        char* methodName = 0;
+        char* classSignature = 0;
+
+#ifndef NDEBUG
+        if (JDWP_TRACE_ENABLED(LOG_KIND_THREAD)) {
+            jclass clazz = 0;
+            JVMTI_TRACE(err, GetJvmtiEnv()->GetMethodName(methodID, &methodName, 0, 0));
+            JVMTI_TRACE(err, GetJvmtiEnv()->GetMethodDeclaringClass(methodID, &clazz));
+            JVMTI_TRACE(err, GetJvmtiEnv()->GetClassSignature(clazz, &classSignature, 0));
+            
+            JDWP_TRACE_THREAD("CheckNativeFrameExistence: method=" 
+                << JDWP_CHECK_NULL(methodName) 
+                << ", class=" << JDWP_CHECK_NULL(classSignature));
+        }
+#endif // NDEBUG
+
+        JvmtiAutoFree methodNameAutoFree(methodName);
+        JvmtiAutoFree classSignatureAutoFree(classSignature);
+        JVMTI_TRACE(err, GetJvmtiEnv()->IsMethodNative(methodID, &isNative));
+        if (err != JVMTI_ERROR_NONE) {
+            throw AgentException(err);
+        }
+        if (isNative) {
+            JDWP_TRACE_THREAD("CheckNativeFrameExistence: method=" 
+                << JDWP_CHECK_NULL(methodName) 
+                << ", class=" << JDWP_CHECK_NULL(classSignature) 
+                << " is native");
+            throw AgentException(JDWP_ERROR_NATIVE_METHOD);
+        }
+    }
+}

Propchange: harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.h?view=auto&rev=480141
==============================================================================
--- harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.h (added)
+++ harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.h Tue Nov 28 09:49:08 2006
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2005-2006 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.
+ */
+
+/**
+ * @author Vitaly A. Provodin, Pavel N. Vyssotski
+ * @version $Revision: 1.16.2.1 $
+ */
+
+/**
+ * @file
+ * ThreadManager.h
+ *
+ */
+
+#ifndef _THREAD_MANAGER_H_
+#define _THREAD_MANAGER_H_
+
+#include <vector>
+
+#include "jni.h"
+#include "jvmti.h"
+#include "AgentBase.h"
+#include "AgentException.h"
+#include "AgentMonitor.h"
+#include "AgentAllocator.h"
+#include "CommandHandler.h"
+
+namespace jdwp {
+
+    class ThreadInfo;
+
+    typedef vector<ThreadInfo*, AgentAllocator<ThreadInfo*> > ThreadInfoList;
+
+    typedef vector<SpecialAsyncCommandHandler*,
+        AgentAllocator<SpecialAsyncCommandHandler*> > ExecList;
+
+    typedef ExecList::iterator ExecListIterator;
+
+    /**
+     * Manages list of known threads, provides agent specific thread info,
+     * such as debug, suspend count, pending step, invoke, etc.
+     * Provides services to support stop, interrupt, suspend/resume.
+     */
+    class ThreadManager : public AgentBase {
+
+    public:
+
+        /**
+         * Constructs a new <code>ThreadManager</code> object.
+         */
+        ThreadManager() throw() : 
+          m_thrdmgrMonitor(0), 
+          m_execMonitor(0),
+          m_stepMonitor(0),
+          m_popFramesMonitor(0),
+          m_popFramesThread(0)
+        {}
+
+        ~ThreadManager();
+
+        /**
+         * Initializes <code>ThreadManager</code> object.
+         *
+         * @param jni - the JNI interface pointer
+         */
+        void Init(JNIEnv *jni) throw();
+
+        /**
+         * Cleans the <code>ThreadManager</code> object.
+         *
+         * @param jni - the JNI interface pointer
+         */
+        void Clean(JNIEnv *jni) throw();
+
+        /**
+         * Reinitializes <code>ThreadManager</code> object.
+         * All suspended threads resumed as many times as necessary and the
+         * internal list is cleaned.
+         *
+         * @param jni - the JNI interface pointer
+         *
+         * @exception AgentException is thrown in case of a 
+         *            universal error, with the corresponded error code.
+         */
+        void Reset(JNIEnv *jni) throw(AgentException);
+
+        /**
+         * Creates a new agent thread and starts the specified function in it.
+         * thread.
+         *
+         * @param jni      - the JNI interface pointer
+         * @param proc     - the start function
+         * @param arg      - the argument to the start function
+         * @param priority - the priority of the started thread
+         * @param name     - the default parameter; if defined, then the created
+         *                   thread has a specified name
+         *
+         * @return Returns the <code>jthread</code> object that holds executed 
+         * thread.
+         *
+         * @exception OutOfMemoryException is thrown if the system 
+         *            runs out of memory.
+         * @exception AgentException JVMTI_ERROR_INVALID_PRIORITY 
+         *            is thrown if the <code>priority</code> has a wrong value.
+         * @exception AgentException JVMTI_ERROR_NULL_POINTER is thrown if
+         *            <code>proc</code> is <code>NULL</code>.  
+         * @exception InternalErrorException is thrown in any other cases.
+         */
+        jthread RunAgentThread(JNIEnv *jni, jvmtiStartFunction proc,
+                                const void *arg, jint priority,
+                                const char *name = 0) throw(AgentException);
+
+        /**
+         * Adds an information about the thread parameter into
+         * the internal list.
+         *
+         * @param jni            - the JNI interface pointer
+         * @param thread         - the thread to be added
+         * @param isAgentThread  - if the added thread is an agent's one, then
+         *                         <code>TRUE</code> is passed, otherwise 
+         *                         <code>FALSE</code>
+         * @param isOnEvent      - whether the thread was suspended on event
+         *
+         * @return Pointer to the new record in the thread list.
+         *
+         * @exception OutOfMemoryException is thrown no more memory
+         *            is available for allocation.
+         */
+        ThreadInfo* AddThread(JNIEnv *jni, jthread thread,
+                    bool isAgentThread = false, bool isOnEvent = false) throw(AgentException);
+        /**
+         * Suspends the specified thread.
+         * If the specified thread is an agent thread, calling this method 
+         * is ineffective.
+         * If the suspend count is equal to <code>0</code> then the thread will
+         * be suspended, otherwise the suspend count will be incremented.
+         *
+         * @param jni        - the JNI interface pointer
+         * @param thread the - thread to be suspended
+         * @param isOnEvent  - <code>TRUE</code> if suspended on event
+         *
+         * @exception AgentException(JVMTI_ERROR_INVALID_THREAD) 
+         *            is thrown if the thread is an agent thread or not a thread 
+         *            object.
+         * @exception AgentException(JVMTI_ERROR_THREAD_NOT_ALIVE) 
+         *            is thrown if thread has not been started or is dead.
+         */
+        void Suspend(JNIEnv *jni, jthread thread, bool isOnEvent = false) throw(AgentException);
+
+        /**
+         * Resumes the specified thread.
+         * If the specified thread is an agent thread, calling this method has
+         * no effect.
+         * If the suspend count is equal to <code>0</code> then the thread will
+         * continue to execute, otherwise the suspend count will be decremented.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param thread - the thread to be resumed
+         *
+         * @exception AgentException(JVMTI_ERROR_INVALID_THREAD)
+         *            is thrown if the thread is an agent thread or not a thread 
+         *            object.
+         * @exception AgentException(JVMTI_ERROR_THREAD_NOT_ALIVE) 
+         *            is thrown if thread has not been started or is dead.
+         */
+        void Resume(JNIEnv *jni, jthread thread) throw(AgentException);
+
+        /**
+         * Suspends all non-agent threads.
+         *
+         * @param jni           - the JNI interface pointer
+         * @param threadOnEvent - thread suspended on event or NULL
+         *
+         * @exception AgentException is thrown in case an universal 
+         *            error, with the corresponded error code.
+         */
+        void SuspendAll(JNIEnv *jni, jthread threadOnEvent = 0) throw(AgentException);
+
+        /**
+         * Resumes all non-agent threads.
+         *
+         * @param jni - the JNI interface pointer
+         *
+         * @exception AgentException is thrown in case an universal 
+         *             error, with the corresponded error code.
+         */
+        void ResumeAll(JNIEnv *jni)                 throw(AgentException);
+
+        /**
+         * Interrupts the specified thread.
+         * 
+         * @param jni    - the JNI interface pointer
+         * @param thread - the thread to be interrupted
+         *
+         * @exception AgentException(JVMTI_ERROR_INVALID_THREAD)
+         *            is thrown if the thread is not a thread object.
+         * @exception AgentException(JVMTI_ERROR_THREAD_NOT_ALIVE) 
+         *            is thrown if thread has not been started or is dead.
+         */
+        void Interrupt(JNIEnv *jni, jthread thread) throw(AgentException);
+
+        /**
+         * Stops the specified thread.
+         * 
+         * @param jni       - the JNI interface pointer
+         * @param thread    - the thread to be interrupted
+         * @param throwable - the asynchronous exception object sent to the thread
+         *
+         * @exception AgentException(JVMTI_ERROR_INVALID_THREAD) 
+         *            is thrown if the thread is not a thread object.
+         * @exception AgentException(JVMTI_ERROR_THREAD_NOT_ALIVE) 
+         *            is thrown if thread has not been started or is dead.
+         * @exception AgentException(JVMTI_ERROR_INVALID_OBJECT) 
+         *            is thrown if exception is not an object.
+         */
+        void Stop(JNIEnv *jni, jthread thread, jobject throwable)
+            throw(AgentException);
+        
+        /**
+         * Checks if the specified thread is an agent thread.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param thread - the thread to be checked
+         *
+         * @return Returns <code>TRUE</code> if the thread is an
+         *         agent thread, otherwise <code>FALSE</code>.
+         */
+        bool IsAgentThread(JNIEnv *jni, jthread thread);
+
+        /**
+         * Returns a suspend count for the specified thread.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param thread - the thread to be checked
+         *
+         * @return Returns a suspend count for the specified thread.
+         */
+        jint GetSuspendCount(JNIEnv *jni, jthread thread);
+
+        /**
+         * Checks if the specified thread is suspended on event.
+         *
+         * @param jni  - the JNI interface pointer
+         * @param thrd - the thread to be checked
+         *
+         * @return Returns <code>TRUE</code> if the thread is suspended on 
+         *         event, otherwise <code>FALSE</code>.
+         *
+         * @exception AgentException(JVMTI_ERROR_INVALID_THREAD)
+         *            is thrown if the thread is not a thread object.
+         */
+        bool IsSuspendedOnEvent(JNIEnv *jni, jthread thrd) throw (AgentException);
+
+        /**
+         * Checks if the specified thread is really suspended.
+         *
+         * @param thrd - the thread to be checked
+         *
+         * @return Returns <code>TRUE</code> if the thread is suspended,
+         *         otherwise <code>FALSE</code>.
+         *
+         * @exception AgentException(JVMTI_ERROR_INVALID_THREAD) 
+         *            is thrown if the thread is not a thread object.
+         */
+        bool IsSuspended(jthread thrd) throw (AgentException);
+
+        /**
+         * Registers instance of <code>SpecialAsyncCommandHandler</code> for 
+         * the deferred invocation of handler's method 
+         * <code>ExecuteDeferredFunc()</code> in the specified thread, 
+         * and resumes thread(s) according to invocation options.
+         *
+         * @param jni     - the JNI interface pointer
+         * @param handler - <code>SpecialAsyncCommandHandler</code> instance 
+         *                  reference
+         *
+         * @exception AgentException(JVMTI_ERROR_THREAD_NOT_SUSPENDED)
+         *            is thrown if the specified thread has not been suspended by 
+         *            an event.
+         */
+        void RegisterInvokeHandler(JNIEnv *jni, SpecialAsyncCommandHandler* handler)
+            throw (AgentException);
+
+        /**
+         * Finds an instance of <code>SpecialAsyncCommandHandler</code> from 
+         * registered for the given thread to invoke the handler's method 
+         * <code>ExecuteDeferredFunc()<code>.
+         *
+         * @param jni     - the JNI interface pointer
+         * @param thread  - thread corresponding to invoke handler
+         *
+         * @return The first handler instance found or NULL.
+         *
+         * @exception AgentException is thrown if any error occurs.
+         */
+        SpecialAsyncCommandHandler* FindInvokeHandler(JNIEnv *jni,
+            jthread thread) throw (AgentException);
+
+        /**
+         * Used for internal purposes. Handles <code>Step Event</code>, 
+         * during <code>PopFrame</code> process on specified thread.
+         *
+         * @param jni      - the JNI interface pointer
+         * @param thread   - thread in which <code>SingleStep</code> was made
+         * @param method   - method in which <code>SingleStep</code> was made
+         * @param location - location in which <code>SingleStep</code> was made
+         *
+         * @exception AgentException is thrown if any error occurs.
+         */
+        void HandleInternalSingleStep(JNIEnv* jni, jthread thread, jmethodID method, jlocation location) throw(AgentException);
+
+        /**
+         * Pops <code>framesToPop</code> number of frames on the specified thread.
+         *
+         * @param jni         - the JNI interface pointer
+         * @param framesToPop - number of frames to pop
+         * @param thread      - thread which frames are popped
+         *
+         * @exception AgentException is thrown if any error occurs.
+         */
+        void PerformPopFrames(JNIEnv* jni, jint framesToPop, jthread thread)
+            throw(AgentException);
+ 
+        /**
+         * Checks if <code>PopFrames</code> command is executed on the specified 
+         * thread.
+         *
+         * @param jni    - the JNI interface pointer
+         * @param thread - the thread to check
+         */
+        jboolean IsPopFramesProcess(JNIEnv* jni, jthread thread);
+
+    private:
+
+        /**
+         * List of suspended threads and agent threads.
+         */
+        ThreadInfoList  m_threadInfoList;
+        
+        /**
+         * Monitor for <code>m_threadInfoList</code>.
+         */
+        AgentMonitor    *m_thrdmgrMonitor;
+
+        /**
+         * List of registered handlers for deferred method invocation.
+         */
+        ExecList m_execList;
+        
+        /**
+         * Monitor for <code>m_execList</code>.
+         */
+        AgentMonitor* m_execMonitor;
+
+        /**
+         * Thread, on which the <code>PopFrame</code> command is executed.
+         */
+        volatile jthread m_popFramesThread;
+
+
+        AgentMonitor* m_stepMonitor;
+        AgentMonitor* m_popFramesMonitor;
+        
+        volatile bool m_popFramesMonitorReleased;
+        volatile bool m_stepMonitorReleased;
+          
+        /**
+         * Checks native frames among <code>numberOfFrames</code> of specified thread.
+         *
+         * @param thread         - hread to check
+         * @param numberOfFrames - number of frames to check
+         *
+         * @exception AgentException(JDWP_ERROR_NATIVE_METHOD)
+         *            is thrown if native frame is found.
+         */
+        void CheckNativeFrameExistence(jthread thread, jint numberOfFrames)
+            throw(AgentException);
+        
+        /**
+         * Creates a new agent thread and adds it to the list.
+         *
+         * @param jni        - the JNI interface pointer
+         * @param threadName - the default parameter, if defined then the created
+         *                     thread has specified name
+         *
+         * @return Returns the <code>jthread</code> object that holds the created
+         *         thread.
+         *
+         * @exception OutOfMemoryException is thrown if the system 
+         *            runs out of memory.
+         * @exception InternalErrorException is thrown in any other
+         *            cases.
+         */
+        jthread CreateAgentThread(JNIEnv *jni, const char *name = 0)
+            throw(AgentException);
+
+        // synchronized
+        void ClearExecList(JNIEnv* jni) throw();
+
+        // synchronized
+        void ClearThreadList(JNIEnv *jni);
+
+        // not synchronized
+        void InternalResume(JNIEnv *jni, jthread thread, bool ignoreInternal) throw(AgentException);
+
+        // not synchronized
+        void InternalSuspend(JNIEnv *jni, jthread thread, bool ignoreInternal, bool isOnEvent = false) throw(AgentException);
+
+    };//class ThreadManager
+
+}//jdwp
+
+#endif //_THREAD_MANAGER_H_

Propchange: harmony/enhanced/jdktools/trunk/modules/jpda/src/common/other/jpda/jdwp/agent/core/ThreadManager.h
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message