Skip to content

Commit

Permalink
add luacompletion
Browse files Browse the repository at this point in the history
  • Loading branch information
sav authored and lneto committed Sep 9, 2024
1 parent 762b967 commit 190d804
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 10 deletions.
1 change: 1 addition & 0 deletions Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ obj-$(CONFIG_LUNATIK_XDP) += lib/luaxdp.o
obj-$(CONFIG_LUNATIK_FIFO) += lib/luafifo.o
obj-$(CONFIG_LUNATIK_XTABLE) += lib/luaxtable.o
obj-$(CONFIG_LUNATIK_NETFILTER) += lib/luanetfilter.o
obj-$(CONFIG_LUNATIK_COMPLETION) += lib/luacompletion.o

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ all: lunatik_sym.h
CONFIG_LUNATIK_RCU=m CONFIG_LUNATIK_THREAD=m CONFIG_LUNATIK_FIB=m \
CONFIG_LUNATIK_DATA=m CONFIG_LUNATIK_PROBE=m CONFIG_LUNATIK_SYSCALL=m \
CONFIG_LUNATIK_XDP=m CONFIG_LUNATIK_FIFO=m CONFIG_LUNATIK_XTABLE=m \
CONFIG_LUNATIK_NETFILTER=m
CONFIG_LUNATIK_NETFILTER=m CONFIG_LUNATIK_COMPLETION=m

clean:
${MAKE} -C ${KDIR} M=${PWD} clean
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,30 @@ address families to Lua.
* `"NETDEV"`: Device ingress and egress path
* `"BRIDGE"`: Ethernet Bridge.
### `completion`
The `completion` library provides support for the [kernel completion primitives](https://docs.kernel.org/scheduler/completion.html).
Task completion is a synchronization mechanism used to coordinate the execution of multiple threads, similar to `pthread_barrier`, it allows threads to wait for a specific event to occur before proceeding, ensuring certain tasks are complete in a race-free manner.
#### `completion.new()`
_completion.new()_ creates a new `completion` object.
#### `c:complete()`
_c:complete()_ signals a single thread waiting on this completion.
#### `c:wait([timeout])`
_c:wait()_ waits for completion of a task until the specified timeout expires.
The timeout is specified in milliseconds. If the `timeout` parameter is omitted, it waits indefinitely. Passing a timeout value less than zero results in undefined behavior.
Threads waiting for events can be interrupted by signals, for example, such as when `thread.stop` is invoked.
Therefore, this function can return in three ways:
* If it succeeds, it returns `true`
* If the timeout is reached, it returns `nil, "timeout"`
* If the task is interrupted, it returns `nil, "interrupt"`
# Examples
### spyglass
Expand Down
2 changes: 1 addition & 1 deletion bin/lunatik
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ local lunatik = {
device = "/dev/lunatik",
modules = {"lunatik", "luadevice", "lualinux", "luanotifier", "luasocket", "luarcu",
"luathread", "luafib", "luadata", "luaprobe", "luasyscall", "luaxdp", "luafifo", "luaxtable",
"luanetfilter", "lunatik_run"}
"luanetfilter", "luacompletion", "lunatik_run"}
}

function lunatik.prompt()
Expand Down
100 changes: 100 additions & 0 deletions lib/luacompletion.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/completion.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#include <lunatik.h>

LUNATIK_OBJECTCHECKER(luacompletion_check, struct completion *);

static int luacompletion_complete(lua_State *L)
{
struct completion *completion = luacompletion_check(L, 1);

complete(completion);
return 0;
}

static int luacompletion_wait(lua_State *L)
{
struct completion *completion = luacompletion_check(L, 1);
lua_Integer timeout = luaL_optinteger(L, 2, MAX_SCHEDULE_TIMEOUT);
unsigned long timeout_jiffies = msecs_to_jiffies((unsigned long)timeout);
long ret;

lunatik_checkruntime(L, true);
ret = wait_for_completion_interruptible_timeout(completion, timeout_jiffies);
if (ret > 0) {
lua_pushboolean(L, true);
return 1;
}

lua_pushnil(L);
switch (ret) {
case 0:
lua_pushliteral(L, "timeout");
break;
case -ERESTARTSYS:
lua_pushliteral(L, "interrupt");
break;
default:
lua_pushliteral(L, "unknown");
break;
}
return 2;
}

static int luacompletion_new(lua_State *L);

static const luaL_Reg luacompletion_lib[] = {
{"new", luacompletion_new},
{NULL, NULL}
};

static const luaL_Reg luacompletion_mt[] = {
{"__gc", lunatik_deleteobject},
{"complete", luacompletion_complete},
{"wait", luacompletion_wait},
{NULL, NULL}
};

static const lunatik_class_t luacompletion_class = {
.name = "completion",
.methods = luacompletion_mt,
.sleep = false,
};

static int luacompletion_new(lua_State *L)
{
lunatik_object_t *object = lunatik_newobject(L, &luacompletion_class, sizeof(struct completion));
struct completion *completion = (struct completion *)object->private;

init_completion(completion);
return 1;
}

LUNATIK_NEWLIB(completion, luacompletion_lib, &luacompletion_class, NULL);

static int __init luacompletion_init(void)
{
return 0;
}

static void __exit luacompletion_exit(void)
{
}

module_init(luacompletion_init);
module_exit(luacompletion_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Savio Sena <[email protected]>");

25 changes: 17 additions & 8 deletions lib/mailbox.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,37 @@
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--

local fifo = require("fifo")
local fifo = require("fifo")
local completion = require("completion")

local mailbox = {}
local MailBox = {}
MailBox.__index = MailBox

local function new(o, allowed, forbidden)
local function new(q, e, allowed, forbidden)
local mbox = {}
mbox.queue = type(o) == 'userdata' and o or fifo.new(o)
if type(q) == 'userdata' then
mbox.queue, mbox.event = q, e
else
mbox.queue, mbox.event = fifo.new(q), completion.new()
end
mbox[forbidden] = function () error(allowed .. "-only mailbox") end
return setmetatable(mbox, MailBox)
end

function mailbox.inbox(o)
return new(o, 'receive', 'send')
function mailbox.inbox(q, e)
return new(q, e, 'receive', 'send')
end

function mailbox.outbox(o)
return new(o, 'send', 'receive')
function mailbox.outbox(q, e)
return new(q, e, 'send', 'receive')
end

local sizeoft = string.packsize("T")
function MailBox:receive()
local ok, err = self.event:wait()
if not ok then error(err) end

local queue = self.queue
local header, header_size = queue:pop(sizeoft)

Expand All @@ -39,7 +47,8 @@ function MailBox:receive()
end

function MailBox:send(message)
return self.queue:push(string.pack("s", message))
self.queue:push(string.pack("s", message))
self.event:complete()
end

return mailbox
Expand Down

0 comments on commit 190d804

Please sign in to comment.