OpenComputers Von Neumann Machine Programs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
4.7 KiB

local coroutine = require("coroutine")
local computer = require("computer")
local event = require("event")
local ll = require("liblua")
local os = require("os")
local table = require("table")
local async = {}
-- TODO FINISH THIS
-- An async wrapper for event.pullFiltered
function async.pullFiltered(...)
-- Check if we're in a coroutine or not
_, status = coroutine.running()
local start = computer.uptime()
local args = {...}
-- Break on interrupts
function f(name, ...)
-- if args[1] happens to be "interrupted" already the second won't trigger
if name == args[1] or name == "interrupted" then
return true
end
end
if type(args[1]) == "string" then
-- Check if not in a coroutine
if not status then return event.pullFiltered(f, ...) end
print("Testing")
repeat
coroutine.yield()
tmp = {event.pullFiltered(.01, f, ...)}
until #tmp > 0
else
local timeout = nil
if type(args[1]) == "number" then
timeout = args[1]
args = ll.slice({...}, 2)
-- For speed purposes check up here even though it's more repeated code
elseif type(args[1]) == "function" then
-- Wrap other function so this will handle interrupts
function g(name, ...)
local a = ll.slice(args, 2)
-- Handle interrupt
if name == "interrupted" then
return true
end
-- Otherwise run other function
return args[1](name, ...)
end
if timeout ~= nil then
-- Check if not in a coroutine
if not status then
return event.pullFiltered(timeout, g, table.unpack(args))
end
repeat
coroutine.yield()
tmp = {event.pullFiltered(.01, g, table.unpack(args))}
until #tmp > 0 or computer.uptime() - start >= timeout
else
-- Check if not in a coroutine
if not status then
return event.pullFiltered(g, ...)
end
repeat
coroutine.yield()
tmp = {event.pullFiltered(.01, g, table.unpack(args))}
until #tmp > 0
end
else
if timeout ~= nil then
-- Check if not in a coroutine
if not status then
return event.pullFiltered(timeout, f, table.unpack(args))
end
repeat
coroutine.yield()
tmp = {event.pullFiltered(.01, f, table.unpack(args))}
until #tmp > 0 or computer.uptime() - start >= timeout
else
-- Check if not in a coroutine
if not status then
return event.pullFiltered(f, table.unpack(args))
end
repeat
coroutine.yield()
tmp = {event.pullFiltered(.01, f, table.unpack(args))}
until #tmp > 0
end
end
end
return table.unpack(tmp)
end
-- An alias for async.pullFiltered which does all of the logic for both functions
async.pull = async.pullFiltered
-- Sleep in a coroutine friendly way
function async.sleep(s)
local _, status = coroutine.running()
-- If not a coroutine just regular sleep
if status then
os.sleep(s)
return
end
local start = computer.uptime()
repeat
coroutine.yield()
until (computer.uptime() - start > s)
end
-- Simple loop
local loop = {
bundles = {},
live = {},
dead = {},
add = function(self, ...)
local bs = {...}
-- Insert both into bundles and live so no deep copy needs to occur later
for _, v in ipairs(bs) do
table.insert(self.bundles, #self.bundles+1, v)
table.insert(self.live, #self.live+1, v)
end
end
}
-- Used to pack function and args into a nice container for the loop and schedulers
function async.bundle(f, ...)
return {
coro = coroutine.create(f),
args = {...},
results = {}
}
end
-- Return a new loop
function async.getLoop()
return setmetatable({}, {__index=loop})
end
-- Most simple scheduling
function async.roundRobin(loop, ignoreError)
-- Ignore a function throwing an error
if ignoreError == nil then
ignoreError = false
end
local i = 1
repeat
local b = loop.live[i]
local r = {coroutine.resume(b.coro, table.unpack(b.args))}
local status, results = r[1], ll.slice(r, 2)
-- Fail and exit if a function is bad
if not status and not ignoreError then
io.stderr:write(results[1])
return
-- Don't exit but print the bad message
elseif not status then
print(results[1])
end
-- Stop running dead coroutines and add the results
if coroutine.status(b.coro) == "dead" then
b.results = results
table.insert(loop.dead, #loop.dead+1, table.remove(loop.live, i))
else
i = (i % (#loop.live)) + 1
end
until #loop.live == 0
return loop
end
return async
-- wget -f http://mc.bashed.rocks:13699/lib/async.lua /usr/lib/async.lua