diff options
author | Andrew Knight <andrew.knight@digia.com> | 2013-10-21 17:45:11 +0300 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-24 13:41:03 +0200 |
commit | 187363886582ba236cf6fed0f956953b699eca53 (patch) | |
tree | 5a5e40f5d7fa6226d1a799a9d2de9946488ded07 /src/client | |
parent | 3e757f8a441c5089b19428778f66f4dc890fe8fb (diff) |
Clipboard: perform non-blocking reads from compositor
Since the compositor recycles file descriptors when offering data to
clients, it is possible that a client (or multiple clients) can attempt
to read from the same FD simultaneously, creating a situation where one
read can wait indefinitely for data. By making the pipe non-blocking,
the client can gracefully time-out if data doesn't arrive in a timely
manner.
This commit also ensures that only one FD is open per client per offered
mime type.
Change-Id: If052e5bf8198df1cdc8fc4df360f83a77950b2f9
Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/qwaylanddataoffer.cpp | 64 | ||||
-rw-r--r-- | src/client/qwaylanddataoffer_p.h | 5 |
2 files changed, 49 insertions, 20 deletions
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp index adaeb5214..f72330928 100644 --- a/src/client/qwaylanddataoffer.cpp +++ b/src/client/qwaylanddataoffer.cpp @@ -84,7 +84,6 @@ QWaylandMimeData::QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay : QInternalMimeData() , m_dataOffer(dataOffer) , m_display(display) - , m_offered_mime_types() { } @@ -94,46 +93,73 @@ QWaylandMimeData::~QWaylandMimeData() void QWaylandMimeData::appendFormat(const QString &mimeType) { - m_offered_mime_types.append(mimeType); + if (m_types.contains(mimeType)) + close(m_types.take(mimeType)); // Unconsumed data + m_data.remove(mimeType); // Clear previous contents + + int pipefd[2]; + if (::pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) { + qWarning("QWaylandMimeData: pipe2() failed"); + return; + } + + m_dataOffer->receive(mimeType, pipefd[1]); + m_display->forceRoundTrip(); + close(pipefd[1]); + m_types.insert(mimeType, pipefd[0]); } bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const { - return m_offered_mime_types.contains(mimeType); + return m_types.contains(mimeType) || m_data.contains(mimeType); } QStringList QWaylandMimeData::formats_sys() const { - return m_offered_mime_types; + return m_types.keys() << m_data.keys(); } QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const { Q_UNUSED(type); - if (m_offered_mime_types.isEmpty()) - return QVariant(); + if (m_data.contains(mimeType)) + return m_data.value(mimeType); - int pipefd[2]; - if (qt_safe_pipe(pipefd, O_CLOEXEC) == -1) { - qWarning("QWaylandMimeData: pipe() failed"); + if (!m_types.contains(mimeType)) return QVariant(); - } - m_dataOffer->receive(mimeType, pipefd[1]); - close(pipefd[1]); + QByteArray content; + int fd = m_types.take(mimeType); + if (readData(fd, content) != 0) { + qWarning("QWaylandDataOffer: error reading data for mimeType %s", qPrintable(mimeType)); + content = QByteArray(); + } -// m_display->forceRoundTrip(); + close(fd); + m_data.insert(mimeType, content); + return content; +} - QByteArray content; +int QWaylandMimeData::readData(int fd, QByteArray &data) const +{ char buf[4096]; + int retryCount = 0; int n; - while ((n = QT_READ(pipefd[0], &buf, sizeof buf)) > 0) { - content.append(buf, n); + while (true) { + n = QT_READ(fd, buf, sizeof buf); + if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && ++retryCount < 1000) + usleep(1000); + else + break; } - close(pipefd[0]); - - return content; + if (retryCount >= 1000) + qWarning("QWaylandDataOffer: timeout reading from pipe"); + if (n > 0) { + data.append(buf, n); + n = readData(fd, data); + } + return n; } QT_END_NAMESPACE diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h index ab34e177f..9f5b6cf1e 100644 --- a/src/client/qwaylanddataoffer_p.h +++ b/src/client/qwaylanddataoffer_p.h @@ -82,9 +82,12 @@ protected: QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const Q_DECL_OVERRIDE; private: + int readData(int fd, QByteArray &data) const; + mutable QWaylandDataOffer *m_dataOffer; QWaylandDisplay *m_display; - QStringList m_offered_mime_types; + mutable QHash<QString, int> m_types; + mutable QHash<QString, QByteArray> m_data; }; QT_END_NAMESPACE |