[Spice-devel] [PATCH spice-streaming-agent v2 3/5] Starts/stops the agent based on VT status

Frediano Ziglio fziglio at redhat.com
Mon May 21 10:45:29 UTC 2018


Check if the current display server is active or not and stream only if
active.
This will allow to support multiple display servers running.
When multiple display servers are running only one have the GPU
associated and is writing to the screen.
Stop capturing and release resources when the display server is not
active and vice versa.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 src/Makefile.am               |  2 ++
 src/eventfd.cpp               | 38 ++++++++++++++++++++
 src/eventfd.hpp               | 34 ++++++++++++++++++
 src/spice-streaming-agent.cpp | 65 +++++++++++++++++++++++++++++++----
 4 files changed, 132 insertions(+), 7 deletions(-)
 create mode 100644 src/eventfd.cpp
 create mode 100644 src/eventfd.hpp

diff --git a/src/Makefile.am b/src/Makefile.am
index 276478f..ffc52b2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,4 +62,6 @@ spice_streaming_agent_SOURCES = \
 	jpeg.hpp \
 	stream-port.cpp \
 	stream-port.hpp \
+	eventfd.cpp \
+	eventfd.hpp \
 	$(NULL)
diff --git a/src/eventfd.cpp b/src/eventfd.cpp
new file mode 100644
index 0000000..e3c1e72
--- /dev/null
+++ b/src/eventfd.cpp
@@ -0,0 +1,38 @@
+/* Linux event file descriptors
+ *
+ * \copyright
+ * Copyright 2018 Red Hat Inc. All rights reserved.
+ */
+#include <config.h>
+#include "eventfd.hpp"
+
+#include <stdexcept>
+#include <sys/eventfd.h>
+
+template<typename T>
+inline void ignore_result(T /* unused result */) {}
+
+namespace spice {
+namespace streaming_agent {
+
+EventFD::EventFD():
+    fd(eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK))
+{
+    if (fd < 0) {
+        throw std::runtime_error("Failed to create eventfd");
+    }
+}
+
+void EventFD::signal()
+{
+    uint64_t n = 1;
+    ignore_result(write(fd, &n, sizeof(n)));
+}
+
+void EventFD::ack()
+{
+    uint64_t n;
+    ignore_result(read(fd, &n, sizeof(n)));
+}
+
+}} // namespace spice::streaming_agent
diff --git a/src/eventfd.hpp b/src/eventfd.hpp
new file mode 100644
index 0000000..48a175c
--- /dev/null
+++ b/src/eventfd.hpp
@@ -0,0 +1,34 @@
+/* Linux event file descriptors
+ *
+ * \copyright
+ * Copyright 2018 Red Hat Inc. All rights reserved.
+ */
+#ifndef SPICE_STREAMING_AGENT_EVENTFD_HPP
+#define SPICE_STREAMING_AGENT_EVENTFD_HPP
+
+#include <unistd.h>
+
+namespace spice {
+namespace streaming_agent {
+
+class EventFD {
+public:
+    EventFD();
+    ~EventFD() { close(fd); }
+    void signal();
+    void ack();
+    /**
+     * Returns underlying file descriptor.
+     * Do not close, should just be used for polling.
+     */
+    int raw_fd() const { return fd; }
+private:
+    EventFD(const EventFD&) = delete;
+    void operator=(const EventFD&) = delete;
+
+    int fd;
+};
+
+}} // namespace spice::streaming_agent
+
+#endif // SPICE_STREAMING_AGENT_EVENTFD_HPP
diff --git a/src/spice-streaming-agent.cpp b/src/spice-streaming-agent.cpp
index 6388bb2..240b9c7 100644
--- a/src/spice-streaming-agent.cpp
+++ b/src/spice-streaming-agent.cpp
@@ -10,6 +10,7 @@
 #include "stream-port.hpp"
 #include "error.hpp"
 #include "xorg-utils.hpp"
+#include "eventfd.hpp"
 
 #include <spice/stream-device.h>
 #include <spice/enums.h>
@@ -36,6 +37,7 @@
 #include <thread>
 #include <vector>
 #include <string>
+#include <atomic>
 #include <functional>
 #include <X11/Xlib.h>
 #include <X11/extensions/Xfixes.h>
