bool CTLSStorageArray::FindAbandonedStorageBlockIndex(unsigned int &nOutFreeBlockIndex, 
	tlsindextype iValueCount)
{
	bool bResult = false;

	do 
	{
		CClientHandleArray haTranslatedHandlesStorage;
		CHandleTranslationMap tmTranslationMapStorage;
		
		const HANDLE *ph_TranslatedHandles;
		const unsigned int *puiTranslationMap;
		
		// Translate handles into array for the case if there are invalids
		unsigned int nHandleCount = TranslateClientHandles(haTranslatedHandlesStorage, tmTranslationMapStorage,
			ph_TranslatedHandles, puiTranslationMap);
		OU_ASSERT(OU_IN_INT_RANGE(nHandleCount, 0, MAXIMUM_WAIT_OBJECTS + 1));
		
		if (nHandleCount == 0)
		{
			break;
		}

		// Since allocating a new storage block is a relatively slow operation
		// it is acceptable to enter kernel for checking for exited threads.
		DWORD dwWaitResult = ::WaitForMultipleObjects(nHandleCount, ph_TranslatedHandles, FALSE, 0);
		
		if (!OU_IN_INT_RANGE(dwWaitResult - WAIT_OBJECT_0, 0, nHandleCount))
		{
			// Wait should not normally fail. If it does it's in most cases an indication
			// of invalid handle passed as parameter. However it may fail because of other
			// reasons as well. If this assertion fails too often and you are sure all the 
			// handles are valid, it is safe to comment it.
			OU_ASSERT(dwWaitResult != WAIT_FAILED);

			break;
		}

		unsigned int nTranslatedBlockIndex = (unsigned int)(dwWaitResult - WAIT_OBJECT_0);
		unsigned int nBlockIndex = !puiTranslationMap ? nTranslatedBlockIndex : puiTranslationMap[nTranslatedBlockIndex];
		
		CTLSStorageBlock *psbStorageBlock = GetStorageBlockPointer(nBlockIndex, iValueCount);
		ReinitializeStorageSingleBlock(psbStorageBlock, iValueCount);

		// Close old handle and make a duplicate of current thread handle
		FreeStorageThreadHandle(nBlockIndex);
		AllocateBlockThreadHandle(nBlockIndex);

		nOutFreeBlockIndex = nBlockIndex;
		bResult = true;
	}
	while (false);

	return bResult;
}
unsigned int CTLSStorageArray::GetStorageBlockIndex(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount) const
{
	const size_t nHeaderSize = CTLSStorageArray::GetHeaderSize();
	const size_t nBlockSize = CTLSStorageBlock::GetRequiredSize(iValueCount);
	const size_t nBlockZeroOffset = CTLSStorageBlock::GetZeroOffset(iValueCount);

	unsigned int uiBlockIndex = (unsigned int)((((int8ou *)psbStorageBlock) - nBlockZeroOffset - nHeaderSize - ((int8ou *)this)) / nBlockSize);
	OU_ASSERT((((int8ou *)psbStorageBlock) - nBlockZeroOffset - nHeaderSize - ((int8ou *)this)) % nBlockSize == 0);
	OU_ASSERT(OU_IN_INT_RANGE(uiBlockIndex, 0, TLS_ARRAY_ELEMENT__MAX));

	return uiBlockIndex;
}
bool CTLSInitialization::InitializeTLSAPI(HTLSKEY &hskOutStorageKey, tlsindextype iValueCount,
	unsigned int uiInitializationFlags/*=0*/)
{
	OU_ASSERT(g_uiThreadLocalStorageInitializationCount != 0U - 1U);

	bool bResult = false;
	
	bool bAtomicAPIInitialized = false;

	do
	{
		const ESTORAGEINSTANCEKIND ikInstanceKind = (uiInitializationFlags & SIF_MANUAL_CLEANUP_ON_THREAD_EXIT) ? SIK_MANUALCLEANUP : SIK_AUTOCLEANUP;

		if (g_apsiStorageGlobalInstances[ikInstanceKind] == NULL) // Initialization/finalization must be called from main thread
		{
			if (!InitializeAtomicAPI())
			{
				break;
			}

			bAtomicAPIInitialized = true;

			if (!InitializeTLSAPIValidated(ikInstanceKind, iValueCount, uiInitializationFlags))
			{
				break;
			}

			const HTLSKEYVALUE &hkvStorageKey = g_apsiStorageGlobalInstances[ikInstanceKind]->RetrieveStorageKey();
			g_ahkvStorageGlobalKeyValues[ikInstanceKind] = hkvStorageKey;
		}

		++g_uiThreadLocalStorageInitializationCount;
	
		hskOutStorageKey = EncodeKeySelectorFromStorageKind(ikInstanceKind);
		OU_ASSERT(iValueCount == g_apsiStorageGlobalInstances[ikInstanceKind]->RetrieveValueCount());
		OU_ASSERT(uiInitializationFlags == g_apsiStorageGlobalInstances[ikInstanceKind]->RetrieveInitializationFlags());

		bResult = true;
	}
	while (false);
	
	if (!bResult)
	{
		if (bAtomicAPIInitialized)
		{
			FinalizeAtomicAPI();
		}
	}

	return bResult;
}
void CTLSInitialization::FinalizeTLSAPIValidated(unsigned int uiInstanceKind)
{
	OU_ASSERT(g_apsiStorageGlobalInstances[uiInstanceKind] != NULL);

	g_apsiStorageGlobalInstances[uiInstanceKind]->FreeInstance();
	g_apsiStorageGlobalInstances[uiInstanceKind] = NULL;
}
void CTLSStorageArray::FreeStorageBlockOnThreadExit(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount)
{
	ReinitializeStorageSingleBlock(psbStorageBlock, iValueCount);
	// OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE) -- assertion further in the code

	unsigned int nBlockIndex = GetStorageBlockIndex(psbStorageBlock, iValueCount);
	OU_ASSERT(GetBlockOccupiedFlag(nBlockIndex));
#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS

	OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE); // The method is not to be called if automatic cleanup is enabled


