Replaces the polling function with a generic class that allows to register multiple file descriptors for polling, along with a callback to call when an event occurs on the descriptor. The patch also effectively replaces the while loop which was in read_command. The loop only ever looped more than once if we didn't have anything to read and we were in blocking mode, which was only in the case we got EINTR. In case of EINTR the loop around poll.poll() will take care of polling again. Signed-off-by: Lukáš Hrázký <lhrazky@xxxxxxxxxx> --- src/Makefile.am | 2 ++ src/poll.cpp | 51 +++++++++++++++++++++++++++++++ src/poll.hpp | 56 +++++++++++++++++++++++++++++++++++ src/spice-streaming-agent.cpp | 51 +++++++------------------------ 4 files changed, 120 insertions(+), 40 deletions(-) create mode 100644 src/poll.cpp create mode 100644 src/poll.hpp diff --git a/src/Makefile.am b/src/Makefile.am index 40544ba..56a8cda 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,6 +62,8 @@ spice_streaming_agent_SOURCES = \ mjpeg-fallback.hpp \ jpeg.cpp \ jpeg.hpp \ + poll.cpp \ + poll.hpp \ stream-port.cpp \ stream-port.hpp \ $(NULL) diff --git a/src/poll.cpp b/src/poll.cpp new file mode 100644 index 0000000..dd9f48a --- /dev/null +++ b/src/poll.cpp @@ -0,0 +1,51 @@ +/* A poll() encapsulation class. + * + * \copyright + * Copyright 2018 Red Hat Inc. All rights reserved. + */ + +#include "poll.hpp" + +#include "error.hpp" + + +namespace spice { +namespace streaming_agent { + +void Poll::add(const pollfd& poll_fd, Callback&& callback) +{ + poll_fds.push_back(poll_fd); + callbacks.push_back(std::move(callback)); +} + +bool Poll::poll(bool blocking) +{ + if (poll_fds.empty()) { + return false; + } + + int res = ::poll(poll_fds.data(), poll_fds.size(), blocking ? -1 : 0); + + if (res == 0) { + return false; + } + + if (res < 0) { + if (errno == EINTR) { + // do nothing, rely on another loop iteration to retry + return false; + } + + throw IOError("poll failed", errno); + } + + for (size_t i = 0; i < poll_fds.size(); ++i) { + if (poll_fds[i].revents) { + callbacks[i](poll_fds[i]); + } + } + + return true; +} + +}} // namespace spice::streaming_agent diff --git a/src/poll.hpp b/src/poll.hpp new file mode 100644 index 0000000..a215159 --- /dev/null +++ b/src/poll.hpp @@ -0,0 +1,56 @@ +/* A poll() encapsulation class. + * + * \copyright + * Copyright 2018 Red Hat Inc. All rights reserved. + */ + +#ifndef SPICE_STREAMING_AGENT_POLL_HPP +#define SPICE_STREAMING_AGENT_POLL_HPP + +#include <functional> +#include <vector> +#include <poll.h> + + +namespace spice { +namespace streaming_agent { + +/** + * A class that implements the poll() mechanism on a collection of file + * descriptors. The fds are added one by one with the add() method, along with + * the callback that should be called when an event occurs on the descriptor. + * In case events occur on more than one descriptor, the callbacks are called + * in the order in which they were added. + */ +class Poll +{ +public: + using Callback = std::function<void(const pollfd&)>; + + /** + * Adds a file descriptor to the list of fds to poll on. + * + * \param poll_fd The pollfd struct for the file descriptor. + * \param callback The callback to call on an event on the file descriptor. + * The signature is void(const pollfd&). + */ + void add(const pollfd& poll_fd, Callback&& callback); + + /** + * Calls poll() on the descriptors registered with add(). + * + * \param blocking If true, sets indefinite timeout on the poll. If false, + * doesn't block and returns immediately. + * + * \return true if there was an event on any fd, false otherwise. + */ + bool poll(bool blocking = true); + +private: + std::vector<pollfd> poll_fds; + std::vector<Callback> callbacks; +}; + +}} // namespace spice::streaming_agent + +#endif // SPICE_STREAMING_AGENT_POLL_HPP diff --git a/src/spice-streaming-agent.cpp b/src/spice-streaming-agent.cpp index 39c53bd..0e383de 100644 --- a/src/spice-streaming-agent.cpp +++ b/src/spice-streaming-agent.cpp @@ -9,6 +9,7 @@ #include "cursor-updater.hpp" #include "frame-log.hpp" #include "stream-port.hpp" +#include "poll.hpp" #include "error.hpp" #include <spice/stream-device.h> @@ -27,7 +28,6 @@ #include <errno.h> #include <fcntl.h> #include <sys/time.h> -#include <poll.h> #include <syslog.h> #include <signal.h> #include <exception> @@ -92,27 +92,7 @@ static bool streaming_requested = false; static bool quit_requested = false; static std::set<SpiceVideoCodecType> client_codecs; -static bool have_something_to_read(StreamPort &stream_port, bool blocking) -{ - struct pollfd pollfd = {stream_port.fd, POLLIN, 0}; - - if (poll(&pollfd, 1, blocking ? -1 : 0) < 0) { - if (errno == EINTR) { - // report nothing to read, next iteration of the enclosing loop will retry - return false; - } - - throw IOError("poll failed on the device", errno); - } - - if (pollfd.revents & POLLIN) { - return true; - } - - return false; -} - -static void read_command_from_device(StreamPort &stream_port) +static void receive_stream_port_message(StreamPort& stream_port) { InboundMessage in_message = stream_port.receive(); @@ -139,22 +119,6 @@ static void read_command_from_device(StreamPort &stream_port) throw std::runtime_error("UNKNOWN msg of type " + std::to_string(in_message.header.type)); } -static void read_command(StreamPort &stream_port, bool blocking) -{ - while (!quit_requested) { - if (have_something_to_read(stream_port, blocking)) { - read_command_from_device(stream_port); - break; - } - - if (!blocking) { - break; - } - - sleep(1); - } -} - static void handle_interrupt(int intr) { syslog(LOG_INFO, "Got signal %d, exiting", intr); @@ -193,9 +157,16 @@ static void do_capture(StreamPort &stream_port, FrameLog &frame_log) { unsigned int frame_count = 0; + + Poll poll; + + poll.add({stream_port.fd, POLLIN, 0}, [&stream_port](const pollfd &pollfd) { + receive_stream_port_message(stream_port); + }); + while (!quit_requested) { while (!quit_requested && !streaming_requested) { - read_command(stream_port, true); + poll.poll(); } if (quit_requested) { @@ -253,7 +224,7 @@ do_capture(StreamPort &stream_port, FrameLog &frame_log) } frame_log.log_stat("Sent frame"); - read_command(stream_port, false); + poll.poll(false); } } } -- 2.17.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel