kfifo(その2)
kfifo(その1)のサンプルで、kfifoにかかる部分のみを抜き出したものです。
__is_kfifo_ptrマクロは、fifoのサイズがstruct __kfifoのサイズと同じなら、unsigned char bufを有していないということで、 __kfifo->data=NULL,有しているなら__kfifo->data=kfifo->buffとなります。
#include <linux/init.h> #include <linux/module.h> #include <linux/kfifo.h> #define FIFO_SIZE 32 static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE); static int __init testfunc(void) { unsigned char buf[6]; unsigned char i, j; unsigned int ret; kfifo_in(&test, "hello", 5); for (i = 0; i != 10; i++) kfifo_put(&test, &i); i = kfifo_out(&test, buf, 5); printk(KERN_INFO "buf: %.*s\n", i, buf); printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); for (j = 0; j != 10; j++) { ret = kfifo_get(&test, &i); printk(KERN_INFO "item = %d\n", i); } return 0; } static int __init example_init(void) { INIT_KFIFO(test); if (testfunc() < 0) { return -EIO; } return 0; } static void __exit example_exit(void) { } module_init(example_init); module_exit(example_exit); MODULE_LICENSE("GPL");
[root@localhost lkm]# dmesg : [48442.749592] buf: hello [48442.749985] queue len: 10 [48442.750644] item = 0 [48442.750976] item = 1 [48442.751359] item = 2 [48442.751641] item = 3 [48442.751954] item = 4 [48442.752224] item = 5 [48442.752652] item = 6 [48442.753036] item = 7 [48442.753396] item = 8 [48442.753673] item = 9DECLARE_KFIFOマクロでfifo構造体を定義します。
struct __kfifo { unsigned int in; unsigned int out; unsigned int mask; unsigned int esize; void *data; }; #define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo #define STRUCT_KFIFO(type, size) \ struct __STRUCT_KFIFO(type, size, 0, type)
#define __STRUCT_KFIFO(type, size, recsize, ptrtype) \ { \ __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \ }buf[((size < 2) || (size & (size - 1))) ? -1 : size] は、配列宣言の負のインデックスはコンパイル時エラーとなり、sizeは2以上で2の倍数のみを可能としています。
#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \ union { \ struct __kfifo kfifo; \ datatype *type; \ char (*rectype)[recsize]; \ ptrtype *ptr; \ const ptrtype *ptr_const; \ }で、static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE)の苛苛するような込み入った実装の結果は、
static struct { union { struct __kfifo kfifo; unsigned char *type; char (*rectype)[0]; unsigned char *ptr; const unsigned char *ptr_const; }; unsigned char buf[((32 < 2) || (32 & (32 - 1))) ? -1 : 32]; } test;INIT_KFIFOマクロで上記構造体を初期化します。このマクロはDECLARE_KFIFOの構造体のunionメンバーのstruct __kfifo kfifoを設定することにあります。
__is_kfifo_ptrマクロは、fifoのサイズがstruct __kfifoのサイズと同じなら、unsigned char bufを有していないということで、 __kfifo->data=NULL,有しているなら__kfifo->data=kfifo->buffとなります。
__kfifo->in 書き込み位置 __kfifo->out 読み込み位置 __kfifo->mask バッファーのエレメント数 __kfifo->esize バッファーのエレメントサイズ __kfifo->data バッファー
#define INIT_KFIFO(fifo) \ (void)({ \ typeof(&(fifo)) __tmp = &(fifo); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ __kfifo->in = 0; \ __kfifo->out = 0; \ __kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\ __kfifo->esize = sizeof(*__tmp->buf); \ __kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \ }) #define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo))kfifo_inマクロはnバイトfifoからのデータをbuffに取得します。__recsize = sizeof(*__tmp->rectype)は__kfifo->inと同値です。__recsize=0ならfifoの先頭から__kfifo_in、そうでないならオフセットとして__kfifo_in_rで取得します。DECLARE_KFIFOマクロで定義すると、第二引数分のバッファが確保されます。
#define kfifo_in(fifo, buf, n) \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ typeof((buf) + 1) __buf = (buf); \ unsigned long __n = (n); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ if (0) { \ typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \ __dummy = (typeof(__buf))NULL; \ } \ (__recsize) ?\ __kfifo_in_r(__kfifo, __buf, __n, __recsize) : \ __kfifo_in(__kfifo, __buf, __n); \ })補足
union { \ struct __kfifo kfifo; \ datatype *type; \ char (*rectype)[recsize]; \ ptrtype *ptr; \ const ptrtype *ptr_const; \ }のunionとしているkfifo以降のメンバーの取り扱いが良くわかりません。