Enable filtering of signal matches
Provide tooling to enable specification of pre-implemented filtering
functors for signal matches.
Add a default 'none' filter to be used when a filter isn't specified.
Change-Id: I3549d8cf44c5f475626875fa94ca3ee8f74d6d26
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/README.md b/README.md
index a06a572..e2415c0 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,20 @@
Supported match tags are:
* signature - A DBus match specification.
+* filter - A filter to apply when a match occurs.
+
+----
+**filter**
+Supported filter tags are:
+
+* name - The name of the filter.
+* args - An optional list of arguments to pass to the filter.
+* value - The argument value.
+* type - The argument type (defaults to string if unspecified).
+
+The available filters provided by PIM are:
+
+* none - A non-filter.
----
diff --git a/examples/match2.yaml b/examples/match2.yaml
index 3e11531..6fb9ff9 100644
--- a/examples/match2.yaml
+++ b/examples/match2.yaml
@@ -12,5 +12,7 @@
path: /xyz/openbmc_project/testing
interface: org.freedesktop.DBus.Properties
member: PropertiesChanged
+ filter:
+ name: none
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/filters.hpp b/filters.hpp
new file mode 100644
index 0000000..eb843a7
--- /dev/null
+++ b/filters.hpp
@@ -0,0 +1,122 @@
+#pragma once
+
+#include <utility>
+#include <memory>
+#include <sdbusplus/message.hpp>
+
+namespace phosphor
+{
+namespace inventory
+{
+namespace manager
+{
+namespace filters
+{
+namespace details
+{
+namespace holder
+{
+
+/** @struct Base
+ * @brief Match event filter functor holder base.
+ *
+ * Provides an un-templated holder for filters of any type with the correct
+ * function call signature.
+ */
+struct Base
+{
+ Base() = default;
+ virtual ~Base() = default;
+ Base(const Base&) = delete;
+ Base& operator=(const Base&) = delete;
+ Base(Base&&) = default;
+ Base& operator=(Base&&) = default;
+
+ virtual bool operator()(sdbusplus::message::message &) const = 0;
+ virtual bool operator()(sdbusplus::message::message &msg)
+ {
+ return const_cast<const Base &>(*this)(msg);
+ }
+};
+
+/** @struct Holder
+ * @brief Match event filter functor holder.
+ *
+ * Adapts a functor of any type (with the correct function call
+ * signature) to a non-templated type usable by the manager for
+ * filtering.
+ *
+ * @tparam T - The functor type.
+ */
+template <typename T>
+struct Holder final : public Base
+{
+ Holder() = delete;
+ ~Holder() = default;
+ Holder(const Holder&) = delete;
+ Holder & operator=(const Holder&) = delete;
+ Holder(Holder&&) = default;
+ Holder& operator=(Holder&&) = default;
+ explicit Holder(T &&func) : _func(std::forward<T>(func)) { }
+
+ virtual bool operator()(sdbusplus::message::message &msg) const override
+ {
+ return _func(msg);
+ }
+
+ virtual bool operator()(sdbusplus::message::message &msg) override
+ {
+ return _func(msg);
+ }
+
+ private:
+ T _func;
+};
+
+} // namespace holder
+
+/** @struct Wrapper
+ * @brief Provides implicit type conversion from filter functors.
+ *
+ * Converts filter functors to ptr-to-holder.
+ */
+struct Wrapper
+{
+ template <typename T>
+ Wrapper(T &&func) :
+ _ptr(std::shared_ptr<holder::Base>(
+ new holder::Holder<T>(std::forward<T>(func)))) { }
+
+ ~Wrapper() = default;
+ Wrapper(const Wrapper&) = default;
+ Wrapper& operator=(const Wrapper&) = delete;
+ Wrapper(Wrapper&&) = default;
+ Wrapper& operator=(Wrapper&&) = default;
+
+ bool operator()(sdbusplus::message::message &msg)
+ {
+ return (*_ptr)(msg);
+ }
+ bool operator()(sdbusplus::message::message &msg) const
+ {
+ return (*_ptr)(msg);
+ }
+
+ private:
+ std::shared_ptr<holder::Base> _ptr;
+};
+
+} // namespace details
+
+/** @brief The default filter. */
+inline bool none(sdbusplus::message::message &) noexcept
+{
+ return true;
+}
+
+} // namespace filters
+} // namespace manager
+} // namespace inventory
+} // namespace phosphor
+
+// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/manager.cpp b/manager.cpp
index 36d47a6..8acd0ec 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -153,6 +153,11 @@
void Manager::signal(sdbusplus::message::message &msg, auto &args)
{
// TODO - unstub
+ auto &filter = std::get<1>(args);
+
+ if(filter(msg)) {
+
+ }
}
#include "generated.hpp"
diff --git a/manager.hpp b/manager.hpp
index 9b8338b..0c78f74 100644
--- a/manager.hpp
+++ b/manager.hpp
@@ -6,6 +6,7 @@
#include <vector>
#include <sdbusplus/server.hpp>
#include <xyz/openbmc_project/Inventory/Manager/server.hpp>
+#include "filters.hpp"
namespace phosphor
{
@@ -121,7 +122,7 @@
/** @brief sd_bus signal callback. */
void signal(sdbusplus::message::message &, auto &);
- using Event = std::tuple<const char *>;
+ using Event = std::tuple<const char *, filters::details::Wrapper>;
using SigArgs = std::vector<
std::unique_ptr<
std::tuple<
diff --git a/pimgen.py b/pimgen.py
index 15c91f6..8350d3a 100755
--- a/pimgen.py
+++ b/pimgen.py
@@ -38,9 +38,10 @@
class MatchRender(object):
- def __init__(self, name, signature):
+ def __init__(self, name, signature, fltr):
self.name = valid_c_name_pattern.sub('_', name).lower()
self.signature = signature
+ self.fltr = fltr
if self.name in all_names:
raise RuntimeError('The name "%s" is not unique.' % name)
@@ -58,20 +59,51 @@
fd.write(' std::make_tuple(\n')
for s in sig:
fd.write(' %s' % s)
- fd.write('\n')
+ fd.write(',\n')
+ self.fltr(fd)
fd.write(' ),\n')
fd.write(' },\n')
+class FilterRender(object):
+ namespace = 'filters'
+ default = 'none'
+
+ def __init__(self, fltr):
+ self.args = None
+ if fltr is None:
+ self.name = self.default
+ else:
+ self.name = fltr.get('name')
+ self.args = fltr.get('args')
+
+ def __call__(self, fd):
+ def fmt(x):
+ if x.get('type') is None:
+ return '"%s"' % x['value']
+ return str(x['value'])
+
+ fd.write(' %s::%s' % (self.namespace, self.name))
+ if self.args:
+ fd.write('(')
+ buf = ','.join(([fmt(x) for x in self.args]))
+ fd.write(buf)
+ fd.write(')')
+
+ fd.write('\n')
+
+
class MatchEventParse(object):
def __init__(self, match):
self.name = match['name']
self.signature = match['signature']
+ self.fltr = match.get('filter')
def __call__(self):
return MatchRender(
self.name,
- self.signature)
+ self.signature,
+ FilterRender(self.fltr))
class EventsParse(object):