/** * Terminates and cleans up resources allocated by the DBGF. * * @returns VBox status code. * @param pVM Pointer to the VM. */ VMMR3DECL(int) DBGFR3Term(PVM pVM) { int rc; /* * Send a termination event to any attached debugger. */ /* wait to become the speaker (we should already be that). */ if ( pVM->dbgf.s.fAttached && RTSemPingShouldWait(&pVM->dbgf.s.PingPong)) RTSemPingWait(&pVM->dbgf.s.PingPong, 5000); /* now, send the event if we're the speaker. */ if ( pVM->dbgf.s.fAttached && RTSemPingIsSpeaker(&pVM->dbgf.s.PingPong)) { DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND); if (enmCmd == DBGFCMD_DETACH_DEBUGGER) /* the debugger beat us to initiating the detaching. */ rc = VINF_SUCCESS; else { /* ignore the command (if any). */ enmCmd = DBGFCMD_NO_COMMAND; pVM->dbgf.s.DbgEvent.enmType = DBGFEVENT_TERMINATING; pVM->dbgf.s.DbgEvent.enmCtx = DBGFEVENTCTX_OTHER; rc = RTSemPing(&pVM->dbgf.s.PingPong); } /* * Process commands until we get a detached command. */ while (RT_SUCCESS(rc) && enmCmd != DBGFCMD_DETACHED_DEBUGGER) { if (enmCmd != DBGFCMD_NO_COMMAND) { /* process command */ bool fResumeExecution; DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData; rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution); enmCmd = DBGFCMD_NO_COMMAND; } else { /* wait for new command. */ rc = RTSemPingWait(&pVM->dbgf.s.PingPong, RT_INDEFINITE_WAIT); if (RT_SUCCESS(rc)) enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND); } } } /* * Terminate the other bits. */ dbgfR3OSTerm(pVM); dbgfR3AsTerm(pVM); dbgfR3RegTerm(pVM); dbgfR3TraceTerm(pVM); dbgfR3InfoTerm(pVM); return VINF_SUCCESS; }
/** * Waits for the debugger to respond. * * @returns VBox status. (clearify) * @param pVM Pointer to the VM. */ static int dbgfR3VMMWait(PVM pVM) { PVMCPU pVCpu = VMMGetCpu(pVM); LogFlow(("dbgfR3VMMWait:\n")); /** @todo stupid GDT/LDT sync hack. go away! */ SELMR3UpdateFromCPUM(pVM, pVCpu); int rcRet = VINF_SUCCESS; /* * Waits for the debugger to reply (i.e. issue an command). */ for (;;) { /* * Wait. */ uint32_t cPollHack = 1; /** @todo this interface is horrible now that we're using lots of VMR3ReqCall stuff all over DBGF. */ for (;;) { int rc; if ( !VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_REQUEST) && !VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_REQUEST)) { rc = RTSemPingWait(&pVM->dbgf.s.PingPong, cPollHack); if (RT_SUCCESS(rc)) break; if (rc != VERR_TIMEOUT) { LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc)); return rc; } } if (VM_FF_ISPENDING(pVM, VM_FF_EMT_RENDEZVOUS)) { rc = VMMR3EmtRendezvousFF(pVM, pVCpu); cPollHack = 1; } else if ( VM_FF_ISPENDING(pVM, VM_FF_REQUEST) || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_REQUEST)) { LogFlow(("dbgfR3VMMWait: Processes requests...\n")); rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, false /*fPriorityOnly*/); if (rc == VINF_SUCCESS) rc = VMR3ReqProcessU(pVM->pUVM, pVCpu->idCpu, false /*fPriorityOnly*/); LogFlow(("dbgfR3VMMWait: VMR3ReqProcess -> %Rrc rcRet=%Rrc\n", rc, rcRet)); cPollHack = 1; } else { rc = VINF_SUCCESS; if (cPollHack < 120) cPollHack++; } if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST) { switch (rc) { case VINF_EM_DBG_BREAKPOINT: case VINF_EM_DBG_STEPPED: case VINF_EM_DBG_STEP: case VINF_EM_DBG_STOP: AssertMsgFailed(("rc=%Rrc\n", rc)); break; /* return straight away */ case VINF_EM_TERMINATE: case VINF_EM_OFF: LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc)); return rc; /* remember return code. */ default: AssertReleaseMsgFailed(("rc=%Rrc is not in the switch!\n", rc)); case VINF_EM_RESET: case VINF_EM_SUSPEND: case VINF_EM_HALT: case VINF_EM_RESUME: case VINF_EM_RESCHEDULE: case VINF_EM_RESCHEDULE_REM: case VINF_EM_RESCHEDULE_RAW: if (rc < rcRet || rcRet == VINF_SUCCESS) rcRet = rc; break; } } else if (RT_FAILURE(rc)) { LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rc)); return rc; } } /* * Process the command. */ bool fResumeExecution; DBGFCMDDATA CmdData = pVM->dbgf.s.VMMCmdData; DBGFCMD enmCmd = dbgfR3SetCmd(pVM, DBGFCMD_NO_COMMAND); int rc = dbgfR3VMMCmd(pVM, enmCmd, &CmdData, &fResumeExecution); if (fResumeExecution) { if (RT_FAILURE(rc)) rcRet = rc; else if ( rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST && (rc < rcRet || rcRet == VINF_SUCCESS)) rcRet = rc; LogFlow(("dbgfR3VMMWait: returns %Rrc\n", rcRet)); return rcRet; } } }
int main() { RTR3Init(); /* * Create a ping pong and kick off a second thread which we'll * exchange TSTSEMPINGPONG_ITERATIONS messages with. */ RTPINGPONG PingPong; int rc = RTSemPingPongInit(&PingPong); if (RT_FAILURE(rc)) { RTPrintf("tstSemPingPong: FATAL ERROR - RTSemPingPongInit -> %Rrc\n", rc); return 1; } RTTHREAD hThread; rc = RTThreadCreate(&hThread, tstSemPingPongThread, &PingPong, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "PONG"); if (RT_FAILURE(rc)) { RTPrintf("tstSemPingPong: FATAL ERROR - RTSemPingPongInit -> %Rrc\n", rc); return 1; } RTPrintf("tstSemPingPong: TESTING - %u iterations...\n", TSTSEMPINGPONG_ITERATIONS); for (uint32_t i = 0; i < TSTSEMPINGPONG_ITERATIONS; i++) { if (!RTSemPingIsSpeaker(&PingPong)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingIsSpeaker returned false before RTSemPing.\n"); } rc = RTSemPing(&PingPong); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPing -> %Rrc\n", rc); break; } if (!RTSemPingShouldWait(&PingPong)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingShouldWait returned false before RTSemPingWait.\n"); } rc = RTSemPingWait(&PingPong, RT_INDEFINITE_WAIT); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingWait -> %Rrc\n", rc); break; } } int rcThread; rc = RTThreadWait(hThread, 5000, &rcThread); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingWait -> %Rrc\n", rc); } rc = RTSemPingPongDelete(&PingPong); if (RT_FAILURE(rc)) { ASMAtomicIncU32(&g_cErrors); RTPrintf("tstSemPingPong: ERROR - RTSemPingPongDestroy -> %Rrc\n", rc); } /* * Summary. */ uint32_t cErrors = ASMAtomicUoReadU32(&g_cErrors); if (cErrors) RTPrintf("tstSemPingPong: FAILED - %d errors\n", cErrors); else RTPrintf("tstSemPingPong: SUCCESS\n"); return cErrors ? 1 : 0; }