Ejemplo n.º 1
0
/*!
    \internal

    Behaves as close to POSIX poll(2) as practical but may be implemented
    using select(2) where necessary. In that case, returns -1 and sets errno
    to EINVAL if passed any descriptor greater than or equal to FD_SETSIZE.
*/
int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
{
    if (!timeout_ts) {
        // no timeout -> block forever
        int ret;
        EINTR_LOOP(ret, qt_ppoll(fds, nfds, Q_NULLPTR));
        return ret;
    }

    timespec start = qt_gettime();
    timespec timeout = *timeout_ts;

    // loop and recalculate the timeout as needed
    forever {
        const int ret = qt_ppoll(fds, nfds, &timeout);
        if (ret != -1 || errno != EINTR)
            return ret;

        // recalculate the timeout
        if (!time_update(&timeout, start, *timeout_ts)) {
            // timeout during update
            // or clock reset, fake timeout error
            return 0;
        }
    }
}
Ejemplo n.º 2
0
int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
                   const struct timeval *orig_timeout)
{
    if (!orig_timeout) {
        // no timeout -> block forever
        register int ret;
        EINTR_LOOP(ret, select(nfds, fdread, fdwrite, fdexcept, 0));
        return ret;
    }

    timeval start = qt_gettime();
    timeval timeout = *orig_timeout;

    // loop and recalculate the timeout as needed
    int ret;
    forever {
        ret = ::select(nfds, fdread, fdwrite, fdexcept, &timeout);
        if (ret != -1 || errno != EINTR)
            return ret;

        // recalculate the timeout
        if (!time_update(&timeout, start, *orig_timeout)) {
            // timeout during update
            // or clock reset, fake timeout error
            return 0;
        }
    }
}
Ejemplo n.º 3
0
QTimerInfoList::QTimerInfoList()
{
    currentTime = qt_gettime();

#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)
    if (!qt_gettime_is_monotonic()) {
        // not using monotonic timers, initialize the timeChanged() machinery
        previousTime = currentTime;

        tms unused;
        previousTicks = times(&unused);

        ticksPerSecond = sysconf(_SC_CLK_TCK);
        msPerTick = 1000/ticksPerSecond;
    } else {
        // detected monotonic timers
        previousTime.tv_sec = previousTime.tv_usec = 0;
        previousTicks = 0;
        ticksPerSecond = 0;
        msPerTick = 0;
    }
#endif

    firstTimerInfo = currentTimerInfo = 0;
}
Ejemplo n.º 4
0
int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
                   const struct timespec *orig_timeout)
{
    if (!orig_timeout) {
        // no timeout -> block forever
        int ret;
        EINTR_LOOP(ret, select(nfds, fdread, fdwrite, fdexcept, 0));
        return ret;
    }

    timespec start = qt_gettime();
    timespec timeout = *orig_timeout;

    // loop and recalculate the timeout as needed
    int ret;
    forever {
#ifndef Q_OS_QNX
        ret = ::pselect(nfds, fdread, fdwrite, fdexcept, &timeout, 0);
#else
        timeval timeoutVal;
        timeoutVal.tv_sec = timeout.tv_sec;
        timeoutVal.tv_usec = timeout.tv_nsec / 1000;
        ret = ::select(nfds, fdread, fdwrite, fdexcept, &timeoutVal);
#endif
        if (ret != -1 || errno != EINTR)
            return ret;

        // recalculate the timeout
        if (!time_update(&timeout, start, *orig_timeout)) {
            // timeout during update
            // or clock reset, fake timeout error
            return 0;
        }
    }
}
Ejemplo n.º 5
0
static inline bool time_update(struct timespec *tv, const struct timespec &start,
                               const struct timespec &timeout)
{
    // clock source is (hopefully) monotonic, so we can recalculate how much timeout is left;
    // if it isn't monotonic, we'll simply hope that it hasn't jumped, because we have no alternative
    struct timespec now = qt_gettime();
    *tv = timeout + start - now;
    return tv->tv_sec >= 0;
}
Ejemplo n.º 6
0
QT_BEGIN_NAMESPACE

