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以降のメンバーの取り扱いが良くわかりません。






