RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem) { PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; if (pThis == NIL_RTSEMEVENTMULTI) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); KernAcquireSpinLock(&pThis->Spinlock); ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */ if (pThis->cWaiters > 0) { /* abort waiting thread, last man cleans up. */ ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters); ULONG cThreads; KernWakeup((ULONG)pThis, WAKEUP_DATA | WAKEUP_BOOST, &cThreads, (ULONG)VERR_SEM_DESTROYED); KernReleaseSpinLock(&pThis->Spinlock); } else if (pThis->cWaking) /* the last waking thread is gonna do the cleanup */ KernReleaseSpinLock(&pThis->Spinlock); else { KernReleaseSpinLock(&pThis->Spinlock); KernFreeSpinLock(&pThis->Spinlock); RTMemFree(pThis); } return VINF_SUCCESS; }
/** * Get the message corresponding to a given status code. * * @returns Pointer to read-only message description. * @param rc The status code. */ RTDECL(PCRTSTATUSMSG) RTErrGet(int rc) { unsigned iFound = ~0; unsigned i; for (i = 0; i < RT_ELEMENTS(g_aStatusMsgs) - 1; i++) { if (g_aStatusMsgs[i].iCode == rc) { /* * Found a match. * Since this isn't a unique key, we must check that it's not * one of those start/end #defines before we return. */ #define STR_ENDS_WITH(a_psz, a_cch, a_sz) \ ( (a_cch) >= sizeof(a_sz) && !strncmp((a_psz) + (a_cch) - sizeof(a_sz) + 1, RT_STR_TUPLE(a_sz)) ) size_t const cchDefine = strlen(g_aStatusMsgs[i].pszDefine); if ( !STR_ENDS_WITH(g_aStatusMsgs[i].pszDefine, cchDefine, "_FIRST") && !STR_ENDS_WITH(g_aStatusMsgs[i].pszDefine, cchDefine, "_LAST") && !STR_ENDS_WITH(g_aStatusMsgs[i].pszDefine, cchDefine, "_LOWEST") && !STR_ENDS_WITH(g_aStatusMsgs[i].pszDefine, cchDefine, "_HIGHEST") ) return &g_aStatusMsgs[i]; iFound = i; } } if (iFound != ~0U) return &g_aStatusMsgs[iFound]; /* * Need to use the temporary stuff. */ int iMsg = ASMAtomicXchgU32(&g_iUnknownMsgs, (g_iUnknownMsgs + 1) % RT_ELEMENTS(g_aUnknownMsgs)); RTStrPrintf(&g_aszUnknownStr[iMsg][0], sizeof(g_aszUnknownStr[iMsg]), "Unknown Status %d (%#x)", rc, rc); return &g_aUnknownMsgs[iMsg]; }
/** * Get the message corresponding to a given status code. * * @returns Pointer to read-only message description. * @param rc The status code. */ RTDECL(PCRTSTATUSMSG) RTErrGet(int rc) { unsigned iFound = ~0; unsigned i; for (i = 0; i < RT_ELEMENTS(g_aStatusMsgs); i++) { if (g_aStatusMsgs[i].iCode == rc) { /* * Found a match. * Since this isn't a unique key, we must check that it's not * one of those start/end #defines before we return. */ if ( !strstr(g_aStatusMsgs[i].pszDefine, "FIRST") && !strstr(g_aStatusMsgs[i].pszDefine, "LAST")) return &g_aStatusMsgs[i]; iFound = i; } } if (iFound != ~0U) return &g_aStatusMsgs[iFound]; /* * Need to use the temporary stuff. */ int iMsg = ASMAtomicXchgU32(&g_iUnknownMsgs, (g_iUnknownMsgs + 1) % RT_ELEMENTS(g_aUnknownMsgs)); RTStrPrintf(&g_aszUnknownStr[iMsg][0], sizeof(g_aszUnknownStr[iMsg]), "Unknown Status 0x%X", rc); return &g_aUnknownMsgs[iMsg]; }
RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem) { /* * Validate input. */ struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); uint32_t u32 = pThis->u32State; AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE); #ifdef RTSEMEVENTMULTI_STRICT if (pThis->fEverHadSignallers) { int rc9 = RTLockValidatorRecSharedCheckSignaller(&pThis->Signallers, NIL_RTTHREAD); if (RT_FAILURE(rc9)) return rc9; } #endif /* * Lock the mutex semaphore. */ int rc = pthread_mutex_lock(&pThis->Mutex); if (rc) { AssertMsgFailed(("Failed to lock event sem %p, rc=%d.\n", hEventMultiSem, rc)); return RTErrConvertFromErrno(rc); } /* * Check the state. */ if (pThis->u32State == EVENTMULTI_STATE_NOT_SIGNALED) { ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_SIGNALED); rc = pthread_cond_broadcast(&pThis->Cond); AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d.\n", hEventMultiSem, rc)); } else if (pThis->u32State == EVENTMULTI_STATE_SIGNALED) { rc = pthread_cond_broadcast(&pThis->Cond); /* give'm another kick... */ AssertMsg(!rc, ("Failed to signal event sem %p, rc=%d. (2)\n", hEventMultiSem, rc)); } else rc = VERR_SEM_DESTROYED; /* * Release the mutex and return. */ int rc2 = pthread_mutex_unlock(&pThis->Mutex); AssertMsg(!rc2, ("Failed to unlock event sem %p, rc=%d.\n", hEventMultiSem, rc)); if (rc) return RTErrConvertFromErrno(rc); if (rc2) return RTErrConvertFromErrno(rc2); return VINF_SUCCESS; }
/** * I/O thread for the memory backend. * * @returns IPRT status code. * * @param hThread The thread handle. * @param pvUser Opaque user data. */ static int vdIoBackendMemThread(RTTHREAD hThread, void *pvUser) { PVDIOBACKENDMEM pIoBackend = (PVDIOBACKENDMEM)pvUser; while (pIoBackend->fRunning) { int rc = RTSemEventWait(pIoBackend->EventSem, RT_INDEFINITE_WAIT); if (RT_FAILURE(rc) || !pIoBackend->fRunning) break; PVDIOBACKENDREQ pReq; PPVDIOBACKENDREQ ppReq; size_t cbData; uint32_t cReqsWaiting = ASMAtomicXchgU32(&pIoBackend->cReqsWaiting, 0); while (cReqsWaiting) { int rcReq = VINF_SUCCESS; /* Do we have another request? */ RTCircBufAcquireReadBlock(pIoBackend->pRequestRing, sizeof(PVDIOBACKENDREQ), (void **)&ppReq, &cbData); Assert(!ppReq || cbData == sizeof(PVDIOBACKENDREQ)); RTCircBufReleaseReadBlock(pIoBackend->pRequestRing, cbData); pReq = *ppReq; cReqsWaiting--; LogFlowFunc(("Processing request\n")); switch (pReq->enmTxDir) { case VDIOTXDIR_READ: { RTSGBUF SgBuf; RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs); rcReq = VDMemDiskRead(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf); break; } case VDIOTXDIR_WRITE: { RTSGBUF SgBuf; RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs); rcReq = VDMemDiskWrite(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf); break; } case VDIOTXDIR_FLUSH: break; default: AssertMsgFailed(("Invalid TX direction!\n")); } /* Notify completion. */ pReq->pfnComplete(pReq->pvUser, rcReq); RTMemFree(pReq); } } return VINF_SUCCESS; }
RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem) { /* * Validate handle. */ struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem; if (pThis == NIL_RTSEMEVENTMULTI) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); uint32_t u32 = pThis->u32State; AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE); /* * Abort all waiters forcing them to return failure. */ int rc; for (int i = 30; i > 0; i--) { ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_UNINITIALIZED); rc = pthread_cond_destroy(&pThis->Cond); if (rc != EBUSY) break; pthread_cond_broadcast(&pThis->Cond); usleep(1000); } if (rc) { AssertMsgFailed(("Failed to destroy event sem %p, rc=%d.\n", hEventMultiSem, rc)); return RTErrConvertFromErrno(rc); } /* * Destroy the semaphore * If it's busy we'll wait a bit to give the threads a chance to be scheduled. */ for (int i = 30; i > 0; i--) { rc = pthread_mutex_destroy(&pThis->Mutex); if (rc != EBUSY) break; usleep(1000); } if (rc) { AssertMsgFailed(("Failed to destroy event sem %p, rc=%d. (mutex)\n", hEventMultiSem, rc)); return RTErrConvertFromErrno(rc); } /* * Free the semaphore memory and be gone. */ #ifdef RTSEMEVENTMULTI_STRICT RTLockValidatorRecSharedDelete(&pThis->Signallers); #endif RTMemFree(pThis); return VINF_SUCCESS; }
/** * Sets the VMM Debug Command variable. * * @returns Previous command. * @param pVM Pointer to the VM. * @param enmCmd The command. */ DECLINLINE(DBGFCMD) dbgfR3SetCmd(PVM pVM, DBGFCMD enmCmd) { DBGFCMD rc; if (enmCmd == DBGFCMD_NO_COMMAND) { Log2(("DBGF: Setting command to %d (DBGFCMD_NO_COMMAND)\n", enmCmd)); rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd); VM_FF_CLEAR(pVM, VM_FF_DBGF); } else { Log2(("DBGF: Setting command to %d\n", enmCmd)); AssertMsg(pVM->dbgf.s.enmVMMCmd == DBGFCMD_NO_COMMAND, ("enmCmd=%d enmVMMCmd=%d\n", enmCmd, pVM->dbgf.s.enmVMMCmd)); rc = (DBGFCMD)ASMAtomicXchgU32((uint32_t volatile *)(void *)&pVM->dbgf.s.enmVMMCmd, enmCmd); VM_FF_SET(pVM, VM_FF_DBGF); VMR3NotifyGlobalFFU(pVM->pUVM, 0 /* didn't notify REM */); } return rc; }
/** * Destroys the per thread data. * * @param pThread The thread to destroy. */ static void rtThreadDestroy(PRTTHREADINT pThread) { RTSEMEVENTMULTI hEvt1, hEvt2; /* * Remove it from the tree and mark it as dead. * * Threads that has seen rtThreadTerminate and should already have been * removed from the tree. There is probably no thread that should * require removing here. However, be careful making sure that cRefs * isn't 0 if we do or we'll blow up because the strict locking code * will be calling us back. */ if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT)) { ASMAtomicIncU32(&pThread->cRefs); rtThreadRemove(pThread); ASMAtomicDecU32(&pThread->cRefs); } /* * Invalidate the thread structure. */ #ifdef IN_RING3 rtLockValidatorSerializeDestructEnter(); rtLockValidatorDeletePerThread(&pThread->LockValidator); #endif #ifdef RT_WITH_ICONV_CACHE rtStrIconvCacheDestroy(pThread); #endif ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD); ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD); pThread->enmType = RTTHREADTYPE_INVALID; hEvt1 = pThread->EventUser; pThread->EventUser = NIL_RTSEMEVENTMULTI; hEvt2 = pThread->EventTerminated; pThread->EventTerminated = NIL_RTSEMEVENTMULTI; #ifdef IN_RING3 rtLockValidatorSerializeDestructLeave(); #endif /* * Destroy semaphore resources and free the bugger. */ RTSemEventMultiDestroy(hEvt1); if (hEvt2 != NIL_RTSEMEVENTMULTI) RTSemEventMultiDestroy(hEvt2); rtThreadNativeDestroy(pThread); RTMemFree(pThread); }
RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem) { PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); KernAcquireSpinLock(&pThis->Spinlock); ASMAtomicXchgU8(&pThis->fSignaled, true); if (pThis->cWaiters > 0) { ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters); ASMAtomicXchgU32(&pThis->cWaiters, 0); ULONG cThreads; KernWakeup((ULONG)pThis, WAKEUP_DATA, &cThreads, VINF_SUCCESS); } KernReleaseSpinLock(&pThis->Spinlock); return VINF_SUCCESS; }
RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx) { PRTSEMFASTMUTEXINTERNAL pThis = hFastMtx; if (pThis == NIL_RTSEMFASTMUTEX) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE); RT_ASSERT_INTS_ON(); ASMAtomicXchgU32(&pThis->u32Magic, RTSEMFASTMUTEX_MAGIC_DEAD); rw_destroy(&pThis->Mtx); RTMemFree(pThis); return VINF_SUCCESS; }
RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem) { /* * Validate input. */ int rc = VINF_SUCCESS; struct RTSEMEVENTMULTIINTERNAL *pThis = hEventMultiSem; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); uint32_t u32 = pThis->u32State; AssertReturn(u32 == EVENTMULTI_STATE_NOT_SIGNALED || u32 == EVENTMULTI_STATE_SIGNALED, VERR_INVALID_HANDLE); /* * Lock the mutex semaphore. */ int rcPosix = pthread_mutex_lock(&pThis->Mutex); if (RT_UNLIKELY(rcPosix)) { AssertMsgFailed(("Failed to lock event multi sem %p, rc=%d.\n", hEventMultiSem, rcPosix)); return RTErrConvertFromErrno(rcPosix); } /* * Check the state. */ if (pThis->u32State == EVENTMULTI_STATE_SIGNALED) ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED); else if (pThis->u32State != EVENTMULTI_STATE_NOT_SIGNALED) rc = VERR_SEM_DESTROYED; /* * Release the mutex and return. */ rcPosix = pthread_mutex_unlock(&pThis->Mutex); if (RT_UNLIKELY(rcPosix)) { AssertMsgFailed(("Failed to unlock event multi sem %p, rc=%d.\n", hEventMultiSem, rcPosix)); return RTErrConvertFromErrno(rcPosix); } return rc; }
/** * Called the first time somebody asks for the time or when the GIP * is mapped/unmapped. */ static DECLCALLBACK(uint64_t) rtTimeNanoTSInternalRediscover(PRTTIMENANOTSDATA pData) { uint32_t iWorker; PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; if ( pGip && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC && ( pGip->u32Mode == SUPGIPMODE_SYNC_TSC || pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)) { if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2) iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? RTTIMENANO_WORKER_SYNC_LFENCE : RTTIMENANO_WORKER_ASYNC_LFENCE; else iWorker = pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? RTTIMENANO_WORKER_SYNC_CPUID : RTTIMENANO_WORKER_ASYNC_CPUID; } else iWorker = RTTIMENANO_WORKER_FALLBACK; ASMAtomicXchgU32((uint32_t volatile *)&g_iWorker, iWorker); return g_apfnWorkers[iWorker](pData); }
/** * DPC handler. * * @param pDPC DPC descriptor. * @param pDevObj Device object. * @param pIrp Interrupt request packet. * @param pContext Context specific pointer. */ void vboxguestwinDpcHandler(PKDPC pDPC, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVOID pContext) { PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension; Log(("VBoxGuest::vboxguestwinGuestDpcHandler: pDevExt=0x%p\n", pDevExt)); /* test & reset the counter */ if (ASMAtomicXchgU32(&pDevExt->u32MousePosChangedSeq, 0)) { Assert(KeGetCurrentIrql() == DISPATCH_LEVEL); /* we need a lock here to avoid concurrency with the set event ioctl handler thread, * i.e. to prevent the event from destroyed while we're using it */ KeAcquireSpinLockAtDpcLevel(&pDevExt->win.s.MouseEventAccessLock); if (pDevExt->win.s.pfnMouseNotify) { pDevExt->win.s.pfnMouseNotify(pDevExt->win.s.pvMouseNotify); } KeReleaseSpinLockFromDpcLevel(&pDevExt->win.s.MouseEventAccessLock); } /* Process the wake-up list we were asked by the scheduling a DPC * in vboxguestwinIsrHandler(). */ VBoxGuestWaitDoWakeUps(pDevExt); }
void pdmacFileEpTaskCompleted(PPDMACTASKFILE pTask, void *pvUser, int rc) { PPDMASYNCCOMPLETIONTASKFILE pTaskFile = (PPDMASYNCCOMPLETIONTASKFILE)pvUser; LogFlowFunc(("pTask=%#p pvUser=%#p rc=%Rrc\n", pTask, pvUser, rc)); if (pTask->enmTransferType == PDMACTASKFILETRANSFER_FLUSH) { pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, rc, true); } else { Assert((uint32_t)pTask->DataSeg.cbSeg == pTask->DataSeg.cbSeg && (int32_t)pTask->DataSeg.cbSeg >= 0); uint32_t uOld = ASMAtomicSubS32(&pTaskFile->cbTransferLeft, (int32_t)pTask->DataSeg.cbSeg); /* The first error will be returned. */ if (RT_FAILURE(rc)) ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS); #ifdef VBOX_WITH_DEBUGGER else { PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pTaskFile->Core.pEndpoint; /* Overwrite with injected error code. */ if (pTask->enmTransferType == PDMACTASKFILETRANSFER_READ) rc = ASMAtomicXchgS32(&pEpFile->rcReqRead, VINF_SUCCESS); else rc = ASMAtomicXchgS32(&pEpFile->rcReqWrite, VINF_SUCCESS); if (RT_FAILURE(rc)) ASMAtomicCmpXchgS32(&pTaskFile->rc, rc, VINF_SUCCESS); } #endif if (!(uOld - pTask->DataSeg.cbSeg) && !ASMAtomicXchgBool(&pTaskFile->fCompleted, true)) { #ifdef PDM_ASYNC_COMPLETION_FILE_WITH_DELAY PPDMASYNCCOMPLETIONENDPOINTFILE pEpFile = (PPDMASYNCCOMPLETIONENDPOINTFILE)pTaskFile->Core.pEndpoint; /* Check if we should delay completion of the request. */ if ( ASMAtomicReadU32(&pEpFile->msDelay) > 0 && ASMAtomicCmpXchgPtr(&pEpFile->pReqDelayed, pTaskFile, NULL)) { /* Arm the delay. */ pEpFile->tsDelayEnd = RTTimeProgramMilliTS() + pEpFile->msDelay; LogRel(("AIOMgr: Delaying request %#p for %u ms\n", pTaskFile, pEpFile->msDelay)); return; } #endif pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, pTaskFile->rc, true); #if PDM_ASYNC_COMPLETION_FILE_WITH_DELAY /* Check for an expired delay. */ if ( pEpFile->pReqDelayed != NULL && RTTimeProgramMilliTS() >= pEpFile->tsDelayEnd) { pTaskFile = ASMAtomicXchgPtrT(&pEpFile->pReqDelayed, NULL, PPDMASYNCCOMPLETIONTASKFILE); ASMAtomicXchgU32(&pEpFile->msDelay, 0); LogRel(("AIOMgr: Delayed request %#p completed\n", pTaskFile)); pdmR3AsyncCompletionCompleteTask(&pTaskFile->Core, pTaskFile->rc, true); } #endif } } }
RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...) { AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER); /* * Allocate semaphore handle. */ int rc; struct RTSEMEVENTMULTIINTERNAL *pThis = (struct RTSEMEVENTMULTIINTERNAL *)RTMemAlloc(sizeof(struct RTSEMEVENTMULTIINTERNAL)); if (pThis) { /* * Create the condition variable. */ pthread_condattr_t CondAttr; rc = pthread_condattr_init(&CondAttr); if (!rc) { #if defined(CLOCK_MONOTONIC) && defined(IPRT_HAVE_PTHREAD_CONDATTR_SETCLOCK) /* ASSUMES RTTimeSystemNanoTS() == RTTimeNanoTS() == clock_gettime(CLOCK_MONOTONIC). */ rc = pthread_condattr_setclock(&CondAttr, CLOCK_MONOTONIC); pThis->fMonotonicClock = rc == 0; #else pThis->fMonotonicClock = false; #endif rc = pthread_cond_init(&pThis->Cond, &CondAttr); if (!rc) { /* * Create the semaphore. */ pthread_mutexattr_t MutexAttr; rc = pthread_mutexattr_init(&MutexAttr); if (!rc) { rc = pthread_mutex_init(&pThis->Mutex, &MutexAttr); if (!rc) { pthread_mutexattr_destroy(&MutexAttr); pthread_condattr_destroy(&CondAttr); ASMAtomicXchgU32(&pThis->u32State, EVENTMULTI_STATE_NOT_SIGNALED); ASMAtomicXchgU32(&pThis->cWaiters, 0); #ifdef RTSEMEVENTMULTI_STRICT if (!pszNameFmt) { static uint32_t volatile s_iSemEventMultiAnon = 0; RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis, true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), "RTSemEventMulti-%u", ASMAtomicIncU32(&s_iSemEventMultiAnon) - 1); } else { va_list va; va_start(va, pszNameFmt); RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis, true /*fSignaller*/, !(fFlags & RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), pszNameFmt, va); va_end(va); } pThis->fEverHadSignallers = false; #endif *phEventMultiSem = pThis; return VINF_SUCCESS; } pthread_mutexattr_destroy(&MutexAttr); } pthread_cond_destroy(&pThis->Cond); } pthread_condattr_destroy(&CondAttr); } rc = RTErrConvertFromErrno(rc); RTMemFree(pThis); } else rc = VERR_NO_MEMORY; return rc; }
RTDECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser) { #ifndef USE_WINMM /* * On windows we'll have to set the timer resolution before * we start the timer. */ ULONG ulMax = UINT32_MAX; ULONG ulMin = UINT32_MAX; ULONG ulCur = UINT32_MAX; NtQueryTimerResolution(&ulMax, &ulMin, &ulCur); Log(("NtQueryTimerResolution -> ulMax=%lu00ns ulMin=%lu00ns ulCur=%lu00ns\n", ulMax, ulMin, ulCur)); if (ulCur > ulMin && ulCur > 10000 /* = 1ms */) { if (NtSetTimerResolution(10000, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to 1ms.\n")); else if (NtSetTimerResolution(20000, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to 2ms.\n")); else if (NtSetTimerResolution(40000, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to 4ms.\n")); else if (ulMin <= 50000 && NtSetTimerResolution(ulMin, TRUE, &ulCur) >= 0) Log(("Changed timer resolution to %lu *100ns.\n", ulMin)); else { AssertMsgFailed(("Failed to configure timer resolution!\n")); return VERR_INTERNAL_ERROR; } } #endif /* !USE_WINN */ /* * Create new timer. */ int rc = VERR_IPE_UNINITIALIZED_STATUS; PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer)); if (pTimer) { pTimer->u32Magic = RTTIMER_MAGIC; pTimer->pvUser = pvUser; pTimer->pfnTimer = pfnTimer; pTimer->iTick = 0; pTimer->uMilliesInterval = uMilliesInterval; #ifdef USE_WINMM /* sync kill doesn't work. */ pTimer->TimerId = timeSetEvent(uMilliesInterval, 0, rttimerCallback, (DWORD_PTR)pTimer, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if (pTimer->TimerId) { ULONG ulMax = UINT32_MAX; ULONG ulMin = UINT32_MAX; ULONG ulCur = UINT32_MAX; NtQueryTimerResolution(&ulMax, &ulMin, &ulCur); Log(("NtQueryTimerResolution -> ulMax=%lu00ns ulMin=%lu00ns ulCur=%lu00ns\n", ulMax, ulMin, ulCur)); *ppTimer = pTimer; return VINF_SUCCESS; } rc = VERR_INVALID_PARAMETER; #else /* !USE_WINMM */ /* * Create Win32 event semaphore. */ pTimer->iError = 0; pTimer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL); if (pTimer->hTimer) { #ifdef USE_APC /* * Create wait semaphore. */ pTimer->hevWait = CreateEvent(NULL, FALSE, FALSE, NULL); if (pTimer->hevWait) #endif { /* * Kick off the timer thread. */ rc = RTThreadCreate(&pTimer->Thread, rttimerCallback, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer"); if (RT_SUCCESS(rc)) { /* * Wait for the timer to successfully create the timer * If we don't get a response in 10 secs, then we assume we're screwed. */ rc = RTThreadUserWait(pTimer->Thread, 10000); if (RT_SUCCESS(rc)) { rc = pTimer->iError; if (RT_SUCCESS(rc)) { *ppTimer = pTimer; return VINF_SUCCESS; } } ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1); RTThreadWait(pTimer->Thread, 250, NULL); CancelWaitableTimer(pTimer->hTimer); } #ifdef USE_APC CloseHandle(pTimer->hevWait); #endif } CloseHandle(pTimer->hTimer); } #endif /* !USE_WINMM */ AssertMsgFailed(("Failed to create timer uMilliesInterval=%d. rc=%d\n", uMilliesInterval, rc)); RTMemFree(pTimer); } else rc = VERR_NO_MEMORY; return rc; }
/** * Releases the lock. */ DECLINLINE(void) rtmemBlockUnlock(void) { Assert(g_BlocksLock == 1); ASMAtomicXchgU32(&g_BlocksLock, 0); }
RTR3DECL(int) RTTimerDestroy(PRTTIMER pTimer) { /* NULL is ok. */ if (!pTimer) return VINF_SUCCESS; /* * Validate handle first. */ int rc; if ( VALID_PTR(pTimer) && pTimer->u32Magic == RTTIMER_MAGIC) { #ifdef USE_WINMM /* * Kill the timer and exit. */ rc = timeKillEvent(pTimer->TimerId); AssertMsg(rc == TIMERR_NOERROR, ("timeKillEvent -> %d\n", rc)); ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1); RTThreadSleep(1); #else /* !USE_WINMM */ /* * Signal that we want the thread to exit. */ ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1); #ifdef USE_APC SetEvent(pTimer->hevWait); CloseHandle(pTimer->hevWait); rc = CancelWaitableTimer(pTimer->hTimer); AssertMsg(rc, ("CancelWaitableTimer lasterr=%d\n", GetLastError())); #else LARGE_INTEGER ll = {0}; ll.LowPart = 100; rc = SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE); AssertMsg(rc, ("CancelWaitableTimer lasterr=%d\n", GetLastError())); #endif /* * Wait for the thread to exit. * And if it don't wanna exit, we'll get kill it. */ rc = RTThreadWait(pTimer->Thread, 1000, NULL); if (RT_FAILURE(rc)) TerminateThread((HANDLE)RTThreadGetNative(pTimer->Thread), UINT32_MAX); /* * Free resource. */ rc = CloseHandle(pTimer->hTimer); AssertMsg(rc, ("CloseHandle lasterr=%d\n", GetLastError())); #endif /* !USE_WINMM */ RTMemFree(pTimer); return rc; } rc = VERR_INVALID_HANDLE; AssertMsgFailed(("Failed to destroy timer %p. rc=%d\n", pTimer, rc)); return rc; }