blob: 56d6d4b71d5537ab73b20bc06272a5383833d1df [file] [log] [blame]
/*
* Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "TimeoutChecker.h"
#include "CallFrame.h"
#include "JSGlobalObject.h"
#if OS(DARWIN)
#include <mach/mach.h>
#elif OS(WINDOWS)
#include <windows.h>
#else
#include <wtf/CurrentTime.h>
#endif
using namespace std;
namespace JSC {
// Number of ticks before the first timeout check is done.
static const int ticksUntilFirstCheck = 1024;
// Number of milliseconds between each timeout check.
static const int intervalBetweenChecks = 1000;
// Returns the time the current thread has spent executing, in milliseconds.
static inline unsigned getCPUTime()
{
#if OS(DARWIN)
mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t info;
// Get thread information
mach_port_t threadPort = mach_thread_self();
thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
mach_port_deallocate(mach_task_self(), threadPort);
unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
return time;
#elif OS(WINDOWS)
union {
FILETIME fileTime;
unsigned long long fileTimeAsLong;
} userTime, kernelTime;
// GetThreadTimes won't accept NULL arguments so we pass these even though
// they're not used.
FILETIME creationTime, exitTime;
GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
#elif OS(QNX)
struct timespec time;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time))
CRASH();
return time.tv_sec * 1000.0 + time.tv_nsec / 1.0e6;
#else
// FIXME: We should return the time the current thread has spent executing.
// use a relative time from first call in order to avoid an overflow
static double firstTime = currentTime();
return static_cast<unsigned> ((currentTime() - firstTime) * 1000);
#endif
}
TimeoutChecker::TimeoutChecker()
: m_timeoutInterval(0)
, m_startCount(0)
{
reset();
}
void TimeoutChecker::reset()
{
m_ticksUntilNextCheck = ticksUntilFirstCheck;
m_timeAtLastCheck = 0;
m_timeExecuting = 0;
}
bool TimeoutChecker::didTimeOut(ExecState* exec)
{
unsigned currentTime = getCPUTime();
if (!m_timeAtLastCheck) {
// Suspicious amount of looping in a script -- start timing it
m_timeAtLastCheck = currentTime;
return false;
}
unsigned timeDiff = currentTime - m_timeAtLastCheck;
if (timeDiff == 0)
timeDiff = 1;
m_timeExecuting += timeDiff;
m_timeAtLastCheck = currentTime;
// Adjust the tick threshold so we get the next checkTimeout call in the
// interval specified in intervalBetweenChecks.
m_ticksUntilNextCheck = static_cast<unsigned>((static_cast<float>(intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck);
// If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
// preferred script check time interval.
if (m_ticksUntilNextCheck == 0)
m_ticksUntilNextCheck = ticksUntilFirstCheck;
if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) {
if (exec->dynamicGlobalObject()->globalObjectMethodTable()->shouldInterruptScript(exec->dynamicGlobalObject()))
return true;
reset();
}
return false;
}
} // namespace JSC