From 542e23ffbe5cd9e49c026e36533902f6df1f4021 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 23 Mar 2023 16:53:01 -0600 Subject: [PATCH] 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. --- gdbsupport/Makefile.am | 1 + gdbsupport/Makefile.in | 6 ++-- gdbsupport/task-group.cc | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ gdbsupport/task-group.h | 61 +++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 gdbsupport/task-group.cc create mode 100644 gdbsupport/task-group.h diff --git a/gdbsupport/Makefile.am b/gdbsupport/Makefile.am index f1a6413..fdca034 100644 --- a/gdbsupport/Makefile.am +++ b/gdbsupport/Makefile.am @@ -79,6 +79,7 @@ libgdbsupport_a_SOURCES = \ search.cc \ signals.cc \ signals-state-save-restore.cc \ + task-group.cc \ tdesc.cc \ thread-pool.cc \ xml-utils.cc \ diff --git a/gdbsupport/Makefile.in b/gdbsupport/Makefile.in index 9fdc23c..070e36a 100644 --- a/gdbsupport/Makefile.in +++ b/gdbsupport/Makefile.in @@ -166,8 +166,8 @@ am_libgdbsupport_a_OBJECTS = agent.$(OBJEXT) btrace-common.$(OBJEXT) \ ptid.$(OBJEXT) rsp-low.$(OBJEXT) run-time-clock.$(OBJEXT) \ safe-strerror.$(OBJEXT) scoped_mmap.$(OBJEXT) search.$(OBJEXT) \ signals.$(OBJEXT) signals-state-save-restore.$(OBJEXT) \ - tdesc.$(OBJEXT) thread-pool.$(OBJEXT) xml-utils.$(OBJEXT) \ - $(am__objects_1) $(am__objects_2) + task-group.$(OBJEXT) tdesc.$(OBJEXT) thread-pool.$(OBJEXT) \ + xml-utils.$(OBJEXT) $(am__objects_1) $(am__objects_2) libgdbsupport_a_OBJECTS = $(am_libgdbsupport_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) @@ -436,6 +436,7 @@ libgdbsupport_a_SOURCES = \ search.cc \ signals.cc \ signals-state-save-restore.cc \ + task-group.cc \ tdesc.cc \ thread-pool.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)/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)/task-group.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)/xml-utils.Po@am__quote@ diff --git a/gdbsupport/task-group.cc b/gdbsupport/task-group.cc new file mode 100644 index 0000000..cec63db --- /dev/null +++ b/gdbsupport/task-group.cc @@ -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 . */ + +#include "common-defs.h" +#include "task-group.h" +#include "thread-pool.h" + +namespace gdb +{ + +class task_group::impl : public std::enable_shared_from_this +{ +public: + + explicit impl (std::function &&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 &&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> m_tasks; + /* The 'done' function. */ + std::function m_done; +}; + +void +task_group::impl::start () +{ + std::shared_ptr 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 &&done) + : m_task (new impl (std::move (done))) +{ +} + +void +task_group::add_task (std::function &&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 */ diff --git a/gdbsupport/task-group.h b/gdbsupport/task-group.h new file mode 100644 index 0000000..7977c60 --- /dev/null +++ b/gdbsupport/task-group.h @@ -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 . */ + +#ifndef GDBSUPPORT_TASK_GROUP_H +#define GDBSUPPORT_TASK_GROUP_H + +#include + +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 &&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 &&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 m_task; +}; + +} /* namespace gdb */ + +#endif /* GDBSUPPORT_TASK_GROUP_H */ -- 2.7.4