threadcontrol.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 2,307 行 · 第 1/5 页
C
2,307 行
/* * @(#)threadControl.c 1.63 06/10/31 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */#include "util.h"#include "eventHandler.h"#include "threadControl.h"#include "commonRef.h"#include "eventHelper.h"#include "stepControl.h"#include "invoker.h"#include "bag.h"#define HANDLING_EVENT(node) ((node)->current_ei != 0)/* * 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_ { EventIndex ei; jclass clazz; jmethodID method; jlocation location;} 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 { jthread thread; unsigned int toBeResumed : 1; unsigned int pendingInterrupt : 1; unsigned int isDebugThread : 1; unsigned int suspendOnStart : 1; unsigned int isStarted : 1; unsigned int popFrameEvent : 1; unsigned int popFrameProceed : 1; unsigned int popFrameThread : 1; EventIndex current_ei; jobject pendingStop; jint suspendCount; jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */ jvmtiEventMode instructionStepMode; StepRequest currentStep; InvokeRequest currentInvoke; struct bag *eventBag; CoLocatedEventInfo cleInfo; struct ThreadNode *next; struct ThreadNode *prev; jlong frameGeneration; struct ThreadList *list; /* Tells us what list this thread is in */} ThreadNode;static jint suspendAllCount;typedef struct ThreadList { ThreadNode *first;} ThreadList;/* * popFrameEventLock is used to notify that the event has been received */static jrawMonitorID popFrameEventLock = NULL;/* * popFrameProceedLock is used to assure that the event thread is * re-suspended immediately after the event is acknowledged. */static jrawMonitorID popFrameProceedLock = NULL;static jrawMonitorID threadLock;#if 0static jlocation resumeLocation;#endifstatic HandlerNode *breakpointHandlerNode;static HandlerNode *framePopHandlerNode;static HandlerNode *catchHandlerNode;static jvmtiError threadControl_removeDebugThread(jthread thread);/* * 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 ThreadList runningThreads;static ThreadList otherThreads;#define MAX_DEBUG_THREADS 10static int debugThreadCount;static jthread debugThreads[MAX_DEBUG_THREADS];typedef struct DeferredEventMode { EventIndex ei; jvmtiEventMode mode; jthread thread; struct DeferredEventMode *next;} DeferredEventMode;typedef struct { DeferredEventMode *first; DeferredEventMode *last;} DeferredEventModeList;static DeferredEventModeList deferredEventModes;/* Get the state of the thread direct from JVMTI */static jvmtiError threadState(jthread thread, jint *pstate){ *pstate = 0; return JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState) (gdata->jvmti, thread, pstate);}/* Set TLS on a specific jthread to the ThreadNode* */static void setThreadLocalStorage(jthread thread, ThreadNode *node){ jvmtiError error; error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage) (gdata->jvmti, thread, (void*)node); 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 */ EXIT_ERROR(error, "cannot set thread local storage"); }}/* Get TLS on a specific jthread, which is the ThreadNode* */static ThreadNode *getThreadLocalStorage(jthread thread){ jvmtiError error; ThreadNode *node; node = NULL; error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadLocalStorage) (gdata->jvmti, thread, (void**)&node); 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 */ EXIT_ERROR(error, "cannot get thread local storage"); } 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 *nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread){ ThreadNode *node; for (node = list->first; node != NULL; node = node->next) { if (isSameObject(env, node->thread, thread)) { 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 *findThread(ThreadList *list, jthread thread) { ThreadNode *node; /* Get thread local storage for quick thread -> node access */ node = getThreadLocalStorage(thread); /* In some rare cases we might get NULL, so we check the list manually for * any threads that we could match. */ if ( node == NULL ) { JNIEnv *env; env = getEnv(); if ( list != NULL ) { node = nonTlsSearch(env, list, thread); } else { node = nonTlsSearch(env, &runningThreads, thread); if ( node == NULL ) { node = nonTlsSearch(env, &otherThreads, thread); } } if ( node != NULL ) { /* Here we make another attempt to set TLS, it's ok if this fails */ setThreadLocalStorage(thread, (void*)node); } } /* If a list is supplied, only return ones in this list */ if ( node != NULL && list != NULL && node->list != list ) { return NULL; } return node;}/* Remove a ThreadNode from a ThreadList */static voidremoveNode(ThreadList *list, ThreadNode *node){ ThreadNode *prev; ThreadNode *next; prev = node->prev; next = node->next; if ( prev != NULL ) { prev->next = next; } if ( next != NULL ) { next->prev = prev; } if ( prev == NULL ) { list->first = next; } node->next = NULL; node->prev = NULL; node->list = NULL;}/* Add a ThreadNode to a ThreadList */static voidaddNode(ThreadList *list, ThreadNode *node){ node->next = NULL; node->prev = NULL; node->list = NULL; if ( list->first == NULL ) { list->first = node; } else { list->first->prev = node; node->next = list->first; list->first = node; } node->list = list;}static ThreadNode *insertThread(JNIEnv *env, ThreadList *list, jthread thread) { ThreadNode *node; struct bag *eventBag; node = findThread(list, thread); if (node == NULL) { node = jvmtiAllocate(sizeof(*node)); if (node == NULL) { EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"); return NULL; } (void)memset(node, 0, sizeof(*node)); eventBag = eventHelper_createEventBag(); if (eventBag == NULL) { jvmtiDeallocate(node); EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"); return NULL; } /* * Init all flags false, all refs NULL, all counts 0 */ saveGlobalRef(env, thread, &(node->thread)); if (node->thread == NULL) { jvmtiDeallocate(node); bagDestroyBag(eventBag); EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"); return NULL; } /* * Remember if it is a debug thread */ if (threadControl_isDebugThread(node->thread)) { node->isDebugThread = JNI_TRUE; } 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->suspendCount = suspendAllCount; node->suspendOnStart = JNI_TRUE; } node->current_ei = 0; node->instructionStepMode = JVMTI_DISABLE; node->eventBag = eventBag; addNode(list, node); /* 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. */ setThreadLocalStorage(node->thread, (void*)node); } return node;}static void clearThread(JNIEnv *env, ThreadNode *node){ if (node->pendingStop != NULL) { tossGlobalRef(env, &(node->pendingStop)); } stepControl_clearRequest(node->thread, &node->currentStep); if (node->isDebugThread) { (void)threadControl_removeDebugThread(node->thread); } /* Clear out TLS on this thread (just a cleanup action) */ setThreadLocalStorage(node->thread, NULL); tossGlobalRef(env, &(node->thread)); bagDestroyBag(node->eventBag); jvmtiDeallocate(node);}static void removeThread(JNIEnv *env, ThreadList *list, jthread thread) { ThreadNode *node; node = findThread(list, thread); if (node != NULL) { removeNode(list, node); clearThread(env, node); }}static voidremoveResumed(JNIEnv *env, ThreadList *list){ ThreadNode *node; node = list->first; while (node != NULL) { ThreadNode *temp = node->next; if (node->suspendCount == 0) { removeThread(env, list, node->thread); } node = temp; }}static void moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node) { removeNode(source, node); JDI_ASSERT(findThread(dest, node->thread) == NULL); addNode(dest, node);}typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *);static jvmtiErrorenumerateOverThreadList(JNIEnv *env, ThreadList *list, ThreadEnumerateFunction function, void *arg){ ThreadNode *node; jvmtiError error = JVMTI_ERROR_NONE; for (node = list->first; node != NULL; node = node->next) { error = (*function)(env, node, arg); if ( error != JVMTI_ERROR_NONE ) { break; } } return error;}static voidinsertEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode){ if (list->last != NULL) { list->last->next = eventMode; } else { list->first = eventMode; } list->last = eventMode;}static voidremoveEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode, DeferredEventMode *prev){ if (prev == NULL) { list->first = eventMode->next; } else { prev->next = eventMode->next; } if (eventMode->next == NULL) { list->last = prev; }}static jvmtiErroraddDeferredEventMode(JNIEnv *env, jvmtiEventMode mode, EventIndex ei, jthread thread){ DeferredEventMode *eventMode; /*LINTED*/ eventMode = jvmtiAllocate((jint)sizeof(DeferredEventMode)); if (eventMode == NULL) { return AGENT_ERROR_OUT_OF_MEMORY; } eventMode->thread = NULL; saveGlobalRef(env, thread, &(eventMode->thread)); eventMode->mode = mode; eventMode->ei = ei; eventMode->next = NULL; insertEventMode(&deferredEventModes, eventMode); return JVMTI_ERROR_NONE;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?