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>
This commit is contained in:
parent
61e621def3
commit
85ff351266
49
config.tests/unix/cloexec/cloexec.cpp
Normal file
49
config.tests/unix/cloexec/cloexec.cpp
Normal file
@ -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;
|
||||
}
|
3
config.tests/unix/cloexec/cloexec.pro
Normal file
3
config.tests/unix/cloexec/cloexec.pro
Normal file
@ -0,0 +1,3 @@
|
||||
SOURCES = cloexec.cpp
|
||||
CONFIG -= qt
|
||||
QT =
|
10
configure
vendored
10
configure
vendored
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user