Ejemplo n.º 1
0
/* Release tracking of an object by ID */
void
commonRef_release(JNIEnv *env, jlong id)
{
    debugMonitorEnter(gdata->refLock); {
        deleteNodeByID(env, id, 1);
    } debugMonitorExit(gdata->refLock);
}
Ejemplo n.º 2
0
void
commonRef_releaseMultiple(JNIEnv *env, jlong id, jint refCount)
{
    debugMonitorEnter(gdata->refLock); {
        deleteNodeByID(env, id, refCount);
    } debugMonitorExit(gdata->refLock);
}
Ejemplo n.º 3
0
/*
 * Given an object ID obtained from the debugger front end, return a
 * strong, global reference to that object (or NULL if the object
 * has been collected). The reference can then be used for JNI and
 * JVMTI calls. Caller is resposible for deleting the returned reference.
 */
jobject
commonRef_idToRef(JNIEnv *env, jlong id)
{
    jobject ref;

    ref = NULL;
    debugMonitorEnter(gdata->refLock); {
        RefNode *node;

        node = findNodeByID(env, id);
        if (node != NULL) {
            if (node->isStrong) {
                saveGlobalRef(env, node->ref, &ref);
            } else {
                jobject lref;

                lref = JNI_FUNC_PTR(env,NewLocalRef)(env, node->ref);
                if ( lref == NULL ) {
                    /* Object was GC'd shortly after we found the node */
                    deleteNodeByID(env, node->seqNum, ALL_REFS);
                } else {
                    saveGlobalRef(env, node->ref, &ref);
                    JNI_FUNC_PTR(env,DeleteLocalRef)(env, lref);
                }
            }
        }
    } debugMonitorExit(gdata->refLock);
    return ref;
}
Ejemplo n.º 4
0
/* Prevent garbage collection of an object */
jvmtiError
commonRef_pin(jlong id)
{
    jvmtiError error;

    error = JVMTI_ERROR_NONE;
    if (id == NULL_OBJECT_ID) {
        return error;
    }
    debugMonitorEnter(gdata->refLock); {
        JNIEnv  *env;
        RefNode *node;

        env  = getEnv();
        node = findNodeByID(env, id);
        if (node == NULL) {
            error = AGENT_ERROR_INVALID_OBJECT;
        } else {
            jobject strongRef;

            strongRef = strengthenNode(env, node);
            if (strongRef == NULL) {
                /*
                 * Referent has been collected, clean up now.
                 */
                error = AGENT_ERROR_INVALID_OBJECT;
                deleteNodeByID(env, id, ALL_REFS);
            }
        }
    } debugMonitorExit(gdata->refLock);
    return error;
}
Ejemplo n.º 5
0
/* Reset the commonRefs usage */
void
commonRef_reset(JNIEnv *env)
{
    debugMonitorEnter(gdata->refLock); {
        int i;

        for (i = 0; i < gdata->objectsByIDsize; i++) {
            RefNode *node;

            node = gdata->objectsByID[i];
            while (node != NULL) {
                RefNode *next;

                next = node->next;
                deleteNode(env, node);
                node = next;
            }
            gdata->objectsByID[i] = NULL;
        }

        /* Toss entire hash table and re-create a new one */
        jvmtiDeallocate(gdata->objectsByID);
        gdata->objectsByID      = NULL;
        gdata->nextSeqNum       = 1; /* 0 used for error indication */
        initializeObjectsByID(HASH_INIT_SIZE);

    } debugMonitorExit(gdata->refLock);
}
Ejemplo n.º 6
0
/*
 * Given a reference obtained from JNI or JVMTI, return an object
 * id suitable for sending to the debugger front end.
 */
