timer implementation on the lua side (driven via event.fire)

This commit is contained in:
Florian Nücke 2013-09-27 08:33:55 +02:00
parent 12da32bc6c
commit d7905fe737
3 changed files with 70 additions and 15 deletions

View File

@ -19,6 +19,8 @@
command that will be executed when pressing enter. command that will be executed when pressing enter.
]] ]]
-------------------------------------------------------------------------------
--[[ Distribute signals as events. ]] --[[ Distribute signals as events. ]]
local listeners = {} local listeners = {}
local weakListeners = {} local weakListeners = {}
@ -36,6 +38,7 @@ end
--[[ Event API table. ]] --[[ Event API table. ]]
event = {} event = {}
local timers = {}
--[[ Register a new event listener for the specified event. ]] --[[ Register a new event listener for the specified event. ]]
function event.listen(name, callback, weak) function event.listen(name, callback, weak)
@ -53,12 +56,51 @@ end
function event.fire(name, ...) function event.fire(name, ...)
if name then if name then
for callback, _ in pairs(listenersFor(name, false)) do for callback, _ in pairs(listenersFor(name, false)) do
callback(name, ...) local result, message = xpcall(callback, event.error, name, ...)
if not result and message then
error(message, 0)
end
end end
for callback, _ in pairs(listenersFor(name, true)) do for callback, _ in pairs(listenersFor(name, true)) do
callback(name, ...) local result, message = xpcall(callback, event.error, name, ...)
if not result and message then
error(message, 0)
end
end end
end end
local elapsed = {}
for id, info in pairs(timers) do
if info.after < os.clock() then
elapsed[id] = info
end
end
for id, _ in pairs(elapsed) do
timers[id] = nil
end
for _, info in pairs(elapsed) do
local result, message = xpcall(info.callback, event.error)
if not result and message then
error(message, 0)
end
end
end
--[[ Calls the specified function after the specified time. ]]
function event.after(timeout, callback)
local id = #timers
timers[id] = {after = os.clock() + timeout, callback = callback}
return id
end
function event.cancel(timerId)
checkArg(1, timerId, "number")
timers[timerId] = nil
end
--[[ Error handler for ALL event callbacks. If this returns a value,
the computer will crash. Otherwise it'll keep going. ]]
function event.error(message)
return message
end end
--[[ Suspends a thread for the specified amount of time. ]] --[[ Suspends a thread for the specified amount of time. ]]
@ -66,10 +108,17 @@ function coroutine.sleep(seconds)
checkArg(1, seconds, "number") checkArg(1, seconds, "number")
local target = os.clock() + seconds local target = os.clock() + seconds
repeat repeat
event.fire(os.signal(nil, target - os.clock())) local closest = target
for _, info in pairs(timers) do
if info.after < closest then
closest = info.after
end
end
event.fire(os.signal(nil, closest - os.clock()))
until os.clock() >= target until os.clock() >= target
end end
-------------------------------------------------------------------------------
--[[ Keep track of connected components across address changes. ]] --[[ Keep track of connected components across address changes. ]]
local components = {} local components = {}
@ -122,6 +171,7 @@ event.listen("component_changed", function(_, newAddress, oldAddress)
components[id].address = newAddress components[id].address = newAddress
end) end)
-------------------------------------------------------------------------------
--[[ Setup terminal API. ]] --[[ Setup terminal API. ]]
local idGpu, idScreen = 0, 0 local idGpu, idScreen = 0, 0
@ -166,16 +216,6 @@ event.listen("screen_resized", function(_, address, w, h)
end end
end) end)
term = {}
function term.gpu()
return boundGpu
end
function term.screenSize()
return screenWidth, screenHeight
end
local function bindIfPossible() local function bindIfPossible()
if idGpu > 0 and idScreen > 0 then if idGpu > 0 and idScreen > 0 then
if not boundGpu then if not boundGpu then
@ -192,6 +232,16 @@ local function bindIfPossible()
end end
end end
term = {}
function term.gpu()
return boundGpu
end
function term.screenSize()
return screenWidth, screenHeight
end
function term.gpuId(id) function term.gpuId(id)
if id then if id then
checkArg(1, id, "number") checkArg(1, id, "number")
@ -272,6 +322,7 @@ write = function(...)
end end
end end
-------------------------------------------------------------------------------
--[[ Primitive command line. ]] --[[ Primitive command line. ]]
local command = "" local command = ""

View File

@ -232,7 +232,8 @@ return pcall(function()
deadline = os.realTime() + 3 deadline = os.realTime() + 3
local result = {coroutine.resume(init, table.unpack(data))} local result = {coroutine.resume(init, table.unpack(data))}
if result[1] then if result[1] then
-- Init should never return, so we have a system yield. -- Init should never return, so we have a yield. The first yielded
-- value can only be set by system yields.
result = result[2] result = result[2]
else else
-- Some other error, go kill ourselves. -- Some other error, go kill ourselves.

View File

@ -44,7 +44,10 @@ class TileEntityComputer(isClient: Boolean) extends TileEntityRotatable with ICo
} }
} }
override protected def onReconnect() = computer.signal("address_change", address) override protected def onReconnect() = {
super.onReconnect()
computer.signal("address_change", address)
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
// General // General