配列でリングバッファ
こんなトコから復習せんと駄目なナニが微妙。kmalloc 使えば良いのでしょうが、vmware の中とかでないと微妙なので ...
出掛けて帰宅
その後、カンニングしつつでっち上げたのが以下。
#include <stdio.h> #include <string.h> #define ARRAY_SIZ 10 static int top = 0, end = 0; static char array[ARRAY_SIZ]; #define next(a) (((a) + 1) % ARRAY_SIZ) static int enqueue(char x) { if(next(end) == top) return EOF; array[end] = x; end = next(end); return 0; } static int dequeue(char *buf) { if(top == end) return EOF; buf[0] = array[top]; top = next(top); return 0; } int read_ring_buffer(char *buf, int siz) { int i; for(i = 0; i < siz; i++) { if(EOF == dequeue(&buf[i])) return EOF; } return 0; } int write_ring_buffer(const char *buf, int siz) { int i; for(i = 0; i < siz; i++) { if(EOF == enqueue(buf[i])) return EOF; } return 0; } int main(void) { char buf[50]; memset(buf, '\0', sizeof(buf)); if (EOF == read_ring_buffer(buf, 5)) printf("if top == end then return EOF\n"); write_ring_buffer("abcde", 5); if(EOF == write_ring_buffer("fghij", 5)) printf("write_ring_buffer return EOF\n"); memset(buf, '\0', sizeof(buf)); read_ring_buffer(buf, 3); if(0 == strcmp(buf, "abc")) printf("read_ring_buffer returns \"abc\"\n"); memset(buf, '\0', sizeof(buf)); read_ring_buffer(buf, 3); if(0 == strcmp(buf, "def")) printf("read_ring_buffer returns \"def\"\n"); memset(buf, '\0', sizeof(buf)); read_ring_buffer(buf, 3); if(0 == strcmp(buf, "ghi")) printf("read_ring_buffer returns \"ghi\"\n"); if (EOF == read_ring_buffer(buf, 5)) printf("if top == end then return EOF\n"); return 0; }
なんとなくこの循環リストっぽいナニで何とかしてみる。
盛り込み
まだ実機でヤッてるんですが大丈夫なのか。例えば read だと定義は以下なカンジで良いのでしょうか。
static ssize_t yamanetoshi_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
- top == end の場合
- 逆端が open してなかったら EOF 戻す
- dequeue が EOF 戻したら sleep_on する
- current は保存 (static なグローバル変数で定義)
- size 分繰り返して memcpy_tofs で buf にコピィ
- 繰り返しの中で dequeue が EOF 戻したら sleep_on して current 保存 (順番逆?
- 基本的には size 戻す方向で良いのかどうか
うーん。offset ガン無視なんだけどいいのかなぁ。
あるいは write は
static ssize_t yamanetoshi_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
の中ではバッファが一杯なソレの心配をせんと駄目なのかな。面倒だからこれはスルーで kmalloc なナニの盛り込みで云々。ヤる事は
- バッファがあふれた時は sleep_on しないとマズい
- ってコトは read 側で write な current を wake_up させないと云々 (面倒
で
考えながらコードをでっち上げてたら微妙なのができた。vmware 上で試験するか実機でヤるか考え中ッス。一応 compile にパスしたソレが以下
#include <linux/module.h> // required by all modules #include <linux/kernel.h> // required by printk() #include <linux/init.h> #include <linux/fs.h> MODULE_LICENSE("GPL"); #define EOF (-1) #define DRIVERNAME "yamanetoshi" int fifo_major = 130; #define BUFSIZ 50 static int readdev, writedev; static struct task_struct *read_task, *write_task; static int write_sleep, read_sleep; static wait_queue_head_t queue; static int top ,end; static char array[BUFSIZ]; #define next(a) (((a) + 1) % BUFSIZ) static int enqueue(char x) { if(next(end) == top) return EOF; array[end] = x; end = next(end); return 0; } static int dequeue(char *buf) { if(top == end) return EOF; buf[0] = array[top]; top = next(top); return 0; } static int yamanetoshi_open(struct inode *inode, struct file *file) { printk("yamanetoshi_open\n"); printk(" file->f_version : %lu\n", file->f_version); printk(" MINOR(inode->i_rdev): %d\n", MINOR(inode->i_rdev)); if(0 == (MINOR(inode->i_rdev % 2))) { read_task = current; } else { write_task = current; } return 0; } static int yamanetoshi_release(struct inode *inode, struct file *file) { printk("yamanetoshi_close\n"); printk(" file->f_version : %lu\n", file->f_version); return 0; } static ssize_t yamanetoshi_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { int i; if(NULL == write_task) return EOF; for(i = 0; i < size; i++) { if(EOF == dequeue(&buf[i])) { read_sleep = 1; interruptible_sleep_on(&queue); } } if(!write_sleep) { write_sleep = 0; wake_up_process(write_task); } return size; } static ssize_t yamanetoshi_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { int i; for(i = 0; i < size; i++) { if(EOF == enqueue(buf[i])) { write_sleep = 1; interruptible_sleep_on(&queue); } } if(!read_sleep) { read_sleep = 0; wake_up_process(read_task); } return size; } struct file_operations fifo_fops = { .owner = THIS_MODULE, .read = yamanetoshi_read, .write = yamanetoshi_write, .ioctl = NULL, .open = yamanetoshi_open, .release = yamanetoshi_release, }; // Start/Init function 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; return 0; } // End/Cleanup function static void yamanetoshi_exit(void) { printk("cleanup the fifo device\n"); unregister_chrdev(fifo_major, DRIVERNAME); } module_init(yamanetoshi_init); module_exit(yamanetoshi_exit);
とても怖くて実機で試験とかできそうにないので vmware な環境作ります。(何