jlong
commonRef_refToID(JNIEnv *env, jobject ref)
{
    jlong id;

    if (ref == NULL) {
        return NULL_OBJECT_ID;
    }

    id = NULL_OBJECT_ID;
    debugMonitorEnter(gdata->refLock); {
        RefNode *node;

        node = findNodeByRef(env, ref);
        if (node == NULL) {
            node = newCommonRef(env, ref);
            if ( node != NULL ) {
                id = node->seqNum;
            }
        } else {
            id = node->seqNum;
            node->count++;
        }
    } debugMonitorExit(gdata->refLock);
    return id;
}
Ejemplo n.º 7
0
static void
notifyTransportError(void) {
    debugMonitorEnter(cmdQueueLock);
    transportError = JNI_TRUE;
    debugMonitorNotify(cmdQueueLock);
    debugMonitorExit(cmdQueueLock);
}
Ejemplo n.º 8
0
static void
enqueue(jdwpPacket *packet)
{
    struct PacketList *pL;
    struct PacketList *walker;

    pL = jvmtiAllocate((jint)sizeof(struct PacketList));
    if (pL == NULL) {
        EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"packet list");
    }

    pL->packet = *packet;
    pL->next = NULL;

    debugMonitorEnter(cmdQueueLock);

    if (cmdQueue == NULL) {
        cmdQueue = pL;
        debugMonitorNotify(cmdQueueLock);
    } else {
        walker = (struct PacketList *)cmdQueue;
        while (walker->next != NULL)
            walker = walker->next;

        walker->next = pL;
    }

    debugMonitorExit(cmdQueueLock);
}
Ejemplo n.º 9
0
static void
enqueueCommand(HelperCommand *command, 
               jboolean wait, jboolean reportingVMDeath) 
{
    static jboolean vmDeathReported = JNI_FALSE;
    CommandQueue *queue = &commandQueue;
    jint size = commandSize(command);
    
    command->done = JNI_FALSE;
    command->waiting = wait;
    command->next = NULL;

    debugMonitorEnter(commandQueueLock);
    while (size + currentQueueSize > maxQueueSize) {
        debugMonitorWait(commandQueueLock);
    }
    log_debugee_location("enqueueCommand(): HelperCommand being processed", NULL, NULL, 0);
    if (vmDeathReported) {
        /* send no more events after VMDeath and don't wait */
        wait = JNI_FALSE;
    } else {
        currentQueueSize += size;

        if (queue->head == NULL) {
            queue->head = command;
        } else {
            queue->tail->next = command;
        }
        queue->tail = command;

        if (reportingVMDeath) {
            vmDeathReported = JNI_TRUE;
        }
    }
    debugMonitorNotifyAll(commandQueueLock);
    debugMonitorExit(commandQueueLock);
    
    if (wait) {
        debugMonitorEnter(commandCompleteLock);
        while (!command->done) {
            log_debugee_location("enqueueCommand(): HelperCommand wait", NULL, NULL, 0);
            debugMonitorWait(commandCompleteLock);
        }
        freeCommand(command);
        debugMonitorExit(commandCompleteLock);
    }
}
Ejemplo n.º 10
0
/*
 * We wait for either ThreadReferenceImpl.c: resume() or
 * VirtualMachineImpl.c: resume() to be called.
 */
static void
doBlockCommandLoop(void) {
    debugMonitorEnter(blockCommandLoopLock);
    while (blockCommandLoop == JNI_TRUE) {
        debugMonitorWait(blockCommandLoopLock);
    }
    debugMonitorExit(blockCommandLoopLock);
}
Ejemplo n.º 11
0
/*
 * Wait for all initialization to complete.
 */
void
debugInit_waitInitComplete(void)
{
    debugMonitorEnter(initMonitor);
    while (!initComplete) {
        debugMonitorWait(initMonitor);
    }
    debugMonitorExit(initMonitor);
}
Ejemplo n.º 12
0
void 
eventHelper_reset(jbyte newSessionID)
{
    debugMonitorEnter(commandQueueLock);
    currentSessionID = newSessionID;
    holdEvents = JNI_FALSE;
    debugMonitorNotifyAll(commandQueueLock);
    debugMonitorExit(commandQueueLock);
}
Ejemplo n.º 13
0
void 
commonRef_release(jlong id) 
{
    JNIEnv *env = getEnv();

    debugMonitorEnter(refLock);

    deleteNodeByID(env, id, 1);

    debugMonitorExit(refLock);
}
Ejemplo n.º 14
0
void 
commonRef_releaseMultiple(jlong id, jint refCount) 
{
    JNIEnv *env = getEnv();

    debugMonitorEnter(refLock);

    deleteNodeByID(env, id, refCount);

    debugMonitorExit(refLock);
}
Ejemplo n.º 15
0
static void
signalInitComplete(void)
{
    /*
     * Initialization is complete
     */
    LOG_MISC(("signal initialization complete"));
    debugMonitorEnter(initMonitor);
    initComplete = JNI_TRUE;
    debugMonitorNotifyAll(initMonitor);
    debugMonitorExit(initMonitor);
}
Ejemplo n.º 16
0
static void 
completeCommand(HelperCommand *command) 
{
    if (command->waiting) {
        debugMonitorEnter(commandCompleteLock);
        command->done = JNI_TRUE;
        log_debugee_location("completeCommand(): HelperCommand done waiting", NULL, NULL, 0);
        debugMonitorNotifyAll(commandCompleteLock);
        debugMonitorExit(commandCompleteLock);
    } else {
        freeCommand(command);
    }
}
Ejemplo n.º 17
0
/*
 * If the command that we are about to execute has a suspend-all
 * policy, then prepare for either ThreadReferenceImpl.c: resume()
 * or VirtualMachineImpl.c: resume() to be called.
 */
