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 + -
显示快捷键?