Compare commits

...

4 Commits

Author SHA1 Message Date
Daniel Barlow 032d0f8aca add netlink socket
it's not hooked up to anything yet, but it proves we can
do this with lualinux
2024-04-23 23:34:25 +01:00
Daniel Barlow b8ac9e5279 convert devout from minisock to lualinux 2024-04-23 23:33:11 +01:00
Daniel Barlow ff2604ca5d think 2024-04-23 23:30:50 +01:00
Daniel Barlow 72789984ce add lualinux package 2024-04-23 22:41:38 +01:00
5 changed files with 128 additions and 31 deletions

View File

@ -4676,3 +4676,57 @@ needs to filter, but the client will anyway have to do some message
parsing so they can distinguish add from remove
* where do we start?
Sun Apr 21 13:31:48 BST 2024
We have the mechanics of it working (albeit implemented in the
simplest possible terms), we need to glue it to some I/O
1) open a netlink socket and read the events from it
2) "create a PF_UNIX socket of type SOCK_STREAM, and accept connections on it, then each time you accept a connection, you get a new fd"
- accept connection
- read terms from it
- register callback that writes event to connected socket
minisock has no support for "test if fd is ready" or "wait for [fds]
to become ready", either we need poll() or we could add a call for "is
this fd ready to read" and use coroutines. Fork minisock or add as
another library?
[ if we fork minisock we could expose the protocol param to Lua
so we could use it for netlink ]
Tue Apr 23 19:13:45 BST 2024
we could convert from minisock to lualinux. if we can also use that to
get rid of nellie and/or lfs, the size tradeoff is minimal
---
Is there some way we could test the devout event loop?
I can register a fd with a callback
when the fd is ready, my callback is called
when the callback return true it remains registered
when the callback return true it is unregistered and the fd is closed
loop.register
loop.registered?
loop.feed
Tue Apr 23 20:34:03 BST 2024
I think we could make the event loop abstraction leak less?
It's not actually a _loop_, all the actual GOTO 10 happens
outside of it
1) see if we can do netlink in lualinux
2) if so, convert it to lualinux
3) add netlink socket to event loop
4) make it send messages to subscribers
5) package it
6) make inout test use it instead of uevent-watcher
7) write an inout test variant that has the stick inserted
at boot time already

View File

