Lunatik C API
#include <lunatik.h>
This page is the C API of Lunatik: what it documents is what a binding may use, and a minor release
only adds to it. A lunatik_ or LUNATIK_ name lunatik.h, or a header it includes, defines and
this page leaves out is the core’s own, which the API’s inline functions and macros are built on
and any release may change; those lunatik.h defines itself sit in a section of their own. The
headers under lib/ belong to the bindings beside them and are not part of the API. A binding uses
the Lua C API besides, and builds as
Building out of tree says.
Types
lunatik_class_t
typedef void (*lunatik_release_t)(void *); typedef struct lunatik_class_s { const char *name; const luaL_Reg *methods; lunatik_release_t release; lunatik_opt_t opt; struct module *owner; } lunatik_class_t;
Describes a Lunatik object class.
name: the class’s type name, quoted by type errors and__name.methods:NULL-terminated array of Lua methods registered in the metatable. It carries{"__gc", lunatik_deleteobject}, which drops the reference the userdata holds: without it, the object and its private are never released.{"__close", lunatik_closeobject}and{"close", lunatik_closeobject}release the private before the collector does, throughlunatik_closeprivate.release: called once with the private, at the first oflunatik_closeprivate, which an object’scloseorstopandlunatik_stoprun, and the drop of the last reference; Lunatik then frees the private, unless the class isLUNATIK_OPT_EXTERNAL. It runs on the task that closed the object or dropped that reference, or, when that drop runs in atomic context, on a kernel worker throughlunatik_defer, so a release may sleep. May beNULL.opt: bitmask ofLUNATIK_OPT_*flags controlling class behaviour. Flags are inherited by every instance viaobject->opt = opt | class->opt(seelunatik_newobject). Flags differ in whether they act as constraints or capabilities:LUNATIK_OPT_SOFTIRQ(constraint): all instances useGFP_ATOMICand a spinlock:
spin_lock_bh, orspin_lock_irqsavewhen interrupts are already off; absence means mutex andGFP_KERNEL. Use for classes whose handlers fire in softirq context (netfilter, XDP). Because this flag is always inherited, a SOFTIRQ class can never produce a non-SOFTIRQ instance.
LUNATIK_OPT_HARDIRQ(constraint): likeSOFTIRQ, but alwaysspin_lock_irqsave, whatever
the interrupt state. Required for classes whose handlers can fire inside an interrupt handler or with interrupts off (e.g. kprobes): an interrupt on the CPU that holds a lock taken with interrupts on would spin on it forever.
LUNATIK_OPT_MONITOR(capability): the class supports a monitored metatable that wraps Lua
method calls with the object lock, enabling safe concurrent access from multiple runtimes. Inherited by default but cancelled when an instance is created withLUNATIK_OPT_SINGLE. A metamethod other than__tostring, which reads the object as a method does, and a method namedcloseorstopare left unwrapped: a close or a stop takes the lock itself, aslunatik_closeprivatedoes, and would wait on the one the wrapper holds. The wrapper waits for the lock withlunatik_lockkillable: the stop of a kernel thread, or a fatal signal to any other task, ends the wait and the call raisesEINTR. While the method runs, the calling runtime allocates with the object'sgfpand its collector is stopped, so no finalizer runs under the lock; the wrapper restarts the collector afterwards only if it was running. A call or return hook the calling thread set with debug.sethook is cleared for the method and restored after it, so no hook runs under the lock either: the hook sees the wrapper's call and return, not the method's. A line or count hook, which a method written in C never fires, stays set.
LUNATIK_OPT_SINGLE(constraint): all instances are private and non-shareable by default.
Like SOFTIRQ, this is always inherited and cannot be overridden per instance.
LUNATIK_OPT_EXTERNAL(constraint):object->privateholds an external pointer — Lunatik
will not free it on release.
LUNATIK_OPT_IRQ: the bit bothSOFTIRQandHARDIRQcarry, whichlunatik_isirq(opt)
tests; it is not set alone.
LUNATIK_OPT_PERCPU: marks thepercpuclass, whose private holds one runtime per CPU;
internal to the core.
LUNATIK_OPT_NONE:0, no flag.owner: the module the class’s methods andreleaselive in,THIS_MODULE, as astruct file_operationsnames its own; a class that leaves itNULL, asTHIS_MODULEis in a built-in build, holds nothing. Every object of the class holds a reference to it from its creation to its release, so the module stays loaded while an object is left, in an rcu.table such as_ENVor in a runtime that never required its library. A state thatlunatik_cloneobjectcreates the class’s metatables in holds another until it closes.
lunatik_object_t
typedef struct lunatik_object_s { struct kref kref; const lunatik_class_t *class; void *private; union { struct mutex mutex; spinlock_t spin; }; struct task_struct *owner; lunatik_opt_t opt; gfp_t gfp; unsigned long flags; struct rcu_head rcu; lunatik_defer_t defer; } lunatik_object_t;
A Lunatik object. A binding reads class, private and opt, and gfp through
lunatik_gfp; the other fields are the core’s.
kref: the count of the object’s references,1at its creation, taken and dropped throughlunatik_getobject,lunatik_trygetobjectandlunatik_putobject, whose drop to zero runs the release. It changes atomically, under no lock.- class: the class the object was created with, set at its creation and never changed.
private: the data of the class.lunatik_newobjectandlunatik_createobjectallocate it zeroed, and the binding sets it for aLUNATIK_OPT_EXTERNALclass.lunatik_closeprivateclears it under the object’s lock, soNULLis a closed object, and a method the monitor does not wrap, acloseor the runtime’sstop, reads it under that lock.mutexandspin: the object’s lock, a mutex for a process-context object and a spinlock for aLUNATIK_OPT_SOFTIRQorLUNATIK_OPT_HARDIRQone, taken throughlunatik_lock, set up at the object’s creation and torn down at its release.owner: the task that holds the lock,NULLwhile none does.lunatik_lockwrites it once it holds the lock andlunatik_unlockclears it before letting go;lunatik_isownerreads it without the lock, since only the holder writes it.opt: theLUNATIK_OPT_*flags of the object, its class’s and those it was created with, aslunatik_newobjectcomputes them, set at its creation and never changed.gfp: the flags the object allocates with,GFP_ATOMICfor aLUNATIK_OPT_SOFTIRQorLUNATIK_OPT_HARDIRQobject andGFP_KERNELotherwise, set at its creation. A runtime’s changes aslunatik_gfpsays, written by the code that runs in it.flags: the interrupt statespin_lock_irqsavesaves, whichlunatik_lockwrites once it holds the lock andlunatik_unlockrestores.- rcu: the head the release frees the object through, after a grace period, so a reader that
found it under
rcu_read_lock()can still read its count. defer: the item the release runs on a kernel worker through, when the last reference drops in atomic context, aslunatik_putobjectsays.
lunatik_opt_t
typedef u8 __bitwise lunatik_opt_t;
The type of the LUNATIK_OPT_ flags, of a class’s opt and of an object’s. It is __bitwise, so
sparse (make C=1) warns on a plain integer mixed into it: flags combine with |, and a cast
into the type carries __force, as the LUNATIK_OPT_ definitions do.
lunatik_isirq
bool lunatik_isirq(lunatik_opt_t opt); bool lunatik_ishardirq(lunatik_opt_t opt); bool lunatik_ismonitor(lunatik_opt_t opt); bool lunatik_issingle(lunatik_opt_t opt); bool lunatik_isexternal(lunatik_opt_t opt); bool lunatik_ispercpu(lunatik_opt_t opt);
Test opt, a class’s or an object’s, for a flag: lunatik_isirq holds for LUNATIK_OPT_SOFTIRQ
and LUNATIK_OPT_HARDIRQ alike, through the LUNATIK_OPT_IRQ bit both carry,
lunatik_ishardirq for LUNATIK_OPT_HARDIRQ alone, and each of the others for the flag it names:
lunatik_ispercpu tells the percpu set lunatik_getpercpu returns from a
runtime. Defined as macros.
Runtime
lunatik_runtime
int lunatik_runtime(lunatik_object_t **pruntime, const char *script, lunatik_opt_t opt);
lunatik_runtime() creates a new runtime environment then loads and runs the script
/lib/modules/lua/<script>.lua as the entry point for this environment.
It must only be called from process context.
The runtime environment is a Lunatik object that holds
a Lua state.
Lunatik objects are special
Lua userdata
which also hold
a lock type and
a reference counter.
opt selects the context the runtime environment runs in.
With LUNATIK_OPT_NONE, lunatik_runtime() will use a
mutex
for locking the runtime environment and the
GFP_KERNEL
flag for allocating new memory later on
lunatik_run() calls.
With LUNATIK_OPT_SOFTIRQ or LUNATIK_OPT_HARDIRQ, it will use a
spinlock,
taken with bottom halves off, or with interrupts off for LUNATIK_OPT_HARDIRQ and wherever
interrupts are already off, and
GFP_ATOMIC
once the script has loaded.
lunatik_runtime() opens the Lua standard libraries
present on Lunatik.
A softirq or hardirq runtime opens every one of them but io, and its lunatik library carries
only lunatik.cpu and lunatik._ENV.
If successful, lunatik_runtime() sets the address pointed by pruntime and
Lua’s extra space
with a pointer for the new created runtime environment,
sets the reference counter to 1 and then returns 0.
The script’s first return value stays on the state’s stack, at index 1, below what a handler
pushes.
Otherwise, it returns -ENOMEM, if insufficient memory is available;
or -ENOEXEC, if it fails to load or run the script, and logs the error with pr_err.
Example: lunatik_runtime
-- /lib/modules/lua/mydevice.lua function myread(len, off) return "42" end
static lunatik_object_t *runtime; static int __init mydevice_init(void) { return lunatik_runtime(&runtime, "mydevice", LUNATIK_OPT_NONE); }
lunatik_stop
int lunatik_stop(lunatik_object_t *runtime);
lunatik_stop()
closes
the
Lua state
created for this runtime environment and decrements the
reference counter.
Once the reference counter is decremented to zero, the
lock type
and the memory allocated for the runtime environment are released.
If the runtime environment has been released, it returns 1;
otherwise, it returns 0.
A hook the script registers with the kernel holds a reference of its own,
so it is lunatik_stop(), and not a lunatik_putobject()
of the caller’s reference, that closes a runtime a hook still holds.
Call it from process context and never from the runtime’s own code: from a handler dispatched on
it, the close waits on the lock that task holds, which lunatik_isowner
tells, and from its script body it closes the state that is running. Nor call it under RTNL when
the script may have registered a netdevice notifier, whose release unregisters it and takes RTNL.
A holder in atomic context drops its reference with lunatik_putobject()
instead.
lunatik_copyobjects
int lunatik_copyobjects(lua_State *Lto, lua_State *Lfrom, int ixfrom, int nobjects);
Clones onto Lto, in order, the nobjects Lunatik objects Lfrom holds from ixfrom, which may
be negative to count from Lfrom’s top. It carries objects and nothing else: a value that is not a
Lunatik object fails it with invalid object; an object marked SINGLE with
'<class>': cannot share SINGLE object; a process-context object copied into a softirq or
hardirq runtime with '<class>': process-context class in interrupt-context runtime; and more
objects than Lto’s stack takes with too many objects. On failure it returns the status of the
protected call and leaves the message on
Lto, which the caller pops; on success it returns LUA_OK.
lunatik_run
void lunatik_run(lunatik_object_t *runtime, <inttype> (*handler)(...), <inttype> &ret, ...);
lunatik_run() locks the runtime environment and calls the handler
passing the associated Lua state as the first argument followed by the variadic arguments.
ret is set with -ENXIO, and the handler does not run, when the Lua state has been closed, when
the script body is still running, as it is when a hook armed from the body fires, and, for a
percpu object, when the runtime of this CPU is not published yet; if the calling task already
holds the runtime’s lock, a dispatch from the runtime’s own code, with -EDEADLK, and the handler
does not run either; otherwise, ret is set with the result of handler(L, ...) call.
Around that call it records the stack pointer in the runtime’s cstack, from which Lua’s bound on
nested C calls counts, raising C stack overflow past five eighths of the kernel stack.
Then, it restores the Lua stack and unlocks the runtime environment.
A process runtime is locked with a mutex, so lunatik_run() on it is called from a context that
may sleep.
A percpu object, which the caller keeps referenced across the call, is resolved first to the
runtime of the CPU the caller runs on, and the caller stays on that CPU until the call returns:
with preemption off for a softirq or hardirq set, with migration off for a process one.
It is defined as a macro.
Example: lunatik_run
typedef struct myread_s { char __user *buf; size_t len; loff_t *off; ssize_t ret; } myread_t; static int l_read(lua_State *L) { myread_t *ctx = lua_touserdata(L, 1); size_t llen; const char *lbuf; loff_t off; lua_getglobal(L, "myread"); lua_pushinteger(L, ctx->len); lua_pushinteger(L, *ctx->off); lua_call(L, 2, 2); /* calls myread(len, off) */ lbuf = lua_tolstring(L, -2, &llen); llen = min(ctx->len, llen); off = (loff_t)luaL_optinteger(L, -1, *ctx->off + llen); if (copy_to_user(ctx->buf, lbuf, llen) != 0) { ctx->ret = -EFAULT; return 0; } *ctx->off = off; ctx->ret = (ssize_t)llen; return 0; } static ssize_t mydevice_read(struct file *f, char __user *buf, size_t len, loff_t *off) { ssize_t ret; lunatik_object_t *runtime = (lunatik_object_t *)f->private_data; myread_t ctx = {.buf = buf, .len = len, .off = off}; lunatik_run(runtime, lunatik_catch, ret, l_read, &ctx, "read"); return ret == 0 ? ctx.ret : ret; }
Everything that can raise, the callback, pushing its arguments, reading what it returned and any
allocation, runs inside l_read, under the protected call lunatik_catch makes: a
raise with no handler is a BUG().
lunatik_handle
void lunatik_handle(lunatik_object_t *runtime, <inttype> (*handler)(...), <inttype> &ret, ...);
Runs handler(L, ...) on runtime’s state and restores the stack. Unlike lunatik_run, it
takes no lock, does not resolve a percpu object, does not check that the state is open or
ready, and records no stack pointer: the caller already runs inside the runtime, holding its lock
or in its script body, and passes a plain runtime whose state it knows is open. Defined as a macro.
lunatik_cpcall
int lunatik_cpcall(lua_State *L, lua_CFunction f, void *ud);
Calls the C function f in protected mode with ud as its only argument, a light userdata, as
Lua 5.1’s lua_cpcall did, and returns the status of the
protected call, leaving the error on the
stack when it fails; what f returns is dropped. A handler of lunatik_run whose work can raise passes its
arguments and its result in a context ud points to and does that work in f, as the example of
lunatik_run does through lunatik_catch.
lunatik_catch
int lunatik_catch(lua_State *L, lua_CFunction f, void *ud, const char *name);
Calls f with ud through lunatik_cpcall and returns 0; when f raises, it logs
the error read through lunatik_errmsg followed by name, rate limited and under the
pr_fmt of the file that calls it, and returns -ECANCELED. It is the handler a binding gives
lunatik_run or lunatik_handle for a callback: f pushes the callback’s arguments, calls it and reads
what it returns, taking its input from ud and leaving its result there, and name says which callback
failed, as read does in the example of lunatik_run.
lunatik_opterrno
int lunatik_opterrno(lua_State *L, int ix);
Returns the errno a callback answered with at ix: 0 for nil or none, and the value itself for an
integer from -MAX_ERRNO to 0 outside the kernel’s own block, -ERESTARTSYS to -ENOGRACE, which
include/linux/errno.h keeps from user programs; any other value raises invalid errno, which
lunatik_catch turns into -ECANCELED. A binding whose callback fails an operation
the kernel asked for by returning a negative errno reads that return through it, in the f it gives
lunatik_catch, and hands the result to the kernel.
lunatik_toruntime
lunatik_object_t *lunatik_toruntime(lua_State *L);
Returns the runtime environment referenced by L’s
extra space.
Defined as a macro.
lunatik_getstate
lua_State *lunatik_getstate(lunatik_object_t *runtime);
Returns the Lua state of runtime, NULL once the runtime is closed. Defined as a macro.
lunatik_runtime_class
extern const lunatik_class_t lunatik_runtime_class;
The class of a runtime, lunatik.runtime in type errors. A binding that takes a runtime as an argument
checks it with lunatik_checkobjectclass(L, ix, &lunatik_runtime_class).
lunatik_env
extern lunatik_object_t *lunatik_env;
The rcu.table every runtime shares as lunatik._ENV, through which scripts exchange objects.
lunatik_run.ko, the module that runs the /dev/lunatik driver, creates it when it loads and
clears it when it unloads; it is NULL while that module is not loaded, and a runtime created then
has no lunatik._ENV.
lunatik_isready
bool lunatik_isready(lunatik_object_t *runtime);
Returns true once runtime is armed, its script body returned, and until it is closed.
It reads only the object, so a task that holds a reference calls it without the runtime’s lock.
thread.run uses it to refuse creating a thread from the script body of the runtime that calls
it, with not allowed before the runtime is armed. Defined as a macro.
lunatik_isclosing
bool lunatik_isclosing(lunatik_object_t *runtime);
Returns true while runtime closes and its state runs the script’s finalizers: a stop and a
script that fails to load clear its private before lua_close, and the drop of its last reference
closes it at a zero count, which a runtime has at no other time. Lua arms no __gc on what those
finalizers create. Defined as a macro.
lunatik_isowner
bool lunatik_isowner(lunatik_object_t *object);
Returns true if the calling task holds object’s lock. lunatik_lock records the owner
and lunatik_unlock clears it, so every holder is seen, whichever route it took into the
lock. The read takes no lock: only the holder writes the field, so the only value that can
make the test true is the reader’s own. lunatik_run reads it before it locks and answers
-EDEADLK to a dispatch on the task that holds the lock, and
lunatik_checkowner refuses an entry point that would take the lock
its own task holds; a binding that dispatches without lunatik_run reads it itself.
The answer is exact for a process-context object, whose mutex is task-owned; a SOFTIRQ or
HARDIRQ class takes a spinlock, owned by a CPU and not by a task, and records whichever task
the softirq or hardirq interrupted. It answers about the object it is given: a percpu set’s own
lock, which no dispatch takes, so lunatik_run reads it on the runtime of the CPU it resolves
and percpu:stop() asks each runtime of the set in turn. And it sees the calling task
only — Lua that blocks under the lock on a second task which then reaches the same lock is a
cycle no owner check can name. The entries a script reaches, the monitor, stop, resume and
thread.run, take a runtime’s lock with lunatik_lockkillable, so the stop of a kernel thread
in that cycle, or a fatal signal to another task in it, ends its wait; a dispatch through
lunatik_run is not one of them and waits for the lock regardless.
lunatik_isrtnl
bool lunatik_isrtnl(void); void lunatik_setrtnl(struct task_struct *task); extern struct task_struct *lunatik_rtnl;
lunatik_isrtnl returns true if the calling task is dispatching a callback under RTNL. A binding
whose kernel callback runs with RTNL held, as notifier.netdevice’s does, sets the task with
lunatik_setrtnl(current) before it runs Lua there, and after it writes back the task
lunatik_rtnl held before, read with READ_ONCE(lunatik_rtnl), so a dispatch nested in another on
the same task leaves the outer one’s in place.
RTNL is held by one task at a time, so one pointer serves every runtime and every coroutine, and
the read takes no lock: only the task that wrote the pointer can find itself there. Use it before a
kernel call that takes RTNL, such as register_netdevice_notifier, which would wait on the lock its
own task holds: lunatik_checkarmed refuses every call that may sleep there. It sees the calling
task only, which is what a softirq runtime leaves to see: nothing that holds its lock sleeps, so no
second task waits for RTNL under it. Defined as macros.
lunatik_iskthread
bool lunatik_iskthread(void);
Returns true if the calling task is a kernel thread, one thread.run or the kernel started, and
not a task that entered from userspace, a device file operation’s or the CLI’s. What ends a wait
differs by the answer: a kernel thread is stopped, which sets the flag an interruptible wait reads
and no fatal signal, so lunatik_lockkillable waits interruptibly there and killably elsewhere,
and thread.shouldstop asks kthread_should_stop only there. Defined as a macro.
lunatik_checkcontext
void lunatik_checkcontext(lua_State *L, const char *name, lunatik_opt_t opt);
Raises runtime context mismatch: <name> needs <context> if the context of L’s runtime does not
match opt, where name names what needs the context, the class whose constructor or method calls
it, and <context> is process, softirq or hardirq, as opt says. Context is determined by
the SOFTIRQ/HARDIRQ bits: a SOFTIRQ class must run in a softirq runtime, a HARDIRQ class in a
hardirq runtime, and a process-context class in a process runtime. Use it alone in an entry point
that needs the context and registers nothing, which a finalizer may then call as the runtime
closes.
lunatik_checkruntime
lunatik_object_t *lunatik_checkruntime(lua_State *L, const char *name, lunatik_opt_t opt);
Returns the runtime associated with L after
lunatik_checkcontext and then
lunatik_checkclosing pass for it. A binding’s constructor calls it to
enforce that a class is only instantiated in a compatible runtime, and that a finalizer that runs
as the runtime closes registers nothing the runtime would dispatch.
lunatik_optcontext
lunatik_opt_t lunatik_optcontext(lua_State *L, int ix);
Reads the context name at ix, "process", the default, "softirq" or "hardirq", and returns
LUNATIK_OPT_NONE, LUNATIK_OPT_SOFTIRQ or LUNATIK_OPT_HARDIRQ. Raises
invalid option '<name>' for any other string, as luaL_checkoption does.
lunatik_checkclass
void lunatik_checkclass(lua_State *L, const lunatik_class_t *class);
Raises '<name>': process-context class in interrupt-context runtime when L’s runtime is a
softirq or hardirq one and class->opt carries neither LUNATIK_OPT_SOFTIRQ nor
LUNATIK_OPT_HARDIRQ: an object whose lock is a mutex cannot live there.
lunatik_cannotsleep
bool lunatik_cannotsleep(lua_State *L, bool s);
Returns true when s holds and L’s runtime is a softirq or hardirq one. An entry point that
would sleep when s holds tests it and refuses rather than deadlocking the machine:
lunatik_checkarmed passes lunatik_isready as s. Defined as a macro.
lunatik_checkarmed
void lunatik_checkarmed(lua_State *L);
Raises a Lua error, "not allowed once the runtime is armed", when L belongs to an
interrupt-context runtime whose script body returned. An IRQ runtime is process context only while
its script body runs, so a call that may sleep is allowed there and must be refused afterwards,
when the runtime lock is a spinlock: from a hook or a handler, and from the resume of such a
runtime. Use it in an entry point that reaches a sleeping kernel call, where lunatik_checkruntime
answers the different question of whether the class matches the runtime at all. It calls
lunatik_checkrtnl first, so the same entry point refuses under RTNL in any
runtime, the replay a netdevice registration delivers in a script body that has not armed yet
included.
lunatik_checkclosing
void lunatik_checkclosing(lua_State *L);
Raises a Lua error, "not allowed while the runtime closes", when
lunatik_isclosing holds for L’s runtime: from a finalizer its close
runs, in whatever coroutine. A registration made there would hold a runtime that never dispatches
again: use it in an entry point that registers one without
lunatik_checkruntime, which runs it.
lunatik_checkrtnl
void lunatik_checkrtnl(lua_State *L);
Raises a Lua error, "not allowed under RTNL", when lunatik_isrtnl holds: from
a callback dispatched under RTNL, in whatever runtime or coroutine the calling task runs.
lunatik_checkarmed calls it, so every entry point that may sleep refuses there.
lunatik_checkowner
void lunatik_checkowner(lua_State *L, lunatik_object_t *runtime);
Raises a Lua error, "not allowed from the runtime itself", when lunatik_isowner
holds for runtime: the calling task is inside it, a callback, a file operation, a thread body or a
resumed body, and an entry point that takes its lock would wait on itself. runtime:stop() and
percpu:stop() use it, since the close locks the runtime it closes; so do a monitored method,
which locks the object it runs on and is runtime:resume()’s route into the lock, percpu:resume(),
which locks each runtime it resumes, and thread.run, which passes the body’s arguments under the
runtime’s lock.
lunatik_checkirqs
void lunatik_checkirqs(lua_State *L);
Raises a Lua error, "not allowed with IRQs disabled", when the calling CPU runs with interrupts
off: in every callback of a hardirq runtime, a probe’s handlers among them, and in a softirq
runtime’s callback reached with them already off. A lock the kernel only takes with interrupts off,
a task’s siglock among them, may then be held by the CPU itself, so an entry point whose kernel call
takes one refuses there, as signal.kill does. It reads irqs_disabled() rather than the runtime’s
context, which says how its lock is taken and not the state of the CPU it runs on.
lunatik_checkhardirq
void lunatik_checkhardirq(lua_State *L);
Raises a Lua error, "not allowed in a hardirq runtime", when L’s runtime is a hardirq one. A
constructor whose object no callback of such a runtime can use calls it, as netlink.channel.new
does, whose send re-enables bottom halves where an nlmon tap is up. It reads the runtime’s context
rather than the CPU’s state, so the refusal comes from the script body, which runs with interrupts on.
lunatik_percpudata
lunatik_object_t *lunatik_percpudata(lua_State *L, const lunatik_class_t *class, size_t size);
Returns the object of class a percpu object holds for its runtimes: the first runtime to ask
creates it, as lunatik_createobject(class, size, LUNATIK_OPT_NONE) does, with its private zeroed;
the following ones get the same object, so every runtime sees one. The percpu object owns it:
percpu:stop() closes it (lunatik_closeprivate, which runs the class’s release in process
context) before closing the runtimes, then drops it, and an object with such data outstanding is
released by stop, never by collection. A registration a script makes once for all its runtimes,
a netfilter hook, say, lives in the private of such an object, with the class’s release
unregistering it. Only the script body may ask, while the runtime loads: afterwards it raises
not allowed once the runtime is armed. It raises not enough memory too. Returns NULL on a
plain runtime, which has no runtimes to share with;
lunatik_getpercpu tells the two apart.
LUNATIK_PERCPUDATA (macro)
#define LUNATIK_PERCPUDATA(prefix, cname, T, free)
Defines static const lunatik_class_t prefix_class, named cname, for the data a percpu object
holds for the registrations its runtimes share, as lunatik_percpudata
creates it: a private that is a struct hlist_head of T entries linked through their
struct hlist_node node, whose release, prefix_release, unlinks every entry and passes it to
free. For example,
LUNATIK_PERCPUDATA(luaprobe_kprobes, "probe.kprobes", luaprobe_t, luaprobe_disarm)
defines luaprobe_kprobes_class.
lunatik_getpercpu
lunatik_object_t *lunatik_getpercpu(lua_State *L);
Returns the percpu object owning the runtime of L, or NULL on a plain runtime. Defined as a
macro.
lunatik_getcpu
#define LUNATIK_CPU_NONE (-1) int lunatik_getcpu(lua_State *L); bool lunatik_hascpu(lua_State *L);
lunatik_getcpu returns the CPU id the runtime of L serves in its percpu set, and
LUNATIK_CPU_NONE on a plain runtime; lunatik_hascpu tells the two apart. Defined as macros.
lunatik_checkpercpu
void lunatik_checkpercpu(lua_State *L);
Raises not allowed in a percpu runtime when L’s runtime belongs to a percpu set. A
constructor whose registration cannot be shared by the set calls it.
Object Lifecycle
lunatik_newobject
lunatik_object_t *lunatik_newobject(lua_State *L, const lunatik_class_t *class, size_t size, lunatik_opt_t opt);
lunatik_newobject() allocates a new Lunatik object and pushes a userdata containing a pointer to the object onto the Lua stack.
object->opt is computed as opt | class->opt: all class flags are inherited by the instance.
opt may add flags on top (e.g. LUNATIK_OPT_SOFTIRQ or LUNATIK_OPT_HARDIRQ for a non-sleepable runtime instance).
LUNATIK_OPT_MONITORwraps method calls with the object lock only for a class whoseoptcarries it, where it is already inherited: the monitored metatable is registered only for such a class, so for any other classlunatik_newobjectandlunatik_cloneobjectraise'<name>': metatable not found.- Pass
LUNATIK_OPT_SINGLEfor a private, non-shareable instance. The object cannot be cloned or passed to another runtime via_ENVorresume.SINGLEcancelsMONITORinheritance: aSINGLEinstance of aMONITORclass does not get monitor wrappers, since non-shared objects do not need them. - Pass
LUNATIK_OPT_NONE(0) to inherit only the class flags.
It allocates size bytes for the object’s private data, unless LUNATIK_OPT_EXTERNAL is set in
class->opt, in which case object->private is expected to be set by the caller. The private is
zeroed and comes from the runtime’s allocator, GFP_ATOMIC in a softirq or hardirq runtime once
it is armed; it is freed with kvfree after release.
The userdata’s __gc drops the reference the object is created with. In a state that is closing,
where Lua arms no __gc (see lunatik_isclosing), the state holds that
reference instead and drops it once lua_close has run every finalizer.
Raises '<name>': process-context class in interrupt-context runtime; '<name>': metatable not
found when the class’s metatables are not in this state’s registry, which
lunatik_require creates beforehand; and not enough memory.
lunatik_createobject
lunatik_object_t *lunatik_createobject(const lunatik_class_t *class, size_t size, lunatik_opt_t opt);
lunatik_createobject() creates a Lunatik object independently of any Lua
state. This is intended for objects created in C that will be shared
with Lua runtimes later via lunatik_cloneobject.
Like lunatik_newobject, object->opt is computed as opt | class->opt.
It allocates with GFP_ATOMIC when opt | class->opt carries LUNATIK_OPT_SOFTIRQ or
LUNATIK_OPT_HARDIRQ, and with GFP_KERNEL otherwise, so a process-context object is created
only where the caller may sleep. The private is size zeroed bytes; the call is not for a
LUNATIK_OPT_EXTERNAL class, whose private it would allocate and never free.
Returns a pointer to the lunatik_object_t on success, or NULL if memory allocation fails.
lunatik_require
void lunatik_require(lua_State *L, const lunatik_class_t *class); void lunatik_newclasses(lua_State *L, const lunatik_class_t **classes);
Creates the class’s metatables in the registry of L from its methods, the monitored one too
for a LUNATIK_OPT_MONITOR class, unless L has them already. It opens no library and adds no
package.loaded entry. A function that creates an object of its class in a state whose script
may not have required the library calls it before lunatik_newobject, as
luadata_new does. lunatik_newclasses requires each class of a NULL-terminated array, as the
opener LUNATIK_NEWLIB defines does, and an opener written by hand calls it.
Raises not enough memory.
lunatik_cloneobject
void lunatik_cloneobject(lua_State *L, lunatik_object_t *object);
lunatik_cloneobject() pushes object onto the Lua stack as a userdata with the correct
metatable, and takes no reference: the userdata’s __gc drops one, which the caller hands over
or takes, as lunatik_pushobject does; in a closing state the state drops
it instead, as lunatik_newobject describes. It calls
lunatik_require first, so the object reaches a state whose script never
required its library; where that creates the metatables, L holds the class’s owner until it
closes, as require holds the module of a library it opens.
Raises '<name>': cannot share SINGLE object for a LUNATIK_OPT_SINGLE object,
'<name>': process-context class in interrupt-context runtime, '<name>': metatable not found
for a LUNATIK_OPT_MONITOR object of a class that does not carry the flag, and not enough
memory; so it runs under a protected call.
lunatik_pushobject
void lunatik_pushobject(lua_State *L, lunatik_object_t *object);
Clones object onto L, as lunatik_cloneobject does, and then takes
the reference the new userdata’s __gc drops, so the caller keeps its own. It raises what
lunatik_cloneobject raises, before the reference is taken.
Use together with lunatik_createobject for C-owned objects that must be passed to Lua:
static int l_share(lua_State *L) { lunatik_object_t *obj = (lunatik_object_t *)lua_touserdata(L, 1); lunatik_pushobject(L, obj); lua_setglobal(L, "foo"); return 0; } static int p_share(lua_State *L, lunatik_object_t *obj) { return lunatik_cpcall(L, l_share, obj); } obj = lunatik_createobject(&luafoo_class, sizeof(foo_t), LUNATIK_OPT_NONE); lunatik_run(runtime, p_share, ret, obj);
The push runs in l_share, under the protected call, and stores the object before l_share
returns, since lunatik_cpcall drops what it returns.
lunatik_getobject
void lunatik_getobject(lunatik_object_t *object);
Increments the reference counter of object.
lunatik_trygetobject
bool lunatik_trygetobject(lunatik_object_t *object);
Takes a reference on an object found under rcu_read_lock() without one held, as an
rcu.table entry hands its readers, and returns true; returns false, taking none, when the
count is zero: the object is being released, and the reader treats it as absent. The object’s
memory outlives the grace period after its release, which is what lets the count be read there.
lunatik_getobject is for a holder of a reference.
lunatik_putobject
int lunatik_putobject(lunatik_object_t *object);
Decrements the reference counter of object.
Returns 1 when it dropped the last reference, and 0 otherwise. The release runs at once, on the
calling task, unless lunatik_isatomic holds there: it then runs on a kernel
worker, through the object’s defer. The object’s memory is freed after an RCU grace period once
the release has run.
lunatik_defer
typedef struct lunatik_defer_s { struct irq_work irq; struct work_struct work; } lunatik_defer_t; void lunatik_initdefer(lunatik_defer_t *defer, work_func_t func); bool lunatik_defer(lunatik_defer_t *defer);
Runs func on a kernel worker, in process context, for a caller that cannot: one in softirq or
hardirq context, with bottom halves or interrupts off, or in a probe handler on code the scheduler
runs under its runqueue lock. lunatik_defer queues irq, an irq_work the CPU raises on itself
without a lock, whose handler queues work on the core’s
workqueue, unbound, allocated when lunatik
loads and drained when it unloads: queuing work directly wakes a kworker, and the wakeup takes the
runqueue lock. It may be called from any context and returns false when the item was already
queued.
The item lives in what defers, so deferring allocates nothing: lunatik_initdefer sets it up before
the first lunatik_defer, and func finds what defers through container_of on work. Calls made
before func starts run it once, and one made while it runs runs it again after it returns, so what
each call hands func goes on a list func drains. A func that frees the item calls
irq_work_sync on irq first, since the first hop still writes it after queuing work. Both are
macros, and lunatik_initdefer gives each call site a lockdep class of its own, as INIT_WORK does.
lunatik_isatomic
bool lunatik_isatomic(void);
Returns true when the calling task runs in softirq or hardirq context, or with bottom halves or
interrupts off, as under every lock of a softirq or hardirq object: irq_count() || irqs_disabled().
A plain spinlock or preempt_disable() in process context, which no lock of the core takes, does not
count. Defined as a macro.
lunatik_closeobject
int lunatik_closeobject(lua_State *L); int lunatik_deleteobject(lua_State *L);
Methods for a class’s methods table. lunatik_closeobject, for close and __close, closes
the object at index 1 through lunatik_closeprivate; its userdata
stays, holding its reference. lunatik_deleteobject, for __gc, drops the reference the
userdata holds and releases the object when it was the last. Both raise invalid object when
index 1 holds no Lunatik object, and lunatik_closeobject raises object of another class when
the object’s own __close is not lunatik_closeobject.
Object Access
lunatik_checkobject
lunatik_object_t *lunatik_checkobject(lua_State *L, int i);
Returns the Lunatik object at stack position i. Raises a Lua error if the value is not a
Lunatik object. Defined as a macro.
lunatik_toobject
lunatik_object_t *lunatik_toobject(lua_State *L, int i);
Returns the pointer stored in the userdata at stack position i, without any check. The value
must be a Lunatik object’s userdata: a value that is no userdata dereferences NULL, and any
other userdata returns whatever its first word holds. Use lunatik_checkobject, or
lunatik_getregistryobject for a value read from the registry.
Defined as a macro.
lunatik_checkshareable
lunatik_object_t *lunatik_checkshareable(lua_State *L, int ix);
Returns the Lunatik object at ix, as lunatik_checkobject does, and raises
cannot share SINGLE object when it is LUNATIK_OPT_SINGLE: for a value about to be handed to
another runtime.
LUNATIK_PRIVATECHECKER
#define LUNATIK_PRIVATECHECKER(checker, T, cls, ...) #define LUNATIK_PRIVATECHECKERS(checker, T, tname, ...)
Generates a static inline function T checker(lua_State *L, int ix) that returns
object->private cast to T, after proving three things about the value at ix, each with a
Lua error: it is a Lunatik object (lunatik_checkobject), it is of the class cls, whose
name the type error quotes, and its private is set, which rules out a closed object. The
second form is for a family of classes sharing one checker: ... lists the classes it accepts,
and tname is the name the type error quotes. The first form’s optional ... are further
validation statements, run with L, ix, object and private in scope, before return
private.
lunatik_argcheckclass
void lunatik_argcheckclass(lua_State *L, int ix, lunatik_object_t *object, const lunatik_class_t *cls);
Raises a type error naming cls->name unless object, the Lunatik object at ix, is of that
class. Defined as a macro.
lunatik_checkobjectclass
lunatik_object_t *lunatik_checkobjectclass(lua_State *L, int ix, const lunatik_class_t *cls);
Returns the Lunatik object at ix after proving it is one and is of the class cls, raising a
Lua error otherwise: the checkers above, for a method that needs the object itself, not only its
private.
Locking
lunatik_lock
void lunatik_lock(lunatik_object_t *object); void lunatik_unlock(lunatik_object_t *object);
Take and release object’s lock: a mutex for a process-context object; for a SOFTIRQ or HARDIRQ
one, a spinlock, taken with spin_lock_irqsave for HARDIRQ or where interrupts are already off,
and with spin_lock_bh otherwise. lunatik_lock records the calling task as the owner and
lunatik_unlock clears it, which is what lunatik_isowner reads. A raise
between the two skips the unlock, so what runs under the lock and can raise runs in a protected
call, as the example of lunatik_run does through lunatik_cpcall. A process-context object is
locked only where the caller may sleep.
lunatik_lockkillable
int lunatik_lockkillable(lunatik_object_t *object);
Like lunatik_lock, but the wait for a process-context object’s mutex ends early, returning
-EINTR without the lock: on a kernel thread, on its stop, since the wait is interruptible there;
on any other task, on a fatal signal. A SOFTIRQ or HARDIRQ object is locked as lunatik_lock
does, and it returns 0. The entries a script reaches take a runtime’s lock through it, and
lunatik_try raises the EINTR.
lunatik_closeprivate
void lunatik_closeprivate(lunatik_object_t *object);
Takes object’s lock, detaches its private (object->private = NULL) and unlocks; then, outside
the lock, runs the class’s release on the private and frees it, unless the class is
LUNATIK_OPT_EXTERNAL. It is how a close or a stop ends an object before its last reference
goes: the userdata stays, and a checker from
LUNATIK_PRIVATECHECKER refuses it. A second call finds no private
and does nothing. It takes the lock, so it is not called under it: a method the monitor wraps
holds it, which is why a close is left unwrapped.
Registry and Attach/Detach
The registry pattern keeps pre-allocated objects alive across lunatik_run calls without
exposing them to the GC:
/* registration, once, at hook setup */ lunatik_attach(L, obj, field, luafoo_attach, opt); /* use, on each callback */ lunatik_object_t *o = lunatik_getregistryobject(L, obj->field); if (o != NULL) luafoo_reset(o, ...); lua_pop(L, 1); /* teardown, on unregister */ lunatik_detach(runtime, obj, field);
lunatik_register
void lunatik_register(lua_State *L, int ix, const void *key);
Stores the value at stack index ix in LUA_REGISTRYINDEX at key and leaves the stack as it
found it. key is an address the caller owns for the life of the entry: an object’s private, or
a static const char the binding declares for a slot of its own.
lunatik_unregister
void lunatik_unregister(lua_State *L, const void *key);
Removes the value stored in LUA_REGISTRYINDEX at key.
lunatik_registerobject
void lunatik_registerobject(lua_State *L, int ix, lunatik_object_t *object);
Stores the value at ix, typically the options table holding the callback, under the key
object->private, where a handler reads it with lunatik_getregistry(L, private), and the
userdata on top of the stack, which must be object’s, under the key object, keeping it from
collection until lunatik_unregisterobject. Call it with the object’s userdata on top, as right
after lunatik_newobject.
lunatik_unregisterobject
void lunatik_unregisterobject(lua_State *L, lunatik_object_t *object);
Clears the registry entries keyed by object->private and by object, so the userdata may be
collected.
lunatik_stopobject
void lunatik_stopobject(lua_State *L, lunatik_object_t *object);
Stops an object lunatik_registerobject anchored: clears its registry entries, as
lunatik_unregisterobject does, and closes its private through
lunatik_closeprivate. An object already stopped, whose private is
NULL, is left as it is, so a stop built on it is idempotent.
lunatik_getregistry
int lunatik_getregistry(lua_State *L, const void *key);
Pushes the value stored in LUA_REGISTRYINDEX at key onto the Lua stack and returns
its type. Defined as a macro wrapping lua_rawgetp.
lunatik_getregistryobject
lunatik_object_t *lunatik_getregistryobject(lua_State *L, const void *key);
Pushes the value stored in LUA_REGISTRYINDEX at key and returns it as a Lunatik object, or
NULL when there is none or it is no Lunatik object: a hook that reaches for the object it
registered (an skb, a handle) reads it through this rather than through lunatik_toobject,
which does not check.
lunatik_setflag
void lunatik_setflag(lua_State *L, const void *key, bool on);
Stores on in LUA_REGISTRYINDEX at key, where a binding keeps a fact its own dispatcher sets
and its own code reads, such as a callback of this state being on the stack. The key is the
binding’s own static const char, so one binding’s callback does not answer for another’s, and the
registry is one per state, so every coroutine of it reads the same slot. A dispatcher that sets the
flag outside a protected call seeds the key in its constructor, with lunatik_seedflag.
lunatik_getflag
bool lunatik_getflag(lua_State *L, const void *key);
Returns the flag stored at key, false where nothing is stored, and leaves the stack as it found
it.
lunatik_seedflag
void lunatik_seedflag(lua_State *L, const void *key);
Writes the flag back to itself, so the registry node exists without what it says changing and the writes made at that key afterwards cannot insert. It is the write that can insert, rehash, fail to allocate and abort the state, so a constructor calls it, where a protected call is on the stack. It preserves the value because a constructor reached from inside the callback must leave the flag set.
lunatik_attach
void lunatik_attach(lua_State *L, obj, field, new_fn, ...);
Creates a new object by calling new_fn(L, ...), stores it in LUA_REGISTRYINDEX keyed by
the returned pointer, sets obj->field to the result, and pops the userdata from the stack.
Defined as a macro.
lunatik_detach
void lunatik_detach(lunatik_object_t *runtime, obj, field);
Unregisters obj->field from the registry and sets obj->field = NULL. Safe to call when
the Lua state may already be closed (e.g., from release after lunatik_stop). Defined as a macro.
Error Handling
lunatik_throw
void lunatik_throw(lua_State *L, int ret);
Pushes the name of the errno ret through lunatik_pusherrname and
raises it with lua_error: lunatik_throw(L, -ENOMEM) raises "ENOMEM". Used to convert
negative kernel error codes into Lua errors.
lunatik_unsupported
int lunatik_unsupported(lua_State *L);
A lua_CFunction that raises EOPNOTSUPP through lunatik_throw: the entry a
binding registers in place of one the kernel it is built for lacks, so the name stays in the module
and a script that calls it learns why.
lunatik_pushfail
int lunatik_pushfail(lua_State *L, int ret);
Pushes nil and the name of the errno ret, and returns 2, so a method answers an expected outcome
with return lunatik_pushfail(L, ret): the value counterpart of lunatik_throw,
for the “there is none” a method answers rather than raises, as socket:receive answers
nil, "EAGAIN" for a wait that ended with nothing to read.
lunatik_pusherrname
void lunatik_pusherrname(lua_State *L, int err);
Pushes the name of the errno err, of either sign, as a string, "EINVAL" for -EINVAL, say,
and "unknown" for a value with no name. The tree passes it negative, as the kernel returns it.
lunatik_try
void lunatik_try(lua_State *L, op, ...);
Calls op(...). If the return value is negative, calls lunatik_throw. Defined as a macro.
lunatik_tryret
void lunatik_tryret(lua_State *L, ret, op, ...);
Like lunatik_try, but stores the return value in ret before checking. Defined as a macro.
lunatik_errmsg
const char *lunatik_errmsg(lua_State *L);
Returns the error on top of the stack of L when it is a string, and "error object is not a string"
for any other value, never NULL. It does not convert a number: lua_tostring converts one in
place, which allocates, and an allocation that fails outside a protected call raises with no
handler, a BUG(). After a protected call or a resume fails, the error is read through it.
LUNATIK_ERR_CLOSED
#define LUNATIK_ERR_CLOSED "closed object" #define LUNATIK_ERR_SINGLE "cannot share SINGLE object" #define LUNATIK_ERR_METATABLE "metatable not found" #define LUNATIK_ERR_CONTEXT "process-context class in interrupt-context runtime" #define LUNATIK_ERR_RUNTIME "runtime context mismatch" #define LUNATIK_ERR_ARMED "not allowed once the runtime is armed" #define LUNATIK_ERR_UNARMED "not allowed before the runtime is armed" #define LUNATIK_ERR_RTNL "not allowed under RTNL" #define LUNATIK_ERR_OWNER "not allowed from the runtime itself" #define LUNATIK_ERR_CLOSING "not allowed while the runtime closes" #define LUNATIK_ERR_IRQS "not allowed with IRQs disabled" #define LUNATIK_ERR_HARDIRQ "not allowed in a hardirq runtime" #define LUNATIK_ERR_PERCPU "not allowed in a percpu runtime"
The messages of the refusals this page documents. A binding that refuses one of their conditions on
its own raises the same message through them, as thread.run raises LUNATIK_ERR_UNARMED from a
script body, so a script reads one message for one condition.
Table Fields
These read fields from a Lua table at stack index idx.
lunatik_checkfield
void lunatik_checkfield(lua_State *L, int idx, const char *field, int type);
Pushes the field named field of the table at idx and raises
bad field '<field>' (<type> expected, got <type>) when its Lua type differs from the one given.
The field stays on the stack for the caller to read and pop.
lunatik_optfield
bool lunatik_optfield(lua_State *L, int idx, const char *field, int type);
Pushes the field named field of the table at idx and returns true when it holds the Lua type
given and false when it is nil or absent; any other type raises
bad field '<field>' (<type> expected, got <type>). The field stays on the stack for the caller to
read and pop.
lunatik_checkfieldinteger
lua_Integer lunatik_checkfieldinteger(lua_State *L, const char *field, lua_Integer min, lua_Integer max);
Returns the integer on top of the stack, the field named field that
lunatik_checkfield or lunatik_optfield pushed as a
number, and raises bad field '<field>' (out of bounds) unless min <= value <= max. A binding
bounds with it a field it stores narrower than lua_Integer, which would otherwise keep the low
bits of a number past its range.
lunatik_optcfunction
void lunatik_optcfunction(lua_State *L, int idx, const char *field, lua_CFunction default_func); int lunatik_nop(lua_State *L);
Pushes the field named field of the table at idx when it is a function, and default_func
otherwise. lunatik_nop returns nothing, the default a binding passes for an optional callback.
lunatik_checkcallbacks
void lunatik_checkcallbacks(lua_State *L, int idx, const char *const *fields);
Raises bad field '<field>' (function expected, got <type>) for each name of the NULL-terminated
fields the table at idx holds as something other than a function or nil. A constructor runs it
over the optional callbacks it documents before it acquires anything, so a callback written as a
value it would ignore at dispatch is refused where the script gave it.
lunatik_setinteger
void lunatik_setinteger(lua_State *L, int idx, hook, field, min, max);
Reads a required integer field named field from the table at idx into hook->field.
Raises a Lua error if the field is missing or not a number, and
bad field '<field>' (out of bounds) unless min <= value <= max, through
lunatik_checkfieldinteger.
lunatik_optinteger
void lunatik_optinteger(lua_State *L, int idx, priv, field, min, max, opt);
Reads an optional integer field named field from the table at idx into priv->field,
through lunatik_optfield. Falls back to opt when the field is nil or
absent, and raises bad field '<field>' (number expected, got <type>) when it holds anything
other than a number, a numeric string included, and bad field '<field>' (out of bounds) unless
min <= value <= max, through lunatik_checkfieldinteger.
lunatik_setstring
void lunatik_setstring(lua_State *L, int idx, hook, field, maxlen);
Reads a required string field named field from the table at idx into hook->field,
a buffer of maxlen bytes holding the string and its terminator. Raises a Lua error if
the field is missing, is not a string, or is too long.
Values
lunatik_checkbounds
void lunatik_checkbounds(lua_State *L, int idx, val, min, max); lua_Integer lunatik_checkinteger(lua_State *L, int idx, lua_Integer min, lua_Integer max);
lunatik_checkbounds raises out of bounds, as an error of the argument at idx, unless
min <= val <= max; it is a macro, so val is any integer the caller computed from the argument.
lunatik_checkinteger reads the integer argument at idx with luaL_checkinteger, bounds it the
same way and returns it. A size, a length or a count that arrives from Lua is bounded with them
for what the binding can serve, and an integer that names a kernel identity, a pid, before the
cast to the kernel’s type.
lunatik_opttimeout
long lunatik_opttimeout(lua_State *L, int idx);
Reads the timeout a script hands a wait at idx, in milliseconds, and returns it in jiffies:
MAX_SCHEDULE_TIMEOUT for nil or none, a wait with no bound, and an integer from 0 to INT_MAX
converted by msecs_to_jiffies, whose unsigned int would keep the low bits of a larger one and
read a negative one as forever; any other integer raises out of bounds.
lunatik_pushexternalstring
const char *lunatik_pushexternalstring(lua_State *L, char *s, size_t len);
Pushes the len bytes at s as a Lua string without copying them: s is a buffer of len + 1
bytes from lunatik_malloc, whose last byte it sets to '\0', and Lua owns
it from the call on, freeing it with the state’s allocator, also when the push raises
not enough memory. Returns the string’s contents.
lunatik_pushoptinteger
void lunatik_pushoptinteger(lua_State *L, cond, val);
Pushes the integer val when cond holds, and nil otherwise; val is evaluated only when
cond holds, so it may read through what cond tests. Defined as a macro.
lunatik_value_t
typedef struct lunatik_value_s { int type; union { int boolean; lua_Integer integer; lunatik_object_t *object; }; } lunatik_value_t; void lunatik_checkvalue(lua_State *L, int ix, lunatik_value_t *value); void lunatik_pushvalue(lua_State *L, lunatik_value_t *value); bool lunatik_isuserdata(lunatik_value_t *value);
A Lua value that can cross runtimes: nil, a boolean, an integer, or a Lunatik object, as an
rcu.table stores it. lunatik_checkvalue reads the value at ix into value, taking no
reference on an object, and raises unsupported type for any other type and
cannot share SINGLE object for a LUNATIK_OPT_SINGLE object. lunatik_pushvalue pushes
value, handing the reference the caller holds on its object to the new userdata; when the push
raises, it drops that reference first. lunatik_isuserdata tells a value that holds an object, and
is a macro.
Module Definition
LUNATIK_OPENER
#define LUNATIK_OPENER(libname)
Declares int luaopen_<libname>(lua_State *L), the opener
LUNATIK_NEWLIB defines, for code that names it ahead of its definition; with
a body, it defines an opener written by hand, whose declaration is LUNATIK_OPENER(foo); ahead
of it.
LUNATIK_CLASSES
#define LUNATIK_CLASSES(name, ...)
Declares a static const lunatik_class_t * array of class pointers with an
implicit trailing NULL sentinel. The array is named lua<name>_classes —
the same token used in LUNATIK_NEWLIB(<name>, ..., lua<name>_classes, ...),
so both macros compose without the author naming the array explicitly.
name: module name suffix; must match thelibnameof the companionLUNATIK_NEWLIBcall....: one or moreconst lunatik_class_t *pointers. The macro appends the terminator, so authors must not include a trailingNULL.
A module may list classes with different execution contexts (e.g. a HARDIRQ
class alongside a process-context class) in the same array; see the note
under LUNATIK_NEWLIB for how context enforcement is
handled at object creation.
When to use
Prefer LUNATIK_CLASSES for the common case of a fixed class list: it
removes boilerplate, enforces the static const qualifiers, and makes
forgetting the NULL sentinel impossible.
Write the array out by hand when any item is guarded by a preprocessor
directive — #if/#endif inside a macro argument list is undefined
behavior in C99 (§6.10.3/11), so the helper cannot express conditional
inclusion:
static const lunatik_class_t *luafoo_classes[] = { &luafoo_class, #if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 15, 0)) &luafoo_legacy_class, #endif NULL }; LUNATIK_NEWLIB(foo, luafoo_lib, luafoo_classes);
The naming convention (lua<libname>_classes) is a convention of the helper,
not a requirement of LUNATIK_NEWLIB: any NULL-terminated array works.
LUNATIK_NEWLIB
#define LUNATIK_NEWLIB(libname, funcs, classes)
Defines and exports the luaopen_<libname> entry point using EXPORT_SYMBOL_GPL.
funcs:luaL_Reg[]of Lua-callable functions (the module table).classes: NULL-terminatedconst lunatik_class_t **array declared withLUNATIK_CLASSES, orNULLif the module defines no object type.
When classes != NULL, LUNATIK_NEWLIB registers the metatable(s) for every
class in the array through lunatik_require.
Metatable registration is context-agnostic: a module may expose classes of
different execution contexts (e.g. a HARDIRQ class alongside a process-context
class) and luaopen_<libname> succeeds in any runtime. Context enforcement
happens later, at object creation time — lunatik_newobject rejects a
process-context class in an IRQ runtime, and each constructor should call
lunatik_checkruntime to reject exact mismatches
(e.g. a SOFTIRQ class in a HARDIRQ runtime). This lets a single module serve
runtimes of different contexts: each runtime sees every class registered, but
can only instantiate the ones whose context matches its own.
Example — single class
static const luaL_Reg luafoo_lib[] = { {"new", luafoo_new}, {NULL, NULL}, }; LUNATIK_CLASSES(foo, &luafoo_class); LUNATIK_NEWLIB(foo, luafoo_lib, luafoo_classes);
Example — multiple classes, different contexts
static const lunatik_class_t luafoo_process_class = { .name = "foo", .methods = luafoo_mt, .release = luafoo_release, .opt = LUNATIK_OPT_SINGLE, .owner = THIS_MODULE, }; static const lunatik_class_t luafoo_hardirq_class = { .name = "foo", .methods = luafoo_mt, .release = luafoo_release, .opt = LUNATIK_OPT_HARDIRQ | LUNATIK_OPT_SINGLE, .owner = THIS_MODULE, }; LUNATIK_CLASSES(foo, &luafoo_process_class, &luafoo_hardirq_class); LUNATIK_NEWLIB(foo, luafoo_lib, luafoo_classes);
require("foo") succeeds in any runtime — both metatables are registered.
Each class can only be instantiated from a runtime whose context matches
its opt; the constructor enforces this via
lunatik_checkruntime.
LUNATIK_RELEASE
#define LUNATIK_VERSION_MAJOR_N <major> #define LUNATIK_VERSION_MINOR_N <minor> #define LUNATIK_VERSION_NUM (LUNATIK_VERSION_MAJOR_N * 100 + LUNATIK_VERSION_MINOR_N) #define LUNATIK_RELEASE "<major>.<minor>" #define LUNATIK_VERSION "Lunatik " LUNATIK_RELEASE
LUNATIK_VERSION_NUM is the release as a number a binding tests with #if, 500 for 5.0; 4.4
and earlier do not define it, and the kernel builds with -Wundef, so a binding that also builds
there tests defined(LUNATIK_VERSION_NUM) first.
LUNATIK_RELEASE is the release, spelled as a module version takes it, and LUNATIK_VERSION the
string a script reads as _LUNATIK_VERSION and lunatik -V prints. A module declares
MODULE_VERSION(LUNATIK_RELEASE) beside its license: modpost writes the srcversion that
lunatik reload compares only for a module that declares a version, unless the kernel sets
CONFIG_MODULE_SRCVERSION_ALL.
Writing a binding
A kernel module exposing a Lua library foo whose objects count: the private structure, its
checker, a method table carrying __gc and __close, the class, a constructor, and the module’s
entry points.
#include <linux/module.h> #include <lunatik.h> typedef struct luafoo_s { lua_Integer count; } luafoo_t; static const lunatik_class_t luafoo_class; LUNATIK_PRIVATECHECKER(luafoo_check, luafoo_t *, &luafoo_class); static int luafoo_inc(lua_State *L) { luafoo_t *foo = luafoo_check(L, 1); lua_pushinteger(L, ++foo->count); return 1; } static const luaL_Reg luafoo_mt[] = { {"__gc", lunatik_deleteobject}, {"__close", lunatik_closeobject}, {"close", lunatik_closeobject}, {"inc", luafoo_inc}, {NULL, NULL} }; static const lunatik_class_t luafoo_class = { .name = "foo", .methods = luafoo_mt, .opt = LUNATIK_OPT_MONITOR, .owner = THIS_MODULE, }; static int luafoo_new(lua_State *L) { lunatik_newobject(L, &luafoo_class, sizeof(luafoo_t), LUNATIK_OPT_NONE); return 1; /* object */ } static const luaL_Reg luafoo_lib[] = { {"new", luafoo_new}, {NULL, NULL} }; LUNATIK_CLASSES(foo, &luafoo_class); LUNATIK_NEWLIB(foo, luafoo_lib, luafoo_classes); static int __init luafoo_init(void) { return 0; } static void __exit luafoo_exit(void) { } module_init(luafoo_init); module_exit(luafoo_exit); MODULE_LICENSE("Dual MIT/GPL"); MODULE_VERSION(LUNATIK_RELEASE); MODULE_DESCRIPTION("Lunatik foo binding");
A script then runs local foo = require("foo") and foo.new():inc().
Building out of tree
A binding kept outside this tree builds against a Lunatik tree that make built for the running
kernel: its headers, and its Module.symvers, which lists what lunatik.ko exports and which
modpost reads to resolve the binding’s calls. The binding’s Kbuild names the directories of the
headers and defines _KERNEL, which configures the Lua headers for the kernel:
obj-m += luafoo.o ccflags-y += -D_KERNEL -I$(LUNATIK) -I$(LUNATIK)/lua -I$(LUNATIK)/include
and its build names that tree as LUNATIK and hands its symbols to modpost:
make -C /lib/modules/$(uname -r)/build M=$PWD LUNATIK=$HOME/lunatik \
KBUILD_EXTRA_SYMBOLS=$HOME/lunatik/Module.symvers modules
require("foo") finds the binding once its module is loaded, by insmod luafoo.ko after
lunatik.ko, or by modprobe luafoo once it is installed under /lib/modules/$(uname -r): the
searcher looks luaopen_foo up among the symbols the loaded modules export, and lunatik load
loads only the tree’s own modules. A binding that registers a kfunc needs the running kernel’s BTF
at build time, which the tree’s sudo make btf_install copies where the build reads it; without it
the module loads with its kfunc unregistered, logging missing module BTF, cannot register kfunc
(kfuncs on v6.8 and earlier), and an eBPF program that calls the kfunc fails to load.
Memory
lunatik_malloc
void *lunatik_malloc(lua_State *L, size_t size);
Allocates size bytes using the Lua allocator. Returns NULL on failure. The allocator asks for
the runtime’s gfp, lunatik_gfp, without an allocation warning; with
GFP_KERNEL, a block larger than a page may come from vmalloc. Free it with lunatik_free,
never kfree.
lunatik_realloc
void *lunatik_realloc(lua_State *L, void *ptr, size_t osize, size_t nsize);
Reallocates ptr, currently osize bytes long, to nsize bytes using the Lua
allocator. Returns NULL when nsize is zero, which frees ptr, and when the
allocation fails, leaving ptr allocated; the exception is a shrink whose
allocation fails, which returns ptr itself, still osize bytes long. When
ptr is NULL, osize is not read as a size: either 0 or a type tag is
accepted.
lunatik_free
void lunatik_free(void *ptr);
Frees memory allocated by lunatik_malloc or lunatik_realloc. Equivalent to kvfree.
lunatik_checkalloc
void *lunatik_checkalloc(lua_State *L, size_t size); void *lunatik_checkzalloc(lua_State *L, size_t size); void *lunatik_checknull(lua_State *L, void *ptr); int lunatik_enomem(lua_State *L);
Raise not enough memory instead of returning NULL: lunatik_checkalloc is
lunatik_malloc, lunatik_checkzalloc the same zeroed, and lunatik_checknull returns ptr,
raising when it is NULL. lunatik_enomem raises the error itself.
lunatik_gfp
gfp_t lunatik_gfp(lunatik_object_t *object);
Returns the gfp_t object allocates with: GFP_ATOMIC for a SOFTIRQ or HARDIRQ object and
GFP_KERNEL otherwise. A runtime’s is its allocator’s, GFP_KERNEL while its script body runs
and the object’s while it calls a monitored method.
A binding that allocates outside the Lua allocator passes lunatik_gfp(lunatik_toruntime(L)).
Defined as a macro.
Symbols
lunatik_lookup
void *lunatik_lookup(const char *symbol);
Returns the address of the kernel symbol named symbol, or NULL when kallsyms does not carry
it. Never sleeps, so it is callable from any context, a softirq or hardirq handler included:
kallsyms_lookup_name, which the kernel does not export, is resolved through a kprobe once,
while lunatik.ko loads. Each call searches the kernel’s symbol table, so a handler resolves a
name once and keeps the address rather than asking per event. Every lookup answers NULL when
that resolution fails, as it does without CONFIG_KPROBES or CONFIG_KALLSYMS.