1 | /* |
2 | * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
15 | * its contributors may be used to endorse or promote products derived |
16 | * from this software without specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | |
30 | #include "config.h" |
31 | #include "TimeoutChecker.h" |
32 | |
33 | #include "CallFrame.h" |
34 | #include "JSGlobalObject.h" |
35 | |
36 | #if OS(DARWIN) |
37 | #include <mach/mach.h> |
38 | #elif OS(WINDOWS) |
39 | #include <windows.h> |
40 | #else |
41 | #include "CurrentTime.h" |
42 | #endif |
43 | |
44 | using namespace std; |
45 | |
46 | namespace JSC { |
47 | |
48 | // Number of ticks before the first timeout check is done. |
49 | static const int ticksUntilFirstCheck = 1024; |
50 | |
51 | // Default number of milliseconds between each timeout check. |
52 | static const int defaultIntervalBetweenChecks = 1000; |
53 | |
54 | // Returns the time the current thread has spent executing, in milliseconds. |
55 | static inline unsigned getCPUTime() |
56 | { |
57 | #if OS(DARWIN) |
58 | mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; |
59 | thread_basic_info_data_t info; |
60 | |
61 | // Get thread information |
62 | mach_port_t threadPort = mach_thread_self(); |
63 | thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount); |
64 | mach_port_deallocate(mach_task_self(), threadPort); |
65 | |
66 | unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000; |
67 | time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000; |
68 | |
69 | return time; |
70 | #elif OS(WINDOWS) |
71 | union { |
72 | FILETIME fileTime; |
73 | unsigned long long fileTimeAsLong; |
74 | } userTime, kernelTime; |
75 | |
76 | // GetThreadTimes won't accept NULL arguments so we pass these even though |
77 | // they're not used. |
78 | FILETIME creationTime, exitTime; |
79 | |
80 | GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime); |
81 | |
82 | return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000; |
83 | #elif OS(SYMBIAN) |
84 | RThread current; |
85 | TTimeIntervalMicroSeconds cpuTime; |
86 | |
87 | TInt err = current.GetCpuTime(cpuTime); |
88 | ASSERT_WITH_MESSAGE(err == KErrNone, "GetCpuTime failed with %d" , err); |
89 | return cpuTime.Int64() / 1000; |
90 | #else |
91 | // FIXME: We should return the time the current thread has spent executing. |
92 | return currentTime() * 1000; |
93 | #endif |
94 | } |
95 | |
96 | TimeoutChecker::TimeoutChecker() |
97 | : m_timeoutInterval(0) |
98 | , m_startCount(0) |
99 | , m_intervalBetweenChecks(defaultIntervalBetweenChecks) |
100 | { |
101 | reset(); |
102 | } |
103 | |
104 | TimeoutChecker::~TimeoutChecker() |
105 | { |
106 | } |
107 | |
108 | void TimeoutChecker::reset() |
109 | { |
110 | m_ticksUntilNextCheck = ticksUntilFirstCheck; |
111 | m_timeAtLastCheck = 0; |
112 | m_timeExecuting = 0; |
113 | } |
114 | |
115 | void TimeoutChecker::copyTimeoutValues(TimeoutChecker* other) |
116 | { |
117 | m_timeoutInterval = other->m_timeoutInterval; |
118 | m_startCount = other->m_startCount; |
119 | m_intervalBetweenChecks = other->m_intervalBetweenChecks; |
120 | } |
121 | |
122 | bool TimeoutChecker::didTimeOut(ExecState* exec) |
123 | { |
124 | unsigned currentTime = getCPUTime(); |
125 | |
126 | if (!m_timeAtLastCheck) { |
127 | // Suspicious amount of looping in a script -- start timing it |
128 | m_timeAtLastCheck = currentTime; |
129 | return false; |
130 | } |
131 | |
132 | unsigned timeDiff = currentTime - m_timeAtLastCheck; |
133 | |
134 | if (timeDiff == 0) |
135 | timeDiff = 1; |
136 | |
137 | m_timeExecuting += timeDiff; |
138 | m_timeAtLastCheck = currentTime; |
139 | |
140 | // Adjust the tick threshold so we get the next checkTimeout call in the |
141 | // interval specified in intervalBetweenChecks. |
142 | m_ticksUntilNextCheck = static_cast<unsigned>((static_cast<float>(m_intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck); |
143 | // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the |
144 | // preferred script check time interval. |
145 | if (m_ticksUntilNextCheck == 0) |
146 | m_ticksUntilNextCheck = ticksUntilFirstCheck; |
147 | |
148 | if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) { |
149 | if (exec->dynamicGlobalObject()->shouldInterruptScript()) |
150 | return true; |
151 | |
152 | reset(); |
153 | } |
154 | |
155 | return false; |
156 | } |
157 | |
158 | } // namespace JSC |
159 | |