summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaszlo Papp <lpapp@kde.org>2014-02-15 18:35:24 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-16 11:59:29 +0100
commit7c8dd1d696c61c4c49ffcb2c1c1b455389edb771 (patch)
treec58327d906fea9a69c7d95de6a19f32795a790f1
parent336fbee2e34c7eaf48550105d542cad1979c6684 (diff)
downloadqtserialport-7c8dd1d696c61c4c49ffcb2c1c1b455389edb771.tar.gz
Use the qt_safe_* methods for open/read/write/close
This makes the operation thread-safe. It also helps with preventing the leaks for child processes. Also, there is now some protection against EINTR when the system call has to be restarted. Thanks go to Thiago Macieira for providing the original patches. Task-number: QTBUG-36824 Change-Id: I90cac87c5e1c55a57e5ba6c20313446c43c6d242 Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com> Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
-rw-r--r--src/serialport/qserialport_unix.cpp16
-rw-r--r--src/serialport/qt4support/include/private/qcore_unix_p.h124
2 files changed, 133 insertions, 7 deletions
diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp
index d99575f..6c92d17 100644
--- a/src/serialport/qserialport_unix.cpp
+++ b/src/serialport/qserialport_unix.cpp
@@ -55,6 +55,8 @@
#endif
#endif
+#include <private/qcore_unix_p.h>
+
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qsocketnotifier.h>
#include <QtCore/qmap.h>
@@ -215,7 +217,7 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
break;
}
- descriptor = ::open(systemLocation.toLocal8Bit().constData(), flags);
+ descriptor = qt_safe_open(systemLocation.toLocal8Bit().constData(), flags);
if (descriptor == -1) {
q->setError(decodeSystemError());
@@ -306,7 +308,7 @@ void QSerialPortPrivate::close()
exceptionNotifier = 0;
}
- if (::close(descriptor) == -1)
+ if (qt_safe_close(descriptor) == -1)
q->setError(decodeSystemError());
if (lockFileScopedPointer->isLocked())
@@ -1087,7 +1089,7 @@ qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize)
if (parity != QSerialPort::MarkParity
&& parity != QSerialPort::SpaceParity) {
#endif
- bytesRead = ::read(descriptor, data, maxSize);
+ bytesRead = qt_safe_read(descriptor, data, maxSize);
} else {// Perform parity emulation.
bytesRead = readPerChar(data, maxSize);
}
@@ -1099,11 +1101,11 @@ qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize)
{
qint64 bytesWritten = 0;
#if defined (CMSPAR)
- bytesWritten = ::write(descriptor, data, maxSize);
+ bytesWritten = qt_safe_write(descriptor, data, maxSize);
#else
if (parity != QSerialPort::MarkParity
&& parity != QSerialPort::SpaceParity) {
- bytesWritten = ::write(descriptor, data, maxSize);
+ bytesWritten = qt_safe_write(descriptor, data, maxSize);
} else {// Perform parity emulation.
bytesWritten = writePerChar(data, maxSize);
}
@@ -1140,7 +1142,7 @@ qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize)
break;
}
- int r = ::write(descriptor, data, 1);
+ int r = qt_safe_write(descriptor, data, 1);
if (r < 0)
return -1;
if (r > 0) {
@@ -1166,7 +1168,7 @@ qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize)
int prefix = 0;
while (ret < maxSize) {
- qint64 r = ::read(descriptor, data, 1);
+ qint64 r = qt_safe_read(descriptor, data, 1);
if (r < 0) {
if (errno == EAGAIN) // It is ok for nonblocking mode.
break;
diff --git a/src/serialport/qt4support/include/private/qcore_unix_p.h b/src/serialport/qt4support/include/private/qcore_unix_p.h
new file mode 100644
index 0000000..2d01d35
--- /dev/null
+++ b/src/serialport/qt4support/include/private/qcore_unix_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCORE_UNIX_P_H
+#define QCORE_UNIX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of Qt code on Unix. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qplatformdefs.h"
+
+#ifndef Q_OS_UNIX
+# error "qcore_unix_p.h included on a non-Unix system"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+#define EINTR_LOOP(var, cmd) \
+ do { \
+ var = cmd; \
+ } while (var == -1 && errno == EINTR)
+
+QT_BEGIN_NAMESPACE
+
+// don't call QT_OPEN or ::open
+// call qt_safe_open
+static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
+{
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif
+ register int fd;
+ EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode));
+
+ // unknown flags are ignored, so we have no way of verifying if
+ // O_CLOEXEC was accepted
+ if (fd != -1)
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+ return fd;
+}
+#undef QT_OPEN
+#define QT_OPEN qt_safe_open
+
+static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
+{
+ qint64 ret = 0;
+ EINTR_LOOP(ret, QT_READ(fd, data, maxlen));
+ return ret;
+}
+#undef QT_READ
+#define QT_READ qt_safe_read
+
+static inline qint64 qt_safe_write(int fd, const void *data, qint64 len)
+{
+ qint64 ret = 0;
+ EINTR_LOOP(ret, QT_WRITE(fd, data, len));
+ return ret;
+}
+#undef QT_WRITE
+#define QT_WRITE qt_safe_write
+
+static inline int qt_safe_close(int fd)
+{
+ register int ret;
+ EINTR_LOOP(ret, QT_CLOSE(fd));
+ return ret;
+}
+#undef QT_CLOSE
+#define QT_CLOSE qt_safe_close
+
+QT_END_NAMESPACE
+
+#endif