From 46a38fe0161f6dfc3e9f385033f476e018c1b68b Mon Sep 17 00:00:00 2001 From: Zygo Blaxell Date: Sun, 18 Dec 2022 00:30:37 -0500 Subject: [PATCH] task: rescue post-exec queue on Task destruction task1.append(task2) is supposed to run task2 after task1 is executed; however, if task1 was just executed, and its last reference was owned by a TaskConsumer, then task2 will be appended to a Task that will never run again. A similar problem arises in Exclusion, which can cause blocked tasks to occasionally be dropped without executing them. Signed-off-by: Zygo Blaxell --- lib/task.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/task.cc b/lib/task.cc index dbcb68f..c18ecd8 100644 --- a/lib/task.cc +++ b/lib/task.cc @@ -55,8 +55,8 @@ namespace crucible { /// Tasks to be executed after the current task is executed list m_post_exec_queue; - /// Incremented by run() and append(). Decremented by exec(). - size_t m_run_count = 0; + /// Set by run() and append(). Cleared by exec(). + bool m_run_now = false; /// Set when task starts execution by exec(). /// Cleared when exec() ends. @@ -221,6 +221,9 @@ namespace crucible { TaskState::~TaskState() { --s_instance_count; + unique_lock lock(m_mutex); + // If any dependent Tasks were appended since the last exec, run them now + TaskState::rescue_queue(m_post_exec_queue); } TaskState::TaskState(string title, function exec_fn) : @@ -275,8 +278,8 @@ namespace crucible { { THROW_CHECK0(invalid_argument, task); PairLock lock(m_mutex, task->m_mutex); - if (!task->m_run_count) { - ++task->m_run_count; + if (!task->m_run_now) { + task->m_run_now = true; append_nolock(task); } } @@ -292,7 +295,7 @@ namespace crucible { append_nolock(shared_from_this()); return; } else { - --m_run_count; + m_run_now = false; m_is_running = true; } @@ -335,10 +338,10 @@ namespace crucible { TaskState::run() { unique_lock lock(m_mutex); - if (m_run_count) { + if (m_run_now) { return; } - ++m_run_count; + m_run_now = true; TaskMasterState::push_back(shared_from_this()); }