static jboolean
needBlockCommandLoop(HelperCommand *cmd) {
    if (cmd->commandKind == COMMAND_REPORT_EVENT_COMPOSITE
    && cmd->u.reportEventComposite.suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) {
        debugMonitorEnter(blockCommandLoopLock);
        blockCommandLoop = JNI_TRUE;
        debugMonitorExit(blockCommandLoopLock);

        return JNI_TRUE;
    }

    return JNI_FALSE;
}
Ejemplo n.º 18
0
static HelperCommand *
dequeueCommand(void)
{
    HelperCommand *command = NULL;
    CommandQueue *queue = &commandQueue;
    jint size;

    debugMonitorEnter(commandQueueLock);

    while (command == NULL) {
        while (holdEvents || (queue->head == NULL)) {
            debugMonitorWait(commandQueueLock);
        }
    
        JDI_ASSERT(queue->head);
        command = queue->head;
        queue->head = command->next;
        if (queue->tail == command) {
            queue->tail = NULL;
        }
    
        log_debugee_location("dequeueCommand(): command being dequeued", NULL, NULL, 0);
        
        size = commandSize(command);
        /*
         * Immediately close out any commands enqueued from a 
         * previously attached debugger. 
         */
        if (command->sessionID != currentSessionID) {
            log_debugee_location("dequeueCommand(): command session removal", NULL, NULL, 0);
            completeCommand(command);
            command = NULL;
        }

        /*
         * There's room in the queue for more.
         */
        currentQueueSize -= size;
        debugMonitorNotifyAll(commandQueueLock);
    }

    debugMonitorExit(commandQueueLock);

    return command;
}
Ejemplo n.º 19
0
/*
 * Given an object ID obtained from the debugger front end, return a
 * strong, global reference to that object (or NULL if the object
 * has been collected). The reference can then be used for JNI and 
 * JVMTI calls. Caller is resposible for deleting the returned reference.
 */
