Add gdb::task_group

This adds gdb::task_group, a convenient way to group background tasks
and then call a function when all the tasks have completed.
This commit is contained in:
Tom Tromey
2023-03-23 16:53:01 -06:00
parent 4ea870efec
commit 542e23ffbe
4 changed files with 160 additions and 2 deletions

View File

@@ -79,6 +79,7 @@ libgdbsupport_a_SOURCES = \
search.cc \ search.cc \
signals.cc \ signals.cc \
signals-state-save-restore.cc \ signals-state-save-restore.cc \
task-group.cc \
tdesc.cc \ tdesc.cc \
thread-pool.cc \ thread-pool.cc \
xml-utils.cc \ xml-utils.cc \

View File

@@ -166,8 +166,8 @@ am_libgdbsupport_a_OBJECTS = agent.$(OBJEXT) btrace-common.$(OBJEXT) \
ptid.$(OBJEXT) rsp-low.$(OBJEXT) run-time-clock.$(OBJEXT) \ ptid.$(OBJEXT) rsp-low.$(OBJEXT) run-time-clock.$(OBJEXT) \
safe-strerror.$(OBJEXT) scoped_mmap.$(OBJEXT) search.$(OBJEXT) \ safe-strerror.$(OBJEXT) scoped_mmap.$(OBJEXT) search.$(OBJEXT) \
signals.$(OBJEXT) signals-state-save-restore.$(OBJEXT) \ signals.$(OBJEXT) signals-state-save-restore.$(OBJEXT) \
tdesc.$(OBJEXT) thread-pool.$(OBJEXT) xml-utils.$(OBJEXT) \ task-group.$(OBJEXT) tdesc.$(OBJEXT) thread-pool.$(OBJEXT) \
$(am__objects_1) $(am__objects_2) xml-utils.$(OBJEXT) $(am__objects_1) $(am__objects_2)
libgdbsupport_a_OBJECTS = $(am_libgdbsupport_a_OBJECTS) libgdbsupport_a_OBJECTS = $(am_libgdbsupport_a_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@) AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -436,6 +436,7 @@ libgdbsupport_a_SOURCES = \
search.cc \ search.cc \
signals.cc \ signals.cc \
signals-state-save-restore.cc \ signals-state-save-restore.cc \
task-group.cc \
tdesc.cc \ tdesc.cc \
thread-pool.cc \ thread-pool.cc \
xml-utils.cc \ xml-utils.cc \
@@ -546,6 +547,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selftest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selftest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signals-state-save-restore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signals-state-save-restore.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signals.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signals.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task-group.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tdesc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tdesc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-pool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml-utils.Po@am__quote@

94
gdbsupport/task-group.cc Normal file
View File

@@ -0,0 +1,94 @@
/* Task group
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "common-defs.h"
#include "task-group.h"
#include "thread-pool.h"
namespace gdb
{
class task_group::impl : public std::enable_shared_from_this<task_group::impl>
{
public:
explicit impl (std::function<void ()> &&done)
: m_done (std::move (done))
{ }
DISABLE_COPY_AND_ASSIGN (impl);
~impl ()
{
if (m_started)
m_done ();
}
/* Add a task to the task group. */
void add_task (std::function<void ()> &&task)
{
m_tasks.push_back (std::move (task));
};
/* Start this task group. */
void start ();
/* True if started. */
bool m_started = false;
/* The tasks. */
std::vector<std::function<void ()>> m_tasks;
/* The 'done' function. */
std::function<void ()> m_done;
};
void
task_group::impl::start ()
{
std::shared_ptr<impl> shared_this = shared_from_this ();
m_started = true;
for (size_t i = 0; i < m_tasks.size (); ++i)
{
gdb::thread_pool::g_thread_pool->post_task ([=] ()
{
/* Be sure to capture a shared reference here. */
shared_this->m_tasks[i] ();
});
}
}
task_group::task_group (std::function<void ()> &&done)
: m_task (new impl (std::move (done)))
{
}
void
task_group::add_task (std::function<void ()> &&task)
{
gdb_assert (m_task != nullptr);
m_task->add_task (std::move (task));
}
void
task_group::start ()
{
gdb_assert (m_task != nullptr);
m_task->start ();
m_task.reset ();
}
} /* namespace gdb */

61
gdbsupport/task-group.h Normal file
View File

@@ -0,0 +1,61 @@
/* Task group
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDBSUPPORT_TASK_GROUP_H
#define GDBSUPPORT_TASK_GROUP_H
#include <memory>
namespace gdb
{
/* A task group is a collection of tasks. Each task in the group is
submitted to the thread pool. When all the tasks in the group have
finished, a final action is run. */
class task_group
{
public:
explicit task_group (std::function<void ()> &&done);
DISABLE_COPY_AND_ASSIGN (task_group);
/* Add a task to the task group. All tasks must be added before the
group is started. Note that a task may not throw an
exception. */
void add_task (std::function<void ()> &&task);
/* Start this task group. A task group may only be started once.
This will submit all the tasks to the global thread pool. */
void start ();
private:
class impl;
/* A task group is just a facade around an impl. This is done
because the impl object must live as long as its longest-lived
task, so it is heap-allocated and destroyed when the last task
completes. */
std::shared_ptr<impl> m_task;
};
} /* namespace gdb */
#endif /* GDBSUPPORT_TASK_GROUP_H */