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:
Thiago Macieira 2015-07-10 22:09:15 -07:00
parent 61e621def3
commit 85ff351266
5 changed files with 87 additions and 53 deletions

View 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;
}

View File

@ -0,0 +1,3 @@
SOURCES = cloexec.cpp
CONFIG -= qt
QT =

10
configure vendored
View File

@ -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"

View File

@ -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)

View File

@ -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