main: Use an sdevent loop to poll POST codes
Currently the daemon spawns a thread to read the kernel device file
and update DBus value. Use sdevent interface such that a single event
loop can process DBus requests as well as IO events.
Tested: on hardware platform tested that daemon still reads POST codes
and update DBus interface as expected.
Change-Id: I998a1fa8d955205faa95ad0002425eb11a4a46eb
Signed-off-by: Kun Yi <kunyi731@gmail.com>
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;
}