Still memory leaks in threadpool all

This commit is contained in:
Dynamitos
2022-03-28 21:18:57 +02:00
parent 3a650237b9
commit 5af5345048
9 changed files with 113 additions and 77 deletions
+1 -1
+1 -1
+1 -1
+34 -17
View File
@@ -11,30 +11,46 @@ List<Promise*> Seele::promises;
//} //}
Event::Event(const std::string &name, const std::source_location &location) Event::Event(const std::string &name, const std::source_location &location)
: name(name) : state(std::make_shared<EventState>())
, location(location)
{ {
state->name = name;
state->location = location;
} }
Event::Event(const std::source_location &location) Event::Event(const std::source_location &location)
: name(location.function_name()) : state(std::make_shared<EventState>())
, location(location)
{ {
state->name = location.function_name();
state->location = location;
}
Event::Event(const Event& other)
{
std::scoped_lock lock(other.eventLock);
state = other.state;
} }
Event::Event(Event&& other) Event::Event(Event&& other)
: name(std::move(other.name))
, location(std::move(other.location))
{ {
std::scoped_lock lock(other.eventLock);
state = std::move(other.state);
} }
Event& Event::operator=(const Event& other)
{
if(this != &other)
{
std::scoped_lock lock(eventLock, other.eventLock);
state = other.state;
}
return *this;
}
Event& Event::operator=(Event&& other) Event& Event::operator=(Event&& other)
{ {
if(this != &other) if(this != &other)
{ {
std::scoped_lock lock(eventLock, other.eventLock); std::scoped_lock lock(eventLock, other.eventLock);
name = std::move(other.name); state = std::move(other.state);
location = std::move(other.location);
} }
return *this; return *this;
} }
@@ -42,26 +58,26 @@ Event& Event::operator=(Event&& other)
void Event::raise() void Event::raise()
{ {
std::scoped_lock lock(eventLock); std::scoped_lock lock(eventLock);
data = true; state->data = true;
if(waitingJobs.size() > 0) if(state->waitingJobs.size() > 0)
{ {
getGlobalThreadPool().scheduleBatch(waitingJobs); getGlobalThreadPool().scheduleBatch(state->waitingJobs);
} }
if(waitingMainJobs.size() > 0) if(state->waitingMainJobs.size() > 0)
{ {
getGlobalThreadPool().scheduleBatch(waitingMainJobs); getGlobalThreadPool().scheduleBatch(state->waitingMainJobs);
} }
} }
void Event::reset() void Event::reset()
{ {
std::scoped_lock lock(eventLock); std::scoped_lock lock(eventLock);
data = false; state->data = false;
} }
bool Event::await_ready() bool Event::await_ready()
{ {
eventLock.lock(); eventLock.lock();
bool result = data; bool result = state->data;
if(result) if(result)
{ {
eventLock.unlock(); eventLock.unlock();
@@ -72,14 +88,14 @@ bool Event::await_ready()
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<false>> h) void Event::await_suspend(std::coroutine_handle<JobPromiseBase<false>> h)
{ {
//h.promise().enqueue(this); //h.promise().enqueue(this);
waitingJobs.add(JobBase<false>(&h.promise())); state->waitingJobs.add(JobBase<false>(&h.promise()));
eventLock.unlock(); eventLock.unlock();
} }
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<true>> h) void Event::await_suspend(std::coroutine_handle<JobPromiseBase<true>> h)
{ {
//h.promise().enqueue(this); //h.promise().enqueue(this);
waitingMainJobs.add(JobBase<true>(&h.promise())); state->waitingMainJobs.add(JobBase<true>(&h.promise()));
eventLock.unlock(); eventLock.unlock();
} }
@@ -117,6 +133,7 @@ void ThreadPool::waitIdle()
std::unique_lock lock(numIdlingLock); std::unique_lock lock(numIdlingLock);
if(numIdling == workers.size()) if(numIdling == workers.size())
{ {
assert(promises.size() == 0);
return; return;
} }
numIdlingIncr.wait(lock); numIdlingIncr.wait(lock);
+58 -39
View File
@@ -19,35 +19,35 @@ public:
//Event(nullptr_t); //Event(nullptr_t);
Event(const std::string& name, const std::source_location& location = std::source_location::current()); Event(const std::string& name, const std::source_location& location = std::source_location::current());
Event(const std::source_location& location = std::source_location::current()); Event(const std::source_location& location = std::source_location::current());
Event(const Event& other) = delete; Event(const Event& other);
Event(Event&& other); Event(Event&& other);
~Event() = default; ~Event() = default;
Event& operator=(const Event& other) = delete; Event& operator=(const Event& other);
Event& operator=(Event&& other); Event& operator=(Event&& other);
auto operator<=>(const Event& other) const auto operator<=>(const Event& other) const
{ {
return name <=> other.name; return state->name <=> other.state->name;
} }
bool operator==(const Event& other) const bool operator==(const Event& other) const
{ {
return name == other.name; return state->name == other.state->name;
} }
operator bool() operator bool()
{ {
std::scoped_lock lock(eventLock); std::scoped_lock lock(eventLock);
return data; return state->data;
} }
friend std::ostream& operator<<(std::ostream& stream, const Event& event) friend std::ostream& operator<<(std::ostream& stream, const Event& event)
{ {
stream stream
<< event.location.file_name() << event.state->location.file_name()
<< "(" << "("
<< event.location.line() << event.state->location.line()
<< ":" << ":"
<< event.location.column() << event.state->location.column()
<< "): " << "): "
<< event.location.function_name(); << event.state->location.function_name();
return stream; return stream;
} }
@@ -58,12 +58,16 @@ public:
void await_suspend(std::coroutine_handle<JobPromiseBase<true>> h); void await_suspend(std::coroutine_handle<JobPromiseBase<true>> h);
constexpr void await_resume() {} constexpr void await_resume() {}
private: private:
std::string name; mutable std::mutex eventLock;
std::source_location location; struct EventState
std::mutex eventLock; {
bool data = false; std::string name;
Array<JobBase<false>> waitingJobs; std::source_location location;
Array<JobBase<true>> waitingMainJobs; bool data = false;
Array<JobBase<false>> waitingJobs;
Array<JobBase<true>> waitingMainJobs;
};
std::shared_ptr<EventState> state;
friend class ThreadPool; friend class ThreadPool;
}; };
@@ -81,14 +85,14 @@ struct JobPromiseBase
DONE DONE
}; };
JobPromiseBase(const std::source_location& location = std::source_location::current()) JobPromiseBase(const std::source_location& location = std::source_location::current())
: pad0(0x7472617453) : pad0(12345)//0x7472617453)
, handle(std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this)) , handle(std::coroutine_handle<JobPromiseBase<MainJob>>::from_promise(*this))
, waitingFor(nullptr) , waitingFor(nullptr)
, continuation(nullptr) , continuation(nullptr)
, numRefs(0) , numRefs(0)
, finishedEvent(location) , finishedEvent(location)
, state(State::READY) , state(State::READY)
, pad1(0x646E45) , pad1(12345)//0x646E45)
{ {
if constexpr(!MainJob) if constexpr(!MainJob)
{ {
@@ -119,6 +123,7 @@ struct JobPromiseBase
void resume() void resume()
{ {
validate();
if(!handle || handle.done() || executing()) if(!handle || handle.done() || executing())
{ {
return; return;
@@ -128,6 +133,7 @@ struct JobPromiseBase
} }
void setContinuation(JobPromiseBase* cont) void setContinuation(JobPromiseBase* cont)
{ {
validate();
assert(cont->ready()); assert(cont->ready());
continuation = cont; continuation = cont;
cont->state = State::SCHEDULED; cont->state = State::SCHEDULED;
@@ -136,32 +142,39 @@ struct JobPromiseBase
} }
bool done() bool done()
{ {
validate();
return state == State::DONE; return state == State::DONE;
} }
bool scheduled() bool scheduled()
{ {
validate();
return state == State::SCHEDULED; return state == State::SCHEDULED;
} }
bool waiting() bool waiting()
{ {
validate();
return state == State::WAITING; return state == State::WAITING;
} }
bool executing() bool executing()
{ {
validate();
return state == State::EXECUTING; return state == State::EXECUTING;
} }
bool ready() bool ready()
{ {
validate();
return state == State::READY; return state == State::READY;
} }
void enqueue(Event* event); void enqueue(Event* event);
bool schedule(); bool schedule();
void addRef() void addRef()
{ {
validate();
numRefs++; numRefs++;
} }
void removeRef() void removeRef()
{ {
validate();
numRefs--; numRefs--;
if(numRefs == 0) if(numRefs == 0)
{ {
@@ -171,6 +184,11 @@ struct JobPromiseBase
} }
} }
} }
void validate()
{
assert(pad0 == 12345);
assert(pad1 == 12345);
}
uint64 pad0; uint64 pad0;
std::coroutine_handle<JobPromiseBase> handle; std::coroutine_handle<JobPromiseBase> handle;
Event* waitingFor; Event* waitingFor;
@@ -199,7 +217,10 @@ public:
JobBase(const JobBase& other) JobBase(const JobBase& other)
{ {
promise = other.promise; promise = other.promise;
promise->addRef(); if(promise != nullptr)
{
promise->addRef();
}
} }
JobBase(JobBase&& other) JobBase(JobBase&& other)
{ {
@@ -223,7 +244,10 @@ public:
promise->removeRef(); promise->removeRef();
} }
promise = other.promise; promise = other.promise;
promise->addRef(); if(promise != nullptr)
{
promise->addRef();
}
} }
return *this; return *this;
} }
@@ -245,15 +269,15 @@ public:
promise->resume(); promise->resume();
} }
template<std::invocable Callable> template<std::invocable Callable>
inline JobBase&& then(Callable callable) inline JobBase then(Callable callable)
{ {
return then(callable()); return then(callable());
} }
JobBase&& then(JobBase&& continuation) JobBase then(JobBase continuation)
{ {
promise->setContinuation(continuation.promise); promise->setContinuation(continuation.promise);
promise->schedule(); continuation.promise->state = JobPromiseBase<MainJob>::State::SCHEDULED;
return std::move(continuation); return continuation;
} }
bool done() bool done()
{ {
@@ -267,9 +291,11 @@ public:
return promise->finishedEvent; return promise->finishedEvent;
} }
static JobBase all() = delete; static JobBase all() = delete;
template<std::ranges::range Iterable> template<std::ranges::range Iterable>
requires std::same_as<std::ranges::range_value_t<Iterable>, JobBase<MainJob>> requires std::same_as<std::ranges::range_value_t<Iterable>, JobBase<MainJob>>
static JobBase<MainJob> all(Iterable collection); static JobBase<MainJob> all(Iterable collection);
template<std::ranges::range Iterable> template<std::ranges::range Iterable>
static JobBase all(Iterable collection) static JobBase all(Iterable collection)
{ {
@@ -278,10 +304,11 @@ public:
co_await it; co_await it;
} }
} }
template<typename... Awaitable> template<typename... Awaitable>
static JobBase all(Awaitable&&... jobs) static JobBase all(Awaitable... jobs)
{ {
return JobBase::all(Array{jobs...}); return JobBase::all(std::initializer_list{jobs...});
} }
template<typename JobFunc, std::ranges::input_range Iterable> template<typename JobFunc, std::ranges::input_range Iterable>
requires std::invocable<JobFunc, std::ranges::range_reference_t<Iterable>> requires std::invocable<JobFunc, std::ranges::range_reference_t<Iterable>>
@@ -299,7 +326,7 @@ using Promise = JobPromiseBase<false>;
class ThreadPool class ThreadPool
{ {
public: public:
ThreadPool(uint32 threadCount = 1);//std::thread::hardware_concurrency()); ThreadPool(uint32 threadCount = std::thread::hardware_concurrency());
virtual ~ThreadPool(); virtual ~ThreadPool();
void waitIdle(); void waitIdle();
void scheduleJob(Job job); void scheduleJob(Job job);
@@ -313,7 +340,7 @@ public:
{ {
//job.promise->addRef(); //job.promise->addRef();
job.promise->state = JobPromiseBase<true>::State::SCHEDULED; job.promise->state = JobPromiseBase<true>::State::SCHEDULED;
mainJobs.add(job); mainJobs.add(std::move(job));
} }
mainJobCV.notify_one(); mainJobCV.notify_one();
} }
@@ -326,7 +353,7 @@ public:
{ {
//job.promise->addRef(); //job.promise->addRef();
job.promise->state = JobPromiseBase<false>::State::SCHEDULED; job.promise->state = JobPromiseBase<false>::State::SCHEDULED;
jobQueue.add(job); jobQueue.add(std::move(job));
} }
jobQueueCV.notify_all(); jobQueueCV.notify_all();
} }
@@ -360,12 +387,14 @@ inline JobBase<MainJob> JobPromiseBase<MainJob>::get_return_object() noexcept
template<bool MainJob> template<bool MainJob>
inline auto JobPromiseBase<MainJob>::initial_suspend() noexcept inline auto JobPromiseBase<MainJob>::initial_suspend() noexcept
{ {
validate();
return std::suspend_always{}; return std::suspend_always{};
} }
template<bool MainJob> template<bool MainJob>
inline auto JobPromiseBase<MainJob>::final_suspend() noexcept inline auto JobPromiseBase<MainJob>::final_suspend() noexcept
{ {
validate();
state = State::DONE; state = State::DONE;
finishedEvent.raise(); finishedEvent.raise();
if(continuation) if(continuation)
@@ -375,20 +404,10 @@ inline auto JobPromiseBase<MainJob>::final_suspend() noexcept
} }
return std::suspend_always{}; return std::suspend_always{};
} }
//template<bool MainJob>
//inline void JobPromiseBase<MainJob>::enqueue(Event* event)
//{
// if(!handle || handle.done() || waiting() || scheduled())
// {
// return;
// }
// state = State::WAITING;
// waitingFor = event;
// getGlobalThreadPool().enqueueWaiting(event, std::move(JobBase<MainJob>(this)));
//}
template<bool MainJob> template<bool MainJob>
inline bool JobPromiseBase<MainJob>::schedule() inline bool JobPromiseBase<MainJob>::schedule()
{ {
validate();
if(!handle || done() || !ready()) if(!handle || done() || !ready())
{ {
return false; return false;
+12 -12
View File
@@ -20,13 +20,13 @@ Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const Viewpo
{ {
scene = new Scene(graphics); scene = new Scene(graphics);
scene->addActor(activeCamera); scene->addActor(activeCamera);
AssetRegistry::importFile("/home/dynamitos/TestSeeleProject/Assets/Ayaka/Avatar_Girl_Sword_Ayaka_Tex_Body_Diffuse.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Body_Diffuse.png");
AssetRegistry::importFile("/home/dynamitos/TestSeeleProject/Assets/Ayaka/Avatar_Girl_Sword_Ayaka_Tex_Body_Lightmap.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Body_Lightmap.png");
AssetRegistry::importFile("/home/dynamitos/TestSeeleProject/Assets/Ayaka/Avatar_Girl_Sword_Ayaka_Tex_Face_Diffuse.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Face_Diffuse.png");
AssetRegistry::importFile("/home/dynamitos/TestSeeleProject/Assets/Ayaka/Avatar_Girl_Sword_Ayaka_Tex_Hair_Diffuse.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Hair_Diffuse.png");
AssetRegistry::importFile("/home/dynamitos/TestSeeleProject/Assets/Ayaka/Avatar_Girl_Sword_Ayaka_Tex_Hair_Lightmap.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Hair_Lightmap.png");
AssetRegistry::importFile("/home/dynamitos/TestSeeleProject/Assets/Ayaka/Avatar_Girl_Tex_FaceLightmap.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Tex_FaceLightmap.png");
AssetRegistry::importFile("/home/dynamitos/TestSeeleProject/Assets/Ayaka/Ayaka.fbx"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Ayaka.fbx");
PPrimitiveComponent ayaka = new PrimitiveComponent(AssetRegistry::findMesh("Ayaka")); PPrimitiveComponent ayaka = new PrimitiveComponent(AssetRegistry::findMesh("Ayaka"));
ayaka->setRelativeLocation(Vector(0, 0, 0)); ayaka->setRelativeLocation(Vector(0, 0, 0));
ayaka->setRelativeScale(Vector(10, 10, 10)); ayaka->setRelativeScale(Vector(10, 10, 10));
@@ -34,12 +34,12 @@ Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const Viewpo
//AssetRegistry::importFile("D:\\Private\\Programming\\Unreal Engine\\Assets\\Ely\\Ely.fbx"); //AssetRegistry::importFile("D:\\Private\\Programming\\Unreal Engine\\Assets\\Ely\\Ely.fbx");
//AssetRegistry::importFile("D:\\Private\\Programming\\Unreal Engine\\Assets\\Cube\\cube.obj"); //AssetRegistry::importFile("D:\\Private\\Programming\\Unreal Engine\\Assets\\Cube\\cube.obj");
//AssetRegistry::importFile("D:\\Private\\Programming\\Unreal Engine\\Assets\\Plane\\plane.fbx"); AssetRegistry::importFile("D:\\Private\\Programming\\Unreal Engine\\Assets\\Plane\\plane.fbx");
//PPrimitiveComponent plane = new PrimitiveComponent(AssetRegistry::findMesh("plane")); PPrimitiveComponent plane = new PrimitiveComponent(AssetRegistry::findMesh("plane"));
//plane->setRelativeScale(Vector(100, 100, 100)); plane->setRelativeScale(Vector(100, 100, 100));
//scene->addPrimitiveComponent(plane); scene->addPrimitiveComponent(plane);
for(uint32 i = 0; i < 100000; ++i) for(uint32 i = 0; i < 10; ++i)
{ {
PMyComponent myComp = new MyComponent(); PMyComponent myComp = new MyComponent();
PMyOtherComponent myOtherComp = new MyOtherComponent(); PMyOtherComponent myOtherComp = new MyOtherComponent();
+1 -1
View File
@@ -9,7 +9,7 @@ using namespace Seele;
int main() int main()
{ {
PWindowManager windowManager = new WindowManager(); PWindowManager windowManager = new WindowManager();
AssetRegistry::init("/home/dynamitos/TestSeeleProject/"); AssetRegistry::init("C:\\Users\\Dynamitos\\TestSeeleProject");
WindowCreateInfo mainWindowInfo; WindowCreateInfo mainWindowInfo;
mainWindowInfo.title = "SeeleEngine"; mainWindowInfo.title = "SeeleEngine";
mainWindowInfo.width = 1280; mainWindowInfo.width = 1280;
+3 -1
View File
@@ -7,7 +7,9 @@ include_directories(${Boost_INCLUDE_DIRS})
add_subdirectory(Engine/) add_subdirectory(Engine/)
target_link_libraries(Seele_unit_tests ${Boost_LIBRARIES}) target_link_libraries(Seele_unit_tests ${Boost_LIBRARIES})
target_compile_definitions(Seele_unit_tests PRIVATE -DBOOST_TEST_DYN_LINK) if(UNIX)
target_compile_definitions(Seele_unit_tests PRIVATE -DBOOST_TEST_DYN_LINK)
endif()
target_precompile_headers(Seele_unit_tests target_precompile_headers(Seele_unit_tests
PRIVATE PRIVATE
+2 -4
View File
@@ -1,5 +1,5 @@
#pragma once #pragma once
//#include <vld.h> #include <vld.h>
namespace Seele namespace Seele
{ {
@@ -7,16 +7,14 @@ namespace Seele
{ {
GlobalFixture() GlobalFixture()
{ {
//_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
} }
~GlobalFixture(); ~GlobalFixture();
void setup() void setup()
{ {
//Fibers::JobQueue::initJobQueues();
} }
void teardown() void teardown()
{ {
//Fibers::JobQueue::cleanupJobQueues();
} }
}; };
}; };