#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS

	ResetBlockOccupiedFlag(nBlockIndex);
}
bool CThreadLocalStorage::AllocateAndSetStorageValue(const HTLSKEYSELECTOR &hksKeySelector,
	tlsindextype iValueIndex, tlsvaluetype vValueData, CTLSValueDestructor fnValueDestructor)
{
	OU_ASSERT(OU_IN_SIZET_RANGE(DecodeInstanceKindFromKeySelector(hksKeySelector), SIK__MIN, SIK__MAX));

	bool bResult = false;
	
	do
	{
		ESTORAGEINSTANCEKIND ikInstanceKind = (ESTORAGEINSTANCEKIND)DecodeInstanceKindFromKeySelector(hksKeySelector);
		CTLSStorageInstance *psiStorageInstance = g_apsiStorageGlobalInstances[ikInstanceKind];

		CTLSStorageBlock *psbStorageBlock;

		if (!psiStorageInstance->FindFreeStorageBlock(psbStorageBlock))
		{
			break;
		}

		SetKeyStorageBlock(hksKeySelector, psbStorageBlock);

		psbStorageBlock->SetValueData(iValueIndex, vValueData);
		psbStorageBlock->SetValueDestructor(iValueIndex, fnValueDestructor);
	
		bResult = true;
	}
	while (false);
	
	return bResult;
}
void CTLSStorageArray::FreeStorageAllBlocks(tlsindextype iValueCount)
{
	for (unsigned int nBlockIndex = 0; nBlockIndex != TLS_ARRAY_ELEMENT__MAX; ++nBlockIndex)
	{
		if (GetBlockOccupiedFlag(nBlockIndex))
		{
			CTLSStorageBlock *psbStorageBlock = GetStorageBlockPointer(nBlockIndex, iValueCount);

			FinalizeStorageSingleBlock(psbStorageBlock, iValueCount);
#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS
			
			FreeStorageThreadHandle(nBlockIndex);


#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS
		}
		else
		{
#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS
			
			OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE); // Where did the handle come from if block is not occupied?
			
			
#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS
		}
	}
}
Пример #8
0
void CTLSInitialization::FinalizeTLSAPIValidated()
{
	OU_ASSERT(g_psiStorageGlobalInstance != NULL);

	g_psiStorageGlobalInstance->FreeInstance();
	g_psiStorageGlobalInstance = NULL;
}
bool CTLSStorageInstance::FindFreeStorageBlockInArrayListSegment(CTLSStorageBlock *&psbOutStorageBlock, 
	CTLSStorageArray *psaListSegmentBegin, CTLSStorageArray *psaListSegmentEnd)
{
	OU_ASSERT(psaListSegmentBegin != psaListSegmentEnd);

	bool bResult;

	CTLSStorageArray *psaListSegmentCurrent = psaListSegmentBegin;

	while (true)
	{
		if (FindFreeStorageBlockFromArray(psbOutStorageBlock, psaListSegmentCurrent))
		{
			bResult = true;
			break;
		}

		psaListSegmentCurrent = psaListSegmentCurrent->GetNextArray();
		
		if (psaListSegmentCurrent == psaListSegmentEnd)
		{
			bResult = false;
			break;
		}
	}

	return bResult;
}
Пример #10
0
bool CTLSInitialization::InitializeTLSAPI(HTLSKEY &hskOutStorageKey, tlsindextype iValueCount,
	unsigned int uiInitializationFlags/*=0*/)
{
	OU_ASSERT(g_uiThreadLocalStorageInitializationCount != 0U - 1U);

	bool bResult = false;
	
	bool bAtomicAPIInitialized = false;

	do
	{
		if (g_uiThreadLocalStorageInitializationCount == 0U) // Initialization/finalization must be called from main thread
		{
			if (!InitializeAtomicAPI())
			{
				break;
			}

			bAtomicAPIInitialized = true;

			if (!InitializeTLSAPIValidated(iValueCount, uiInitializationFlags))
			{
				break;
			}
		}

		++g_uiThreadLocalStorageInitializationCount;
	
		hskOutStorageKey = g_psiStorageGlobalInstance->RetrieveStorageKey();
		OU_ASSERT(iValueCount == g_psiStorageGlobalInstance->RetrieveValueCount());
		OU_ASSERT(uiInitializationFlags == g_psiStorageGlobalInstance->RetrieveInitializationFlags());

		bResult = true;
	}
	while (false);
	
	if (!bResult)
	{
		if (bAtomicAPIInitialized)
		{
			FinalizeAtomicAPI();
		}
	}

	return bResult;
}
Пример #11
0
/*extern*/ void FinalizeAtomicAPI()
{
	OU_ASSERT(g_uiAtomicAPIInitializationCount != 0U);

	if (--g_uiAtomicAPIInitializationCount == 0) // Initialization/finalization must be called from main thread
	{
		FinalizeAtomicAPIValidated();
	}
}
CTLSStorageArray::~CTLSStorageArray()
{
#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS
	
	OU_ASSERT(CheckIfAllBlocksHaveInvalidThreads());
	
	
#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS
}
CTLSStorageBlock *CTLSStorageArray::GetStorageBlockPointer(unsigned int nBlockIndex, tlsindextype iValueCount) const
{
	OU_ASSERT(OU_IN_INT_RANGE(nBlockIndex, 0, TLS_ARRAY_ELEMENT__MAX));

	const size_t nHeaderSize = CTLSStorageArray::GetHeaderSize();
	const size_t nBlockSize = CTLSStorageBlock::GetRequiredSize(iValueCount);
	const size_t nBlockZeroOffset = CTLSStorageBlock::GetZeroOffset(iValueCount);
	
	CTLSStorageBlock *psbStorageBlock = (CTLSStorageBlock *)(((int8ou *)this) + nHeaderSize + nBlockIndex * nBlockSize + nBlockZeroOffset);
	return psbStorageBlock;
}
Пример #14
0
void CTLSInitialization::FinalizeTLSAPI()
{
	OU_ASSERT(g_uiThreadLocalStorageInitializationCount != 0U);

	if (--g_uiThreadLocalStorageInitializationCount == 0U) // Initialization/finalization must be called from main thread
	{
		FinalizeTLSAPIValidated();

		FinalizeAtomicAPI();
	}
}
void CTLSInitialization::CleanupOnThreadExit()
{
	const ESTORAGEINSTANCEKIND ikInstanceKind = SIK_MANUALCLEANUP;
	CTLSStorageInstance *psiStorageInstance = g_apsiStorageGlobalInstances[ikInstanceKind];

	if (psiStorageInstance != NULL)
	{
		OU_ASSERT(psiStorageInstance->GetIsThreadManualCleanup());

		const HTLSKEYSELECTOR &hksKeySelector = EncodeKeySelectorFromStorageKind(ikInstanceKind);
		CTLSStorageBlock *psbStorageBlock = CThreadLocalStorage::GetKeyStorageBlock(hksKeySelector);
		
		if (psbStorageBlock)
		{
			psiStorageInstance->FreeStorageBlockOnThreadExit(psbStorageBlock);

			CThreadLocalStorage::SetKeyStorageBlock(hksKeySelector, NULL);
		}
	}
	else
	{
		OU_ASSERT(false); // The method is not supposed to be called if manual cleanup was not requested on initialization
	}
}
void CTLSInitialization::FinalizeTLSAPI()
{
	OU_ASSERT(g_uiThreadLocalStorageInitializationCount != 0U);

	ESTORAGEINSTANCEKIND ikInstanceKind = 
		(--g_uiThreadLocalStorageInitializationCount == 0U) ? SIK__MIN : SIK__MAX; // Initialization/finalization must be called from main thread
	for (; ikInstanceKind != SIK__MAX; ++ikInstanceKind) 
	{
		if (g_apsiStorageGlobalInstances[ikInstanceKind])
		{
			g_ahkvStorageGlobalKeyValues[ikInstanceKind] = 0;

			FinalizeTLSAPIValidated(ikInstanceKind);

			FinalizeAtomicAPI();
		}
	}
}
bool CTLSInitialization::InitializeTLSAPIValidated(unsigned int uiInstanceKind, 
	tlsindextype iValueCount, unsigned int uiInitializationFlags)
{
	OU_ASSERT(g_apsiStorageGlobalInstances[uiInstanceKind] == NULL);

	bool bResult = false;
	
	CTLSStorageInstance *psiStorageInstance;

	do
	{
		// Use static methods instead of constructor/destructor 
		// to avoid overloading operators new/delete and for 
		// uniformity with CTLSStorageArray class
		psiStorageInstance = CTLSStorageInstance::AllocateInstance(iValueCount, uiInitializationFlags);
		
		if (!psiStorageInstance)
		{
			break;
		}

		if (!psiStorageInstance->Init((ESTORAGEINSTANCEKIND)uiInstanceKind))
		{
			break;
		}

		g_apsiStorageGlobalInstances[uiInstanceKind] = psiStorageInstance;
	
		bResult = true;
	}
	while (false);
	
	if (!bResult)
	{
		if (psiStorageInstance)
		{
			psiStorageInstance->FreeInstance();
		}
	}

	return bResult;
}
void CTLSStorageArray::AllocateBlockThreadHandle(unsigned int nBlockIndex)
{
	OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE);
	
	HANDLE hCurrentThreadDuplicate;
	
	HANDLE hCurrentProcess = ::GetCurrentProcess();
	HANDLE hCurrentThread = ::GetCurrentThread();
	if (!::DuplicateHandle(hCurrentProcess, hCurrentThread, hCurrentProcess, &hCurrentThreadDuplicate, SYNCHRONIZE, FALSE, 0))
	{
		// Handle duplication should not normally fail. 
		// Thread and process pseudo-handles have full access allowed.
		// The duplication may only fail in case of kernel internal problems
		// (like lack of the resources or resource limit hits).
		// Well, in this case thread data will remain in memory until 
		// CTLSInitialization::FinalizeTLSAPI() is called.
		hCurrentThreadDuplicate = INVALID_HANDLE_VALUE;
	}
	
	SetBlockThreadHandle(nBlockIndex, hCurrentThreadDuplicate);
}
Пример #19
0
void CTLSInitialization::CleanupOnThreadExit()
{
	CTLSStorageInstance *psiStorageInstance = g_psiStorageGlobalInstance;

	if (psiStorageInstance->GetIsThreadManualCleanup())
	{
		const HTLSKEY &hskStorageKey = g_psiStorageGlobalInstance->RetrieveStorageKey();
		CTLSStorageBlock *psbStorageBlock = CThreadLocalStorage::GetKeyStorageBlock(hskStorageKey);
		
		if (psbStorageBlock)
		{
			psiStorageInstance->FreeStorageBlockOnThreadExit(psbStorageBlock);

			CThreadLocalStorage::SetKeyStorageBlock(hskStorageKey, NULL);
		}
	}
	else
	{
		OU_ASSERT(false); // The method is not supposed to be called if manual cleanup was not requested on initialization
	}
}
void CTLSStorageInstance::FreeStorageKey(const HTLSKEYVALUE &hkvStorageKey)
{
#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS
	
	DWORD dwTlsIndex = (DWORD)(size_t)(HTLSKEYVALUE::value_type)hkvStorageKey;
	OU_ASSERT(dwTlsIndex != TLS_OUT_OF_INDEXES);

	BOOL bIndexFreeingResult = ::TlsFree(dwTlsIndex);
	OU_VERIFY(bIndexFreeingResult);
	
	
#else // #if _OU_TARGET_OS != _OU_TARGET_OS_WINDOWS
	
	pthread_key_t pkThreadKey = (pthread_key_t)(size_t)(HTLSKEYVALUE::value_type)hkvStorageKey;
	
	int iKeyDeletionResult = pthread_key_delete(pkThreadKey);
	OU_VERIFY(iKeyDeletionResult == EOK);
	
	
#endif // #if _OU_TARGET_OS == ...
}
Пример #21
0
bool CTLSStorageArray::FindFreeStorageBlockIndex(unsigned int &nOutFreeBlockIndex,
  tlsindextype /*iValueCount*/, bool bIsManualCleanup)
