/** * Attempts to alter the priority of the current process. * * The scheduling attributes are targeted at threads and they are protected * by the thread read-write semaphore, that's why RTProc is forwarding the * operation to RTThread. This operation also involves updating all thread * which is much faster done from RTThread. * * @returns iprt status code. * @param enmPriority The new priority. */ DECLHIDDEN(int) rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority) { LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority)); /* * First validate that we're allowed by the OS to use all the * scheduling attributes defined by the specified process priority. */ RT_THREAD_LOCK_RW(); int rc = rtProcNativeSetPriority(enmPriority); if (RT_SUCCESS(rc)) { /* * Update the priority of existing thread. */ rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL); if (RT_SUCCESS(rc)) ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority); else { /* * Failed, restore the priority. */ rtProcNativeSetPriority(g_enmProcessPriority); RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL); } } RT_THREAD_UNLOCK_RW(); LogFlow(("rtThreadDoSetProcPriority: returns %Rrc\n", rc)); return rc; }
/** * Stops the service. * * @returns VBox status. */ int USBProxyService::stop(void) { int rc = VINF_SUCCESS; if (mThread != NIL_RTTHREAD) { /* * Mark the thread for termination and kick it. */ ASMAtomicXchgSize(&mTerminate, true); rc = interruptWait(); AssertRC(rc); /* * Wait for the thread to finish and then update the state. */ rc = RTThreadWait(mThread, 60000, NULL); if (rc == VERR_INVALID_HANDLE) rc = VINF_SUCCESS; if (RT_SUCCESS(rc)) { LogFlowThisFunc(("stopped mThread=%RTthrd\n", mThread)); mThread = NIL_RTTHREAD; mTerminate = false; } else { AssertRC(rc); mLastError = rc; } } else LogFlowThisFunc(("not active\n")); return rc; }
RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem) { /* * Validate input. */ struct RTSEMEVENTINTERNAL *pThis = hEventSem; if (pThis == NIL_RTSEMEVENT) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->iMagic == RTSEMEVENT_MAGIC, VERR_INVALID_HANDLE); /* * Invalidate the semaphore and wake up anyone waiting on it. */ ASMAtomicXchgSize(&pThis->iMagic, RTSEMEVENT_MAGIC | UINT32_C(0x80000000)); if (ASMAtomicXchgS32(&pThis->cWaiters, INT32_MIN / 2) > 0) { sys_futex(&pThis->fSignalled, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); usleep(1000); } /* * Free the semaphore memory and be gone. */ #ifdef RTSEMEVENT_STRICT RTLockValidatorRecSharedDelete(&pThis->Signallers); #endif if (!(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)) RTMemFree(pThis); else rtMemBaseFree(pThis); return VINF_SUCCESS; }
RTDECL(int) RTReqWait(PRTREQ hReq, RTMSINTERVAL cMillies) { LogFlow(("RTReqWait: hReq=%p cMillies=%d\n", hReq, cMillies)); /* * Verify the supplied package. */ PRTREQINT pReq = hReq; AssertPtrReturn(pReq, VERR_INVALID_HANDLE); AssertReturn(pReq->u32Magic == RTREQ_MAGIC, VERR_INVALID_HANDLE); AssertMsgReturn( pReq->enmState != RTREQSTATE_QUEUED || pReq->enmState != RTREQSTATE_PROCESSING || pReq->enmState != RTREQSTATE_COMPLETED, ("Invalid state %d\n", pReq->enmState), VERR_RT_REQUEST_STATE); AssertMsgReturn(pReq->uOwner.hQueue && pReq->EventSem != NIL_RTSEMEVENT, ("Invalid request package! Anyone cooking their own packages???\n"), VERR_RT_REQUEST_INVALID_PACKAGE); AssertMsgReturn(pReq->enmType > RTREQTYPE_INVALID && pReq->enmType < RTREQTYPE_MAX, ("Invalid package type %d valid range %d-%d inclusively. This was verified on alloc too...\n", pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1), VERR_RT_REQUEST_INVALID_TYPE); /* * Wait on the package. */ int rc; if (cMillies != RT_INDEFINITE_WAIT) rc = RTSemEventWait(pReq->EventSem, cMillies); else { do { rc = RTSemEventWait(pReq->EventSem, RT_INDEFINITE_WAIT); Assert(rc != VERR_TIMEOUT); } while (pReq->enmState != RTREQSTATE_COMPLETED); } if (rc == VINF_SUCCESS) ASMAtomicXchgSize(&pReq->fEventSemClear, true); if (pReq->enmState == RTREQSTATE_COMPLETED) rc = VINF_SUCCESS; LogFlow(("RTReqWait: returns %Rrc\n", rc)); Assert(rc != VERR_INTERRUPTED); Assert(pReq->cRefs >= 1); return rc; }
/** * Changes the type of the specified thread. * * @returns iprt status code. * @param Thread The thread which type should be changed. * @param enmType The new thread type. */ RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType) { /* * Validate input. */ int rc; if ( enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END) { PRTTHREADINT pThread = rtThreadGet(Thread); if (pThread) { if (rtThreadIsAlive(pThread)) { /* * Do the job. */ RT_THREAD_LOCK_RW(); rc = rtThreadNativeSetPriority(pThread, enmType); if (RT_SUCCESS(rc)) ASMAtomicXchgSize(&pThread->enmType, enmType); RT_THREAD_UNLOCK_RW(); if (RT_FAILURE(rc)) Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc)); } else rc = VERR_THREAD_IS_DEAD; rtThreadRelease(pThread); } else rc = VERR_INVALID_HANDLE; } else { AssertMsgFailed(("enmType=%d\n", enmType)); rc = VERR_INVALID_PARAMETER; } return rc; }
/** * Process one request. * * @returns IPRT status code. * * @param pReq Request packet to process. */ DECLHIDDEN(int) rtReqProcessOne(PRTREQINT pReq) { LogFlow(("rtReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags)); /* * Process the request. */ Assert(pReq->enmState == RTREQSTATE_QUEUED); pReq->enmState = RTREQSTATE_PROCESSING; int rcRet = VINF_SUCCESS; /* the return code of this function. */ int rcReq = VERR_NOT_IMPLEMENTED; /* the request status. */ switch (pReq->enmType) { /* * A packed down call frame. */ case RTREQTYPE_INTERNAL: { uintptr_t *pauArgs = &pReq->u.Internal.aArgs[0]; union { PFNRT pfn; DECLCALLBACKMEMBER(int, pfn00)(void); DECLCALLBACKMEMBER(int, pfn01)(uintptr_t); DECLCALLBACKMEMBER(int, pfn02)(uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn03)(uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn04)(uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn05)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn06)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn07)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn08)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn09)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn10)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn11)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); DECLCALLBACKMEMBER(int, pfn12)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); } u; u.pfn = pReq->u.Internal.pfn; #ifndef RT_ARCH_X86 switch (pReq->u.Internal.cArgs) { case 0: rcRet = u.pfn00(); break; case 1: rcRet = u.pfn01(pauArgs[0]); break; case 2: rcRet = u.pfn02(pauArgs[0], pauArgs[1]); break; case 3: rcRet = u.pfn03(pauArgs[0], pauArgs[1], pauArgs[2]); break; case 4: rcRet = u.pfn04(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3]); break; case 5: rcRet = u.pfn05(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4]); break; case 6: rcRet = u.pfn06(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5]); break; case 7: rcRet = u.pfn07(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6]); break; case 8: rcRet = u.pfn08(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7]); break; case 9: rcRet = u.pfn09(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8]); break; case 10: rcRet = u.pfn10(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9]); break; case 11: rcRet = u.pfn11(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10]); break; case 12: rcRet = u.pfn12(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10], pauArgs[11]); break; default: AssertReleaseMsgFailed(("cArgs=%d\n", pReq->u.Internal.cArgs)); rcRet = rcReq = VERR_INTERNAL_ERROR; break; } #else /* RT_ARCH_X86 */ size_t cbArgs = pReq->u.Internal.cArgs * sizeof(uintptr_t); # ifdef __GNUC__ __asm__ __volatile__("movl %%esp, %%edx\n\t" "subl %2, %%esp\n\t" "andl $0xfffffff0, %%esp\n\t" "shrl $2, %2\n\t" "movl %%esp, %%edi\n\t" "rep movsl\n\t" "movl %%edx, %%edi\n\t" "call *%%eax\n\t" "mov %%edi, %%esp\n\t" : "=a" (rcRet), "=S" (pauArgs), "=c" (cbArgs) : "0" (u.pfn), "1" (pauArgs), "2" (cbArgs) : "edi", "edx"); # else __asm { xor edx, edx /* just mess it up. */ mov eax, u.pfn mov ecx, cbArgs shr ecx, 2 mov esi, pauArgs mov ebx, esp sub esp, cbArgs and esp, 0xfffffff0 mov edi, esp rep movsd call eax mov esp, ebx mov rcRet, eax } # endif #endif /* RT_ARCH_X86 */ if ((pReq->fFlags & (RTREQFLAGS_RETURN_MASK)) == RTREQFLAGS_VOID) rcRet = VINF_SUCCESS; rcReq = rcRet; break; } default: AssertMsgFailed(("pReq->enmType=%d\n", pReq->enmType)); rcReq = VERR_NOT_IMPLEMENTED; break; } /* * Complete the request and then release our request handle reference. */ pReq->iStatusX = rcReq; pReq->enmState = RTREQSTATE_COMPLETED; if (pReq->fFlags & RTREQFLAGS_NO_WAIT) LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc (no wait)\n", pReq, rcReq, rcRet)); else { /* Notify the waiting thread. */ LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - notifying waiting thread\n", pReq, rcReq, rcRet)); ASMAtomicXchgSize(&pReq->fEventSemClear, false); int rc2 = RTSemEventSignal(pReq->EventSem); if (rc2 != VINF_SUCCESS) { AssertRC(rc2); rcRet = rc2; } } RTReqRelease(pReq); return rcRet; }
/** * The PDM thread function. * * @returns return from pfnThread. * * @param Thread The thread handle. * @param pvUser Pointer to the PDMTHREAD structure. */ static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser) { PPDMTHREAD pThread = (PPDMTHREAD)pvUser; Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread))); pThread->Thread = Thread; PUVM pUVM = pThread->Internal.s.pVM->pUVM; if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtInit) pUVM->pVmm2UserMethods->pfnNotifyPdmtInit(pUVM->pVmm2UserMethods, pUVM); /* * The run loop. * * It handles simple thread functions which returns when they see a suspending * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning * parts to us. */ int rc; for (;;) { switch (pThread->Internal.s.enmType) { case PDMTHREADTYPE_DEVICE: rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread); break; case PDMTHREADTYPE_USB: rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread); break; case PDMTHREADTYPE_DRIVER: rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread); break; case PDMTHREADTYPE_INTERNAL: rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread); break; case PDMTHREADTYPE_EXTERNAL: rc = pThread->u.Ext.pfnThread(pThread); break; default: AssertMsgFailed(("%d\n", pThread->Internal.s.enmType)); rc = VERR_PDM_THREAD_IPE_1; break; } if (RT_FAILURE(rc)) break; /* * If this is a simple thread function, the state will be suspending * or initializing now. If it isn't we're supposed to terminate. */ if ( pThread->enmState != PDMTHREADSTATE_SUSPENDING && pThread->enmState != PDMTHREADSTATE_INITIALIZING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmSuspending(pThread); if (RT_FAILURE(rc)) break; if (pThread->enmState != PDMTHREADSTATE_RESUMING) { Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING); break; } rc = PDMR3ThreadIAmRunning(pThread); if (RT_FAILURE(rc)) break; } if (RT_FAILURE(rc)) LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc)); /* * Advance the state to terminating and then on to terminated. */ for (;;) { PDMTHREADSTATE enmState = pThread->enmState; if ( enmState == PDMTHREADSTATE_TERMINATING || pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState)) break; } ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED); int rc2 = RTThreadUserSignal(Thread); AssertRC(rc2); if ( pUVM->pVmm2UserMethods && pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm) pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm(pUVM->pVmm2UserMethods, pUVM); Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc)); return rc; }