kfifo 試す (6)
ええと、昨晩の不具合ですが、再現しません。
ってか release の処理で
if(0 == MINOR(inode->i_rdev) % 2) { kfifo_reset(fifo_ptr); write_open = 0; } else { read_open = 0; }
なコトをヤッてたのですが、reset をコメントアウトしたら現象が出なくなってます。理由については別途解析予定。もしかするとこれと関連しているのかどうかは不明なんですが、ある端末で
$ cat >./fifo100130
ってヤッてて違う端末で fifo101130 から読み込む以下のプログラム
#include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp = NULL; char buf[255]; if(NULL == (fp = fopen("./fifo101130", "r"))) exit(1); for(;;) { memset(buf, '\0', sizeof(buf)); if(NULL == fgets(buf, sizeof(buf), fp)) break; printf("%s", buf); } fclose(fp); fp = NULL; return 0; }
を実行して、な試験をしてるんですが cat 側で Ctrl-d 入力して処理を終了させても読み込み側な fgets が NULL を戻さない。sleep してるのかなぁ。sleep 前後で printk させてみるか。
結果
見てると sleep してる間に write 側のプロセスが終了しても眠ったままである事が判明。てーコトは write 側の close にて sleep してたら起こす、という処理が必要なのか。
if(0 == MINOR(inode->i_rdev) % 2) { /* ... */ if(TRUE == read_sleep && NULL != read_task) { read_sleep = FALSE; wake_up_process(read_task); } write_open = 0; } else { read_open = 0; }
これはしかし違う意味で格好悪い。
# 全く同じ手続きが write 側に存在
とりあえず
現行のナニを以下にサラして云々
#include <linux/module.h> // required by all modules #include <linux/kernel.h> // required by printk() #include <linux/init.h> #include <linux/fs.h> #include <linux/sched.h> #include <asm/uaccess.h> // required by copy_{to_user, from_user} #include <linux/errno.h> #include <linux/kfifo.h> // fifo MODULE_LICENSE("GPL"); #define TRUE 1 #define FALSE 0 #define BUFSIZ 256 #define DRIVERNAME "yamanetoshi" static int fifo_major = 130; static int read_open, write_open; static struct kfifo *fifo_ptr; static spinlock_t fifo_lock; static DECLARE_WAIT_QUEUE_HEAD(queue); static struct task_struct *read_task; static int read_sleep; static int yamanetoshi_open(struct inode *inode, struct file *file) { printk("yamanetoshi_open\n"); printk(" MINOR(inode->i_rdev): %d\n", MINOR(inode->i_rdev)); if(0 == MINOR(inode->i_rdev) % 2) { if(0 == write_open) { write_open++; } else { return -EAGAIN; } } else { if(0 == read_open) { read_task = current; read_open++; } else { return -EAGAIN; } } return 0; } static void wakeup_read(void) { if(TRUE == read_sleep && NULL != read_task) { read_sleep = FALSE; wake_up_process(read_task); } return ; } static int yamanetoshi_release(struct inode *inode, struct file *file) { printk("yamanetoshi_close\n"); if(0 == MINOR(inode->i_rdev) % 2) { wakeup_read(); write_open = 0; } else { read_open = 0; } return 0; } static ssize_t yamanetoshi_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { int ret = 0, len = 0; unsigned char *ptr = NULL; printk("read start\n"); if(0 == kfifo_len(fifo_ptr)) { if(0 == write_open) { return 0; } else { read_sleep = TRUE; interruptible_sleep_on(&queue); } } len = kfifo_len(fifo_ptr); if(size>len) size = len; 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); printk("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, len; unsigned char *ptr = NULL; printk("write start\n"); len = strlen(buf); if(size>len) size = len; ptr = kmalloc(size, GFP_KERNEL); if(!ptr) return -ENOMEM; memset(ptr, '\0', size); ret = copy_from_user(ptr, buf, size); if(ret) { kfree(ptr); return ret; } ret = kfifo_put(fifo_ptr, ptr, size); kfree(ptr); wakeup_read(); printk("write end\n"); return size; } struct file_operations fifo_fops = { .owner = THIS_MODULE, .read = yamanetoshi_read, .write = yamanetoshi_write, .ioctl = NULL, .open = yamanetoshi_open, .release = yamanetoshi_release, }; static int yamanetoshi_init(void) { int ret; printk("initialize the fifo device\n"); ret = register_chrdev(fifo_major, DRIVERNAME, &fifo_fops); if(ret < 0) return ret; if(fifo_major == 0) fifo_major = ret; spin_lock_init(&fifo_lock); fifo_ptr = kfifo_alloc(BUFSIZ, GFP_KERNEL, &fifo_lock); if(IS_ERR(fifo_ptr)) return -ENOMEM; return 0; } static void yamanetoshi_exit(void) { printk("cleanup the fifo device\n"); kfifo_free(fifo_ptr); unregister_chrdev(fifo_major, DRIVERNAME); } module_init(yamanetoshi_init); module_exit(yamanetoshi_exit);
あと、バッファあふれに関するナニが致命的です。もひとつ、何故に tail -f だと駄目なのか、が微妙。