summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2015-07-10 22:09:15 -0700
committerThiago Macieira <thiago.macieira@intel.com>2015-07-17 17:36:19 +0000
commit85ff35126623e6f26c84d9fa8a35b6762aefb110 (patch)
treec4ddd4482f4d0f435612d4471ee0af311396cf00
parent61e621def380f28183b6ce7047e9a88a49f81f82 (diff)
Revamp the CLOEXEC support in Qt
The pipe2/dup3/accept4 functions and SOCK_CLOEXEC are quite old nowadays on Linux. They were introduced on Linux 2.6.28 and glibc 2.10, all from 2008. They were also picked up by uClibc in 2011 and FreeBSD as of version 10.0. So we no longer need the runtime detection of whether the feature is available. Instead, if the libc has support for it, use it unconditionally and fail at runtime if the syscall isn't implemented. Change-Id: Ib056b47dde3341ef9a52ffff13efcc39ef8dff7d Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
-rw-r--r--config.tests/unix/cloexec/cloexec.cpp49
-rw-r--r--config.tests/unix/cloexec/cloexec.pro3
-rwxr-xr-xconfigure10
-rw-r--r--src/corelib/kernel/qcore_unix_p.h60
-rw-r--r--src/network/socket/qnet_unix_p.h18
5 files changed, 87 insertions, 53 deletions
diff --git a/config.tests/unix/cloexec/cloexec.cpp b/config.tests/unix/cloexec/cloexec.cpp
new file mode 100644
index 0000000000..3f127d8d3f
--- /dev/null
+++ b/config.tests/unix/cloexec/cloexec.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Intel Corporation.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the configuration module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define _GNU_SOURCE 1
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main()
+{
+ int pipes[2];
+ (void) pipe2(pipes, O_CLOEXEC | O_NONBLOCK);
+ (void) fcntl(0, F_DUPFD_CLOEXEC, 0);
+ (void) dup3(0, 3, O_CLOEXEC);
+ (void) accept4(0, 0, 0, SOCK_CLOEXEC | SOCK_NONBLOCK);
+ return 0;
+}
diff --git a/config.tests/unix/cloexec/cloexec.pro b/config.tests/unix/cloexec/cloexec.pro
new file mode 100644
index 0000000000..bc735f9b1f
--- /dev/null
+++ b/config.tests/unix/cloexec/cloexec.pro
@@ -0,0 +1,3 @@
+SOURCES = cloexec.cpp
+CONFIG -= qt
+QT =
diff --git a/configure b/configure
index a53eaff16d..864b747919 100755
--- a/configure
+++ b/configure
@@ -728,6 +728,7 @@ CFG_IPV6IFNAME=auto
CFG_GETIFADDRS=auto
CFG_INOTIFY=auto
CFG_EVENTFD=auto
+CFG_CLOEXEC=no
CFG_RPATH=yes
CFG_FRAMEWORK=auto
CFG_USE_GOLD_LINKER=auto
@@ -5869,6 +5870,11 @@ if [ "$CFG_GETIFADDRS" != "no" ]; then
fi
fi
+# find if the platform provides thread-safe CLOEXEC support
+if compileTest unix/cloexec; then
+ CFG_CLOEXEC=yes
+fi
+
# detect OpenSSL
if [ "$CFG_OPENSSL" != "no" ]; then
if compileTest unix/openssl "OpenSSL"; then
@@ -6147,6 +6153,9 @@ fi
if [ "$CFG_EVENTFD" = "yes" ]; then
QT_CONFIG="$QT_CONFIG eventfd"
fi
+if [ "$CFG_CLOEXEC" = "yes" ]; then
+ QT_CONFIG="$QT_CONFIG threadsafe-cloexec"
+fi
if [ "$CFG_LIBJPEG" = "no" ]; then
CFG_JPEG="no"
elif [ "$CFG_LIBJPEG" = "system" ]; then
@@ -6627,6 +6636,7 @@ QMakeVar set sql-plugins "$SQL_PLUGINS"
[ "$CFG_GETIFADDRS" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_GETIFADDRS"
[ "$CFG_INOTIFY" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_INOTIFY"
[ "$CFG_EVENTFD" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_EVENTFD"
+[ "$CFG_CLOEXEC" = "yes" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_THREADSAFE_CLOEXEC=1"
[ "$CFG_NIS" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_NIS"
[ "$CFG_OPENSSL" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_OPENSSL"
[ "$CFG_OPENSSL" = "linked" ]&& QCONFIG_FLAGS="$QCONFIG_FLAGS QT_LINKED_OPENSSL"
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
index ce8d9f6d65..c744873fce 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -67,24 +67,6 @@
struct sockaddr;
-#if defined(Q_OS_LINUX) && defined(O_CLOEXEC)
-# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1
-QT_BEGIN_NAMESPACE
-namespace QtLibcSupplement {
- inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int)
- { errno = ENOSYS; return -1; }
- inline int dup3(int, int, int)
- { errno = ENOSYS; return -1; }
- inline int pipe2(int [], int )
- { errno = ENOSYS; return -1; }
-}
-QT_END_NAMESPACE
-using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
-
-#else
-# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 0
-#endif
-
#define EINTR_LOOP(var, cmd) \
do { \
var = cmd; \
@@ -181,16 +163,12 @@ static inline int qt_safe_pipe(int pipefd[2], int flags = 0)
{
Q_ASSERT((flags & ~O_NONBLOCK) == 0);
- int ret;
-#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
+#ifdef QT_THREADSAFE_CLOEXEC
// use pipe2
flags |= O_CLOEXEC;
- ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR
- if (ret == 0 || errno != ENOSYS)
- return ret;
-#endif
-
- ret = ::pipe(pipefd);
+ return ::pipe2(pipefd, flags); // pipe2 is documented not to return EINTR
+#else
+ int ret = ::pipe(pipefd);
if (ret == -1)
return -1;
@@ -204,6 +182,7 @@ static inline int qt_safe_pipe(int pipefd[2], int flags = 0)
}
return 0;
+#endif
}
#endif // Q_OS_VXWORKS
@@ -213,22 +192,19 @@ static inline int qt_safe_dup(int oldfd, int atleast = 0, int flags = FD_CLOEXEC
{
Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
- int ret;
#ifdef F_DUPFD_CLOEXEC
- // use this fcntl
- if (flags & FD_CLOEXEC) {
- ret = ::fcntl(oldfd, F_DUPFD_CLOEXEC, atleast);
- if (ret != -1 || errno != EINVAL)
- return ret;
- }
-#endif
-
+ int cmd = F_DUPFD;
+ if (flags & FD_CLOEXEC)
+ cmd = F_DUPFD_CLOEXEC;
+ return ::fcntl(oldfd, cmd, atleast);
+#else
// use F_DUPFD
- ret = ::fcntl(oldfd, F_DUPFD, atleast);
+ int ret = ::fcntl(oldfd, F_DUPFD, atleast);
if (flags && ret != -1)
::fcntl(ret, F_SETFD, flags);
return ret;
+#endif
}
// don't call dup2
@@ -238,14 +214,11 @@ static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
int ret;
-#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
+#ifdef QT_THREADSAFE_CLOEXEC
// use dup3
- if (flags & FD_CLOEXEC) {
- EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC));
- if (ret == 0 || errno != ENOSYS)
- return ret;
- }
-#endif
+ EINTR_LOOP(ret, ::dup3(oldfd, newfd, flags ? O_CLOEXEC : 0));
+ return ret;
+#else
EINTR_LOOP(ret, ::dup2(oldfd, newfd));
if (ret == -1)
return -1;
@@ -253,6 +226,7 @@ static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
if (flags)
::fcntl(newfd, F_SETFD, flags);
return 0;
+#endif
}
static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
index cd118afd63..a5a87fc7c1 100644
--- a/src/network/socket/qnet_unix_p.h
+++ b/src/network/socket/qnet_unix_p.h
@@ -77,15 +77,13 @@ static inline int qt_safe_socket(int domain, int type, int protocol, int flags =
Q_ASSERT((flags & ~O_NONBLOCK) == 0);
int fd;
-#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+#ifdef QT_THREADSAFE_CLOEXEC
int newtype = type | SOCK_CLOEXEC;
if (flags & O_NONBLOCK)
newtype |= SOCK_NONBLOCK;
fd = ::socket(domain, newtype, protocol);
- if (fd != -1 || errno != EINVAL)
- return fd;
-#endif
-
+ return fd;
+#else
fd = ::socket(domain, type, protocol);
if (fd == -1)
return -1;
@@ -97,6 +95,7 @@ static inline int qt_safe_socket(int domain, int type, int protocol, int flags =
::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
return fd;
+#endif
}
// Tru64 redefines accept -> _accept with _XOPEN_SOURCE_EXTENDED
@@ -105,16 +104,14 @@ static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *add
Q_ASSERT((flags & ~O_NONBLOCK) == 0);
int fd;
-#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+#ifdef QT_THREADSAFE_CLOEXEC
// use accept4
int sockflags = SOCK_CLOEXEC;
if (flags & O_NONBLOCK)
sockflags |= SOCK_NONBLOCK;
fd = ::accept4(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen), sockflags);
- if (fd != -1 || !(errno == ENOSYS || errno == EINVAL))
- return fd;
-#endif
-
+ return fd;
+#else
fd = ::accept(s, addr, static_cast<QT_SOCKLEN_T *>(addrlen));
if (fd == -1)
return -1;
@@ -126,6 +123,7 @@ static inline int qt_safe_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *add
::fcntl(fd, F_SETFL, ::fcntl(fd, F_GETFL) | O_NONBLOCK);
return fd;
+#endif
}
// UnixWare 7 redefines listen -> _listen