From 0642412ebc5c4a72b01b47eff707d544915c965b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 25 Apr 2023 16:27:41 +0900 Subject: [PATCH] common taskscheduler: fix a potential crash issue. Guarantee the tasks are not deleted until the taskscheduler finished them. @Issue: https://github.com/thorvg/thorvg/issues/1370 Change-Id: I9304539f5960a05405ac3993f39894d46a4ff57b --- src/lib/tvgTaskScheduler.cpp | 9 +++--- src/lib/tvgTaskScheduler.h | 70 +++++++++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/lib/tvgTaskScheduler.cpp b/src/lib/tvgTaskScheduler.cpp index 4aef6b3..0194680 100644 --- a/src/lib/tvgTaskScheduler.cpp +++ b/src/lib/tvgTaskScheduler.cpp @@ -100,13 +100,12 @@ struct TaskQueue { }; -class TaskSchedulerImpl +struct TaskSchedulerImpl { -public: - unsigned threadCnt; + uint32_t threadCnt; vector threads; vector taskQueues; - atomic idx{0}; + atomic idx{0}; TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt) { @@ -190,4 +189,4 @@ unsigned TaskScheduler::threads() { if (inst) return inst->threadCnt; return 0; -} \ No newline at end of file +} diff --git a/src/lib/tvgTaskScheduler.h b/src/lib/tvgTaskScheduler.h index 7dd1dce..72c17fb 100644 --- a/src/lib/tvgTaskScheduler.h +++ b/src/lib/tvgTaskScheduler.h @@ -43,47 +43,83 @@ struct TaskScheduler struct Task { private: - mutex mtx; + mutex finishedMtx; + mutex preparedMtx; condition_variable cv; - bool ready{true}; - bool pending{false}; + bool finished = true; //if run() finished + bool prepared = false; //the task is requested public: - virtual ~Task() = default; + virtual ~Task() + { + if (!prepared) return; + + //Guarantee the task is finished by TaskScheduler. + unique_lock lock(preparedMtx); - void done() + while (prepared) { + cv.wait(lock); + } + } + + void done(unsigned tid = 0) { - if (!pending) return; + if (finished) return; + + lock_guard lock(finishedMtx); - unique_lock lock(mtx); - while (!ready) cv.wait(lock); - pending = false; + if (finished) return; + + //the job hasn't been launched yet. + + //set finished so that operator() quickly returns. + finished = true; + + run(tid); } protected: virtual void run(unsigned tid) = 0; private: + void finish() + { + lock_guard lock(preparedMtx); + prepared = false; + cv.notify_one(); + } + void operator()(unsigned tid) { + if (finished) { + finish(); + return; + } + + lock_guard lock(finishedMtx); + + if (finished) { + finish(); + return; + } + run(tid); - lock_guard lock(mtx); - ready = true; - cv.notify_one(); + finished = true; + + finish(); } void prepare() { - ready = false; - pending = true; + finished = false; + prepared = true; } - friend class TaskSchedulerImpl; + friend struct TaskSchedulerImpl; }; - - } #endif //_TVG_TASK_SCHEDULER_H_ + -- 2.7.4