jobject 
commonRef_idToRef(jlong id) 
{
    JNIEnv *env = getEnv();
    jobject ref = NULL;
    RefNode *node;

    debugMonitorEnter(refLock);

    node = findNodeByID(env, id);
    if (node != NULL) {
        saveGlobalRef(env, node->ref, &ref);
    }

    debugMonitorExit(refLock);

    return ref;
}
Ejemplo n.º 20
0
/* Get rid of RefNodes for objects that no longer exist */
void 
commonRef_compact(void) 
{
    JNIEnv  *env;
    RefNode *node;
    RefNode *prev;
    int      i;

    env = getEnv();
    debugMonitorEnter(gdata->refLock); {
        if ( gdata->objectsByIDsize > 0 ) {
            /* 
             * Walk through the id-based hash table. Detach any nodes
             * for which the ref has been collected. 
             */
            for (i = 0; i < gdata->objectsByIDsize; i++) {
                node = gdata->objectsByID[i];
                prev = NULL;
                while (node != NULL) {
                    /* Has the object been collected? */
                    if ( (!node->isStrong) &&
                          isSameObject(env, node->ref, NULL)) {
                        RefNode *freed;
                        
                        /* Detach from the ID list */
                        if (prev == NULL) {
                            gdata->objectsByID[i] = node->next;
                        } else {
                            prev->next = node->next;
                        }
                        freed = node;
                        node = node->next;
                        deleteNode(env, freed);
                    } else {
                        prev = node;
                        node = node->next;
                    }
                }
            }
        }
    } debugMonitorExit(gdata->refLock);
}
Ejemplo n.º 21
0
static void
connectionInitiated(jdwpTransportEnv *t)
{
    jint isValid = JNI_FALSE;

    debugMonitorEnter(listenerLock);

    /*
     * Don't allow a connection until initialization is complete
     */
    debugInit_waitInitComplete();

    /* Are we the first transport to get a connection? */

    if (transport == NULL) {
        transport = t;
        isValid = JNI_TRUE;
    } else {
        if (transport == t) {
            /* connected with the same transport as before */
            isValid = JNI_TRUE;
        } else {
            /*
             * Another transport got a connection - multiple transports
             * not fully supported yet so shouldn't get here.
             */
            (*t)->Close(t);
            JDI_ASSERT(JNI_FALSE);
        }
    }

    if (isValid) {
        debugMonitorNotifyAll(listenerLock);
    }

    debugMonitorExit(listenerLock);

    if (isValid) {
        debugLoop_run();
    }

}
Ejemplo n.º 22
0
void
transport_waitForConnection(void)
{
    /*
     * If the VM is suspended on debugger initialization, we wait
     * for a connection before continuing. This ensures that all
     * events are delivered to the debugger. (We might as well do this
     * this since the VM won't continue until a remote debugger attaches
     * and resumes it.) If not suspending on initialization, we must
     * just drop any packets (i.e. events) so that the VM can continue
     * to run. The debugger may not attach until much later.
     */
    if (debugInit_suspendOnInit()) {
        debugMonitorEnter(listenerLock);
        while (transport == NULL) {
            debugMonitorWait(listenerLock);
        }
        debugMonitorExit(listenerLock);
    }
}
Ejemplo n.º 23
0
/* Permit garbage collection of an object */
jvmtiError 
commonRef_unpin(jlong id) 
{
    JNIEnv *env = getEnv();
    jvmtiError error = JVMTI_ERROR_NONE;
    RefNode *node;

    debugMonitorEnter(refLock);

    node = findNodeByID(env, id);
    if (node != NULL) {
        jweak weakRef = weakenNode(env, node);
        if (weakRef == NULL) {
            error = JVMTI_ERROR_OUT_OF_MEMORY;
        } 
    }

    debugMonitorExit(refLock);

    return error;
}
Ejemplo n.º 24
0
static jboolean
dequeue(jdwpPacket *packet) {
    struct PacketList *node = NULL;

    debugMonitorEnter(cmdQueueLock);

    while (!transportError && (cmdQueue == NULL)) {
        debugMonitorWait(cmdQueueLock);
    }

    if (cmdQueue != NULL) {
        node = (struct PacketList *)cmdQueue;
        cmdQueue = node->next;
    }
    debugMonitorExit(cmdQueueLock);

    if (node != NULL) {
        *packet = node->packet;
        jvmtiDeallocate(node);
    }
    return (node != NULL);
}
Ejemplo n.º 25
0
void 
commonRef_reset(void)
{
    JNIEnv *env = getEnv();
    int i;
    RefNode *node;

    debugMonitorEnter(refLock);

    for (i = 0; i < CR_HASH_SLOT_COUNT; i++) {
        node = objectsByID[i];
        while (node != NULL) {
            RefNode *temp = node->nextByID;
            deleteNode(env, node);
            node = temp;
        }
        objectsByID[i] = NULL;
        objectsByRef[i] = NULL;
    }
    nextSeqNum = 1;

    debugMonitorExit(refLock);
}
Ejemplo n.º 26
0
void 
commonRef_unlock(void) 
{
    debugMonitorExit(refLock);
}
Ejemplo n.º 27
0
/*
 * Get rid of RefNodes for objects that no longer exist
 */
