[Spice-devel] [PATCH 20/22] Move the X11CursorUpdater and X11CursorThread classes in a separate file

Christophe de Dinechin christophe.de.dinechin at gmail.com
Thu Mar 1 16:02:45 UTC 2018



> On 1 Mar 2018, at 16:12, Lukáš Hrázký <lhrazky at redhat.com> wrote:
> 
> On Wed, 2018-02-28 at 16:43 +0100, Christophe de Dinechin wrote:
>> From: Christophe de Dinechin <dinechin at redhat.com>
>> 
>> This makes it possible to remove X11 dependencies from the main agent file.
>> 
>> Note: it may be unsafe to call XCloseDisplay from the destructor.
>> Doing some experiments throwing exceptions, I noticed messages such as:
>> 
>> [xcb] Unknown request in queue while dequeuing
>> [xcb] Most likely this is a multi-threaded client and XInitThreads
>>      has not been called
>> [xcb] Aborting, sorry about that.
>> spice-streaming-agent: xcb_io.c:165: dequeue_pending_request:
>> Assertion `!xcb_xlib_unknown_req_in_deq' failed.
>> Aborted (core dumped)
> 
> Hmm, I think it is quite clear. The destructor gets called in the main
> thread, meanwhile stuff is happening in the cursor thread. Apparently,
> if we wanna do that, we need to either join the thread before
> destroying the object (probably a good idea and I think we can do
> that), or see if XInitThreads solves the issue (it might introduce some
> locking?).

Re-reading the code, I think I had just not paid enough attention to the ‘thread.detach()’ call. Why is there? It is causing the problem, because as a result, destroying the thread does not wait for its completion, so the destructor of the updater can be called while it runs.

Frediano, what was the rationale behind the ‘detach()’? I suggest we remove it.

> 
>> The stack trace looks like this:
>> 
>>    #1  0x00007ffff65cf4da in abort () from /lib64/libc.so.6
>>    #2  0x00007ffff65c5d67 in __assert_fail_base () from /lib64/libc.so.6
>>    #3  0x00007ffff65c5e12 in __assert_fail () from /lib64/libc.so.6
>>    #4  0x00007ffff76b6ecc in dequeue_pending_request () from /lib64/libX11.so.6
>>    #5  0x00007ffff76b7d20 in _XReply () from /lib64/libX11.so.6
>>    #6  0x00007ffff76b36cd in XSync () from /lib64/libX11.so.6
>>    #7  0x00007ffff769494e in XCloseDisplay () from /lib64/libX11.so.6
>> 
>> If we hit this problem in practice, we may need to remove the
>> XCloseDisplay call from the destructor.
>> 
>> Signed-off-by: Christophe de Dinechin <dinechin at redhat.com>
>> ---
>> src/Makefile.am               |   2 +
>> src/message.hpp               |   2 +
>> src/spice-streaming-agent.cpp | 121 +-----------------------------------------
>> src/x11-cursor.cpp            |  65 +++++++++++++++++++++++
>> src/x11-cursor.hpp            |  91 +++++++++++++++++++++++++++++++
>> 5 files changed, 161 insertions(+), 120 deletions(-)
>> create mode 100644 src/x11-cursor.cpp
>> create mode 100644 src/x11-cursor.hpp
>> 
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index 923a103..4a03e5e 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -58,4 +58,6 @@ spice_streaming_agent_SOURCES = \
>> 	stream.cpp \
>> 	stream.hpp \
>> 	errors.cpp \
>> +	x11-cursor.hpp \
>> +	x11-cursor.cpp \
>> 	$(NULL)
>> diff --git a/src/message.hpp b/src/message.hpp
>> index 28b3e28..650bd66 100644
>> --- a/src/message.hpp
>> +++ b/src/message.hpp
>> @@ -6,6 +6,8 @@
>> #ifndef SPICE_STREAMING_AGENT_MESSAGE_HPP
>> #define SPICE_STREAMING_AGENT_MESSAGE_HPP
>> 
>> +#include "stream.hpp"
>> +
>> #include <spice/stream-device.h>
>> 
>> namespace spice
>> diff --git a/src/spice-streaming-agent.cpp b/src/spice-streaming-agent.cpp
>> index c401a34..2264af2 100644
>> --- a/src/spice-streaming-agent.cpp
>> +++ b/src/spice-streaming-agent.cpp
>> @@ -7,6 +7,7 @@
>> #include "concrete-agent.hpp"
>> #include "stream.hpp"
>> #include "message.hpp"
>> +#include "x11-cursor.hpp"
>> #include "hexdump.h"
>> #include "mjpeg-fallback.hpp"
>> 
>> @@ -36,8 +37,6 @@
>> #include <vector>
>> #include <string>
>> #include <functional>
>> -#include <X11/Xlib.h>
>> -#include <X11/extensions/Xfixes.h>
>> 
>> using namespace spice::streaming_agent;
>> 
>> @@ -86,63 +85,6 @@ public:
>>     }
>> };
>> 
>> -class X11CursorMessage : public Message<StreamMsgCursorSet, X11CursorMessage, STREAM_TYPE_CURSOR_SET>
>> -{
>> -public:
>> -    X11CursorMessage(XFixesCursorImage *cursor): Message(cursor) {}
>> -    static size_t size(XFixesCursorImage *cursor)
>> -    {
>> -        return sizeof(payload_t) + sizeof(uint32_t) * pixel_count(cursor);
>> -    }
>> -
>> -    void write_message_body(Stream &stream, XFixesCursorImage *cursor)
>> -    {
>> -        StreamMsgCursorSet msg = {
>> -            .width = cursor->width,
>> -            .height = cursor->height,
>> -            .hot_spot_x = cursor->xhot,
>> -            .hot_spot_y = cursor->yhot,
>> -            .type = SPICE_CURSOR_TYPE_ALPHA,
>> -            .padding1 = { },
>> -            .data = { }
>> -        };
>> -
>> -        size_t pixcount = pixel_count(cursor);
>> -        size_t pixsize = pixcount * sizeof(uint32_t);
>> -        std::unique_ptr<uint32_t[]> pixels(new uint32_t[pixcount]);
>> -        uint32_t *pixbuf = pixels.get();
>> -        fill_pixels(cursor, pixcount, pixbuf);
>> -
>> -        stream.write_all("cursor message", &msg, sizeof(msg));
>> -        stream.write_all("cursor pixels", pixbuf, pixsize);
>> -    }
>> -
>> -private:
>> -    static size_t pixel_count(XFixesCursorImage *cursor)
>> -    {
>> -        return cursor->width * cursor->height;
>> -    }
>> -
>> -    void fill_pixels(XFixesCursorImage *cursor, unsigned count, uint32_t *pixbuf)
>> -    {
>> -        for (unsigned i = 0; i < count; ++i) {
>> -            pixbuf[i] = cursor->pixels[i];
>> -        }
>> -    }
>> -};
>> -
>> -class X11CursorUpdater
>> -{
>> -public:
>> -    X11CursorUpdater(Stream &stream);
>> -    ~X11CursorUpdater();
>> -    void send_cursor_changes();
>> -
>> -private:
>> -    Stream &stream;
>> -    Display *display;
>> -};
>> -
>> class FrameLog
>> {
>> public:
>> @@ -182,67 +124,6 @@ void FrameLog::dump(const void *buffer, size_t length)
>>     }
>> }
>> 
>> -class X11CursorThread
>> -{
>> -public:
>> -    X11CursorThread(Stream &stream);
>> -    static void record_cursor_changes(X11CursorThread *self) { self->updater.send_cursor_changes(); }
>> -
>> -private:
>> -    X11CursorUpdater updater;
>> -    std::thread thread;
>> -};
>> -
>> -X11CursorUpdater::X11CursorUpdater(Stream &stream)
>> -    : stream(stream),
>> -      display(XOpenDisplay(NULL))
>> -{
>> -    if (display == NULL) {
>> -        throw Error("failed to open display").syslog();
>> -    }
>> -}
>> -
>> -X11CursorUpdater::~X11CursorUpdater()
>> -{
>> -    XCloseDisplay(display);
>> -}
>> -
>> -void X11CursorUpdater::send_cursor_changes()
>> -{
>> -    unsigned long last_serial = 0;
>> -
>> -    int event_base, error_base;
>> -    if (!XFixesQueryExtension(display, &event_base, &error_base)) {
>> -        syslog(LOG_WARNING, "XFixesQueryExtension failed, not sending cursor changes\n");
>> -        return; // also terminates the X11CursorThread if that's how we were launched
>> -    }
>> -    Window rootwindow = DefaultRootWindow(display);
>> -    XFixesSelectCursorInput(display, rootwindow, XFixesDisplayCursorNotifyMask);
>> -
>> -    while (true) {
>> -        XEvent event;
>> -        XNextEvent(display, &event);
>> -        if (event.type != event_base + 1) {
>> -            continue;
>> -        }
>> -
>> -        XFixesCursorImage *cursor = XFixesGetCursorImage(display);
>> -        if (!cursor || cursor->cursor_serial == last_serial) {
>> -            continue;
>> -        }
>> -
>> -        last_serial = cursor->cursor_serial;
>> -        stream.send<X11CursorMessage>(cursor);
>> -    }
>> -}
>> -
>> -X11CursorThread::X11CursorThread(Stream &stream)
>> -    : updater(stream),
>> -      thread(record_cursor_changes, this)
>> -{
>> -    thread.detach();
>> -}
>> -
>> }} // namespace spice::streaming_agent
>> 
>> bool quit_requested = false;
>> diff --git a/src/x11-cursor.cpp b/src/x11-cursor.cpp
>> new file mode 100644
>> index 0000000..6abc258
>> --- /dev/null
>> +++ b/src/x11-cursor.cpp
>> @@ -0,0 +1,65 @@
>> +/* X11 cursor transmission
>> + *
>> + * \copyright
>> + * Copyright 2018 Red Hat Inc. All rights reserved.
>> + */
>> +#include "x11-cursor.hpp"
>> +
>> +#include <syslog.h>
>> +
>> +namespace spice
>> +{
>> +namespace streaming_agent
>> +{
>> +
>> +X11CursorUpdater::X11CursorUpdater(Stream &stream)
>> +    : stream(stream),
>> +      display(XOpenDisplay(NULL))
>> +{
>> +    if (display == NULL) {
>> +        throw Error("failed to open display").syslog();
>> +    }
>> +}
>> +
>> +X11CursorUpdater::~X11CursorUpdater()
>> +{
>> +    XCloseDisplay(display);
>> +}
>> +
>> +void X11CursorUpdater::send_cursor_changes()
>> +{
>> +    unsigned long last_serial = 0;
>> +
>> +    int event_base, error_base;
>> +    if (!XFixesQueryExtension(display, &event_base, &error_base)) {
>> +        syslog(LOG_WARNING, "XFixesQueryExtension failed, not sending cursor changes\n");
>> +        return; // also terminates the X11CursorThread if that's how we were launched
>> +    }
>> +    Window rootwindow = DefaultRootWindow(display);
>> +    XFixesSelectCursorInput(display, rootwindow, XFixesDisplayCursorNotifyMask);
>> +
>> +    while (true) {
>> +        XEvent event;
>> +        XNextEvent(display, &event);
>> +        if (event.type != event_base + 1) {
>> +            continue;
>> +        }
>> +
>> +        XFixesCursorImage *cursor = XFixesGetCursorImage(display);
>> +        if (!cursor || cursor->cursor_serial == last_serial) {
>> +            continue;
>> +        }
>> +
>> +        last_serial = cursor->cursor_serial;
>> +        stream.send<X11CursorMessage>(cursor);
>> +    }
>> +}
>> +
>> +X11CursorThread::X11CursorThread(Stream &stream)
>> +    : updater(stream),
>> +      thread(record_cursor_changes, this)
>> +{
>> +    thread.detach();
>> +}
>> +
>> +}} // namespace spic::streaming_agent
>> diff --git a/src/x11-cursor.hpp b/src/x11-cursor.hpp
>> new file mode 100644
>> index 0000000..2038b1d
>> --- /dev/null
>> +++ b/src/x11-cursor.hpp
>> @@ -0,0 +1,91 @@
>> +/* X11 cursor transmission
>> + *
>> + * \copyright
>> + * Copyright 2018 Red Hat Inc. All rights reserved.
>> + */
>> +#ifndef SPICE_STREAMING_AGENT_X11_CURSOR_HPP
>> +#define SPICE_STREAMING_AGENT_X11_CURSOR_HPP
>> +
>> +#include "message.hpp"
>> +
>> +#include <spice-streaming-agent/errors.hpp>
>> +
>> +#include <thread>
>> +#include <X11/Xlib.h>
>> +#include <X11/extensions/Xfixes.h>
>> +
>> +namespace spice {
>> +namespace streaming_agent {
>> +
>> +class X11CursorMessage : public Message<StreamMsgCursorSet, X11CursorMessage,
>> +                                        STREAM_TYPE_CURSOR_SET>
>> +{
>> +public:
>> +    X11CursorMessage(XFixesCursorImage *cursor): Message(cursor) {}
>> +    static size_t size(XFixesCursorImage *cursor)
>> +    {
>> +        return sizeof(payload_t) + sizeof(uint32_t) * pixel_count(cursor);
>> +    }
>> +
>> +    void write_message_body(Stream &stream, XFixesCursorImage *cursor)
>> +    {
>> +        StreamMsgCursorSet msg = {
>> +            .width = cursor->width,
>> +            .height = cursor->height,
>> +            .hot_spot_x = cursor->xhot,
>> +            .hot_spot_y = cursor->yhot,
>> +            .type = SPICE_CURSOR_TYPE_ALPHA,
>> +            .padding1 = { },
>> +            .data = { }
>> +        };
>> +
>> +        size_t pixcount = pixel_count(cursor);
>> +        size_t pixsize = pixcount * sizeof(uint32_t);
>> +        std::unique_ptr<uint32_t[]> pixels(new uint32_t[pixcount]);
>> +        uint32_t *pixbuf = pixels.get();
>> +        fill_pixels(cursor, pixcount, pixbuf);
>> +
>> +        stream.write_all("cursor message", &msg, sizeof(msg));
>> +        stream.write_all("cursor pixels", pixbuf, pixsize);
>> +    }
>> +
>> +private:
>> +    static size_t pixel_count(XFixesCursorImage *cursor)
>> +    {
>> +        return cursor->width * cursor->height;
>> +    }
>> +
>> +    void fill_pixels(XFixesCursorImage *cursor, unsigned count, uint32_t *pixbuf)
>> +    {
>> +        for (unsigned i = 0; i < count; ++i) {
>> +            pixbuf[i] = cursor->pixels[i];
>> +        }
>> +    }
>> +};
>> +
>> +class X11CursorUpdater
>> +{
>> +public:
>> +    X11CursorUpdater(Stream &stream);
>> +    ~X11CursorUpdater();
>> +    void send_cursor_changes();
>> +
>> +private:
>> +    Stream &stream;
>> +    Display *display;
>> +};
>> +
>> +class X11CursorThread
>> +{
>> +public:
>> +    X11CursorThread(Stream &stream);
>> +    static void record_cursor_changes(X11CursorThread *self) { self->updater.send_cursor_changes(); }
>> +
>> +private:
>> +    X11CursorUpdater updater;
>> +    std::thread thread;
>> +};
>> +
>> +}} // namespace spice::streaming_agent
>> +
>> +#endif // SPICE_STREAMING_AGENT_X11_CURSOR_HPP
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel



More information about the Spice-devel mailing list