kfifo 試す (2)
EOF はどう戻すのか云々、と微妙に悩む。man 2 read 見たら
成功した場合、読み込んだバイト数を返す (0 はファイルの終わりを意味する)。
との事。
てーコトは 0 戻せば良いのか、と言いつつ盛り込んで以下なプログラムにて試験。
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char buf[255]; FILE *fp = NULL; fp = fopen("./fifo101130", "r"); if(NULL == fp) exit(1); memset(buf, '\0', sizeof(buf)); if(NULL == fgets(buf, sizeof(buf), fp)) printf("returns NULL\n"); return 0; }
一応 returns NULL なメセジが出力されているので read な API では 0 を戻せば EOF が戻る事が分かった。
次
ええと、現時点の read な実装が以下
static ssize_t yamanetoshi_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { DEBUG_OUT("read start\n"); if(0 == kfifo_len(fifo_ptr)) return 0; DEBUG_OUT("read end\n"); return 0; }
仕様としては (空な FIFO デバイスから読み込む場合限定すると
- もう一方の端がオープンしていないなら EOF を戻す
- そうでないなら読み取り操作を呼び出したプロセスをブロック
となっている。オープンしたかどうか、は {read, write}_open というカウンタがありますのでこれを使えば良い。で、sleep_on と wake_up を使ってナニだな。ちなみに
書き込み操作 (および書き込みデバイスに対するクローズ操作) は、ブロックされている読み取りプロセス (読み取りプロセスが存在するとして) を目覚めさせる必要がある。
との記述。ぼさっと以下なカンジででっち上げてみた
static ssize_t yamanetoshi_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { int ret = 0; char *ptr = NULL; DEBUG_OUT("read start\n"); if(0 == kfifo_len(fifo_ptr)) { if(0 == write_open) { return 0; } else { read_sleep = TRUE; sleep_on(&queue); } } ptr = kmalloc(size, GFP_KERNEL); if(!ptr) return -ENOMEM; ret = kfifo_get(fifo_ptr, ptr, size); if(!copy_to_user(buf, ptr, ret)) ret = -EFAULT; kfree(ptr); DEBUG_OUT("read end\n"); return ret; } static ssize_t yamanetoshi_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { int ret = 0; char *ptr = NULL; DEBUG_OUT("write start\n"); if(TRUE == read_sleep && NULL != read_task) { read_sleep = FALSE; wake_up_process(read_task); } ptr = kmalloc(size, GFP_KERNEL); if(!ptr) return -ENOMEM; if(!copy_from_user(ptr, buf, size)) ret = -EFAULT; else ret = kfifo_put(fifo_ptr, ptr, size); kfree(ptr); DEBUG_OUT("write end\n"); return 0; }
微妙。手順としては間違ってないはず、と思いたい。一応 make はパスしてるんですが、どうなります事やら。
試験
vmware に二つログインして cat と tail してみる。と
- write 側で ENOMEM と思われるエラー発生
- read 側で_不正なアドレス_とのメセジ出力されて停止
ただ、コンソールを見るに read のブロックは正常 (??) な模様。
む
read は微妙だな。sleep_on でストップしてるはずなので、size を使って領域確保はダウトじゃないか、と。
if(0 == kfifo_len(fifo_ptr)) { if(0 == write_open) { return 0; } else { read_sleep = TRUE; sleep_on(&queue); } } ptr = kmalloc(size, GFP_KERNEL); if(!ptr) return -ENOMEM;
大体 read に渡される size って一体何なんだ、と。ここでは kfifo_len とかで length 持ってきてから kmalloc しないと駄目だな。
で、kmalloc 呼び出し直前に以下を挿入
size = kfifo_len(fifo_ptr);
size 上書きしているあたりは微妙ですがスルー (を
それでもダメ
メセジ的に kmalloc が微妙そげなんですが、もしかしてアレも power of 2 限定なのかなぁ。なかなか前に進まねぇ。
read 側では copy_to_user で失敗してるんだろな。ちょっとへろへろなので今日はこれで終了。