void 
commonRef_compact(void) 
{
    JNIEnv *env = getEnv();
    RefNode *node;
    RefNode *prev;
    int i;

    /* printRefTables(); */

    debugMonitorEnter(refLock);

    /* 
     * Part 1: Walk through the id-based hash table. Detach any nodes
     * for which the ref has been collected. Mark the node instead of 
     * deleting it so that the second part through the ref-based hash
     * table can find it.
     */
    for (i = 0; i < CR_HASH_SLOT_COUNT; i++) {
        node = objectsByID[i];
        prev = NULL;
        while (node != NULL) {
            /* Has the object been collected? */
            if (isSameObject(env, node->ref, NULL)) {
                /* Mark it to be freed by part 2 */
                node->count = 0;

                /* Detach from the ID list */
                if (prev == NULL) {
                    objectsByID[i] = node->nextByID;
                } else {
                    prev->nextByID = node->nextByID;
                }
            } else {
                prev = node;
            }
            node = node->nextByID;
        }
    }

    /*
     * Part 2: Walk through the ref-based hash table. Detach and 
     * delete all nodes that were marked in pass 1.
     */
    for (i = 0; i < CR_HASH_SLOT_COUNT; i++) {
        node = objectsByRef[i];
        prev = NULL;
        while (node != NULL) {
            /* Has the object been marked? */
            if (node->count == 0) {
                RefNode *freed = node;
                /* Detach from the ref list */
                if (prev == NULL) {
                    objectsByRef[i] = freed->nextByRef;
                } else {
                    prev->nextByRef = freed->nextByRef;
                }
                node = node->nextByRef;
                deleteNode(env, freed);
            } else {
                prev = node;
                node = node->nextByRef;
            }
        }
    }
    debugMonitorExit(refLock);

    /* printRefTables(); */
}
Ejemplo n.º 28
0
void
debugLoop_sync(void)
{
    debugMonitorEnter(resumeLock);
    debugMonitorExit(resumeLock);
}
Ejemplo n.º 29
0
void
debugLoop_run(void)
{
    jboolean shouldListen;
    jdwpPacket p;
    jvmtiStartFunction func;

    /* Initialize all statics */
    /* We may be starting a new connection after an error */
    cmdQueue = NULL;
    cmdQueueLock = debugMonitorCreate("JDWP Command Queue Lock");
    transportError = JNI_FALSE;

    shouldListen = JNI_TRUE;

    func = &reader;
    (void)spawnNewThread(func, NULL, "JDWP Command Reader");

    standardHandlers_onConnect();
    threadControl_onConnect();

    /* Okay, start reading cmds! */
    while (shouldListen) {
        if (!dequeue(&p)) {
            break;
        }

        if (p.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
            /*
             * Its a reply packet.
             */
           continue;
        } else {
            /*
             * Its a cmd packet.
             */
            jdwpCmdPacket *cmd = &p.type.cmd;
            PacketInputStream in;
            PacketOutputStream out;
            CommandHandler func;

            /* Should reply be sent to sender.
             * For error handling, assume yes, since
             * only VM/exit does not reply
             */
            jboolean replyToSender = JNI_TRUE;

            /*
             * For VirtualMachine.Resume commands we hold the resumeLock
             * while executing and replying to the command. This ensures
             * that a Resume after VM_DEATH will be allowed to complete
             * before the thread posting the VM_DEATH continues VM
             * termination.
             */
            if (resumeCommand(cmd)) {
                debugMonitorEnter(resumeLock);
            }

            /* Initialize the input and output streams */
            inStream_init(&in, p);
            outStream_initReply(&out, inStream_id(&in));

            LOG_MISC(("Command set %d, command %d", cmd->cmdSet, cmd->cmd));

            func = debugDispatch_getHandler(cmd->cmdSet,cmd->cmd);
            if (func == NULL) {
                /* we've never heard of this, so I guess we
                 * haven't implemented it.
                 * Handle gracefully for future expansion
                 * and platform / vendor expansion.
                 */
                outStream_setError(&out, JDWP_ERROR(NOT_IMPLEMENTED));
            } else if (gdata->vmDead &&
             ((cmd->cmdSet) != JDWP_COMMAND_SET(VirtualMachine))) {
                /* Protect the VM from calls while dead.
                 * VirtualMachine cmdSet quietly ignores some cmds
                 * after VM death, so, it sends it's own errors.
                 */
                outStream_setError(&out, JDWP_ERROR(VM_DEAD));
            } else {
                /* Call the command handler */
                replyToSender = func(&in, &out);
            }

            /* Reply to the sender */
            if (replyToSender) {
                if (inStream_error(&in)) {
                    outStream_setError(&out, inStream_error(&in));
                }
                outStream_sendReply(&out);
            }

            /*
             * Release the resumeLock as the reply has been posted.
             */
            if (resumeCommand(cmd)) {
                debugMonitorExit(resumeLock);
            }

            inStream_destroy(&in);
            outStream_destroy(&out);

            shouldListen = !lastCommand(cmd);
        }
    }
    threadControl_onDisconnect();
    standardHandlers_onDisconnect();

    /*
     * Cut off the transport immediately. This has the effect of
     * cutting off any events that the eventHelper thread might
     * be trying to send.
     */
    transport_close();
    debugMonitorDestroy(cmdQueueLock);

    /* Reset for a new connection to this VM if it's still alive */
    if ( ! gdata->vmDead ) {
        debugInit_reset(getEnv());
    }
}
Ejemplo n.º 30
0
void 
eventHelper_unlock(void)
{
    debugMonitorExit(commandCompleteLock);
    debugMonitorExit(commandQueueLock);
}