Browse Source

Add async library with basic scheduler

master
BuildTools 1 year ago
parent
commit
dd9194a31e
  1. 2
      .gitignore
  2. 85
      lib/async.lua
  3. 70
      lib/liblua.lua
  4. 6
      lib/net.lua
  5. 0
      lib/slice.lua
  6. 16
      lib/split.lua

2
.gitignore

@ -0,0 +1,2 @@
windowmanager/
test*

85
lib/async.lua

@ -1,5 +1,88 @@
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 = {}
return async
-- 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 async.lua

70
lib/liblua.lua

@ -1,5 +1,5 @@
#!/bin/lua
local event = require("event")
local computer = require("computer")
local string = require("string")
local table = require("table")
@ -22,11 +22,11 @@ split = ll.split
-- Slice table
function ll.slice(tbl, first, last, step)
local sliced = {}
for i = first or 1, last or #tbl, step or 1 do
sliced[#sliced+1] = tbl[i]
end
return sliced
end
slice = ll.slice
@ -57,15 +57,15 @@ end
filter = ll.filter
-- Returns true is something is in the sequence
function liblua.any(seq)
for i, v in ipairs(seq) do
if v then
return true
end
end
return false
function ll.any(seq)
for i, v in ipairs(seq) do
if v then
return true
end
end
return false
end
any = liblua.any
any = ll.any
-- TODO finish this
-- Reduce a regular list
@ -97,13 +97,45 @@ function ll.tprint(...)
end
end
ll.tprint(ll.filter(
function(a)
if a > 5 then
return a
-- An async wrapper for event.pullFiltered
function ll.pullFiltered(...)
-- Check if we're in a coroutine or not
_, status = coroutine.running()
-- Check use regular if we don't need to block
if status then return event.pullFiltered(...) end
local start = computer.uptime()
local args = {...}
if type(args[1]) == "string" then
repeat
coroutine.yield()
tmp = {event.pullFiltered(.01, ...)}
until #tmp > 0
else
checkArg(1, args[1], "number")
local timeout = args[1]
local args = ll.slice({...}, 2)
-- For speed purposes check up here even though it's more repeated code
if type(args[1]) == "function" then
repeat
coroutine.yield()
tmp = {event.pullFiltered(.01, table.unpack(args))}
until #tmp > 0 or computer.uptime() - start >= timeout
else
return nil
repeat
coroutine.yield()
tmp = {event.pull(.01, table.unpack(args))}
until #tmp > 0 or computer.uptime() - start >= timeout
end
end, {1,4,8,3,12,10}))
end
end
-- An alias for ll.pullFiltered which does all of the logic for both functions
function ll.pull(...)
ll.pullFiltered(...)
end
return ll
return ll
-- wget -f http://mc.bashed.rocks:13699/lib/liblua.lua /usr/lib/liblua.lua

6
lib/net.lua

@ -104,7 +104,7 @@ end
function net.recv(t)
local pkt = {}
local tmp = {}
-- This allows deafault and keyword args
-- This allows default and keyword args
if t ~= nil then
setmetatable(t,{__index={
port = nil,
@ -167,7 +167,7 @@ function net.recv(t)
repeat
coroutine.yield()
tmp = {event.pullFiltered(.05, f)}
until (#tmp > 0 or computer.uptime() - start >= timeout)
until #tmp > 0 or computer.uptime() - start >= timeout
else
tmp = {event.pullFiltered(timeout, f)}
end
@ -176,7 +176,7 @@ function net.recv(t)
repeat
coroutine.yield()
tmp = {event.pullFiltered(.05, f)}
until (#tmp > 0)
until #tmp > 0
else
tmp = {event.pullFiltered(f)}
end

0
lib/slice.lua

16
lib/split.lua

@ -1,16 +0,0 @@
local string = require("string")
local table = require("table")
function split(s, sep)
if sep == nil then
sep = "%s"
end
local t = {}
for str in string.gmatch(s, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
return split
Loading…
Cancel
Save