bool ezPipeChannel_win::ProcessOutgoingMessages(DWORD uiBytesWritten) { EZ_ASSERT_DEBUG(m_Connected, "Must be connected to process outgoing messages."); EZ_ASSERT_DEBUG(m_ThreadId == ezThreadUtils::GetCurrentThreadID(), "Function must be called from worker thread!"); if (m_OutputState.IsPending) { if (uiBytesWritten == 0) { // Don't reset isPending right away as we want to use it to decide // whether we need to wake up the worker thread again. ezLog::Error("pipe error: {0}", ezArgErrorCode(GetLastError())); m_OutputState.IsPending = false; return false; } EZ_LOCK(m_OutputQueueMutex); //message was send m_OutputQueue.PopFront(); } if (m_PipeHandle == INVALID_HANDLE_VALUE) { m_OutputState.IsPending = false; return false; } const ezMemoryStreamStorage* storage = nullptr; { EZ_LOCK(m_OutputQueueMutex); if (m_OutputQueue.IsEmpty()) { m_OutputState.IsPending = false; return true; } storage = &m_OutputQueue.PeekFront(); } BOOL res = WriteFile(m_PipeHandle, storage->GetData(), storage->GetStorageSize(), &uiBytesWritten, &m_OutputState.Context.Overlapped); if (!res) { ezUInt32 error = GetLastError(); if (error == ERROR_IO_PENDING) { m_OutputState.IsPending = true; return true; } ezLog::Error("Write to pipe failed: {0}", ezArgErrorCode(error)); return false; } m_OutputState.IsPending = true; return true; }
void ezPipeChannel_win::OnIOCompleted(IOContext* pContext, DWORD uiBytesTransfered, DWORD uiError) { EZ_ASSERT_DEBUG(m_ThreadId == ezThreadUtils::GetCurrentThreadID(), "Function must be called from worker thread!"); bool bRes = true; if (pContext == &m_InputState.Context) { if (!m_Connected) { if (!ProcessConnection()) return; bool bHasOutput = false; { EZ_LOCK(m_OutputQueueMutex); bHasOutput = !m_OutputQueue.IsEmpty(); } if (bHasOutput && m_OutputState.IsPending == 0) ProcessOutgoingMessages(0); if (m_InputState.IsPending) return; } bRes = ProcessIncomingMessages(uiBytesTransfered); } else { EZ_ASSERT_DEBUG(pContext == &m_OutputState.Context, ""); bRes = ProcessOutgoingMessages(uiBytesTransfered); } if (!bRes && m_PipeHandle != INVALID_HANDLE_VALUE) { InternalDisconnect(); } }
void ezPipeChannel_win::InternalDisconnect() { #if EZ_ENABLED(EZ_COMPILE_FOR_DEBUG) if (m_ThreadId != 0) EZ_ASSERT_DEBUG(m_ThreadId == ezThreadUtils::GetCurrentThreadID(), "Function must be called from worker thread!"); #endif if (m_InputState.IsPending || m_OutputState.IsPending) { CancelIo(m_PipeHandle); } if (m_PipeHandle != INVALID_HANDLE_VALUE) { CloseHandle(m_PipeHandle); m_PipeHandle = INVALID_HANDLE_VALUE; } while (m_InputState.IsPending || m_OutputState.IsPending) { FlushPendingOperations(); } { EZ_LOCK(m_OutputQueueMutex); m_OutputQueue.Clear(); m_Connected = false; } m_Events.Broadcast(ezIpcChannelEvent(m_Mode == Mode::Client ? ezIpcChannelEvent::DisconnectedFromServer : ezIpcChannelEvent::DisconnectedFromClient, this)); // Raise in case another thread is waiting for new messages (as we would sleep forever otherwise). m_IncomingMessages.RaiseSignal(); }
void ezTaskSystem::TaskHasFinished(ezTask* pTask, ezTaskGroup* pGroup) { // this might deallocate the task, make sure not to reference it later anymore if (pTask && pTask->m_OnTaskFinished.IsValid()) pTask->m_OnTaskFinished(pTask); if (pGroup->m_iRemainingTasks.Decrement() == 0) { // If this was the last task that had to be finished from this group, make sure all dependent groups are started if (!pGroup->m_OthersDependingOnMe.IsEmpty()) { EZ_LOCK(s_TaskSystemMutex); for (ezUInt32 dep = 0; dep < pGroup->m_OthersDependingOnMe.GetCount(); ++dep) { DependencyHasFinished(pGroup->m_OthersDependingOnMe[dep].m_pTaskGroup); } } if (pGroup->m_OnFinishedCallback.IsValid()) pGroup->m_OnFinishedCallback(); // set this task group to be finished and available for reuse pGroup->m_uiGroupCounter += 2; pGroup->m_bInUse = false; } }
ezResult ezTaskSystem::CancelTask(ezTask* pTask, ezOnTaskRunning::Enum OnTaskRunning) { if (pTask->IsTaskFinished()) return EZ_SUCCESS; EZ_PROFILE_SCOPE("CancelTask"); EZ_ASSERT_DEV(pTask->m_BelongsToGroup.m_pTaskGroup->m_uiGroupCounter == pTask->m_BelongsToGroup.m_uiGroupCounter, "The task to be removed is in an invalid group."); // we set the cancel flag, to make sure that tasks that support canceling will terminate asap pTask->m_bCancelExecution = true; { EZ_LOCK(s_TaskSystemMutex); // if the task is still in the queue of its group, it had not yet been scheduled if (!pTask->m_bTaskIsScheduled && pTask->m_BelongsToGroup.m_pTaskGroup->m_Tasks.RemoveAndSwap(pTask)) { // we set the task to finished, even though it was not executed pTask->m_bIsFinished = true; return EZ_SUCCESS; } // check if the task has already been scheduled for execution // if so, remove it from the work queue { for (ezUInt32 i = 0; i < ezTaskPriority::ENUM_COUNT; ++i) { auto it = s_Tasks[i].GetIterator(); while (it.IsValid()) { if (it->m_pTask == pTask) { s_Tasks[i].Remove(it); // we set the task to finished, even though it was not executed pTask->m_bIsFinished = true; // tell the system that one task of that group is 'finished', to ensure its dependencies will get scheduled TaskHasFinished(it->m_pTask, it->m_pBelongsToGroup); return EZ_SUCCESS; } ++it; } } } } // if we made it here, the task was already running // thus we just wait for it to finish if (OnTaskRunning == ezOnTaskRunning::WaitTillFinished) WaitForTask(pTask); return EZ_FAILURE; }
ezHashedString ezMaterialResource::GetPermutationValue(const ezTempHashedString& sName) { UpdateCaches(); EZ_LOCK(m_CacheMutex); ezHashedString sResult; m_CachedPermutationVars.TryGetValue(sName, sResult); return sResult; }
ezVariant ezMaterialResource::GetParameter(const ezTempHashedString& sName) { EZ_LOCK(m_CacheMutex); UpdateCaches(); ezVariant value; m_CachedParameters.TryGetValue(sName, value); return value; }
ezTextureCubeResourceHandle ezMaterialResource::GetTextureCubeBinding(const ezTempHashedString& sName) { EZ_LOCK(m_CacheMutex); UpdateCaches(); // Use pointer to prevent ref counting ezTextureCubeResourceHandle* pBinding; if (m_CachedTextureCubeBindings.TryGetValue(sName, pBinding)) { return *pBinding; } return ezTextureCubeResourceHandle(); }
void ezCollectionResource::UnregisterNames() { if (!m_bRegistered) return; m_bRegistered = false; EZ_LOCK(ezResourceManager::GetMutex()); for (const auto& entry : m_Collection.m_Resources) { if (!entry.m_sLookupName.IsEmpty()) { ezResourceManager::UnregisterNamedResource(entry.m_sLookupName); } } }
void ezStats::RemoveStat(const char* szStatName) { EZ_LOCK(s_Mutex); MapType::Iterator it = s_Stats.Find(szStatName); if (!it.IsValid()) return; s_Stats.Remove(it); StatsEventData e; e.m_EventType = StatsEventData::Remove; e.m_szStatName = szStatName; s_StatsEvents.Broadcast(e); }
void ezStats::SetStat(const char* szStatName, const ezVariant& value) { EZ_LOCK(s_Mutex); bool bExisted = false; auto it = s_Stats.FindOrAdd(szStatName, &bExisted); if (it.Value() == value) return; it.Value() = value; StatsEventData e; e.m_EventType = bExisted ? StatsEventData::Set : StatsEventData::Add; e.m_szStatName = szStatName; e.m_NewStatValue = value; s_StatsEvents.Broadcast(e); }
bool ezSceneViewContext::UpdateThumbnailCamera(const ezBoundingBoxSphere& bounds) { ezView* pView = nullptr; if (ezRenderWorld::TryGetView(m_hView, pView)) { pView->SetViewRenderMode(ezViewRenderMode::Default); pView->SetRenderPassProperty("EditorSelectionPass", "Active", false); pView->SetExtractorProperty("EditorShapeIconsExtractor", "Active", false); pView->SetExtractorProperty("EditorGridExtractor", "Active", false); pView->SetRenderPassProperty("EditorPickingPass", "PickSelected", true); } EZ_LOCK(m_pSceneContext->GetWorld()->GetWriteMarker()); const ezCameraComponentManager* pCamMan = m_pSceneContext->GetWorld()->GetComponentManager<ezCameraComponentManager>(); if (pCamMan) { for (auto it = pCamMan->GetComponents(); it.IsValid(); ++it) { const ezCameraComponent* pCamComp = it; if (pCamComp->GetUsageHint() == ezCameraUsageHint::Thumbnail) { m_Camera.LookAt(pCamComp->GetOwner()->GetGlobalPosition(), pCamComp->GetOwner()->GetGlobalPosition() + pCamComp->GetOwner()->GetGlobalDirForwards(), pCamComp->GetOwner()->GetGlobalDirUp()); m_Camera.SetCameraMode(ezCameraMode::PerspectiveFixedFovY, 70.0f, 0.1f, 100.0f); m_CullingCamera = m_Camera; return true; } } } bool bResult = !FocusCameraOnObject(m_Camera, bounds, 70.0f, -ezVec3(5, -2, 3)); m_CullingCamera = m_Camera; return bResult; }
void ezTokenizedFileCache::Remove(const ezString& sFileName) { EZ_LOCK(m_Mutex); m_Cache.Remove(sFileName); }
ezMap<ezString, ezTokenizedFileCache::FileData>::ConstIterator ezTokenizedFileCache::Lookup(const ezString& sFileName) const { EZ_LOCK(m_Mutex); auto it = m_Cache.Find(sFileName); return it; }
const ezTokenizer* ezTokenizedFileCache::Tokenize(const ezString& sFileName, const ezDynamicArray<ezUInt8>& FileContent, const ezTimestamp& FileTimeStamp, ezLogInterface* pLog) { EZ_LOCK(m_Mutex); auto& data = m_Cache[sFileName]; data.m_Timestamp = FileTimeStamp; ezTokenizer* pTokenizer = &data.m_Tokens; pTokenizer->Tokenize(FileContent, pLog); ezDeque<ezToken>& Tokens = pTokenizer->GetTokens(); ezHashedString sFile; sFile.Assign(sFileName.GetData()); ezInt32 iLineOffset = 0; for (ezUInt32 i = 0; i + 1 < Tokens.GetCount(); ++i) { const ezUInt32 uiCurLine = Tokens[i].m_uiLine; Tokens[i].m_File = sFile; Tokens[i].m_uiLine += iLineOffset; if (Tokens[i].m_iType == ezTokenType::NonIdentifier && ezString(Tokens[i].m_DataView) == "#") { ezUInt32 uiNext = i + 1; SkipWhitespace(Tokens, uiNext); if (uiNext < Tokens.GetCount() && Tokens[uiNext].m_iType == ezTokenType::Identifier && ezString(Tokens[uiNext].m_DataView) == "line") { ++uiNext; SkipWhitespace(Tokens, uiNext); if (uiNext < Tokens.GetCount() && Tokens[uiNext].m_iType == ezTokenType::Identifier) { ezInt32 iNextLine = 0; const ezString sNumber = Tokens[uiNext].m_DataView; if (ezConversionUtils::StringToInt(sNumber.GetData(), iNextLine).Succeeded()) { iLineOffset = (iNextLine - uiCurLine) - 1; ++uiNext; SkipWhitespace(Tokens, uiNext); if (uiNext < Tokens.GetCount()) { if (Tokens[uiNext].m_iType == ezTokenType::String1) { ezStringBuilder sFileName = Tokens[uiNext].m_DataView; sFileName.Shrink(1, 1); // remove surrounding " sFile.Assign(sFileName.GetData()); } } } } } } } return pTokenizer; }
void ezTokenizedFileCache::Clear() { EZ_LOCK(m_Mutex); m_Cache.Clear(); }
ezTaskSystem::TaskData ezTaskSystem::GetNextTask(ezTaskPriority::Enum FirstPriority, ezTaskPriority::Enum LastPriority, ezTask* pPrioritizeThis) { // this is the central function that selects tasks for the worker threads to work on // do a quick and dirty check, whether we would find any work (without a lock) // if nothing is found, the thread can go to sleep, without entering the mutex // note: There is NO race condition here. Even if this loop would miss a work item, because it is added after it looked at the // corresponding queue, it will not be a problem. The function will return with 'no work' for the thread, the thread will try to go to // sleep, but the thread-signal will be signaled already and thus the thread will loop again, call 'GetNextTask' a second time and THEN // detect the new work item EZ_ASSERT_DEV(FirstPriority >= ezTaskPriority::EarlyThisFrame && LastPriority < ezTaskPriority::ENUM_COUNT, "Priority Range is invalid: {0} to {1}", FirstPriority, LastPriority); for (ezUInt32 i = FirstPriority; i <= (ezUInt32)LastPriority; ++i) { if (!s_Tasks[i].IsEmpty()) goto foundany; } { TaskData td; td.m_pTask = nullptr; td.m_pBelongsToGroup = nullptr; return td; } foundany: // we have detected that there MIGHT be work EZ_LOCK(s_TaskSystemMutex); // if there is a task that should be prioritized, check if it exists in any of the task lists if (pPrioritizeThis != nullptr) { // only search for the task in the lists that this thread is willing to work on // otherwise we might execute a main-thread task in a thread that is not the main thread for (ezUInt32 i = FirstPriority; i <= (ezUInt32)LastPriority; ++i) { auto it = s_Tasks[i].GetIterator(); // just blindly search the entire list while (it.IsValid()) { // if we find that task, return it // otherwise this whole search will do nothing and the default priority based // system will take over if (it->m_pTask == pPrioritizeThis) { TaskData td = *it; s_Tasks[i].Remove(it); return td; } ++it; } } } // go through all the task lists that this thread is willing to work on for (ezUInt32 i = FirstPriority; i <= (ezUInt32)LastPriority; ++i) { // if the list is not empty, just take the first task and execute that if (!s_Tasks[i].IsEmpty()) { TaskData td = *s_Tasks[i].GetIterator(); s_Tasks[i].Remove(s_Tasks[i].GetIterator()); return td; } } { TaskData td; td.m_pTask = nullptr; td.m_pBelongsToGroup = nullptr; return td; } }
void ezWorld::UpdateFromThread() { EZ_LOCK(GetWriteMarker()); Update(); }