kfifo(その1)


kernel fifoをkfifoと言います。fifoはパイプそのもので、スペシャルファイルのiノードにpipeバッファを紐付け、読み/書きするプロセスがこのパイプバッファを参照することで実現しています。従ってその処理はvfs下に依存し、read/write単位の処理となります。(VFSで実装故、ユーザプロセスも利用できる事になります。)

kfifoは実装をvfsでなく、リングバッファのように読み手/書き手に参照ポイントを有し、読み手/書き手間でロックする事なく参照を実現し、また、FIFO単位(文字列/int/float等)を自由に設定できるようになっています。(それ故、マクロを多用した実装になっています。)

以下は、カーネルソースにあるkfifoのサンプルです。サンプルとしては冗長ぎみかな?って感じがしますが、以下の内容で検証をおこなっています。
・helloを書き込む。
・0から9まで数値を書き込む。
・5バイト読み出す。
・2バイト読み出す。そしてその内容を書き込む。
・1バイトスキップする。
・20からバッファーフルまで順に書き込む
もし、途中の読み込み処理をスキップすれば、test,0,1・・・8,9,20,21・・・42の順でfifoにはデータが蓄えられまが、fifo故、expected_result[]となりますよ。って事です。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include <linux/kfifo.h>

/* fifo size in elements (bytes) */
#define FIFO_SIZE       32

/* name of the proc entry */
#define PROC_FIFO       "bytestream-fifo"

/* lock for procfs read access */
static DEFINE_MUTEX(read_lock);

/* lock for procfs write access */
static DEFINE_MUTEX(write_lock);

#if 0
#define DYNAMIC
#endif

#ifdef DYNAMIC
static struct kfifo test;
#else
static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE);
#endif

static const unsigned char expected_result[FIFO_SIZE] = {
        3,  4,  5,  6,  7,  8,  9,  0,
        1, 20, 21, 22, 23, 24, 25, 26,
       27, 28, 29, 30, 31, 32, 33, 34,
       35, 36, 37, 38, 39, 40, 41, 42,
};

static int __init testfunc(void)
{
       unsigned char   buf[6];
       unsigned char   i, j;
       unsigned int    ret;

       printk(KERN_INFO "byte stream fifo test start\n");

       /* put string into the fifo */
       kfifo_in(&test, "hello", 5);

       /* put values into the fifo */
       for (i = 0; i != 10; i++)
               kfifo_put(&test, &i);

       /* show the number of used elements */
       printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));

       /* get max of 5 bytes from the fifo */
       i = kfifo_out(&test, buf, 5);
       printk(KERN_INFO "buf: %.*s\n", i, buf);

       /* get max of 2 elements from the fifo */
       ret = kfifo_out(&test, buf, 2);
       printk(KERN_INFO "ret: %d\n", ret);
       /* and put it back to the end of the fifo */
       ret = kfifo_in(&test, buf, ret);
       printk(KERN_INFO "ret: %d\n", ret);

       /* skip first element of the fifo */
       printk(KERN_INFO "skip 1st element\n");
       kfifo_skip(&test);

       /* put values into the fifo until is full */
       for (i = 20; kfifo_put(&test, &i); i++)
               ;

       printk(KERN_INFO "queue len: %u\n", kfifo_len(&test));

       /* show the first value without removing from the fifo */
       if (kfifo_peek(&test, &i))
               printk(KERN_INFO "%d\n", i);

       /* check the correctness of all values in the fifo */
       j = 0;
       while (kfifo_get(&test, &i)) {
               printk(KERN_INFO "item = %d\n", i);
               if (i != expected_result[j++]) {
                       printk(KERN_WARNING "value mismatch: test failed\n");
                       return -EIO;
               }
       }
       if (j != ARRAY_SIZE(expected_result)) {
               printk(KERN_WARNING "size mismatch: test failed\n");
               return -EIO;
       }
       printk(KERN_INFO "test passed\n");

       return 0;
}

static ssize_t fifo_write(struct file *file, const char __user *buf,
                                               size_t count, loff_t *ppos)
{
       int ret;
       unsigned int copied;

       if (mutex_lock_interruptible(&write_lock))
               return -ERESTARTSYS;

       ret = kfifo_from_user(&test, buf, count, &copied);

       mutex_unlock(&write_lock);

       return ret ? ret : copied;
}

static ssize_t fifo_read(struct file *file, char __user *buf,
                                               size_t count, loff_t *ppos)
{
       int ret;
       unsigned int copied;

       if (mutex_lock_interruptible(&read_lock))
               return -ERESTARTSYS;

       ret = kfifo_to_user(&test, buf, count, &copied);

       mutex_unlock(&read_lock);

       return ret ? ret : copied;
}

static const struct file_operations fifo_fops = {
       .owner          = THIS_MODULE,
       .read           = fifo_read,
       .write          = fifo_write,
       .llseek         = noop_llseek,
};

static int __init example_init(void)
{
#ifdef DYNAMIC
       int ret;

       ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
       if (ret) {
               printk(KERN_ERR "error kfifo_alloc\n");
               return ret;
       }
#else
       INIT_KFIFO(test);
#endif
       if (testfunc() < 0) {
#ifdef DYNAMIC
               kfifo_free(&test);
#endif
               return -EIO;
       }

       if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) {
#ifdef DYNAMIC
               kfifo_free(&test);
#endif
               return -ENOMEM;
       }
       return 0;
}

static void __exit example_exit(void)
{
       remove_proc_entry(PROC_FIFO, NULL);
#ifdef DYNAMIC
       kfifo_free(&test);
#endif
}

module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");

[root@localhost ~]# dmesg
[11715.316317] byte stream fifo test start
[11715.316329] fifo len: 15            <-データ数(test,0,1,2・・・9)
[11715.316334] buf: hello
[11715.316337] ret: 2                  <-読み込んだバイト数
[11715.316363] ret: 2                  <-書き込んだバイト数
[11715.316367] skip 1st element
[11715.316370] queue len: 32           <-データ数(バッファフルまで書き込んだ後。=FIFO_SIZE
[11715.316373] 3                       <-バッファ先頭の内容
[11715.316376] item = 3
[11715.316379] item = 4
[11715.316381] item = 5
[11715.316384] item = 6
[11715.316386] item = 7
[11715.316389] item = 8
[11715.316391] item = 9
[11715.316394] item = 0
[11715.316396] item = 1
[11715.316399] item = 20
[11715.316401] item = 21
[11715.316404] item = 22
[11715.316406] item = 23
[11715.316409] item = 24
[11715.316411] item = 25
[11715.316414] item = 26
[11715.316416] item = 27
[11715.316419] item = 28
[11715.316421] item = 29
[11715.316423] item = 30
[11715.316426] item = 31
[11715.316428] item = 32
[11715.316431] item = 33
[11715.316433] item = 34
[11715.316435] item = 35
[11715.316438] item = 36
[11715.316440] item = 37
[11715.316443] item = 38
[11715.316445] item = 39
[11715.316448] item = 40
[11715.316450] item = 41
[11715.316453] item = 42
[11715.316455] test passed
procfsでbytestream-fifoを作成し、ユーザプロセスからもこのkfifoを参照可能としています。


最終更新 2013/08/10 22:34:00 - north
(2013/08/10 22:34:00 作成)


検索

アクセス数
3697960
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。