/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "util.h"
#include "eventHandler.h"
#include "threadControl.h"
#include "commonRef.h"
#include "eventHelper.h"
#include "stepControl.h"
#include "invoker.h"
#include "bag.h"
/*
* Collection of info for properly handling co-located events.
* If the ei field is non-zero, then one of the possible
* co-located events has been posted and the other fields describe
* the event's location.
*/
typedef struct CoLocatedEventInfo_ {
/**
* The main data structure in threadControl is the ThreadNode.
* This is a per-thread structure that is allocated on the
* first event that occurs in a thread. It is freed after the
* thread's thread end event has completed processing. The
* structure contains state information on its thread including
* suspend counts. It also acts as a repository for other
* per-thread state such as the current method invocation or
* current step.
*
* suspendCount is the number of outstanding suspends
* from the debugger. suspends from the app itself are
* not included in this count.
*/
typedef struct ThreadNode {
} ThreadNode;
typedef struct ThreadList {
} ThreadList;
/*
* popFrameEventLock is used to notify that the event has been received
*/
/*
* popFrameProceedLock is used to assure that the event thread is
* re-suspended immediately after the event is acknowledged.
*/
/*
* Threads which have issued thread start events and not yet issued thread
* end events are maintained in the "runningThreads" list. All other threads known
* to this module are kept in the "otherThreads" list.
*/
static int debugThreadCount;
typedef struct DeferredEventMode {
typedef struct {
static jint
{
if (error != JVMTI_ERROR_NONE) {
}
return count;
}
/* Get the state of the thread direct from JVMTI */
static jvmtiError
{
*pstate = 0;
}
/* Set TLS on a specific jthread to the ThreadNode* */
static void
{
if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
/* Just return, thread hasn't started yet */
return;
} else if ( error != JVMTI_ERROR_NONE ) {
/* The jthread object must be valid, so this must be a fatal error */
}
}
/* Get TLS on a specific jthread, which is the ThreadNode* */
static ThreadNode *
{
if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) {
/* Just return NULL, thread hasn't started yet */
return NULL;
} else if ( error != JVMTI_ERROR_NONE ) {
/* The jthread object must be valid, so this must be a fatal error */
}
return node;
}
/* Search list for nodes that don't have TLS set and match this thread.
* It assumed that this logic is never dealing with terminated threads,
* since the ThreadEnd events always delete the ThreadNode while the
* jthread is still alive. So we can only look at the ThreadNode's that
* have never had their TLS set, making the search much faster.
* But keep in mind, this kind of search should rarely be needed.
*/
static ThreadNode *
{
break;
}
}
return node;
}
/*
* These functions maintain the linked list of currently running threads.
* All assume that the threadLock is held before calling.
* If list==NULL, search both lists.
*/
static ThreadNode *
{
/* Get thread local storage for quick thread -> node access */
/* In some rare cases we might get NULL, so we check the list manually for
* any threads that we could match.
*/
} else {
}
}
/* Here we make another attempt to set TLS, it's ok if this fails */
}
}
/* If a list is supplied, only return ones in this list */
return NULL;
}
return node;
}
/* Remove a ThreadNode from a ThreadList */
static void
{
}
}
}
}
/* Add a ThreadNode to a ThreadList */
static void
{
} else {
}
}
static ThreadNode *
{
return NULL;
}
return NULL;
}
/*
* Init all flags false, all refs NULL, all counts 0
*/
return NULL;
}
/*
* Remember if it is a debug thread
*/
} else if (suspendAllCount > 0){
/*
* If there is a pending suspendAll, all new threads should
* be initialized as if they were suspended by the suspendAll,
* and the thread will need to be suspended when it starts.
*/
}
node->current_ei = 0;
/* Set thread local storage for quick thread -> node access.
* Some threads may not be in a state that allows setting of TLS,
* which is ok, see findThread, it deals with threads without TLS set.
*/
}
return node;
}
static void
{
}
if (node->isDebugThread) {
}
/* Clear out TLS on this thread (just a cleanup action) */
}
static void
{
}
}
static void
{
if (node->suspendCount == 0) {
}
}
}
static void
{
}
static jvmtiError
{
if ( error != JVMTI_ERROR_NONE ) {
break;
}
}
return error;
}
static void
{
} else {
}
}
static void
{
} else {
}
}
}
static jvmtiError
{
/*LINTED*/
return AGENT_ERROR_OUT_OF_MEMORY;
}
return JVMTI_ERROR_NONE;
}
static void
{
}
}
static jvmtiError
{
/* record single step mode */
if (ei == EI_SINGLE_STEP) {
}
return error;
}
static void
{
if (error != JVMTI_ERROR_NONE) {
}
} else {
}
}
}
static void
getLocks(void)
{
/*
* Anything which might be locked as part of the handling of
* a JVMTI event (which means: might be locked by an application
* thread) needs to be grabbed here. This allows thread control
* code to safely suspend and resume the application threads
* while ensuring they don't hold a critical lock.
*/
invoker_lock();
}
static void
releaseLocks(void)
{
}
void
threadControl_initialize(void)
{
suspendAllCount = 0;
debugThreadCount = 0;
}
if (gdata->threadResume==0) {
}
/* Get the java.lang.Thread.resume() method beginning location */
if (error != JVMTI_ERROR_NONE) {
}
}
static jthread
{
if (error == JVMTI_ERROR_NONE) {
}
return resumee;
}
static jboolean
{
list = &runningThreads;
if (node->resumeFrameDepth > 0) {
if (includeSuspended) {
return JNI_TRUE;
} else {
if (error != JVMTI_ERROR_NONE) {
}
if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
return JNI_TRUE;
}
}
}
}
return JNI_FALSE;
}
static void
notifyAppResumeComplete(void)
{
if (!pendingAppResume(JNI_TRUE)) {
if (framePopHandlerNode != NULL) {
(void)eventHandler_free(framePopHandlerNode);
}
if (catchHandlerNode != NULL) {
(void)eventHandler_free(catchHandlerNode);
}
}
}
static void
{
if (node->resumeFrameDepth > 0) {
compareDepth--;
}
node->resumeFrameDepth = 0;
}
}
}
}
static void
{
}
}
}
static void
{
fnum = 0;
if (error == JVMTI_ERROR_NONE) {
thread);
thread);
if ((framePopHandlerNode == NULL) ||
(catchHandlerNode == NULL)) {
(void)eventHandler_free(framePopHandlerNode);
(void)eventHandler_free(catchHandlerNode);
}
}
if ((framePopHandlerNode != NULL) &&
(catchHandlerNode != NULL) &&
(frameDepth > 0)) {
}
}
}
}
static void
{
/*
* Hold up any attempt to resume as long as the debugger
* has suspended the resumee.
*/
}
/*
* Track the resuming thread by marking it as being within
* a resume and by setting up for notification on
* a frame pop or exception. We won't allow the debugger
* to suspend threads while any thread is within a
* call to resume. This (along with the block above)
* ensures that when the debugger
* suspends a thread it will remain suspended.
*/
}
}
void
threadControl_onConnect(void)
{
}
void
{
if (breakpointHandlerNode != NULL) {
}
if (framePopHandlerNode != NULL) {
(void)eventHandler_free(framePopHandlerNode);
}
if (catchHandlerNode != NULL) {
(void)eventHandler_free(catchHandlerNode);
}
}
void
threadControl_onHook(void)
{
/*
* As soon as the event hook is in place, we need to initialize
* the thread list with already-existing threads. The threadLock
* has been held since initialize, so we don't need to worry about
* insertions or deletions from the event handlers while we do this
*/
/*
* Prevent any event processing until OnHook has been called
*/
} else {
int i;
for (i = 0; i < threadCount; i++) {
/*
* This is a tiny bit risky. We have to assume that the
* pre-existing threads have been started because we
* can't rely on a thread start event for them. The chances
* of a problem related to this are pretty slim though, and
* there's really no choice because without setting this flag
* there is no way to enable stepping and other events on
* the threads that already exist (e.g. the finalizer thread).
*/
}
}
}
static jvmtiError
{
/*
* Mark for resume only if suspend succeeded
*/
if (error == JVMTI_ERROR_NONE) {
}
/*
* If the thread was suspended by another app thread,
* do nothing and report no error (we won't resume it later).
*/
if (error == JVMTI_ERROR_THREAD_SUSPENDED) {
}
return error;
}
/*
* Deferred suspends happen when the suspend is attempted on a thread
* that is not started. Bookkeeping (suspendCount,etc.)
* is handled by the original request, and once the thread actually
* starts, an actual suspend is attempted. This function does the
* deferred suspend without changing the bookkeeping that is already
* in place.
*/
static jint
{
if (node->isDebugThread) {
/* Ignore requests for suspending debugger threads */
return JVMTI_ERROR_NONE;
}
/*
* Do the actual suspend only if a subsequent resume hasn't
* made it irrelevant.
*/
if (node->suspendCount > 0) {
/*
* Attempt to clean up from any error by decrementing the
* suspend count. This compensates for the increment that
* happens when suspendOnStart is set to true.
*/
if (error != JVMTI_ERROR_NONE) {
node->suspendCount--;
}
}
return error;
}
static jvmtiError
{
if (node->isDebugThread) {
/* Ignore requests for suspending debugger threads */
return JVMTI_ERROR_NONE;
}
/*
* Just increment the suspend count if we are waiting
* for a deferred suspend.
*/
if (node->suspendOnStart) {
node->suspendCount++;
return JVMTI_ERROR_NONE;
}
if (node->suspendCount == 0) {
if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) {
/*
* This error means that the thread is either a zombie or not yet
* started. In either case, we ignore the error. If the thread
* started, it will be suspended for real during the processing
* of its thread start event.
*/
}
}
if (error == JVMTI_ERROR_NONE) {
node->suspendCount++;
}
return error;
}
static jvmtiError
{
if (node->isDebugThread) {
/* never suspended by debugger => don't ever try to resume */
return JVMTI_ERROR_NONE;
}
if (node->suspendCount > 0) {
node->suspendCount--;
!node->suspendOnStart) {
/*
* We successfully "suspended" this thread, but
* we never received a THREAD_START event for it.
* Since the thread never ran, we can ignore our
* failure to resume the thread.
*/
}
}
}
return error;
}
/*
* threads.
* Suspends and resumes add and subtract from a count respectively.
* The thread is only suspended when the count goes from 0 to 1 and
* resumed only when the count goes from 1 to 0.
*
* These functions suspend and resume application threads
* without changing the
* state of threads that were already suspended beforehand.
* They must not be called from an application thread because
* that thread may be suspended somewhere in the middle of things.
*/
static void
preSuspend(void)
{
getLocks(); /* Avoid debugger deadlocks */
/*
* Delay any suspend while a call to java.lang.Thread.resume is in
* progress (not including those in suspended threads). The wait is
* timed because the threads suspended through
* java.lang.Thread.suspend won't result in a notify even though
* it may change the result of pendingAppResume()
*/
while (pendingAppResume(JNI_FALSE)) {
/*
* This is ugly but we need to release the locks from getLocks
* or else the notify will never happen. The locks must be
* released and reacquired in the right order. else deadlocks
* can happen. It is possible that, during this dance, the
* notify will be missed, but since the wait needs to be timed
* anyway, it won't be a disaster. Note that this code will
* execute only on very rare occasions anyway.
*/
releaseLocks();
getLocks();
}
}
static void
postSuspend(void)
{
releaseLocks();
}
/*
* This function must be called after preSuspend and before postSuspend.
*/
static jvmtiError
{
/*
* If the thread is not between its start and end events, we should
* still suspend it. To keep track of things, add the thread
* to a separate list of threads so that we'll resume it later.
*/
}
if ( deferred ) {
return deferredSuspendThreadByNode(node);
} else {
return suspendThreadByNode(node);
}
}
static jvmtiError
{
if (node->isDebugThread) {
/* never suspended by debugger => don't ever try to resume */
return JVMTI_ERROR_NONE;
}
node->suspendCount--;
/* nested suspend so just undo one level */
return JVMTI_ERROR_NONE;
}
/*
* This thread was marked for suspension since its THREAD_START
* event came in during a suspendAll, but the helper hasn't
* completed the job yet. We decrement the count so the helper
* won't suspend this thread after we are done with the resumeAll.
* Another case to be handled here is when the debugger suspends
* the thread while the app has it suspended. In this case,
* the toBeResumed flag has been cleared indicating that
* the thread should not be resumed when the debugger does a resume.
* In this case, we also have to decrement the suspend count.
* If we don't then when the app resumes the thread and our Thread.resume
* bkpt handler is called, blockOnDebuggerSuspend will not resume
* the thread because suspendCount will be 1 meaning that the
* debugger has the thread suspended. See bug 6224859.
*/
node->suspendCount--;
return JVMTI_ERROR_NONE;
}
/* nothing to hard resume so we're done */
return JVMTI_ERROR_NONE;
}
/*
* This is tricky. A suspendCount of 1 and toBeResumed means that
* on this thread. The check for !suspendOnStart is paranoia that
* we inherited from resumeThreadByNode().
*/
(*listPtr)++;
}
return JVMTI_ERROR_NONE;
}
static jvmtiError
{
if (node->isDebugThread) {
/* never suspended by debugger => don't ever try to resume */
return JVMTI_ERROR_NONE;
}
/*
* This is tricky. A suspendCount of 1 and toBeResumed means that
* on this thread. The check for !suspendOnStart is paranoia that
* we inherited from resumeThreadByNode().
*/
(*counter)++;
}
return JVMTI_ERROR_NONE;
}
static void *
{
void *ptr;
}
return ptr;
}
static void
{
}
/*
* This function must be called with the threadLock held.
*
* Two facts conspire to make this routine complicated:
*
* 1) the VM doesn't support nested external suspend
* 2) the original resumeAll code structure doesn't retrieve the
* entire thread list from JVMTI so we use the runningThreads
* list and two helpers to get the job done.
*
* Because we hold the threadLock, state seen by resumeCountHelper()
* is the same state seen in resumeCopyHelper(). resumeCountHelper()
* just counts up the number of threads to be hard resumed.
* resumeCopyHelper() does the accounting for nested suspends and
* special cases and, finally, populates the list of hard resume
* threads to be passed to ResumeThreadList().
*
* At first glance, you might think that the accounting could be done
* in resumeCountHelper(), but then resumeCopyHelper() would see
* "post-resume" state in the accounting values (suspendCount and
* toBeResumed) and would not be able to distinguish between a thread
* that needs a hard resume versus a thread that is already running.
*/
static jvmtiError
{
jint i;
reqCnt = 0;
/* count number of threads to hard resume */
&reqCnt);
if (reqCnt == 0) {
/* nothing to hard resume so do just the accounting part */
NULL);
return JVMTI_ERROR_NONE;
}
/*LINTED*/
}
/*LINTED*/
}
/* copy the jthread values for threads to hard resume */
&reqPtr);
for (i = 0; i < reqCnt; i++) {
}
/*
* always works and does all the accounting updates. We do
* the same here. We also don't clear the error.
*/
node->suspendCount--;
}
return error;
}
/*
* This function must be called after preSuspend and before postSuspend.
*/
static jvmtiError
{
jint i;
reqCnt = 0;
}
/*
* Go through the initial list and see if we have anything to suspend.
*/
for (i = 0; i < initCount; i++) {
/*
* If the thread is not between its start and end events, we should
* still suspend it. To keep track of things, add the thread
* to a separate list of threads so that we'll resume it later.
*/
}
if (node->isDebugThread) {
/* Ignore requests for suspending debugger threads */
continue;
}
/*
* Just increment the suspend count if we are waiting
* for a deferred suspend or if this is a nested suspend.
*/
node->suspendCount++;
continue;
}
if (node->suspendCount == 0) {
/* thread is not suspended yet so put it on the request list */
}
}
if (reqCnt > 0) {
}
/*
* We have something to suspend so try to do it.
*/
for (i = 0; i < reqCnt; i++) {
}
if (results[i] == JVMTI_ERROR_NONE) {
/* thread was suspended as requested */
} else if (results[i] == JVMTI_ERROR_THREAD_SUSPENDED) {
/*
* If the thread was suspended by another app thread,
* do nothing and report no error (we won't resume it later).
*/
results[i] = JVMTI_ERROR_NONE;
} else if (results[i] == JVMTI_ERROR_THREAD_NOT_ALIVE) {
/*
* This error means that the suspend request failed
* because the thread is either a zombie or not yet
* started. In either case, we ignore the error. If the
* thread is not started, it will be suspended for real
* during the processing of its thread start event.
*/
results[i] = JVMTI_ERROR_NONE;
}
/* count real, app and deferred (suspendOnStart) suspensions */
if (results[i] == JVMTI_ERROR_NONE) {
node->suspendCount++;
}
}
}
return error;
}
static jvmtiError
{
/*
* The thread is normally between its start and end events, but if
* not, check the auxiliary list used by threadControl_suspendThread.
*/
/*
* If the node is in neither list, the debugger never suspended
* this thread, so do nothing.
*/
}
return error;
}
{
preSuspend();
postSuspend();
return error;
}
{
eventHandler_lock(); /* for proper lock order */
if (do_unblock) {
/* let eventHelper.c: commandLoop() know we resumed one thread */
}
return error;
}
{
}
} else {
/*
* If the node is in neither list, the debugger never suspended
* this thread, so the suspend count is 0.
*/
*count = 0;
}
return error;
}
static jboolean
{
int i;
for (i = 0; i < count; i++) {
return JNI_TRUE;
}
}
return JNI_FALSE;
}
typedef struct {
static jvmtiError
{
}
return error;
}
threadControl_suspendAll(void)
{
preSuspend();
/*
* Get a list of all threads and suspend them.
*/
goto err;
}
if (canSuspendResumeThreadLists()) {
if (error != JVMTI_ERROR_NONE) {
goto err;
}
} else {
int i;
for (i = 0; i < count; i++) {
if (error != JVMTI_ERROR_NONE) {
goto err;
}
}
}
/*
* Update the suspend count of any threads not yet (or no longer)
* in the thread list above.
*/
{
suspendAllHelper, &arg);
}
if (error == JVMTI_ERROR_NONE) {
}
err: ;
postSuspend();
return error;
}
static jvmtiError
{
/*
* Since this helper is called with the threadLock held, we
* don't need to recheck to see if the node is still on one
* of the two thread lists.
*/
return resumeThreadByNode(node);
}
threadControl_resumeAll(void)
{
eventHandler_lock(); /* for proper lock order */
/*
* Resume only those threads that the debugger has suspended. All
* such threads must have a node in one of the thread lists, so there's
* no need to get the whole thread list from JVMTI (unlike
* suspendAll).
*/
if (canSuspendResumeThreadLists()) {
} else {
resumeHelper, NULL);
}
resumeHelper, NULL);
}
if (suspendAllCount > 0) {
}
/* let eventHelper.c: commandLoop() know we are resuming */
return error;
}
{
}
return step;
}
{
}
return request;
}
{
if (debugThreadCount >= MAX_DEBUG_THREADS) {
} else {
} else {
}
}
return error;
}
static jvmtiError
{
int i;
for (i = 0; i< debugThreadCount; i++) {
int j;
for (j = i+1; j < debugThreadCount; j++) {
}
break;
}
}
return error;
}
{
int i;
for (i = 0; i < debugThreadCount; i++) {
break;
}
}
return rc;
}
static void
initLocks(void)
{
if (popFrameEventLock == NULL) {
}
}
static jboolean
{
{
} else {
}
}
return popFrameThread;
}
static void
{
{
} else {
}
}
}
static jboolean
{
{
} else {
}
}
return popFrameEvent;
}
static void
{
{
} else {
}
}
}
static jboolean
{
{
} else {
}
}
return popFrameProceed;
}
static void
{
{
} else {
}
}
}
/**
* Special event handler for events on the popped thread
* that occur during the pop operation.
*/
static void
{
{
/* notify that we got the event */
{
}
/* make sure we get suspended again */
}
}
}
/**
* Pop one frame off the stack of thread.
* popFrameEventLock is already held
*/
static jvmtiError
{
if (error != JVMTI_ERROR_NONE) {
return error;
}
/* resume the popped thread so that the pop occurs and so we */
/* will get the event (step or method entry) after the pop */
if (error != JVMTI_ERROR_NONE) {
return error;
}
/* wait for the event to occur */
}
/* make sure not to suspend until the popped thread is on the wait */
{
/* return popped thread to suspended state */
/* notify popped thread so it can proceed when resumed */
}
return error;
}
/**
* pop frames of the stack of 'thread' until 'frame' is popped.
*/
{
initLocks();
/* compute the number of frames to pop */
if (popCount < 1) {
return AGENT_ERROR_NO_MORE_FRAMES;
}
/* enable instruction level single step, but first note prev value */
/*
* Fix bug 6517249. The pop processing will disable invokes,
* so remember if invokes are enabled now and restore
* that state after we finish popping.
*/
if (error != JVMTI_ERROR_NONE) {
return error;
}
/* Inform eventHandler logic we are in a popFrame for this thread */
{
/* pop frames using single step */
while (framesPopped++ < popCount) {
if (error != JVMTI_ERROR_NONE) {
break;
}
}
}
/* Reset StepRequest info (fromLine and stackDepth) after popframes
* only if stepping is enabled.
*/
if (prevStepMode == JVMTI_ENABLE) {
}
if (prevInvokeRequestMode) {
}
/* restore state */
return error;
}
/* Check to see if any events are being consumed by a popFrame(). */
static jboolean
{
if ( getPopFrameThread(thread) ) {
switch (ei) {
case EI_THREAD_START:
/* Excuse me? */
break;
case EI_THREAD_END:
/* Thread wants to end? let it. */
break;
case EI_SINGLE_STEP:
/* This is an event we requested to mark the */
/* completion of the pop frame */
return JNI_TRUE;
case EI_BREAKPOINT:
case EI_EXCEPTION:
case EI_FIELD_ACCESS:
case EI_FIELD_MODIFICATION:
case EI_METHOD_ENTRY:
case EI_METHOD_EXIT:
/* Tell event handler to assume event has been consumed. */
return JNI_TRUE;
default:
break;
}
}
/* Pretend we were never called */
return JNI_FALSE;
}
struct bag *
threadControl_onEventHandlerEntry(jbyte sessionID, EventIndex ei, jthread thread, jobject currentException)
{
/* Events during pop commands may need to be ignored here. */
if ( consumed ) {
/* Always restore any exception (see below). */
if (currentException != NULL) {
} else {
}
return NULL;
}
/*
* Check the list of unknown threads maintained by suspend
* and resume. If this thread is currently present in the
* list, it should be
* moved to the runningThreads list, since it is a
* well-known thread now.
*/
} else {
/*
* Get a thread node for the reporting thread. For thread start
* events, or if this event precedes a thread start event,
* the thread node may need to be created.
*
* to precede thread start for some VM implementations.
*/
}
if (ei == EI_THREAD_START) {
}
if (node->suspendOnStart) {
}
if (threadToSuspend != NULL) {
/*
* An attempt was made to suspend this thread before it started.
* We must suspend it now, before it starts to run. This must
* be done with no locks held.
*/
}
return eventBag;
}
static void
{
/*
* Take care of any pending interrupts/stops, and clear out
* info on pending interrupts/stops.
*/
if (node->pendingInterrupt) {
/*
* TO DO: Log error
*/
}
/*
* TO DO: Log error
*/
}
}
void
{
if (ei == EI_THREAD_END) {
eventHandler_lock(); /* for proper lock order */
}
} else {
if (ei == EI_THREAD_END) {
/*
* Clean up mechanism used to detect end of
* resume.
*/
if (inResume) {
}
} else {
/* No point in doing this if the thread is about to die.*/
node->current_ei = 0;
}
}
if (ei == EI_THREAD_END) {
}
}
/* Returns JDWP flavored status and status flags. */
{
if (error == JVMTI_ERROR_NONE) {
/*
* While processing an event, an application thread is always
* considered to be running even if its handler happens to be
* cond waiting on an internal debugger monitor, etc.
*
* Leave suspend status untouched since it is not possible
* to distinguish debugger suspends from app suspends.
*/
}
}
return error;
}
{
} else {
/*
* Hold any interrupts until after the event is processed.
*/
}
return error;
}
void
{
}
}
}
{
}
return result;
}
void
{
/* Create a class ref that will live beyond */
/* the end of this call */
/* if returned clazz is NULL, we just won't match */
}
}
void
{
}
}
{
} else {
/*
* Hold any stops until after the event is processed.
*/
}
return error;
}
static jvmtiError
{
return JVMTI_ERROR_NONE;
}
void
{
invoker_lock(); /* for proper lock order */
}
static jvmtiError
{
if (node->toBeResumed) {
}
node->suspendCount = 0;
return JVMTI_ERROR_NONE;
}
void
threadControl_reset(void)
{
eventHandler_lock(); /* for proper lock order */
suspendAllCount = 0;
/* Everything should have been resumed */
}
{
}
return mode;
}
{
/* Global event */
} else {
/* Thread event */
{
} else {
}
}
}
return error;
}
/*
* Returns the current thread, if the thread has generated at least
* one event, and has not generated a thread end event.
*/
{
{
}
return thread;
}
{
{
}
}
return frameGeneration;
}