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) RTSemEventDestroy(RTSEMEVENT hEventSem) { struct RTSEMEVENTINTERNAL *pThis = hEventSem; if (pThis == NIL_RTSEMEVENT) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, VERR_INVALID_HANDLE); /* * Invalidate the handle and close the semaphore. */ int rc = VINF_SUCCESS; AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMEVENT_MAGIC, RTSEMEVENT_MAGIC), VERR_INVALID_HANDLE); if (CloseHandle(pThis->hev)) { #ifdef RTSEMEVENT_STRICT RTLockValidatorRecSharedDelete(&pThis->Signallers); #endif if (!(pThis->fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)) RTMemFree(pThis); else rtMemBaseFree(pThis); } else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); AssertMsgFailed(("Destroy hEventSem %p failed, lasterr=%u (%Rrc)\n", pThis, dwErr, rc)); /* Leak it. */ } return rc; }
RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem) { /* * Validate handle. */ struct RTSEMEVENTINTERNAL *pThis = hEventSem; if (pThis == NIL_RTSEMEVENT) return VINF_SUCCESS; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); uint32_t u32 = pThis->u32State; AssertReturn(u32 == EVENT_STATE_NOT_SIGNALED || u32 == EVENT_STATE_SIGNALED, VERR_INVALID_HANDLE); /* * Abort all waiters forcing them to return failure. */ int rc; for (int i = 30; i > 0; i--) { ASMAtomicWriteU32(&pThis->u32State, EVENT_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", pThis, 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", pThis, rc)); return RTErrConvertFromErrno(rc); } /* * 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) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...) { AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER); Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL)); struct RTSEMEVENTINTERNAL *pThis; if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)) pThis = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(*pThis)); else pThis = (struct RTSEMEVENTINTERNAL *)rtMemBaseAlloc(sizeof(*pThis)); if (!pThis) return VERR_NO_MEMORY; /* * Create the semaphore. * (Auto reset, not signaled, private event object.) */ pThis->hev = CreateEvent(NULL, FALSE, FALSE, NULL); if (pThis->hev != NULL) /* not INVALID_HANDLE_VALUE */ { pThis->u32Magic = RTSEMEVENT_MAGIC; pThis->fFlags = fFlags; #ifdef RTSEMEVENT_STRICT if (!pszNameFmt) { static uint32_t volatile s_iSemEventAnon = 0; RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis, true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL), "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1); } else { va_list va; va_start(va, pszNameFmt); RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis, true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL), pszNameFmt, va); va_end(va); } pThis->fEverHadSignallers = false; #else RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt); #endif *phEventSem = pThis; return VINF_SUCCESS; } DWORD dwErr = GetLastError(); if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)) RTMemFree(pThis); else rtMemBaseFree(pThis); return RTErrConvertFromWin32(dwErr); }
/** * Allocates one or more pages off the heap. * * @returns IPRT status code. * @param pHeap The page heap. * @param pv Pointer to what RTHeapPageAlloc returned. * @param cPages The number of pages that was allocated. */ int RTHeapPageFree(PRTHEAPPAGE pHeap, void *pv, size_t cPages) { /* * Validate input. */ if (!pv) return VINF_SUCCESS; AssertPtrReturn(pHeap, VERR_INVALID_HANDLE); AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE); /* * Grab the lock and look up the page. */ int rc = RTCritSectEnter(&pHeap->CritSect); if (RT_SUCCESS(rc)) { PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)RTAvlrPVRangeGet(&pHeap->BlockTree, pv); if (pBlock) { /* * Validate the specified address range. */ uint32_t const iPage = (uint32_t)(((uintptr_t)pv - (uintptr_t)pBlock->Core.Key) >> PAGE_SHIFT); /* Check the range is within the block. */ bool fOk = iPage + cPages <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT; /* Check that it's the start of an allocation. */ fOk = fOk && ASMBitTest(&pBlock->bmFirst[0], iPage); /* Check that the range ends at an allocation boundrary. */ fOk = fOk && ( iPage + cPages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT || ASMBitTest(&pBlock->bmFirst[0], iPage + cPages) || !ASMBitTest(&pBlock->bmAlloc[0], iPage + cPages)); /* Check the other pages. */ uint32_t const iLastPage = iPage + cPages - 1; for (uint32_t i = iPage + 1; i < iLastPage && fOk; i++) fOk = ASMBitTest(&pBlock->bmAlloc[0], i) && !ASMBitTest(&pBlock->bmFirst[0], i); if (fOk) { /* * Free the memory. */ ASMBitClearRange(&pBlock->bmAlloc[0], iPage, iPage + cPages); ASMBitClear(&pBlock->bmFirst[0], iPage); pBlock->cFreePages += cPages; pHeap->cFreePages += cPages; pHeap->cFreeCalls++; if (!pHeap->pHint1 || pHeap->pHint1->cFreePages < pBlock->cFreePages) pHeap->pHint1 = pBlock; /* * Shrink the heap. Not very efficient because of the AVL tree. */ if ( pHeap->cFreePages >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT * 3 && pHeap->cFreePages >= pHeap->cHeapPages / 2 /* 50% free */ && pHeap->cFreeCalls - pHeap->uLastMinimizeCall > RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT ) { uint32_t cFreePageTarget = pHeap->cHeapPages / 4; /* 25% free */ while (pHeap->cFreePages > cFreePageTarget) { pHeap->uLastMinimizeCall = pHeap->cFreeCalls; pBlock = NULL; RTAvlrPVDoWithAll(&pHeap->BlockTree, false /*fFromLeft*/, rtHeapPageFindUnusedBlockCallback, &pBlock); if (!pBlock) break; void *pv2 = RTAvlrPVRemove(&pHeap->BlockTree, pBlock->Core.Key); Assert(pv2); NOREF(pv2); pHeap->cHeapPages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT; pHeap->cFreePages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT; pHeap->pHint1 = NULL; pHeap->pHint2 = NULL; RTCritSectLeave(&pHeap->CritSect); munmap(pBlock->Core.Key, RTMEMPAGEPOSIX_BLOCK_SIZE); pBlock->Core.Key = pBlock->Core.KeyLast = NULL; pBlock->cFreePages = 0; rtMemBaseFree(pBlock); RTCritSectEnter(&pHeap->CritSect); } } } else rc = VERR_INVALID_POINTER; } else rc = VERR_INVALID_POINTER; RTCritSectLeave(&pHeap->CritSect); }
RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...) { AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER); Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL)); /* * Allocate semaphore handle. */ int rc; struct RTSEMEVENTINTERNAL *pThis; if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)) pThis = (struct RTSEMEVENTINTERNAL *)RTMemAlloc(sizeof(*pThis)); else pThis = (struct RTSEMEVENTINTERNAL *)rtMemBaseAlloc(sizeof(*pThis)); if (pThis) { /* * Create the condition variable. */ rc = pthread_cond_init(&pThis->Cond, NULL); if (!rc) { /* * Create the semaphore. */ rc = pthread_mutex_init(&pThis->Mutex, NULL); if (!rc) { ASMAtomicWriteU32(&pThis->u32State, EVENT_STATE_NOT_SIGNALED); ASMAtomicWriteU32(&pThis->cWaiters, 0); pThis->fFlags = fFlags; #ifdef RTSEMEVENT_STRICT if (!pszNameFmt) { static uint32_t volatile s_iSemEventAnon = 0; RTLockValidatorRecSharedInit(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis, true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL), "RTSemEvent-%u", ASMAtomicIncU32(&s_iSemEventAnon) - 1); } else { va_list va; va_start(va, pszNameFmt); RTLockValidatorRecSharedInitV(&pThis->Signallers, hClass, RTLOCKVAL_SUB_CLASS_ANY, pThis, true /*fSignaller*/, !(fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL), pszNameFmt, va); va_end(va); } pThis->fEverHadSignallers = false; #else RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt); #endif *phEventSem = pThis; return VINF_SUCCESS; } pthread_cond_destroy(&pThis->Cond); } rc = RTErrConvertFromErrno(rc); if (!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)) RTMemFree(pThis); else rtMemBaseFree(pThis); } else rc = VERR_NO_MEMORY; return rc; }