#endif
{
  bool bResult = false;

  if (!GetAreAllBlocksOccupied() && FindFreeStorageBlockIndexWithPossibilityVerified(nOutFreeBlockIndex, bIsManualCleanup))
  {
    bResult = true;
  }
#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS

  else if (!bIsManualCleanup)
  {
    // Execution gets here is all slots were already occupied or
    // they become occupied during search (otherwise why
    // FindFreeStorageBlockIndexWithPossibilityVerified call failed???).
    // In Automatic cleanup mode a block can't become free by itself -
    // it is just re-allocated for new thread and remains busy.
    OU_ASSERT(GetAreAllBlocksOccupied());

    // The locking is performed to avoid more than one threads checking
    // for abandoned handles simultaneously.
    // If locking fails, execution just proceeds to next array in the chain
    if (SetArrayLockedFlag())
    {
      bResult = FindAbandonedStorageBlockIndex(nOutFreeBlockIndex, iValueCount);

      ResetArrayLockedFlag();
    }
  }


#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS

  return bResult;
}
Пример #22
0
/*extern*/ bool InitializeAtomicAPI()
{
	OU_ASSERT(g_uiAtomicAPIInitializationCount != 0U - 1U);

	bool bResult = false;
	
	do
	{
		if (g_uiAtomicAPIInitializationCount == 0) // Initialization/finalization must be called from main thread
		{
			if (!InitializeAtomicAPIValidated())
			{
				break;
			}
		}
	
		++g_uiAtomicAPIInitializationCount;

		bResult = true;
	}
	while (false);

	return bResult;
}