?? qeventdispatcher_unix.cpp
字號:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtCore module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.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 GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qplatformdefs.h"#include "qcoreapplication.h"#include "qpair.h"#include "qsocketnotifier.h"#include "qthread.h"#include "qeventdispatcher_unix_p.h"#include <private/qthread_p.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false;/***************************************************************************** UNIX signal handling *****************************************************************************/static sig_atomic_t signal_received;static sig_atomic_t signals_fired[NSIG];static void signalHandler(int sig){ signals_fired[sig] = 1; signal_received = 1;}QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate(){ extern Qt::HANDLE qt_application_thread_id; mainThread = (QThread::currentThreadId() == qt_application_thread_id); // initialize the common parts of the event loop pipe(thread_pipe); fcntl(thread_pipe[0], F_SETFD, FD_CLOEXEC); fcntl(thread_pipe[1], F_SETFD, FD_CLOEXEC); fcntl(thread_pipe[0], F_SETFL, fcntl(thread_pipe[0], F_GETFL) | O_NONBLOCK); fcntl(thread_pipe[1], F_SETFL, fcntl(thread_pipe[1], F_GETFL) | O_NONBLOCK); sn_highest = -1; interrupt = false;}QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate(){ // cleanup the common parts of the event loop close(thread_pipe[0]); close(thread_pipe[1]); // cleanup timers qDeleteAll(timerList);}int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout){ Q_Q(QEventDispatcherUNIX); int nsel; do { if (mainThread) { while (signal_received) { signal_received = 0; for (int i = 0; i < NSIG; ++i) { if (signals_fired[i]) { signals_fired[i] = 0; emit QCoreApplication::instance()->unixSignal(i); } } } } // Process timers and socket notifiers - the common UNIX stuff int highest = 0; FD_ZERO(&sn_vec[0].select_fds); FD_ZERO(&sn_vec[1].select_fds); FD_ZERO(&sn_vec[2].select_fds); if (! (flags & QEventLoop::ExcludeSocketNotifiers) && (sn_highest >= 0)) { // return the highest fd we can wait for input on if (!sn_vec[0].list.isEmpty()) sn_vec[0].select_fds = sn_vec[0].enabled_fds; if (!sn_vec[1].list.isEmpty()) sn_vec[1].select_fds = sn_vec[1].enabled_fds; if (!sn_vec[2].list.isEmpty()) sn_vec[2].select_fds = sn_vec[2].enabled_fds; highest = sn_highest; } FD_SET(thread_pipe[0], &sn_vec[0].select_fds); highest = qMax(highest, thread_pipe[0]); nsel = q->select(highest + 1, &sn_vec[0].select_fds, &sn_vec[1].select_fds, &sn_vec[2].select_fds, timeout); } while (nsel == -1 && (errno == EINTR || errno == EAGAIN)); if (nsel == -1) { if (errno == EBADF) { // it seems a socket notifier has a bad fd... find out // which one it is and disable it fd_set fdset; timeval tm; tm.tv_sec = tm.tv_usec = 0l; for (int type = 0; type < 3; ++type) { QList<QSockNot *> &list = sn_vec[type].list; if (list.size() == 0) continue; for (int i = 0; i < list.size(); ++i) { QSockNot *sn = list.at(i); FD_ZERO(&fdset); FD_SET(sn->fd, &fdset); int ret = -1; do { switch (type) { case 0: // read ret = select(sn->fd + 1, &fdset, 0, 0, &tm); break; case 1: // write ret = select(sn->fd + 1, 0, &fdset, 0, &tm); break; case 2: // except ret = select(sn->fd + 1, 0, 0, &fdset, &tm); break; } } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); if (ret == -1 && errno == EBADF) { // disable the invalid socket notifier static const char *t[] = { "Read", "Write", "Exception" }; qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...", sn->fd, t[type]); sn->obj->setEnabled(false); } } } } else { // EINVAL... shouldn't happen, so let's complain to stderr // and hope someone sends us a bug report perror("select"); } } // some other thread woke us up... consume the data on the thread pipe so that // select doesn't immediately return next time int nevents = 0; if (nsel > 0 && FD_ISSET(thread_pipe[0], &sn_vec[0].select_fds)) { char c[16]; while (::read(thread_pipe[0], c, sizeof(c)) > 0) ; if (!wakeUps.testAndSetRelease(1, 0)) { // hopefully, this is dead code qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!"); } ++nevents; } // activate socket notifiers if (! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0 && sn_highest >= 0) { // if select says data is ready on any socket, then set the socket notifier // to pending for (int i=0; i<3; i++) { QList<QSockNot *> &list = sn_vec[i].list; for (int j = 0; j < list.size(); ++j) { QSockNot *sn = list.at(j); if (FD_ISSET(sn->fd, &sn_vec[i].select_fds)) q->setSocketNotifierPending(sn->obj); } } } return (nevents + q->activateSocketNotifiers());}/* * Internal functions for manipulating timer data structures. The * timerBitVec array is used for keeping track of timer identifiers. */QTimerInfoList::QTimerInfoList(){ getTime(watchtime);}void QTimerInfoList::updateWatchTime(const timeval ¤tTime){ if (currentTime < watchtime) // clock was turned back timerRepair(watchtime - currentTime); watchtime = currentTime;}/* insert timer info into list*/void QTimerInfoList::timerInsert(QTimerInfo *ti){ int index = size(); while (index--) { register const QTimerInfo * const t = at(index); if (!(ti->timeout < t->timeout)) break; } insert(index+1, ti);}/* repair broken timer*/void QTimerInfoList::timerRepair(const timeval &diff){ // repair all timers for (int i = 0; i < size(); ++i) { register QTimerInfo *t = at(i); t->timeout = t->timeout - diff; }}/* Returns the time to wait for the next timer, or null if no timers are waiting.*/bool QTimerInfoList::timerWait(timeval &tm){ timeval currentTime; getTime(currentTime); updateWatchTime(currentTime); if (isEmpty()) return false; QTimerInfo *t = first(); // first waiting timer if (currentTime < t->timeout) { // time to wait tm = t->timeout - currentTime; } else { // no time to wait tm.tv_sec = 0; tm.tv_usec = 0; } return true;}QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent) : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent){ }QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent) : QAbstractEventDispatcher(dd, parent){ }QEventDispatcherUNIX::~QEventDispatcherUNIX(){ }int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timeval *timeout){ Q_D(QEventDispatcherUNIX); if (timeout) { // handle the case where select returns with a timeout, too // soon. timeval tvStart = d->timerList.watchtime; timeval tvCurrent = tvStart; timeval originalTimeout = *timeout; int nsel; do { timeval tvRest = originalTimeout + tvStart - tvCurrent; nsel = ::select(nfds, readfds, writefds, exceptfds, &tvRest); getTime(tvCurrent); } while (nsel == 0 && (tvCurrent - tvStart) < originalTimeout); return nsel; } return ::select(nfds, readfds, writefds, exceptfds, timeout);}/*! \internal*/void QEventDispatcherUNIX::registerTimer(int timerId, int interval, QObject *obj){ if (timerId < 1 || interval < 0 || !obj) { qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments"); return; } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { qWarning("QObject::startTimer: timers cannot be started from another thread"); return; } QTimerInfo *t = new QTimerInfo; // create timer t->id = timerId; t->interval.tv_sec = interval / 1000; t->interval.tv_usec = (interval % 1000) * 1000; timeval currentTime; getTime(currentTime); t->timeout = currentTime + t->interval; t->obj = obj; t->inTimerEvent = false; Q_D(QEventDispatcherUNIX); d->timerList.timerInsert(t); // put timer in list}/*! \internal*/bool QEventDispatcherUNIX::unregisterTimer(int timerId){ if (timerId < 1) { qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument"); return false; } else if (thread() != QThread::currentThread()) { qWarning("QObject::killTimer: timers cannot be stopped from another thread"); return false; } Q_D(QEventDispatcherUNIX); // set timer inactive for (int i = 0; i < d->timerList.size(); ++i) { register QTimerInfo *t = d->timerList.at(i); if (t->id == timerId) { d->timerList.removeAt(i); delete t; return true; } } // id not found return false;}/*! \internal*/bool QEventDispatcherUNIX::unregisterTimers(QObject *object){ if (!object) { qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument"); return false; } else if (object->thread() != thread() || thread() != QThread::currentThread()) { qWarning("QObject::killTimers: timers cannot be stopped from another thread"); return false;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -