]> hydra-www.ietfng.org Git - acmetensortoys-esp-lua_core/commitdiff
Plumbing: modularize fifo, improve tq
authorNathaniel Wesley Filardo <nwf@cs.jhu.edu>
Mon, 21 Nov 2016 00:10:24 +0000 (19:10 -0500)
committerNathaniel Wesley Filardo <nwf@cs.jhu.edu>
Mon, 21 Nov 2016 20:51:26 +0000 (15:51 -0500)
fifo/fifo-diag.lua [new file with mode: 0644]
fifo/fifo.lua [new file with mode: 0644]
host/pushcommon.sh
host/pushinit.sh
net/fifosock.lua [new file with mode: 0644]
telnetd/telnetd.lua
test/fifotest.lua [new file with mode: 0644]
test/tqstress.lua [new file with mode: 0644]
tq/tq.lua
util/fifosock.lua [deleted file]

diff --git a/fifo/fifo-diag.lua b/fifo/fifo-diag.lua
new file mode 100644 (file)
index 0000000..5a19d42
--- /dev/null
@@ -0,0 +1,5 @@
+return function(q)
+  local k,v
+  print("FIFOQ")
+  for k,v in ipairs(q) do print("",k,v) end
+end
diff --git a/fifo/fifo.lua b/fifo/fifo.lua
new file mode 100644 (file)
index 0000000..794ad08
--- /dev/null
@@ -0,0 +1,25 @@
+-- Remove an element and pass it to k; if that returns a function, leave that
+-- pending at the top of the fifo.  Thus, we can get events that do multiple
+-- things.  If the queue is empty, do not invoke k but flag it to enable
+-- immediate execution at the next call to queue.
+--
+-- Returns 'true' if the queue was not empty, 'false' otherwise.
+local function dequeue(q,k)
+  if #q > 0
+   then local new = k(q[1]) ; if new == nil then table.remove(q,1) else q[1] = new end ; return true
+   else q._go = true ; return false
+  end
+end
+-- Queue a on queue q.
+--
+-- If k is provided and the queue has previously drained, dequeue immediately
+-- as if k had passed to dequeue.  This is useful when k will arrange for
+-- subsequent dequeues.
+local function queue(q,a,k)
+  table.insert(q,a)
+  if k ~= nil and q._go then q._go = false; q:dequeue(k) end
+end
+-- return a FIFO constructor
+return function()
+  return { ['_go'] = true ; ['queue'] = queue ; ['dequeue'] = dequeue }
+end
index 730f70f18b1b8465b438e5fa6664b3589edf68f6..bc08badf4b02760acf46bda169798679e0fb22aa 100644 (file)
@@ -1,11 +1,11 @@
-if [ -z ${HOST:-} ]; then
+if [ -z ${MCUHOST:-} ]; then
   # Uses LUATOOL to push init and dependencies to the device; bootstrap!
   PUSHCMD="${LUATOOL} --delay 0.1 -p ${MCUPORT} -b ${MCUBAUD}"
   dopush() { ${PUSHCMD} -f $1 -t ${2:-`basename $1`}; }
   dopushcompile() { ${PUSHCMD} -f $1 -t ${2:-`basename $1`} -c; }
 else
-  # Uses host/pushvia to push everything if HOST is set
-  PUSHCMD="./host/pushvia.expect ${HOST} ${PORT:-23}"
+  # Uses host/pushvia to push everything if MCUHOST is set
+  PUSHCMD="./host/pushvia.expect ${MCUHOST} ${PORT:-23}"
   dopush() { ${PUSHCMD} ${2:-`basename $1`} $1; }
   dopushcompile() { ${PUSHCMD} ${2:-`basename $1`} $1 compile; }
 fi
index 504d587936ab0de7e7556fbd430710a93701ea24..708069a8b5a260fb1b4ed1f71458f31c89d998d2 100755 (executable)
@@ -4,16 +4,18 @@ set -e -u
 . ./host/pushcommon.sh
 
 dopushcompile util/diag.lua
+dopushcompile fifo/fifo.lua
+dopushcompile fifo/fifo-diag.lua
 dopushcompile tq/tq.lua
 dopushcompile tq/tq-diag.lua
 dopushcompile net/nwfnet.lua
 dopushcompile net/nwfnet-sntp.lua
 dopushcompile net/nwfnet-go.lua
 dopushcompile net/nwfnet-diag.lua
