Merge "maintainers: Add new maintainers"
diff --git a/example.cpp b/example.cpp
index 55bd4ed..6754b0e 100644
--- a/example.cpp
+++ b/example.cpp
@@ -19,35 +19,39 @@
#include <iostream>
#include <memory>
-#include <sdbusplus/bus.hpp>
-#include <sdbusplus/message.hpp>
-#include <sdbusplus/server.hpp>
+#include "lpcsnoop/snoop_listen.hpp"
-#include "lpcsnoop/snoop.hpp"
-
-/*
- * Handle incoming dbus signal we care about.
- */
-static int DbusHandleSignal(sd_bus_message* msg, void* data, sd_bus_error* err);
-
-/*
- * Get the match signal for dbus.
- */
-static std::string GetMatch(void);
-
-// Example object that listens for dbus updates.
-class SnoopListen
+/* Example PostCode handler which simply prints them */
+static void printPostcode(uint64_t postcode)
{
- public:
- SnoopListen(sdbusplus::bus::bus& bus) :
- _bus(bus), _signal(bus, GetMatch().c_str(), DbusHandleSignal, this)
- {
- }
+ /* Print output to verify the example program is receiving values. */
+ std::printf("recv: 0x%" PRIx64 "\n", postcode);
+}
- private:
- sdbusplus::bus::bus& _bus;
- sdbusplus::server::match::match _signal;
-};
+/*
+ * One can also specify custom handler that operates on
+ * sdbusplus::message::message type and pass them to constructor.
+ * e.g.
+ *
+ * static void PrintMessageMap(sdbusplus::message::message& m)
+ * {
+ * using sdbusplus::message::variant_ns::get;
+ * std::string messageBusName;
+ * std::map<std::string, sdbusplus::message::variant<uint64_t>>
+ * messageData;
+ *
+ * m.read(messageBusName, messageData);
+ *
+ * std::cout << "Got message from " << messageBusName << std::endl;
+ * for (const auto& kv : messageData)
+ * {
+ * std::cout << "Key: " << kv.first << std::endl;
+ * std::cout << "Value: " << get<uint64_t>(kv.second) << std::endl;
+ * }
+ * }
+ *
+ * lpcsnoop::SnoopListen snoop(ListenBus, PrintMessageMap);
+ */
/*
* This is the entry point for the application.
@@ -58,7 +62,7 @@
int main(int argc, char* argv[])
{
auto ListenBus = sdbusplus::bus::new_default();
- SnoopListen snoop(ListenBus);
+ lpcsnoop::SnoopListen snoop(ListenBus, printPostcode);
while (true)
{
@@ -68,34 +72,3 @@
return 0;
}
-
-static int DbusHandleSignal(sd_bus_message* msg, void* data, sd_bus_error* err)
-{
- auto sdbpMsg = sdbusplus::message::message(msg);
-
- std::string msgSensor, busName{SNOOP_BUSNAME};
- std::map<std::string, sdbusplus::message::variant<uint64_t>> msgData;
- sdbpMsg.read(msgSensor, msgData);
-
- if (msgSensor == busName)
- {
- auto valPropMap = msgData.find("Value");
- if (valPropMap != msgData.end())
- {
- uint64_t rawValue = sdbusplus::message::variant_ns::get<uint64_t>(
- valPropMap->second);
-
- /* Print output to verify the example program is receiving values.
- */
- std::printf("recv: 0x%" PRIx64 "\n", rawValue);
- }
- }
-
- return 0;
-}
-
-static std::string GetMatch(void)
-{
- return "type='signal',interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged',path='" SNOOP_OBJECTPATH "'";
-}
diff --git a/lpcsnoop/snoop_listen.hpp b/lpcsnoop/snoop_listen.hpp
index 15b8c0f..4d0ef36 100644
--- a/lpcsnoop/snoop_listen.hpp
+++ b/lpcsnoop/snoop_listen.hpp
@@ -22,26 +22,39 @@
namespace lpcsnoop
{
-
-using DbusSignalHandler = int (*)(sd_bus_message*, void*, sd_bus_error*);
+using sdbusplus::message::variant_ns::get;
/* Returns matching string for what signal to listen on Dbus */
static const std::string GetMatchRule()
{
- return "type='signal',"
- "interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged',"
- "path='" SNOOP_OBJECTPATH "'";
+ using namespace sdbusplus::bus::match::rules;
+
+ return type::signal() + interface("org.freedesktop.DBus.Properties") +
+ member("PropertiesChanged") + path(SNOOP_OBJECTPATH);
}
class SnoopListen
{
+ using message_handler_t = std::function<void(sdbusplus::message::message&)>;
+ using postcode_handler_t = std::function<void(uint64_t)>;
+
public:
- SnoopListen(sdbusplus::bus::bus& busIn, DbusSignalHandler handler) :
+ SnoopListen(sdbusplus::bus::bus& busIn, sd_bus_message_handler_t handler) :
bus(busIn), signal(busIn, GetMatchRule().c_str(), handler, this)
{
}
+ SnoopListen(sdbusplus::bus::bus& busIn, message_handler_t handler) :
+ bus(busIn), signal(busIn, GetMatchRule(), handler)
+ {
+ }
+
+ SnoopListen(sdbusplus::bus::bus& busIn, postcode_handler_t handler) :
+ SnoopListen(busIn, std::bind(defaultMessageHandler, handler,
+ std::placeholders::_1))
+ {
+ }
+
SnoopListen() = delete; // no default constructor
~SnoopListen() = default;
SnoopListen(const SnoopListen&) = delete;
@@ -52,6 +65,27 @@
private:
sdbusplus::bus::bus& bus;
sdbusplus::server::match::match signal;
+
+ /*
+ * Default message handler which listens to published messages on snoop
+ * DBus path, and calls the given postcode_handler on each value received.
+ */
+ static void defaultMessageHandler(postcode_handler_t& handler,
+ sdbusplus::message::message& m)
+ {
+ std::string messageBusName;
+ std::map<std::string, sdbusplus::message::variant<uint64_t>>
+ messageData;
+ constexpr char propertyKey[] = "Value";
+
+ m.read(messageBusName, messageData);
+
+ if (messageBusName == SNOOP_BUSNAME &&
+ messageData.find(propertyKey) != messageData.end())
+ {
+ handler(get<uint64_t>(messageData[propertyKey]));
+ }
+ }
};
} // namespace lpcsnoop
diff --git a/main.cpp b/main.cpp
index a780335..f1e644a 100644
--- a/main.cpp
+++ b/main.cpp
@@ -16,13 +16,14 @@
#include <fcntl.h>
#include <getopt.h>
-#include <poll.h>
#include <unistd.h>
#include <array>
#include <cstdint>
#include <iostream>
#include <memory>
+#include <sys/epoll.h>
+#include <systemd/sd-event.h>
#include <thread>
#include "lpcsnoop/snoop.hpp"
@@ -37,20 +38,6 @@
*/
static constexpr size_t BUFFER_SIZE = 256;
-/*
- * Process any incoming dbus inquiries, which include introspection etc.
- */
-void ProcessDbus(sdbusplus::bus::bus& bus)
-{
- while (true)
- {
- bus.process_discard();
- bus.wait(); // wait indefinitely
- }
-
- return;
-}
-
static void usage(const char* name)
{
fprintf(stderr,
@@ -76,6 +63,47 @@
}
/*
+ * Callback handling IO event from the POST code fd. i.e. there is new
+ * POST code available to read.
+ */
+int PostCodeEventHandler(sd_event_source* s, int postFd, uint32_t revents,
+ void* userdata)
+{
+ PostReporter* reporter = static_cast<PostReporter*>(userdata);
+ std::array<uint8_t, BUFFER_SIZE> buffer;
+ int readb;
+
+ // TODO(kunyi): more error handling for EPOLLPRI/EPOLLERR.
+ if (revents & EPOLLIN)
+ {
+ readb = read(postFd, buffer.data(), buffer.size());
+ if (readb < 0)
+ {
+ /* Read failure. */
+ return readb;
+ }
+
+ if (readb % codeSize != 0)
+ {
+ fprintf(stderr,
+ "Warning: read size %d not a multiple of "
+ "POST code length %zu. Some codes may be "
+ "corrupt or missing\n",
+ readb, codeSize);
+ readb -= (readb % codeSize);
+ }
+
+ /* Broadcast the values read. */
+ for (int i = 0; i < readb; i += codeSize)
+ {
+ reporter->value(assembleBytes(buffer, i, codeSize));
+ }
+ }
+
+ return 0;
+}
+
+/*
* TODO(venture): this only listens one of the possible snoop ports, but
* doesn't share the namespace.
*
@@ -86,11 +114,8 @@
{
int rc = 0;
int opt;
- struct pollfd pollset;
- int pollr;
- int readb;
int postFd = -1;
- std::array<uint8_t, BUFFER_SIZE> buffer;
+ sd_event* event = NULL;
/*
* These string constants are only used in this method within this object
@@ -143,82 +168,45 @@
return -1;
}
- pollset.fd = postFd;
- pollset.events |= POLLIN;
-
auto bus = sdbusplus::bus::new_default();
// Add systemd object manager.
sdbusplus::server::manager::manager(bus, snoopObject);
PostReporter reporter(bus, snoopObject, deferSignals);
- reporter.emit_object_added();
- bus.request_name(snoopDbus);
+ // Create sdevent and add IO source
+ // TODO(kunyi): the current interface is really C-style. Move to a C++
+ // wrapper when there is a SdEventPlus or some sort of that is ready.
+ rc = sd_event_default(&event);
- /*
- * I don't see a public interface for getting the underlying sd_bus*
- * so instead of poll(bus, driver), I'll just create a separate thread.
- *
- * TODO(venture): There may be a way to use sdevent to poll both the file
- * and the dbus in the same event loop. If I could get the sdbus pointer
- * from bus directly, I'd grab a file handler from it, and then just poll on
- * both in one loop. From a cursory look at sdevent, I should be able to do
- * something similar with that at some point.
- */
- std::thread lt(ProcessDbus, std::ref(bus));
-
- /* infinitely listen for POST codes and broadcast. */
- while (true)
+ if (rc < 0)
{
- pollr = poll(&pollset, 1, -1); /* polls indefinitely. */
- if (pollr < 0)
- {
- /* poll returned error. */
- rc = -errno;
- goto exit;
- }
-
- if (pollr > 0)
- {
- if (pollset.revents & POLLIN)
- {
- readb = read(postFd, buffer.data(), buffer.size());
- if (readb < 0)
- {
- /* Read failure. */
- rc = readb;
- goto exit;
- }
- else
- {
- if (readb % codeSize != 0)
- {
- fprintf(stderr,
- "Warning: read size %d not a multiple of "
- "POST code length %zu. Some codes may be "
- "corrupt or missing\n",
- readb, codeSize);
- readb -= (readb % codeSize);
- }
-
- /* Broadcast the values read. */
- for (int i = 0; i < readb; i += codeSize)
- {
- reporter.value(assembleBytes(buffer, i, codeSize));
- }
- }
- }
- }
+ fprintf(stderr, "Failed to allocate event loop:%s\n", strerror(-rc));
+ goto finish;
}
-exit:
+ sd_event_source* source;
+ rc = sd_event_add_io(event, &source, postFd, EPOLLIN, PostCodeEventHandler,
+ &reporter);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Failed to add sdevent io source:%s\n", strerror(-rc));
+ goto finish;
+ }
+
+ // Enable bus to handle incoming IO and bus events
+ reporter.emit_object_added();
+ bus.request_name(snoopDbus);
+ bus.attach_event(event, SD_EVENT_PRIORITY_NORMAL);
+
+ rc = sd_event_loop(event);
+
+finish:
if (postFd > -1)
{
close(postFd);
}
- lt.join();
-
return rc;
}