[NetBSD logo]    &    [Google logo]

NetBSD-SoC: Provide support for dynamic NetBSD kernel extensions using the Lua language - Lunatik/NetBSD

What is it?

This project has the goal to develop a kernel subsystem, called Lunatik, to provide support for dynamically extending the NetBSD kernel using the Lua programming language. We intend to allow the adaptation of the kernel for different purposes at runtime, through loading Lua scripts into the kernel and exposing the kernel internals to these scripts. Lunatik will provide also support for rapid prototyping and experimentation with new algorithms and mechanisms inside the kernel. Here are some examples of possible kernel extensions using Lunatik:

Status

Deliverables

Mandatory (must-have) components:

Optional (would-be-nice) components:

Documentation

Prerequisites

To use Lunatik, you first need to patch your -current kernel with the Lunatik latest patch.

1. Building Lunatik

Then, you need to build the Lunatik kernel module and the Lunatik user-space command:
cd /usr/src/sys/lunatik
# make
# make install
# modload lunatik
lunatik: cmajor = 198

cd /usr/src/sys/lunatik/userspace
# make

# sh mknodlunatik.sh 198

2. Extending a kernel module

For instance, suppose we want to run a user-defined function to compute the nth Fibonacci number (a very useful extension ;-) inside a kernel module. First we need to create a new in-kernel Lua environment. We provide this environment through a special data structure, called Lunatik state, that holds a Lua state and a mutex(9) descriptor (to guarantee mutual exclusion to our Lua state).
#include <sys/lunatik.h>

static kmutex_t kmutex;

static lunatik_State *Lk;
(...)
mutex_init(&kmutex, MUTEX_DEFAULT, IPL_NONE);
	
Lk = lunatikL_newstate(KM_SLEEP, &kmutex, MUTEX_DEFAULT);
if (Lk == NULL)
	return ENOMEM;

After creating a new Lunatik state, we need to register it to allow the Lunatik user-space command to dynamically load scripts.

extern lunatik_State *lunatik_registry[];
(...)
/* we use this array to register Lunatik states. */
lunatik_registry[ 0 ] = Lk;

Then, we can define a function to bind the user-defined Fibonacci function, using the Lua C API:

static int fibo(lua_State *L)
{
	int *n = (int *) lua_touserdata(L, -1);
	lua_getglobal(L, "fibo");
	lua_pushnumber(L, *n);
	lua_pcall(L, 1, 1, 0);
	*n = lua_tonumber(L, -1);

	return 0;
}

...and call the bind through the Lunatik run CFunction function (to handle the mutual exclusion to our Lua state).

int n = 10;
int ret = -1;
int size = -1;
char *result = NULL;

ret = lunatik_runcfunction(Lk, fibo, &n, &result, &size); 
if (ret != 0){
	printf("error: %s\n", result);
        lunatik_free(Lk, result, size);
}
else
	printf("fibo(10) = %d\n", n);

3. Loading scripts from the user-space

To load scripts from the user-space we just need to run the Lunatik command passing our state id (the index used in the lunatik_registry array) and our script in the standard input or use the interactive command prompt. For example:
# cd /usr/src/sys/lunatik/userspace
# ./lunatik 0
Lunatik 0.1
> function fibo(n) if (n == 0) then return 0 elseif (n == 1) then return 1 else return fibo(n-1) + fibo(n-2) end end

Technical Details

Here is a draft of the Lunatik(9) man page:
NAME
	Lunatik -- kernel scripting with Lua

SYNOPSIS

#include <sys/lunatik.h>

lunatik_State *
lunatik_newstate(lua_Alloc, void *, void *, lunatik_lock_t, lunatik_unlock_t);

void
lunatik_close(lunatik_State *);

inline void
lunatik_lock(lunatik_State *);

inline void
lunatik_unlock(lunatik_State *);

inline void *
lunatik_alloc(lunatik_State *, size_t);

inline void
lunatik_free(lunatik_State *, void *, size_t);

inline lua_State *
lunatik_getluastate(lunatik_State *);

int 
lunatik_runstring(lunatik_State *, const char *, char **, size_t *);

int
lunatik_runcfunction(lunatik_State *, lua_CFunction, void *, char **, size_t *);

int
lunatik_registerstate(lunatik_State *, const char *);

#include <sys/kmem.h>
#include <sys/mutex.h>

lunatik_State *lunatikL_newstate(km_flag_t, kmutex_t *, kmutex_type_t);

DESCRIPTION

Lunatik is a subsystem designed to provide support for scripting the kernel with Lua.

typedef void (*lunatik_lock_t)(void *);

typedef void (*lunatik_unlock_t)(void *);

typedef struct lunatik_State lunatik_State;


FUNCTIONS

- lunatik_newstate(allocf, ud, mutex, lockf, unlockf)

Creates a new instance of the Lua interpreter in-kernel. This instance is called Lunatik State and holds a 
Lua state descriptor, and the givens data structures and functions. Returns the new Lunatik state allocated
by the allocf function. If there is no memory available it returns NULL.

- lunatik_close(Lk)

Closes a given Lunatik state. The Lunatik state descriptor are freed using the registered allocf function. 

- lunatik_lock(Lk)

Locks a Lunatik state using the registered lock function.

- lunatik_unlock(Lk)

Unlocks a Lunatik state using the registered unlock function.

- lunatik_alloc(Lk, size)

Allocates memory using the registered allocator function. If there is no memory available it returns NULL.

- lunatik_free(Lk, ptr, size_t)

Frees memory using the registered allocator function.

- lunatik_getluastate(Lk)

Returns the Lua state encapsulated in the given Lunatik state.

- lunatik_runstring(Lk, string, resultp, sizep)

Runs a string containing Lua code. Returns the execution result on resultp pointer if the pointer is not null. 
Returns the size of the result on sizep pointer if the pointer is not null. The result is allocated using the
allocf registered function, so it must be freed using the lunatik_free call.

- lunatik_runcfunction(Lk, cfunction, lightuserdata, resultp, sizep);

Runs a lua_CFuntion on the encapsulated Lua state. Returns the execution result on resultp pointer if the pointer 
is not null. Returns the size of the result on sizep pointer if the pointer is not null. The result is allocated 
using the allocf registered function, so it must be freed using the lunatik_free call. The lightuserdata argument 
is put in the Lua stack.

- lunatikL_newstate(km_flags, kmutex, kmutex_type)

Creates a new Lunatik state using kmem allocator and a initialized given kmutex. The km_flags argument is given to
kmem_alloc on each call. The kmutex_type argument determines the lock/unlock functions. Returns the new Lunatik
state allocated by the kmem_alloc function. If there is no memory available it returns NULL.


Get NetBSD Summer of Code projects at SourceForge.net. Fast, secure and Free Open Source software downloads
Lourival Vieira Neto <lourival.neto@gmail.com>
$Id: index.html,v 1.5 2010/10/04 04:59:22 lneto Exp $