static inline bool time_update(struct timeval *tv, const struct timeval &start,
                               const struct timeval &timeout)
{
    if (!QElapsedTimer::isMonotonic()) {
        // we cannot recalculate the timeout without a monotonic clock as the time may have changed
        return false;
    }

    // clock source is monotonic, so we can recalculate how much timeout is left
    struct timeval now = qt_gettime();
    *tv = timeout + start - now;
    return tv->tv_sec >= 0;
}
QT_BEGIN_NAMESPACE

#if !defined(QT_HAVE_PPOLL) && defined(QT_HAVE_POLLTS)
# define ppoll pollts
# define QT_HAVE_PPOLL
#endif

static inline bool time_update(struct timespec *tv, const struct timespec &start,
                               const struct timespec &timeout)
{
    // clock source is (hopefully) monotonic, so we can recalculate how much timeout is left;
    // if it isn't monotonic, we'll simply hope that it hasn't jumped, because we have no alternative
    struct timespec now = qt_gettime();
    *tv = timeout + start - now;
    return tv->tv_sec >= 0;
}
Ejemplo n.º 8
0
void qt_abstime_for_timeout(timespec *ts, int timeout)
{
#ifdef Q_OS_MAC
    // on Mac, qt_gettime() (on qelapsedtimer_mac.cpp) returns ticks related to the Mach absolute time
    // that doesn't work with pthread
    // Mac also doesn't have clock_gettime
    struct timeval tv;
    gettimeofday(&tv, 0);
    ts->tv_sec = tv.tv_sec;
    ts->tv_nsec = tv.tv_usec * 1000;
#else
    *ts = qt_gettime();
#endif

    ts->tv_sec += timeout / 1000;
    ts->tv_nsec += timeout % 1000 * Q_UINT64_C(1000) * 1000;
    normalizedTimespec(*ts);
}
Ejemplo n.º 9
0
timespec QTimerInfoList::updateCurrentTime()
{
    return (currentTime = qt_gettime());
}
int QEventDispatcherBlackberry::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
                                       timespec *timeout)
{
    Q_UNUSED(nfds);
    Q_D(QEventDispatcherBlackberry);
    const BBScopedLoopLevelCounter bbLoopCounter(d);

    BpsChannelScopeSwitcher channelSwitcher(d->bps_channel);

    // prepare file sets for bps callback
    d->ioData->count = 0;
    d->ioData->readfds = readfds;
    d->ioData->writefds = writefds;
    d->ioData->exceptfds = exceptfds;

    // reset all file sets
    if (readfds)
        FD_ZERO(readfds);

    if (writefds)
        FD_ZERO(writefds);

    if (exceptfds)
        FD_ZERO(exceptfds);

    bps_event_t *event = 0;
    unsigned int eventCount = 0;

    // If an event handler called through filterEvent() starts a nested event loop by creating a
    // new QEventLoop, we will recursively enter this function again.  However, each time
    // bps_get_event() is called, it destroys the last event it handed out before returning the
    // next event.  We don't want it to destroy the event that triggered the nested event loop,
    // since there may still be more handlers that need to get that event, once the nested event
    // loop is done and control returns to the outer event loop.
    //
    // So we move an event to a holding channel, which takes ownership of the event.  Putting
    // the event on our own channel allows us to manage when it is destroyed, keeping it alive
    // until we know we are done with it.  Each recursive call of this function needs to have
    // it's own holding channel, since a channel is a queue, not a stack.
    //
    // However, a recursive call into this function happens very rarely compared to the many
    // times this function is called.  We don't want to create a holding channel for each time
    // this function is called, only when it is called recursively.  Thus we have the instance
    // variable d->holding_channel to use in the common case.  We keep track of recursive calls
    // with d->loop_level.  If we are in a recursive call, then we create a new holding channel
    // for this run.
    int holding_channel = d->holding_channel;
    if ((d->loop_level > 1) &&
        Q_UNLIKELY(bps_channel_create(&holding_channel, 0) != BPS_SUCCESS)) {
        qWarning("QEventDispatcherBlackberry: bps_channel_create failed");
        holding_channel = -1;
    }

    // Convert timeout to milliseconds
    int timeoutTotal = -1;
    if (timeout)
        timeoutTotal = timespecToMillisecs(*timeout);
    int timeoutLeft = timeoutTotal;
    timespec startTime = qt_gettime();

    // This loop exists such that we can drain the bps event queue of all native events
    // more efficiently than if we were to return control to Qt after each event. This
    // is important for handling touch events which can come in rapidly.
    forever {
        // Only emit the awake() and aboutToBlock() signals in the second iteration. For the
        // first iteration, the UNIX event dispatcher will have taken care of that already.
        // Also native events are actually processed one loop iteration after they were
        // retrieved with bps_get_event().

        // Filtering the native event should happen between the awake() and aboutToBlock()
        // signal emissions. The calls awake() - filterNativeEvent() - aboutToBlock() -
        // bps_get_event() need not to be interrupted by a break or return statement.
        if (eventCount > 0) {
            if (event) {
                emit awake();
                filterNativeEvent(QByteArrayLiteral("bps_event_t"), static_cast<void*>(event), 0);
                emit aboutToBlock();

                if (Q_LIKELY(holding_channel != -1)) {
                    // We are now done with this BPS event.  Destroy it.
                    destroyHeldBpsEvent(holding_channel);
                }
            }

            // Update the timeout
            // Clock source is monotonic, so we can recalculate how much timeout is left
            if (timeoutTotal != -1) {
                timespec t2 = qt_gettime();
                timeoutLeft = timeoutTotal
                              - (timespecToMillisecs(t2) - timespecToMillisecs(startTime));
                if (timeoutLeft < 0)
                    timeoutLeft = 0;
            }

            timespec tnext;
            if (d->timerList.timerWait(tnext)) {
                int timeoutNext = timespecToMillisecs(tnext);
                if (timeoutNext < timeoutLeft || timeoutTotal == -1) {
                    timeoutTotal = timeoutLeft = timeoutNext;
                    startTime = qt_gettime();
                }
            }
        }

        event = 0;
        {   // We need to increase loop level in this scope,
            // because bps_get_event can also invoke callbacks
            QScopedLoopLevelCounter loopLevelCounter(d->threadData);

            // Wait for event or file to be ready
            const int result = bps_get_event(&event, timeoutLeft);
            if (Q_UNLIKELY(result != BPS_SUCCESS))
                qWarning("QEventDispatcherBlackberry: bps_get_event failed");
        }

        if (!event)    // In case of !event, we break out of the loop to let Qt process the timers
            break;     // (since timeout has expired) and socket notifiers that are now ready.

        if (bps_event_get_domain(event) == bpsUnblockDomain) {
            timeoutTotal = 0;   // in order to immediately drain the event queue of native events
            event = 0;          // (especially touch move events) we don't break out here
        } else {
            // Move the event to our holding channel so we can manage when it is destroyed.
            if (Q_LIKELY(holding_channel != 1) &&
                Q_UNLIKELY(bps_channel_push_event(holding_channel, event) != BPS_SUCCESS)) {
                qWarning("QEventDispatcherBlackberry: bps_channel_push_event failed");
            }
        }

        ++eventCount;

        // Make sure we are not trapped in this loop due to continuous native events
        // also we cannot recalculate the timeout without a monotonic clock as the time may have changed
        const unsigned int maximumEventCount = 12;
        if (Q_UNLIKELY((eventCount > maximumEventCount && timeoutLeft == 0)
                       || !QElapsedTimer::isMonotonic())) {
            if (event) {
                filterNativeEvent(QByteArrayLiteral("bps_event_t"), static_cast<void*>(event), 0);

                if (Q_LIKELY(holding_channel != -1)) {
                    // We are now done with this BPS event.  Destroy it.
                    destroyHeldBpsEvent(holding_channel);
                }
            }
            break;
        }
    }

    // If this was a recursive call into this function, a new holding channel was created for
    // this run, so destroy it now.
    if ((holding_channel != d->holding_channel) &&
        Q_LIKELY(holding_channel != -1) &&
        Q_UNLIKELY(bps_channel_destroy(holding_channel) != BPS_SUCCESS)) {
        qWarning("QEventDispatcherBlackberry: bps_channel_destroy failed");
    }

    // the number of bits set in the file sets
    return d->ioData->count;
}