From e65ffae850a7265c1d477957a5b24865b91ec3ad Mon Sep 17 00:00:00 2001 From: Louai Al-Khanji Date: Thu, 3 Dec 2015 10:00:24 -0800 Subject: QEventDispatcherUNIX: Clean up thread_pipe logic Change-Id: Ic13ad54a5b3c7bd3e3e5921b3dbbe321690fad21 Reviewed-by: Thiago Macieira --- src/corelib/kernel/qeventdispatcher_unix.cpp | 161 +++++++++++++++------------ src/corelib/kernel/qeventdispatcher_unix_p.h | 30 +++-- 2 files changed, 111 insertions(+), 80 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 7fd18dc9c1..1faeb7dc39 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -95,6 +95,28 @@ static pollfd make_pollfd(int fd, short events) return pfd; } +QThreadPipe::QThreadPipe() +{ + fds[0] = -1; + fds[1] = -1; +#if defined(Q_OS_VXWORKS) + name[0] = '\0'; +#endif +} + +QThreadPipe::~QThreadPipe() +{ + if (fds[0] >= 0) + close(fds[0]); + + if (fds[1] >= 0) + close(fds[1]); + +#if defined(Q_OS_VXWORKS) + pipeDevDelete(name, true); +#endif +} + #if defined(Q_OS_VXWORKS) static void initThreadPipeFD(int fd) { @@ -112,103 +134,110 @@ static void initThreadPipeFD(int fd) } #endif -QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() +bool QThreadPipe::init() { - bool pipefail = false; - - // initialize the common parts of the event loop #if defined(Q_OS_NACL) // do nothing. #elif defined(Q_OS_VXWORKS) - char name[20]; qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdSelf())); // make sure there is no pipe with this name pipeDevDelete(name, true); + // create the pipe if (pipeDevCreate(name, 128 /*maxMsg*/, 1 /*maxLength*/) != OK) { - perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe device"); - pipefail = true; - } else { - if ((thread_pipe[0] = open(name, O_RDWR, 0)) < 0) { - perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); - pipefail = true; - } else { - initThreadPipeFD(thread_pipe[0]); - thread_pipe[1] = thread_pipe[0]; - } + perror("QThreadPipe: Unable to create thread pipe device %s", name); + return false; } + + if ((fds[0] = open(name, O_RDWR, 0)) < 0) { + perror("QThreadPipe: Unable to open pipe device %s", name); + return false; + } + + initThreadPipeFD(fds[0]); + fds[1] = fds[0]; #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" + if ((fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)) >= 0) + return true; # endif - if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) { - perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe"); - pipefail = true; + if (qt_safe_pipe(fds, O_NONBLOCK) == -1) { + perror("QThreadPipe: Unable to create pipe"); + return false; } #endif - if (Q_UNLIKELY(pipefail)) - qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe"); + return true; } -QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() +pollfd QThreadPipe::prepare() const { -#if defined(Q_OS_NACL) - // do nothing. -#elif defined(Q_OS_VXWORKS) - close(thread_pipe[0]); - - char name[20]; - qsnprintf(name, sizeof(name), "/pipe/qt_%08x", int(taskIdSelf())); + return make_pollfd(fds[0], POLLIN); +} - pipeDevDelete(name, true); -#else - // cleanup the common parts of the event loop - close(thread_pipe[0]); - if (thread_pipe[1] != -1) - close(thread_pipe[1]); +void QThreadPipe::wakeUp() +{ + if (wakeUps.testAndSetAcquire(0, 1)) { +#ifndef QT_NO_EVENTFD + if (fds[1] == -1) { + // eventfd + eventfd_t value = 1; + int ret; + EINTR_LOOP(ret, eventfd_write(fds[0], value)); + return; + } #endif - - // cleanup timers - qDeleteAll(timerList); + char c = 0; + qt_safe_write(fds[1], &c, 1); + } } -int QEventDispatcherUNIXPrivate::processThreadWakeUp(const pollfd &pfd) +int QThreadPipe::check(const pollfd &pfd) { - Q_ASSERT(pfd.fd == thread_pipe[0]); + Q_ASSERT(pfd.fd == fds[0]); + + char c[16]; + const int readyread = pfd.revents & POLLIN; - if (pfd.revents & POLLIN) { - // some other thread woke us up... consume the data on the thread pipe so that - // select doesn't immediately return next time + if (readyread) { + // consume the data on the thread pipe so that + // poll doesn't immediately return next time #if defined(Q_OS_VXWORKS) - char c[16]; - ::read(thread_pipe[0], c, sizeof(c)); - ::ioctl(thread_pipe[0], FIOFLUSH, 0); + ::read(fds[0], c, sizeof(c)); + ::ioctl(fds[0], FIOFLUSH, 0); #else # ifndef QT_NO_EVENTFD - if (thread_pipe[1] == -1) { + if (fds[1] == -1) { // eventfd eventfd_t value; - eventfd_read(thread_pipe[0], &value); + eventfd_read(fds[0], &value); } else # endif { - char c[16]; - while (::read(thread_pipe[0], c, sizeof(c)) > 0) { - } + while (::read(fds[0], c, sizeof(c)) > 0) {} } #endif + if (!wakeUps.testAndSetRelease(1, 0)) { // hopefully, this is dead code - qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!"); + qWarning("QThreadPipe: internal error, wakeUps.testAndSetRelease(1, 0) failed!"); } - return 1; } - return 0; + + return readyread; +} + +QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() +{ + if (Q_UNLIKELY(threadPipe.init() == false)) + qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe"); +} + +QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate() +{ + // cleanup timers + qDeleteAll(timerList); } void QEventDispatcherUNIXPrivate::setSocketNotifierPending(QSocketNotifier *notifier) @@ -465,7 +494,7 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) d->pollfds.append(make_pollfd(it.key(), it.value().events())); // This must be last, as it's popped off the end below - d->pollfds.append(make_pollfd(d->thread_pipe[0], POLLIN)); + d->pollfds.append(d->threadPipe.prepare()); int nevents = 0; @@ -476,7 +505,7 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags) case 0: break; default: - nevents += d->processThreadWakeUp(d->pollfds.takeLast()); + nevents += d->threadPipe.check(d->pollfds.takeLast()); if (include_notifiers) nevents += d->activateSocketNotifiers(); break; @@ -511,19 +540,7 @@ int QEventDispatcherUNIX::remainingTime(int timerId) 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 ); - } + d->threadPipe.wakeUp(); } void QEventDispatcherUNIX::interrupt() diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index b401c07040..d728040343 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -75,6 +75,27 @@ struct Q_CORE_EXPORT QSocketNotifierSetUNIX Q_DECL_FINAL Q_DECLARE_TYPEINFO(QSocketNotifierSetUNIX, Q_PRIMITIVE_TYPE); +struct QThreadPipe +{ + QThreadPipe(); + ~QThreadPipe(); + + bool init(); + pollfd prepare() const; + + void wakeUp(); + int check(const pollfd &pfd); + + // note for eventfd(7) support: + // if fds[1] is -1, then eventfd(7) is in use and is stored in fds[0] + int fds[2]; + QAtomicInt wakeUps; + +#if defined(Q_OS_VXWORKS) + static const int len_name = 20; + char name[len_name]; +#endif +}; class Q_CORE_EXPORT QEventDispatcherUNIX : public QAbstractEventDispatcher { @@ -114,26 +135,19 @@ public: QEventDispatcherUNIXPrivate(); ~QEventDispatcherUNIXPrivate(); - int processThreadWakeUp(const pollfd &pfd); - int activateTimers(); void markPendingSocketNotifiers(); int activateSocketNotifiers(); void setSocketNotifierPending(QSocketNotifier *notifier); - // 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]; - + QThreadPipe threadPipe; QVector pollfds; QHash socketNotifiers; QVector pendingNotifiers; QTimerInfoList timerList; - - QAtomicInt wakeUps; QAtomicInt interrupt; // bool }; -- cgit v1.2.3