// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. #include "Engine/Platform/Thread.h" #include "Engine/Threading/IRunnable.h" #include "Engine/Threading/ThreadRegistry.h" #include "Engine/Core/Log.h" Delegate ThreadBase::ThreadStarting; Delegate ThreadBase::ThreadExiting; ThreadBase::ThreadBase(IRunnable* runnable, const String& name, ThreadPriority priority) : _runnable(runnable) , _priority(priority) , _name(name) , _id(0) , _isRunning(false) , _callAfterWork(true) { ASSERT(_runnable); #if BUILD_DEBUG // Cache name (in case if object gets deleted somewhere) _runnableName = _runnable->ToString(); #endif } void ThreadBase::SetPriority(ThreadPriority priority) { // Check if value won't change if (_priority != priority) { // Set new value _priority = priority; SetPriorityInternal(priority); } } void ThreadBase::Kill(bool waitForJoin) { if (!_isRunning) return; ASSERT(GetID()); const auto thread = static_cast(this); // Stop runnable object if (_callAfterWork && _runnable) { _runnable->Stop(); } LOG(Info, "Killing thread \'{0}\' ID=0x{1:x}", _name, _id); // Kill platform thread KillInternal(waitForJoin); ClearHandleInternal(); // End if (_callAfterWork) { _callAfterWork = false; _runnable->AfterWork(true); } _isRunning = false; ThreadRegistry::Remove(thread); } int32 ThreadBase::Run() { // Setup ASSERT(_runnable); const auto thread = static_cast(this); _id = Platform::GetCurrentThreadID(); ThreadRegistry::Add(thread); ThreadStarting(thread); int32 exitCode = 1; _isRunning = true; LOG(Info, "Thread \'{0}\' ID=0x{1:x} started with priority {2}", _name, _id, ::ToString(GetPriority())); if (_runnable->Init()) { exitCode = _runnable->Run(); if (_callAfterWork) // Prevent from calling this after calling AfterWork since object may be deleted _runnable->Exit(); } LOG(Info, "Thread \'{0}\' ID=0x{1:x} exits with code {2}", _name, _id, exitCode); // End if (_callAfterWork) { _callAfterWork = false; _runnable->AfterWork(false); } ClearHandleInternal(); _isRunning = false; ThreadExiting(thread, exitCode); ThreadRegistry::Remove(thread); return exitCode; }