Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

NetBSDのLuaカーネルモジュールからLuaスクリプトの関数を呼び出してみる

More than 1 year has passed since last update.

遅ればせながら NetBSD Advent Calendar 2018 24日目の記事です。
今日はLuaカーネルモジュールからLuaスクリプトの関数を呼び出してみる手順を紹介してみようと思います。

Luaカーネルモジュール

18日目の記事でNetBSD-8.0におけるLuaカーネルの変更箇所を紹介しました(あまり変更箇所はありませんでしたが...)。
今回の記事では、Luaカーネルモジュールをもうちょっと掘り下げて見てみます。

サンプルのluareadを読み込んでみる

3日目の記事でNetBSDカーネルモジュールの紹介をした際に、サンプルとして readhappy カーネルモジュールを試していました。
readhappy のLuaカーネルモジュール版として、 luareadhappy カーネルモジュールがサンプルとして提供されているので、今回はこちらを試してみます。

他のカーネルモジュールと同じく、 make して modload するだけです。

# cd /usr/src/sys/modules/examples/luareadhappy/
# ls -F
CVS/              Makefile          happy.lua         luareadhappy.c
# make
# ls -F
CVS/                       happy.lua                  luareadhappy.kmod          machine@
Makefile                   i386@                      luareadhappy.kmod.map      x86@
amd64@                     luareadhappy.c             luareadhappy.o
# modload ./luareadhappy.kmod
# modstat | grep happy
happy                   misc     filesys  -        0     646 lua

luareadhappy カーネルモジュールは、 modload した時点で happy という名前のLua stateが内部的に作られています。

# luactl
1 active state:
Name             Creator  Description
happy            kernel   Example Happy Number calculator

happy stateに対し、サンプルディレクトリにある happy.lua をロードします。

# luactl load happy ./happy.lua
./happy.lua loaded into happy

happy.lua はソースコメント部分を除くと以下のようなコードになっています。

local HAPPY_NUMBER = 1

local SAD_NUMBER = 4

function dsum(n)
        local sum = 0
        while n > 0 do
                local x = n % 10
                sum = sum + (x * x)
                n = n / 10
        end
        return sum
end

function is_happy(n)
        while true do
                local total = dsum(n)

                if total == HAPPY_NUMBER then
                        return 1
                end
                if total == SAD_NUMBER then
                        return 0
                end

                n = total
        end
end

luareadhappy カーネルモジュールの中では、read(2)された時に happy_read() が呼ばれ、さらにそこから呼ばれる check_happy() の中で先述したLuaスクリプト内の関数 is_happy() を呼び出しているようです。

/usr/src/sys/modules/examples/luareadhappy/luareadhappy.c:
 68 static struct cdevsw happy_cdevsw = {
 69         .d_open = happy_open,
 70         .d_close = happy_close,
 71         .d_read = happy_read,
 ...
 92 /* Function that calls a Lua routine and returns whether a number is happy */
 93 static int
 94 check_happy(unsigned n)
 95 {
 96         int rv;
 97
 98         klua_lock(sc.kL);
 99         lua_getglobal(sc.kL->L, "is_happy");
100
101         if (!lua_isfunction(sc.kL->L, -1)) {
102                 lua_pop(sc.kL->L, 1);
103                 klua_unlock(sc.kL);
104                 return -1;
105         }
...
154 int
155 happy_read(dev_t self __unused, struct uio *uio, int flags __unused)
156 {
157         int rv;
158         char line[80];
159
160         /* Get next happy number */
161         while ((rv = check_happy(++sc.last)) == 0)
162                 continue;
...
168         /* Print it into line[] with trailing \n */
169         int len = snprintf(line, sizeof(line), "%u\n", sc.last);
...
177         /* Send it to User-Space */
178         int e;
179         if ((e = uiomove(line, len, uio)))
180                 return e;
181
182         return 0;
183 }

ユーザランド側で、以下のような簡単なサンプルを走らせ、Luaカーネルモジュールの動作を見てみましょう。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
        char buf[BUFSIZ];
        char line[BUFSIZ];
        int fd;

        fd = open("/dev/happy", O_RDONLY);
        if (fd == -1) {
                fprintf(stderr, "open() failed.\n");
                exit(-1);
        }

        printf("Ctrl-D to quit > ");
        while (fgets(line, BUFSIZ, stdin) != NULL) {
                read(fd, buf, BUFSIZ);
                printf("%s", buf);
                printf("Ctrl-D to quit > ");
        }
        printf("\n");

        close(fd);

        return 0;
}

サンプルプログラムを動かすと、以下のような動作になります。カーネルから返された値がユーザランド側で取得されていることが確認できます。

sample9.gif

まとめ

NetBSDのLuaカーネルモジュールからLuaスクリプトの関数を呼び出してみる手順を紹介しました。
happy.luaを動かす手順では、単に printf() 的な動作をさせるだけでしたが、Luaカーネルモジュール内でLua stateを作成し、その中からLuaスクリプトの関数を呼び出す形にすると、カーネル内の処理をLuaで記述できるという形になります。むしろこちらの使い方の方がLuaカーネルモジュールで想定されている使い方かもしれません。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away