-dopush        net/conf/nwfnet.conf
-dopush        net/conf/nwfnet.cert
-dopush        net/conf/nwfnet.conf2
-dopushcompile util/fifosock.lua
+#dopush        net/conf/nwfnet.conf
+#dopush        net/conf/nwfnet.cert
+#dopush        net/conf/nwfnet.conf2
+dopushcompile net/fifosock.lua
 dopushcompile telnetd/telnetd.lua
 dopushcompile telnetd/telnetd-file.lua
 dopushcompile telnetd/telnetd-diag.lua
diff --git a/net/fifosock.lua b/net/fifosock.lua
new file mode 100644 (file)
index 0000000..d125894
--- /dev/null
@@ -0,0 +1,26 @@
+-- STATELESS
+--
+-- Wrap a socket object so that it queues sends.  Must call :fini after
+-- done to avoid a memory leak (that I don't understand in full)
+--
+-- Ideally, import this once, wrap all the sockets you need, and then forget
+-- it.  If one needs new sockets periodically, it is unclear to me whether
+-- it's better to load this once and hold it in RAM or to load it every
+-- time.
+return function(fifo,sock)
+  local function dosend(s) sock:send(s) end
+  sock:on("sent", function() fifo:dequeue(dosend) end)
+
+  local nsock = {}
+  function nsock.send(_,s)
+    if s == nil or s == "" then return end
+    fifo:queue(s,dosend)
+  end
+  function nsock.fini(_) sock = nil end
+  local sockit = getmetatable(sock)["__index"]
+  setmetatable(nsock,{ __index = function(_,k)
+    local fn = sockit[k]
+    return function(a,...) if a == nsock then fn(sock,...) else fn(a,...) end end
+  end })
+  return nsock
+end
index ef6c5ffcaa8e1470d0461c1b57303a5f5a8aad13..504367d4711883d2922230578b8e06110ccd04da 100644 (file)
@@ -24,11 +24,11 @@ function self.rx(tx,input,k)
   k(true)
 end
 function self.server(sock_)
-  local sock = (dofile("fifosock.lc")).wrap(sock_)
+  local sock = (dofile("fifosock.lc"))((require "fifo")(), sock_)
   local dosend = function(...) sock:send(...) end
   local k = function(c) if c then sock:send("\n$ ") else sock:close() end end
   sock:on("receive",function(s_,input) self.rx(dosend,input,k) end)
-  sock:on("disconnection",function(s_) tryon("disconn",sock); sock.fini(); sock=nil end)
+  sock:on("disconnection",function(s_) tryon("disconn",sock) ; sock:fini() end)
   tryon("conn",sock)
   sock:send("\n$ ")
 end
diff --git a/test/fifotest.lua b/test/fifotest.lua
new file mode 100644 (file)
index 0000000..01fd784
--- /dev/null
@@ -0,0 +1,84 @@
+fmk = dofile("util/fifo.lua")
+tmk = dofile("tq/tq.lua")
+tdiag = loadfile("tq/tq-diag.lua")()
+
+f = fmk()
+t = tmk()
+
+ttime    = 0
+tfirearm = nil
+t.arm = function(_,fire,when) tfirearm = fire; print("t arm: ", when) end
+t.now = function(_) return ttime end
+function tfire(step)
+  ttime = ttime + step*1000
+  if tfirearm
+   then print("t fire"); tfa = tfirearm; tfirearm = nil; tfa()
+   else print("t fizzle")
+  end
+end
+
+function tqp(w,s) t:queue(w,print,s) end
+function td()
+  tdiag(t,
+    function(...) print("td set",...) end,
+    function(...) print("td elem",...) end)
+end
+
+function deq(n)
+  if f:dequeue(function(e) print("deq", e) ; return n end)
+   then print("deq enqueue"); t:queue(1000,deq,nil)
+  end
+end
+
+f:queue(1)
+f:queue(2)
+f:queue(3)
+f:queue(4)
+
+print("SETUP")
+t:queue(1000,deq,5)
+t:queue(1500,deq,6)
+t:queue(2000,deq,7)
+td()
+print()
+
+print("PREMATURE FIRE")
+tfire(50)
+td()
+print()
+
+print("POSTMATURE FIRE")
+tfire(1000)
+td()
+print()
+
+print("EXACT FIRE 1")
+tfire(450)
+td()
+print()
+
+print("EXACT FIRE 2")
+tfire(500)
+td()
+print()
+
+tfire(50)
+print()
+
+tfire(450)
+print()
+
+tfire(500)
+print()
+
+tfire(50)
+print()
+
+tfire(450)
+print()
+
+tfire(600)
+print()
+
+td()
+print()
diff --git a/test/tqstress.lua b/test/tqstress.lua
new file mode 100644 (file)
index 0000000..4e55a38
--- /dev/null
@@ -0,0 +1,28 @@
+t = dofile("tq/tq.lua")()
+
+tdiag = dofile("tq/tq-diag.lua")
+function td()
+  tdiag(t,
+    function(...) print("td set",...) end,
+    function(...) print("td elem",...) end)
+end
+
+ttime    = 0
+tfirearm = nil
+tfirewhen = nil
+t.arm = function(_,fire,when) tfirearm = fire ; tfirewhen = when end
+t.now = function(_) return ttime end
+function tfire(step)
+  ttime = ttime + step*1000
+  if tfirearm then tfa = tfirearm; tfirearm = nil; tfa() end
+end
+
+ctr = 0
+function rec()
+  ctr = ctr + 1; t:queue(math.random(5),rec)
+end
+rec()
+
+for i = 1, 100000 do tfire(tfirewhen or 1) end
+print(ctr, ttime)
+td()
index 9fda3d8c650a8b2610ab8c477ca57288561bd574..c9ef8ba6e38bc4327ed59f6704413692c7bf1cba 100644 (file)
--- a/tq/tq.lua
+++ b/tq/tq.lua
@@ -1,21 +1,40 @@
 -- DEPENDS: tmr [only by default]
 local fire, doarm
 function fire(self)
-  local cbs = table.remove(self._q,1)
-  if #self._q > 0 then doarm(self, self._q[1]["t"]) end
-  local v
-  for _,v in ipairs(cbs) do v() end
+  local cbt = {}
+  local entryt = self:now()
+  local lapsed = (entryt - self._tst)/1000
+  if #self._q > 0 and lapsed < self._q[1].t then
+    -- premature fire?  adjust and rearm
+    self._q[1].t = self._q[1].t - lapsed
+    doarm(self, self._q[1].t)
+    return
+  end
+  while #self._q > 0 and self._q[1].t <= lapsed do
+    -- collect events in the past into cbt
+    local cbs = table.remove(self._q,1)
+    lapsed = lapsed - cbs.t
+    table.insert(cbt,cbs)
+  end
+  if #self._q > 0 then
+    -- leftover events: credit excess lapsed time and rearm
+    self._q[1].t = self._q[1].t - lapsed
+    doarm(self, self._q[1].t)
+  end
+  -- run all collected callbacks, having adjusted queue
+  local k, cbs, v
+  for k,cbs in ipairs(cbt) do for k,v in ipairs(cbs) do v() end end
 end
 function doarm(self,when) self:arm(function() fire(self) end, when); self._tst = self:now() end
 local function queue(self,when,what,...)
   if #self._q > 0 then
     local lapsed = (self:now() - self._tst)/1000
-    self._q[1]["t"] = self._q[1]["t"] - lapsed
+    self._q[1].t = self._q[1].t - lapsed
   end
   local ix = 0; local tleft = when
   while (ix < #self._q) do
-    if (tleft < self._q[ix+1]["t"]) then break end
-    ix = ix + 1; tleft = tleft - self._q[ix]["t"]
+    if (tleft < self._q[ix+1].t) then break end
+    ix = ix + 1; tleft = tleft - self._q[ix].t
   end
   local warg = {...}; local nwarg = select('#',...)
   local wfn = function () return what(unpack(warg,1,nwarg)) end
@@ -24,7 +43,7 @@ local function queue(self,when,what,...)
   end
   table.insert(self._q,ix+1,{["t"] = tleft, [1] = wfn})
   if ix+1 < #self._q then
-    self._q[ix+2]["t"] = self._q[ix+2]["t"] - tleft
+    self._q[ix+2].t = self._q[ix+2].t - tleft
   end
   return wfn
 end
diff --git a/util/fifosock.lua b/util/fifosock.lua
deleted file mode 100644 (file)
index 0c0f882..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
--- STATELESS
-local fs = {}
-function fs.wrap(sock)
-  local sf = {}
-  local sfe = true
-  local function sfd() if #sf > 0 then sock:send(table.remove(sf,1)) else sfe = true end end
-  sock:on("sent", sfd)
-  local nsock = {}
-  nsock.send = function(k,s)
-    if s == nil or s == "" then return end
-    table.insert(sf,s)
-    if sfe then sfe = false; sfd() end
-  end
-  nsock.fini = function() sf=nil; sock=nil end
-  local sockit = getmetatable(sock)["__index"]
-  setmetatable(nsock,{ __index = function(_,k)
-    local fn = sockit[k]
-    return function(a,...) if a == nsock then fn(sock,...) else fn(a,...) end end
-  end })
-  return nsock
-end
-return fs