Exemplo n.º 1
0
bool Watchdog::didFireSlow(ExecState* exec)
{
    {
        LockHolder locker(m_lock);

        ASSERT(m_timerDidFire);
        m_timerDidFire = false;

        if (currentWallClockTime() < m_wallClockDeadline)
            return false; // Just a stale timer firing. Nothing to do.

        // Set m_wallClockDeadline to noTimeLimit here so that we can reject all future
        // spurious wakes.
        m_wallClockDeadline = noTimeLimit;

        auto cpuTime = currentCPUTime();
        if (cpuTime < m_cpuDeadline) {
            auto remainingCPUTime = m_cpuDeadline - cpuTime;
            startTimer(locker, remainingCPUTime);
            return false;
        }
    }

    // Note: we should not be holding the lock while calling the callbacks. The callbacks may
    // call setTimeLimit() which will try to lock as well.

    // If m_callback is not set, then we terminate by default.
    // Else, we let m_callback decide if we should terminate or not.
    bool needsTermination = !m_callback
                            || m_callback(exec, m_callbackData1, m_callbackData2);
    if (needsTermination)
        return true;

    {
        LockHolder locker(m_lock);

        // If we get here, then the callback above did not want to terminate execution. As a
        // result, the callback may have done one of the following:
        //   1. cleared the time limit (i.e. watchdog is disabled),
        //   2. set a new time limit via Watchdog::setTimeLimit(), or
        //   3. did nothing (i.e. allow another cycle of the current time limit).
        //
        // In the case of 1, we don't have to do anything.
        // In the case of 2, Watchdog::setTimeLimit() would already have started the timer.
        // In the case of 3, we need to re-start the timer here.

        ASSERT(m_hasEnteredVM);
        bool callbackAlreadyStartedTimer = (m_cpuDeadline != noTimeLimit);
        if (hasTimeLimit() && !callbackAlreadyStartedTimer)
            startTimer(locker, m_timeLimit);
    }
    return false;
}
Exemplo n.º 2
0
void Watchdog::startCountdownIfNeeded()
{
    if (!m_isStopped)
        return; // Already started.

    if (!isArmed())
        return; // Not executing JS script. No need to start.

    if (isEnabled()) {
        m_elapsedTime = std::chrono::microseconds::zero();
        m_startTime = currentCPUTime();
        startCountdown(m_limit);
    }
}
Exemplo n.º 3
0
bool Watchdog::didFire(ExecState* exec)
{
    if (m_didFire)
        return true;

    if (!m_timerDidFire)
        return false;
    m_timerDidFire = false;
    stopCountdown();

    auto currentTime = currentCPUTime();
    auto deltaTime = currentTime - m_startTime;
    auto totalElapsedTime = m_elapsedTime + deltaTime;
    if (totalElapsedTime > m_limit) {
        // Case 1: the allowed CPU time has elapsed.

        // If m_callback is not set, then we terminate by default.
        // Else, we let m_callback decide if we should terminate or not.
        bool needsTermination = !m_callback
            || m_callback(exec, m_callbackData1, m_callbackData2);
        if (needsTermination) {
            m_didFire = true;
            return true;
        }

        // The m_callback may have set a new limit. So, we may need to restart
        // the countdown.
        startCountdownIfNeeded();

    } else {
        // Case 2: the allowed CPU time has NOT elapsed.

        // Tell the timer to alarm us again when it thinks we've reached the
        // end of the allowed time.
        auto remainingTime = m_limit - totalElapsedTime;
        m_elapsedTime = totalElapsedTime;
        m_startTime = currentTime;
        startCountdown(remainingTime);
    }

    return false;
}
Exemplo n.º 4
0
void Watchdog::startTimer(LockHolder&, std::chrono::microseconds timeLimit)
{
    ASSERT(m_hasEnteredVM);
    ASSERT(hasTimeLimit());
    ASSERT(timeLimit <= m_timeLimit);

    m_cpuDeadline = currentCPUTime() + timeLimit;
    auto wallClockTime = currentWallClockTime();
    auto wallClockDeadline = wallClockTime + timeLimit;

    if ((wallClockTime < m_wallClockDeadline)
            && (m_wallClockDeadline <= wallClockDeadline))
        return; // Wait for the current active timer to expire before starting a new one.

    // Else, the current active timer won't fire soon enough. So, start a new timer.
    this->ref(); // m_timerHandler will deref to match later.
    m_wallClockDeadline = wallClockDeadline;

    m_timerQueue->dispatchAfter(std::chrono::nanoseconds(timeLimit), m_timerHandler);
}
Exemplo n.º 5
0
double currentCPUTimeMS()
{
    return currentCPUTime() * 1000;
}