File size: 3,996 Bytes
b6a38d7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
-- detect infinite loop functions
local last_call = false
local call_counts = {}
local last_call_ex = false
local call_counts_ex = {}
local call_stacks = {}
local function Reset()
last_call = false
call_counts = {}
last_call_ex = false
call_counts_ex = {}
call_stacks = {}
end
OnMsg.PostDoneMap = Reset
OnMsg.PreNewMap = Reset
OnMsg.LoadGame = Reset
if not Platform.developer then
function DetectInfiniteLoop()
end
function DetectInfiniteLoopEx(src, id, limit, log)
local time_now = GameTime()
if time_now ~= last_call_ex then
last_call_ex = time_now
call_counts_ex = {}
end
local call_counts = call_counts_ex[id]
if not call_counts then
call_counts = {}
call_counts_ex[id] = call_counts
end
call_counts[src] = (call_counts[src] or 0) + 1
if call_counts[src] > limit+3 then
Sleep(2000)
end
return true
end
else
-- developers
local trace = {}
function TraceThread(thread)
if trace[thread] then return end
local getinfo = debug.getinfo
local function DebugHook(event, line)
if event == "line" then
local info = getinfo(thread, 2, "S")
local tbl = trace[thread]
if not string.find(info.source, "lib.lua", -10, true) then
tbl[#tbl + 1] = tostring(info.source) .. "("..tostring(line).."): " .. GameTime()
if #tbl > 1000 then
table.remove(tbl, 1)
end
end
end
end
trace[thread] = {}
local old_debug_hook, old_debug_mask, old_debug_count = debug.gethook(thread)
if (string.match(old_debug_mask, "[lL]")) then
debug.sethook(thread, DebugHook, old_debug_mask)
else
debug.sethook(thread, DebugHook, old_debug_mask .. "l")
end
end
function DumpTrace(thread)
print("-------- trace -------")
local tbl = trace[thread]
for i = 1, #tbl do
print(tbl[i])
end
end
-- May fuck up if being called frequently for interchanging sync and async threads
function DetectInfiniteLoop(src, ...)
local time_now = GameTime()
if time_now ~= last_call then
last_call = time_now
call_counts = {}
end
call_counts[src] = (call_counts[src] or 0) + 1
--if src.NetUpdateHash then src:NetUpdateHash("DetectInfiniteLoop", call_counts[src]) end
if call_counts[src] > 2 then
print(...)
error("Infinite loop game time " .. tostring(GameTime()), 1)
--end
--if call_counts[src] > 5 then
Sleep(200)
end
return true
end
-- May fuck up if being called frequently for interchanging sync and async threads
function DetectInfiniteLoopEx(src, id, limit, log)
local time_now = GameTime()
if time_now ~= last_call_ex then
last_call_ex = time_now
call_counts_ex = {}
call_stacks = {}
end
local call_counts = call_counts_ex[id]
local stacks = call_stacks[id]
if not call_counts then
call_counts = {}
stacks = {}
call_stacks[id] = stacks
call_counts_ex[id] = call_counts
end
local logs = stacks[src]
if not logs then
logs = {}
stacks[src] = logs
end
logs[#logs + 1] = log or GetStack(2)
local call_count = (call_counts[src] or 0) + 1
call_counts[src] = call_count
if call_count > limit then
local thread = CurrentThread()
--TraceThread(thread)
error("Infinite loop game time " .. tostring(GameTime()), 1)
if IsValid(src) then
local text = 'class = "' .. src.class .. '"'
if src:IsKindOf("CommandObject") then
text = text .. ', command = "' .. tostring(src.command) .. '"'
end
print(text)
end
if log then
-- join repeated logs
local i = 1
while i <= call_count do
local entry = logs[i]
local j = i
repeat
i = i + 1
until i > call_count or logs[i] ~= entry
if i - j == 1 then
printf("call #%d: %s", j, entry)
else
printf("call #%d-%d: %s", j, i-1, entry)
end
end
else
for i = 1, call_count do
printf("call #%d", i)
string.gsub(logs[i], "(.-)\n", function(s) print(s) end)
end
end
--DumpTrace(thread)
end
if call_count > 5 + limit then
Sleep(200)
end
return true
end
end
|