@@ -61,12 +63,21 @@ static bool quit_requested = false;
 static bool log_binary = false;
 static bool log_frames = false;
 static std::set<SpiceVideoCodecType> client_codecs;
+static EventFD update_fd;
+static const char vt_property_name[] = "XFree86_has_VT";
+static const char *stream_port_name = "/dev/virtio-ports/org.spice-space.stream.0";
+static Atom vt_property = None;
+static std::atomic_bool vt_active;
 
-static bool have_something_to_read(StreamPort &stream_port, bool blocking)
+static bool have_something_to_read(StreamPort &stream_port, bool blocking, int &fd)
 {
-    struct pollfd pollfd = {stream_port.fd, POLLIN, 0};
+    struct pollfd pollfds[2] = {
+        { stream_port.fd, POLLIN, 0 },
+        { update_fd.raw_fd(), POLLIN, 0 },
+    };
 
-    if (poll(&pollfd, 1, blocking ? -1 : 0) < 0) {
+    fd = -1;
+    if (poll(pollfds, 2, blocking ? -1 : 0) < 0) {
         if (errno == EINTR) {
             // report nothing to read, next iteration of the enclosing loop will retry
             return false;
@@ -75,7 +86,13 @@ static bool have_something_to_read(StreamPort &stream_port, bool blocking)
         throw IOError("poll failed on the device", errno);
     }
 
-    if (pollfd.revents & POLLIN) {
+    if (pollfds[1].revents & POLLIN) {
+        fd = update_fd.raw_fd();
+        return true;
+    }
+
+    if (pollfds[0].revents & POLLIN) {
+        fd = stream_port.fd;
         return true;
     }
 
@@ -173,8 +190,18 @@ static void read_command_from_device(StreamPort &stream_port)
 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);
+        int fd;
+        if (have_something_to_read(stream_port, blocking, fd)) {
+            if (fd == stream_port.fd) {
+                read_command_from_device(stream_port);
+            } else if (fd == update_fd.raw_fd()) {
+                update_fd.ack();
+                bool vt_active = ::vt_active.load(std::memory_order_relaxed);
+                if (!vt_active) {
+                    throw std::runtime_error("VT disabled");
+                }
+                continue;
+            }
             break;
         }
 
@@ -305,10 +332,22 @@ send_cursor(StreamPort &stream_port, unsigned width, unsigned height, int hotspo
 static void cursor_changes(StreamPort *stream_port, Display *display, int event_base)
 {
     unsigned long last_serial = 0;
+    Window rootwindow = DefaultRootWindow(display);
 
     while (1) {
         XEvent event;
         XNextEvent(display, &event);
+
+        if (event.type == PropertyNotify) {
+            if (vt_property == None || event.xproperty.atom != vt_property)
+                continue;
+            // update vt property, activate screen read if needed
+            vt_active.store(get_win_prop_int(display, rootwindow, vt_property) != 0, std::memory_order_relaxed);
+            std::atomic_thread_fence(std::memory_order_acquire);
+            update_fd.signal();
+            continue;
+        }
+
         if (event.type != event_base + 1) {
             continue;
         }
@@ -416,7 +455,6 @@ do_capture(StreamPort &stream_port, FILE *f_log)
 
 int main(int argc, char* argv[])
 {
-    const char *stream_port_name = "/dev/virtio-ports/org.spice-space.stream.0";
     int opt;
     const char *log_filename = NULL;
     int logmask = LOG_UPTO(LOG_WARNING);
@@ -522,6 +560,19 @@ int main(int argc, char* argv[])
     Window rootwindow = DefaultRootWindow(display);
     XFixesSelectCursorInput(display, rootwindow, XFixesDisplayCursorNotifyMask);
 
+    vt_property = XInternAtom(display, vt_property_name, True);
+    if (vt_property == None) {
+        syslog(LOG_ERR, "VT property not found\n");
+        return EXIT_FAILURE;
+    }
+    XSelectInput(display, rootwindow, PropertyChangeMask);
+
+    vt_active.store(get_win_prop_int(display, rootwindow, vt_property) != 0, std::memory_order_relaxed);
+    if (!::vt_active.load(std::memory_order_relaxed)) {
+        syslog(LOG_ERR, "VT is disabled");
+        return EXIT_FAILURE;
+    }
+
     int ret = EXIT_SUCCESS;
 
     try {
-- 
2.17.0



More information about the Spice-devel mailing list