FThreadSingleton* FThreadSingletonInitializer::Get( const FThreadSingleton::TCreateSingletonFuncPtr CreateFunc, const FThreadSingleton::TDestroySingletonFuncPtr DestroyFunc, uint32& TlsSlot ) { check( CreateFunc != nullptr ); check( DestroyFunc != nullptr ); if( TlsSlot == 0 ) { check( IsInGameThread() ); TlsSlot = FPlatformTLS::AllocTlsSlot(); } FThreadSingleton* ThreadSingleton = (FThreadSingleton*)FPlatformTLS::GetTlsValue( TlsSlot ); if( !ThreadSingleton ) { const uint32 ThreadId = FPlatformTLS::GetCurrentThreadId(); ThreadSingleton = (*CreateFunc)(); FRunnableThread::GetThreadRegistry().Lock(); FRunnableThread* RunnableThread = FRunnableThread::GetThreadRegistry().GetThread( ThreadId ); if( RunnableThread ) { RunnableThread->OnThreadDestroyed().AddRaw( ThreadSingleton, DestroyFunc ); } FRunnableThread::GetThreadRegistry().Unlock(); FPlatformTLS::SetTlsValue( TlsSlot, ThreadSingleton ); } return ThreadSingleton; }
FRunnableThread* FRunnableThread::Create( class FRunnable* InRunnable, const TCHAR* ThreadName, uint32 InStackSize, EThreadPriority InThreadPri, uint64 InThreadAffinityMask) { FRunnableThread* NewThread = nullptr; if (FPlatformProcess::SupportsMultithreading()) { check(InRunnable); // Create a new thread object NewThread = FPlatformProcess::CreateRunnableThread(); if (NewThread) { // Call the thread's create method if (NewThread->CreateInternal(InRunnable,ThreadName,InStackSize,InThreadPri,InThreadAffinityMask) == false) { // We failed to start the thread correctly so clean up delete NewThread; NewThread = nullptr; } } } else if (InRunnable->GetSingleThreadInterface()) { // Create a fake thread when multithreading is disabled. NewThread = new FFakeThread(); if (NewThread->CreateInternal(InRunnable,ThreadName,InStackSize,InThreadPri) == false) { // We failed to start the thread correctly so clean up delete NewThread; NewThread = nullptr; } } #if STATS if( NewThread ) { FStartupMessages::Get().AddThreadMetadata( FName( *NewThread->GetThreadName() ), NewThread->GetThreadID() ); } #endif // STATS return NewThread; }
/** * Tells the thread to exit. If the caller needs to know when the thread * has exited, it should use the bShouldWait value and tell it how long * to wait before deciding that it is deadlocked and needs to be destroyed. * NOTE: having a thread forcibly destroyed can cause leaks in TLS, etc. * * @return True if the thread exited graceful, false otherwise */ virtual bool KillThread() { bool bDidExitOK = true; // Tell the thread it needs to die FPlatformAtomics::InterlockedExchange(&TimeToDie,1); // Trigger the thread so that it will come out of the wait state if // it isn't actively doing work DoWorkEvent->Trigger(); // If waiting was specified, wait the amount of time. If that fails, // brute force kill that thread. Very bad as that might leak. Thread->WaitForCompletion(); // Clean up the event FPlatformProcess::ReturnSynchEventToPool(DoWorkEvent); DoWorkEvent = nullptr; delete Thread; return bDidExitOK; }
void TestLightmass() { UE_LOG(LogLightmass, Display, TEXT("\n\n")); UE_LOG(LogLightmass, Display, TEXT("===============================================================================================")); UE_LOG(LogLightmass, Display, TEXT("Running \"unit test\". This will take several seconds, and will end with an assertion.")); UE_LOG(LogLightmass, Display, TEXT("This is on purpose, as it's testing the callstack gathering...")); UE_LOG(LogLightmass, Display, TEXT("===============================================================================================")); UE_LOG(LogLightmass, Display, TEXT("\n\n")); void* Buf = FMemory::Malloc(1024); TArray<int32> TestArray; TestArray.Add(5); TArray<int32> ArrayCopy = TestArray; FVector4 TestVectorA(1, 0, 0, 1); FVector4 TestVectorB(1, 1, 1, 1); FVector4 TestVector = TestVectorA + TestVectorB; FString TestString = FString::Printf(TEXT("Copy has %d, Vector is [%.2f, %.2f, %.2f, %.2f]\n"), ArrayCopy[0], TestVector.X, TestVector.Y, TestVector.Z, TestVector.W); wprintf(*TestString); FMemory::Free(Buf); struct FAlignTester { uint8 A; FMatrix M1; uint8 B; FMatrix M2; uint8 C; FVector4 V; }; FAlignTester AlignTest; checkf(((PTRINT)(&FMatrix::Identity) & 15) == 0, TEXT("Identity matrix unaligned")); checkf(((PTRINT)(&AlignTest.M1) & 15) == 0, TEXT("First matrix unaligned")); checkf(((PTRINT)(&AlignTest.M2) & 15) == 0, TEXT("Second matrix unaligned")); checkf(((PTRINT)(&AlignTest.V) & 15) == 0, TEXT("Vector unaligned")); FGuid Guid(1, 2, 3, 4); UE_LOG(LogLightmass, Display, TEXT("Guid is %s"), *Guid.ToString()); TMap<FString, int32> TestMap; TestMap.Add(FString(TEXT("Five")), 5); TestMap.Add(TEXT("Ten"), 10); UE_LOG(LogLightmass, Display, TEXT("Map[Five] = %d, Map[Ten] = %d"), TestMap.FindRef(TEXT("Five")), TestMap.FindRef(FString(TEXT("Ten")))); FMatrix TestMatrix(FVector(0, 0, 0.1f), FVector(0, 1.0f, 0), FVector(0.9f, 0, 0), FVector(0, 0, 0)); UE_LOG(LogLightmass, Display, TEXT("Mat=\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]"), TestMatrix.M[0][0], TestMatrix.M[0][1], TestMatrix.M[0][2], TestMatrix.M[0][3], TestMatrix.M[1][0], TestMatrix.M[1][1], TestMatrix.M[1][2], TestMatrix.M[1][3], TestMatrix.M[2][0], TestMatrix.M[2][1], TestMatrix.M[2][2], TestMatrix.M[2][3], TestMatrix.M[3][0], TestMatrix.M[3][1], TestMatrix.M[3][2], TestMatrix.M[3][3] ); TestMatrix = TestMatrix.GetTransposed(); UE_LOG(LogLightmass, Display, TEXT("Transposed Mat=\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]"), TestMatrix.M[0][0], TestMatrix.M[0][1], TestMatrix.M[0][2], TestMatrix.M[0][3], TestMatrix.M[1][0], TestMatrix.M[1][1], TestMatrix.M[1][2], TestMatrix.M[1][3], TestMatrix.M[2][0], TestMatrix.M[2][1], TestMatrix.M[2][2], TestMatrix.M[2][3], TestMatrix.M[3][0], TestMatrix.M[3][1], TestMatrix.M[3][2], TestMatrix.M[3][3] ); TestMatrix = TestMatrix.GetTransposed().InverseFast(); UE_LOG(LogLightmass, Display, TEXT("Inverted Mat=\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]\n [%0.2f, %0.2f, %0.2f, %0.2f]"), TestMatrix.M[0][0], TestMatrix.M[0][1], TestMatrix.M[0][2], TestMatrix.M[0][3], TestMatrix.M[1][0], TestMatrix.M[1][1], TestMatrix.M[1][2], TestMatrix.M[1][3], TestMatrix.M[2][0], TestMatrix.M[2][1], TestMatrix.M[2][2], TestMatrix.M[2][3], TestMatrix.M[3][0], TestMatrix.M[3][1], TestMatrix.M[3][2], TestMatrix.M[3][3] ); UE_LOG(LogLightmass, Display, TEXT("sizeof FDirectionalLight = %d, FLight = %d, FDirectionalLightData = %d"), sizeof(FDirectionalLight), sizeof(FLight), sizeof(FDirectionalLightData)); TOctree<float, FTestOctreeSemantics> TestOctree(FVector4(0), 10.0f); TestOctree.AddElement(5); // kDOP test TkDOPTree<FTestCollisionDataProvider, uint16> TestkDOP; FTestCollisionDataProvider TestDataProvider(TestkDOP); FHitResult TestResult; FkDOPBuildCollisionTriangle<uint16> TestTri(0, FVector4(0,0,0,0), FVector4(1,1,1,0), FVector4(2,2,2,0), INDEX_NONE, INDEX_NONE, INDEX_NONE, false, true); TArray<FkDOPBuildCollisionTriangle<uint16> > TestTriangles; TestTriangles.Add(TestTri); TestkDOP.Build(TestTriangles); UE_LOG(LogLightmass, Display, TEXT("\nStarting a thread")); FTestRunnable* TestRunnable = new FTestRunnable; // create a thread with the test runnable, and let it auto-delete itself FRunnableThread* TestThread = FRunnableThread::Create(TestRunnable, TEXT("TestRunnable")); double Start = FPlatformTime::Seconds(); UE_LOG(LogLightmass, Display, TEXT("\nWaiting 4 seconds"), Start); FPlatformProcess::Sleep(4.0f); UE_LOG(LogLightmass, Display, TEXT("%.2f seconds have passed, killing thread"), FPlatformTime::Seconds() - Start); // wait for thread to end double KillStart = FPlatformTime::Seconds(); TestRunnable->Stop(); TestThread->WaitForCompletion(); delete TestThread; delete TestRunnable; UE_LOG(LogLightmass, Display, TEXT("It took %.2f seconds to kill the thread [should be < 1 second]"), FPlatformTime::Seconds() - KillStart); UE_LOG(LogLightmass, Display, TEXT("\n\n")); checkf(5 == 2, TEXT("And boom goes the dynamite\n")); }