kfifo 試す (4)

早めに目が覚めたのでいぢり始める。
write の中で kfifo 構造体のメンバを printk してたら、release 時に初期化していない事が判明。buffer の中身も微妙。rmmod して insmod したら初期化されているな。当たり前と言えば当たり前か。
で、ごりごりと printk しながら値を確認しているのですが、write は普通に動作している模様。とは言え、一文字づつ入力して中身を確認しただけの話で、まだまだ微妙なソレはあるのでしょうが。

read??

$ tail ./fifo101130

でカタマる。昨晩は kill できなかった記憶がおぼろにあるんですが、一応 kill できた。
んですが、いろいろ確認している内に kill できなくなる。昨晩この挙動を見つつ意識を失なった記憶があるな。やむなく仮想マシンを reboot。
微妙と思いつつも sleep_on を interruptible_sleep_on にしてみる。kill できた。

tail

なかなか出力されぬ、と言いつつ printk の出力によるときちんとデータが扱えている模様。fgets して printf するプログラムを作ってそっちでナニしてみたら出力された。
微妙ですが、現時点のをサラして一旦休憩

#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 EOF (-1)
#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 const int debugsw = 1;

#define DEBUG_OUT(data) \
	if(debugsw) \
		printk((data));

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 int yamanetoshi_release(struct inode *inode, struct file *file)
{
	printk("yamanetoshi_close\n");
	if(0 == MINOR(inode->i_rdev) % 2) {
		kfifo_reset(fifo_ptr);
		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;

	DEBUG_OUT("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);
/*
	{
		int i;
		for(i = 0; i < size; i++) {
			printk("ptr[%d] = %x\n", i, ptr[i]);
		}
	}
*/
	if(copy_to_user(buf, ptr, ret))
		ret = -EFAULT;

	kfree(ptr);

	{
		int i;
		for(i = 0; i < ret; i++) {
			printk("ptr[%d] = %02x\n", i, ptr[i]);
			printk("buf[%d] = %02x\n", i, buf[i]);
		}
	}

	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, len;
	unsigned char *ptr = NULL;

	DEBUG_OUT("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);
/*
	{
		int i;
		for(i = 0; i < fifo_ptr->in; i++) {
			printk("fifo_ptr->buffer[%d] = %02x\n", i, fifo_ptr->buffer[i]);
		}
	}
*/
	kfree(ptr);

	if(TRUE == read_sleep && NULL != read_task) {
		read_sleep = FALSE;
		wake_up_process(read_task);
	}

	DEBUG_OUT("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);

とりあえず、ReadingGauche 方面に去ります。