On Fri, Nov 14, 2025 at 10:31 AM David Malcolm <[email protected]> wrote: > > This patch introduces a publish/subscribe mechanism, allowing for > loosely-coupled senders and receivers, with strongly-typed messages > passing between them. For example, a GCC subsystem could publish > messages about events, and a plugin could subscribe to them.
LGTM. Also really printer events; I had a laugh at least. Thanks, Andrew > > An example can be seen in the selftests. > > gcc/ChangeLog: > * Makefile.in (OBJS-libcommon): Add pub-sub.o. > * pub-sub.cc: New file. > * pub-sub.h: New file. > * selftest-run-tests.cc (selftest::run_tests): Call > selftest::pub_sub_cc_tests. > * selftest.h (selftest::pub_sub_cc_tests): New decl. > --- > gcc/Makefile.in | 1 + > gcc/pub-sub.cc | 138 ++++++++++++++++++++++++++++++++++++++ > gcc/pub-sub.h | 68 +++++++++++++++++++ > gcc/selftest-run-tests.cc | 1 + > gcc/selftest.h | 1 + > 5 files changed, 209 insertions(+) > create mode 100644 gcc/pub-sub.cc > create mode 100644 gcc/pub-sub.h > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index 5c24a9aab00a5..f09915780192c 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1892,6 +1892,7 @@ OBJS-libcommon = \ > graphviz.o pex.o \ > pretty-print.o intl.o \ > json.o json-parsing.o \ > + pub-sub.o \ > xml.o \ > sbitmap.o \ > vec.o input.o hash-table.o ggc-none.o memory-block.o \ > diff --git a/gcc/pub-sub.cc b/gcc/pub-sub.cc > new file mode 100644 > index 0000000000000..192cfa59fd3d6 > --- /dev/null > +++ b/gcc/pub-sub.cc > @@ -0,0 +1,138 @@ > +/* Loosely-coupled notifications via the Publish-Subscribe pattern. > + Copyright (C) 2025 Free Software Foundation, Inc. > + Contributed by David Malcolm <[email protected]>. > + > +This file is part of GCC. > + > +GCC 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, or (at your option) any later > +version. > + > +GCC 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 GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +#define INCLUDE_LIST > +#define INCLUDE_STRING > +#include "config.h" > + > +#include "system.h" > +#include "coretypes.h" > + > +#include "pub-sub.h" > + > + > +#if CHECKING_P > + > +#include "selftest.h" > + > +namespace selftest { > + > +/* Selftests. */ > + > +// A topic for use in selftests > + > +namespace snafu { > + > +struct paper_jam {}; > + > +struct out_of_paper > +{ > + int tray; > +}; > + > +struct ink_low > +{ > + std::string color; > +}; > + > +struct subscriber > +{ > + virtual void on_message (const paper_jam &m) = 0; > + virtual void on_message (const out_of_paper &m) = 0; > + virtual void on_message (const ink_low &m) = 0; > +}; > + > +} // namespace snafu > + > +static void > +test_example () > +{ > + struct logger : public snafu::subscriber > + { > + void on_message (const snafu::paper_jam &) final override > + { > + m_log += "paper jam\n"; > + } > + void on_message (const snafu::out_of_paper &m) final override > + { > + m_log += "out of paper (tray " + std::to_string (m.tray) + ")\n"; > + } > + void on_message (const snafu::ink_low &m) final override > + { > + m_log += "ink low: " + m.color + "\n"; > + } > + > + std::string m_log; > + }; > + > + pub_sub::channel<snafu::subscriber> printer_a; > + pub_sub::channel<snafu::subscriber> printer_b; > + pub_sub::channel<snafu::subscriber> printer_c; > + > + // No subscribers yet > + ASSERT_EQ (printer_a.get_if_active (), nullptr); > + ASSERT_EQ (printer_b.get_if_active (), nullptr); > + ASSERT_EQ (printer_c.get_if_active (), nullptr); > + > + // Subscribers to individual channels > + logger log_a; > + logger log_b; > + logger log_c; > + printer_a.add_subscriber (log_a); > + printer_b.add_subscriber (log_b); > + printer_c.add_subscriber (log_c); > + > + // A subscriber to all channels > + logger log_all; > + printer_a.add_subscriber (log_all); > + printer_b.add_subscriber (log_all); > + printer_c.add_subscriber (log_all); > + > + // The channels now have subscribers > + ASSERT_EQ (printer_a.get_if_active (), &printer_a); > + ASSERT_EQ (printer_b.get_if_active (), &printer_b); > + ASSERT_EQ (printer_c.get_if_active (), &printer_c); > + > + // Publish a message to each channel > + printer_a.publish (snafu::paper_jam {}); > + printer_b.publish (snafu::out_of_paper {1}); > + printer_c.publish (snafu::ink_low {"cyan"}); > + > + // Verify that the subscribers got the messages they were meant to > + ASSERT_EQ (log_a.m_log, "paper jam\n"); > + ASSERT_EQ (log_b.m_log, "out of paper (tray 1)\n"); > + ASSERT_EQ (log_c.m_log, "ink low: cyan\n"); > + ASSERT_EQ (log_all.m_log, > + "paper jam\n" > + "out of paper (tray 1)\n" > + "ink low: cyan\n"); > +} > + > +/* Run all of the selftests within this file. */ > + > +void > +pub_sub_cc_tests () > +{ > + test_example (); > +} > + > +} // namespace selftest > + > +#endif /* #if CHECKING_P */ > diff --git a/gcc/pub-sub.h b/gcc/pub-sub.h > new file mode 100644 > index 0000000000000..30837c4c85216 > --- /dev/null > +++ b/gcc/pub-sub.h > @@ -0,0 +1,68 @@ > +/* Loosely-coupled notifications via the Publish-Subscribe pattern. > + Copyright (C) 2025 Free Software Foundation, Inc. > + Contributed by David Malcolm <[email protected]>. > + > +This file is part of GCC. > + > +GCC 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, or (at your option) any later > +version. > + > +GCC 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 GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +#ifndef GCC_PUB_SUB_H > +#define GCC_PUB_SUB_H > + > +namespace pub_sub { > + > +template <typename Subscriber> > +class channel > +{ > +public: > + using subscriber = Subscriber; > + > + // A node within the std::list > + using subscription = typename std::list<subscriber *>::iterator; > + > + /* Return this if this channel has subscribers, or nullptr if > + there are none. */ > + const channel * > + get_if_active () const > + { > + if (m_subscribers.empty ()) > + return nullptr; > + return this; > + } > + > + template <typename Message> > + void publish (const Message &m) const > + { > + for (auto sub : m_subscribers) > + sub->on_message (m); > + } > + > + subscription > + add_subscriber (subscriber &s) > + { > + return m_subscribers.insert (m_subscribers.end (), &s); > + } > + void unsubscribe (subscription s) > + { > + m_subscribers.remove (s); > + } > + > +private: > + std::list<subscriber *> m_subscribers; > +}; > + > +} // namespace pub_sub > + > +#endif /* GCC_PUB_SUB_H */ > diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc > index c68d3e79a3109..d0e210492f414 100644 > --- a/gcc/selftest-run-tests.cc > +++ b/gcc/selftest-run-tests.cc > @@ -83,6 +83,7 @@ selftest::run_tests () > splay_tree_cc_tests (); > xml_cc_tests (); > graphviz_cc_tests (); > + pub_sub_cc_tests (); > > /* Mid-level data structures. */ > input_cc_tests (); > diff --git a/gcc/selftest.h b/gcc/selftest.h > index 4501d34181c7c..dc0b080de210e 100644 > --- a/gcc/selftest.h > +++ b/gcc/selftest.h > @@ -246,6 +246,7 @@ extern void ordered_hash_map_tests_cc_tests (); > extern void path_coverage_cc_tests (); > extern void predict_cc_tests (); > extern void pretty_print_cc_tests (); > +extern void pub_sub_cc_tests (); > extern void range_op_tests (); > extern void range_tests (); > extern void read_rtl_function_cc_tests (); > -- > 2.26.3 >