@ -71,6 +71,7 @@ in {
levitate = callPackage ./levitate {};
libubootenv = callPackage ./libubootenv {};
linotify = callPackage ./linotify {};
lualinux = callPackage ./lualinux {};
# we need to build real lzma instead of using xz, because the lzma
# decoder in u-boot doesn't understand streaming lzma archives

View File

@ -6,7 +6,7 @@
, fennel
, stdenv
, fennelrepl
, minisock
, lualinux
}:
stdenv.mkDerivation {
name = "devout";
@ -15,12 +15,12 @@ stdenv.mkDerivation {
installPhase = ''
mkdir -p $out/bin
cp -p ${writeFennel "devout" {
packages = [fennel anoia nellie lua.pkgs.luafilesystem minisock];
packages = [fennel anoia nellie lua.pkgs.luafilesystem lualinux];
mainFunction = "run";
} ./devout.fnl} $out/bin/devout
'';
checkPhase = ''
LUA_CPATH=${minisock}/lib/lua/5.3/?.so\;$LUA_CPATH \
LUA_CPATH=${lualinux}/lib/lua/5.3/?.so\;$LUA_CPATH \
fennelrepl ./test.fnl
'';
doCheck = true;

View File

@ -1,8 +1,8 @@
(local sock (require :minisock))
(local ll (require :lualinux))
(local { : view } (require :fennel))
(fn trace [expr]
(doto expr (print :TRACE (view expr))))
(do (print :TRACE (view expr)) expr))
(fn parse-uevent [s]
(let [at (string.find s "@" 1 true)
@ -50,29 +50,39 @@
:unsubscribe (fn [_ id] (tset subscribers id nil))
}))
;; #define POLLIN 0x0001
;; #define POLLPRI 0x0002
;; #define POLLOUT 0x0004
;; #define POLLERR 0x0008
;; #define POLLHUP 0x0010
;; #define POLLNVAL 0x0020
;; grepped from kernel headers
(local POLLIN 0x0001)
(local POLLPRI 0x0002)
(local POLLOUT 0x0004)
(local POLLERR 0x0008)
(local POLLHUP 0x0010)
(local POLLNVAL 0x0020)
(local AF_LOCAL 1)
(local AF_NETLINK 16)
(local SOCK_STREAM 1)
(local SOCK_DGRAM 2)
(local SOCK_RAW 3)
(local NETLINK_KOBJECT_UEVENT 15)
(fn unix-socket [name]
(let [addr (.. "\1\0" name "\0\0\0\0\0")
(sock err) (sock.bind addr)]
(assert sock err)))
(let [addr (.. "\1\0" name "\0\0\0\0\0")]
(match (ll.socket AF_LOCAL SOCK_STREAM 0)
fd (match (ll.bind fd addr)
0 (doto fd (ll.listen 32))
(nil err) (values nil err))
(nil err) (values nil err))))
(fn pollfds-for [fds]
(table.concat (icollect [_ v (ipairs fds)] (string.pack "iHH" v 1 0))))
(icollect [_ v (ipairs fds)]
(bor (lshift v 32) (lshift 1 16))))
(fn unpack-pollfds [pollfds]
(var i 1)
(let [fds {}]
(while (< i (# pollfds))
(let [(fd _ revents i_) (string.unpack "iHH" pollfds i)]
(if (> revents 0) (tset fds fd revents))
(set i i_)))
fds))
(collect [_ v (ipairs pollfds)]
(let [fd (band (rshift v 32) 0xffffffff)
revent (band v 0xffff)]
(values fd revent))))
(fn parse-terms [str]
(print :terms str)
@ -80,7 +90,7 @@
(string.match n "(.-)=(.+)")))
(fn handle-client [db client]
(match (trace (sock.read client))
(match (ll.read client)
"" (do
(db:unsubscribe client)
false)
@ -88,11 +98,18 @@
(db:subscribe
client
(fn [e]
(sock.write client (view e)))
(ll.write client (view e)))
(parse-terms s))
true)
(nil err) (do (print err) false)))
(fn open-netlink [groups]
(match (ll.socket AF_NETLINK SOCK_RAW NETLINK_KOBJECT_UEVENT)
fd (doto fd (ll.bind (string.pack "I2I2I4I4" ; family pad pid groups
AF_NETLINK 0 0 groups)))
(nil errno) (values nil errno)))
(fn event-loop []
(let [fds {}]
{
@ -101,27 +118,30 @@
(each [fd revent (pairs revents)]
(when (not ((. fds fd) fd))
(tset fds fd nil)
(sock.close fd))))
(ll.close fd))))
:fds #(icollect [fd _ (pairs fds)] fd)
:_tbl #(do fds) ;exposed for tests
}))
(fn run []
(let [[sockname] arg
(let [[sockname nl-groups] arg
s (unix-socket sockname)
db (database)
nl (open-netlink nl-groups)
loop (event-loop)]
(loop:register
s
#(match (sock.accept s)
#(match (ll.accept s)
(client addr)
(do
(loop:register client (partial handle-client db))
true)))
(loop:register
nl
#(do (print :netlink (ll.read nl)) true))
(while true
(let [pollfds (pollfds-for (loop:fds))
(rpollfds numfds) (sock.poll pollfds 1000)]
(when (> numfds 0)
(loop:feed (unpack-pollfds rpollfds)))))))
(let [pollfds (pollfds-for (loop:fds))]
(ll.poll pollfds 5000)
(loop:feed (unpack-pollfds pollfds))))))
{ : database : run : event-loop }

22
pkgs/lualinux/default.nix Normal file
View File

@ -0,0 +1,22 @@
{ lua, lib, fetchFromGitHub }:
let
pname = "lualinux";
src = fetchFromGitHub {
repo = "lualinux";
owner = "philanc";
rev = "1d4c962aad9cbe01c05df741b91e8b39c356362c";
hash = "sha256-+Ys4sERG+TI8nRzG38UP+KqbH0efspaX0j4IHCt56RI=";
};
in lua.pkgs.buildLuaPackage {
inherit pname;
version = "0.1"; # :shrug:
inherit src;
makeFlags = [ "LUADIR=." "lualinux.so" ];
installPhase = ''
mkdir -p "$out/lib/lua/${lua.luaversion}"
cp ${pname}.so "$out/lib/lua/${lua.luaversion}/"
'';
}