From f927efd77a8e75e330b3592996277ad6e6eb6a8d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 25 Oct 2012 12:38:13 -0700 Subject: Add support for Linux eventfd(7) in the UNIX event loop eventfd(7) uses less resources than a pipe, as it only needs to store a single 64-bit integer, as opposed to a full buffer. It was introduced first on Linux version 2.6.22 and glibc 2.7. However, both the configure-time test and the runtime usage require the use of EFD_CLOEXEC for thread-safety, so this code will be enabled only for Linux 2.6.27 and up as well as glibc 2.9 and up. Change-Id: Ic7e10b28d7b1d4ca24be614ed84055c4429a68e4 Reviewed-by: Robin Burchell Reviewed-by: Oswald Buddenhagen --- config.tests/unix/eventfd/eventfd.pro | 3 ++ config.tests/unix/eventfd/main.cpp | 51 ++++++++++++++++++++++++++++ configure | 22 ++++++++++++ src/corelib/kernel/qeventdispatcher_unix.cpp | 37 +++++++++++++++++--- src/corelib/kernel/qeventdispatcher_unix_p.h | 3 ++ 5 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 config.tests/unix/eventfd/eventfd.pro create mode 100644 config.tests/unix/eventfd/main.cpp diff --git a/config.tests/unix/eventfd/eventfd.pro b/config.tests/unix/eventfd/eventfd.pro new file mode 100644 index 0000000000..c41204f49f --- /dev/null +++ b/config.tests/unix/eventfd/eventfd.pro @@ -0,0 +1,3 @@ +SOURCES = main.cpp +CONFIG -= qt dylib +mac:CONFIG -= app_bundle diff --git a/config.tests/unix/eventfd/main.cpp b/config.tests/unix/eventfd/main.cpp new file mode 100644 index 0000000000..0523ee0320 --- /dev/null +++ b/config.tests/unix/eventfd/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Intel Corporation +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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$ +** +****************************************************************************/ + +#include + +int main() +{ + eventfd_t value; + int fd = eventfd(0, EFD_CLOEXEC); + eventfd_read(fd, &value); + eventfd_write(fd, value); + return 0; +} diff --git a/configure b/configure index 89246c8d7c..e0886f5907 100755 --- a/configure +++ b/configure @@ -842,6 +842,7 @@ CFG_GETADDRINFO=auto CFG_IPV6IFNAME=auto CFG_GETIFADDRS=auto CFG_INOTIFY=auto +CFG_EVENTFD=auto CFG_RPATH=yes CFG_FRAMEWORK=auto CFG_MAC_HARFBUZZ=no @@ -5099,6 +5100,23 @@ if [ "$CFG_INOTIFY" != "no" ]; then fi fi +# find if the platform provides eventfd +if [ "$CFG_EVENTFD" != "no" ]; then + if compileTest unix/eventfd "eventfd"; then + CFG_EVENTFD=yes + else + if [ "$CFG_EVENTFD" = "yes" ] && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then + echo "eventfd support cannot be enabled due to functionality tests!" + echo " Turn on verbose messaging (-v) to $0 to see the final report." + echo " If you believe this message is in error you may use the continue" + echo " switch (-continue) to $0 to continue." + exit 101 + else + CFG_EVENTFD=no + fi + fi +fi + # find if the platform provides if_nametoindex (ipv6 interface name support) if [ "$CFG_IPV6IFNAME" != "no" ]; then if compileTest unix/ipv6ifname "IPv6 interface name"; then @@ -5386,6 +5404,9 @@ fi if [ "$CFG_INOTIFY" = "yes" ]; then QT_CONFIG="$QT_CONFIG inotify" fi +if [ "$CFG_EVENTFD" = "yes" ]; then + QT_CONFIG="$QT_CONFIG eventfd" +fi if [ "$CFG_LIBJPEG" = "no" ]; then CFG_JPEG="no" elif [ "$CFG_LIBJPEG" = "system" ]; then @@ -5862,6 +5883,7 @@ QMakeVar set sql-plugins "$SQL_PLUGINS" [ "$CFG_IPV6IFNAME" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_IPV6IFNAME" [ "$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_NIS" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_NIS" [ "$CFG_OPENSSL" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_OPENSSL QT_NO_SSL" [ "$CFG_OPENSSL" = "linked" ]&& QCONFIG_FLAGS="$QCONFIG_FLAGS QT_LINKED_OPENSSL" diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 995f5101cb..6408147567 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -56,6 +56,10 @@ #include #include +#ifndef QT_NO_EVENTFD +# include +#endif + // VxWorks doesn't correctly set the _POSIX_... options #if defined(Q_OS_VXWORKS) # if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK <= 0) @@ -127,6 +131,12 @@ QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() } } #else +# ifndef QT_NO_EVENTFD + thread_pipe[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (thread_pipe[0] != -1) + thread_pipe[1] = -1; + else // fall through the next "if" +# endif if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) { perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); pipefail = true; @@ -155,7 +165,8 @@ QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() #else // cleanup the common parts of the event loop close(thread_pipe[0]); - close(thread_pipe[1]); + if (thread_pipe[1] != -1) + close(thread_pipe[1]); #endif // cleanup timers @@ -279,9 +290,18 @@ int QEventDispatcherUNIXPrivate::processThreadWakeUp(int nsel) ::read(thread_pipe[0], c, sizeof(c)); ::ioctl(thread_pipe[0], FIOFLUSH, 0); #else - char c[16]; - while (::read(thread_pipe[0], c, sizeof(c)) > 0) - ; +# ifndef QT_NO_EVENTFD + if (thread_pipe[1] == -1) { + // eventfd + eventfd_t value; + eventfd_read(thread_pipe[0], &value); + } else +# endif + { + char c[16]; + while (::read(thread_pipe[0], c, sizeof(c)) > 0) { + } + } #endif if (!wakeUps.testAndSetRelease(1, 0)) { // hopefully, this is dead code @@ -630,6 +650,15 @@ void QEventDispatcherUNIX::wakeUp() { Q_D(QEventDispatcherUNIX); if (d->wakeUps.testAndSetAcquire(0, 1)) { +#ifndef QT_NO_EVENTFD + if (d->thread_pipe[1] == -1) { + // eventfd + eventfd_t value = 1; + int ret; + EINTR_LOOP(ret, eventfd_write(d->thread_pipe[0], value)); + return; + } +#endif char c = 0; qt_safe_write( d->thread_pipe[1], &c, 1 ); } diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index 98ea19ced8..e96acf65af 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -148,6 +148,9 @@ public: virtual int processThreadWakeUp(int nsel); bool mainThread; + + // note for eventfd(7) support: + // if thread_pipe[1] is -1, then eventfd(7) is in use and is stored in thread_pipe[0] int thread_pipe[2]; // highest fd for all socket notifiers -- cgit v1.2.3