设计一个信号量,当有人写入时唤醒读出程序,从内核缓冲区读出数据
内核的新建,实例与卸载相关代码可以自行查询,一对一只需设置一个信号量即可实现
内核驱动#include读者模块#include #include #include #include #include #include #include #include #include #include #define MAXNUM 100 #define MAJOR_NUM 290 struct dev{ struct cdev devm; //字符设备 struct semaphore sem; //PV操作 wait_queue_head_t outq; int flag; //唤醒标志 char buffer[MAXNUM + 1]; char *rd, *wr, *end; }globalvar; static struct class *my_class; int major = MAJOR_NUM; static ssize_t globalvar_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { if(wait_event_interruptible(globalvar.outq, globalvar.flag!=0)) //不可读时 阻塞读进程 { return -ERESTARTSYS; } if(down_interruptible(&globalvar.sem)) //P 操作 { return -ERESTARTSYS; } globalvar.flag = 0; if(globalvar.rd < globalvar.wr) len = min(len,(size_t)(globalvar.wr - globalvar.rd)); //更新读写长度 else len = min(len,(size_t)(globalvar.end - globalvar.rd)); if(copy_to_user(buf,globalvar.rd,len)) { printk(KERN_alert"copy failedn"); up(&globalvar.sem); return -EFAULT; } globalvar.rd = globalvar.rd + len; if(globalvar.rd == globalvar.end) globalvar.rd = globalvar.buffer; //字符缓冲区循环 up(&globalvar.sem); //V 操作 return len; } static ssize_t globalvar_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { if(down_interruptible(&globalvar.sem)) //P 操作 { return -ERESTARTSYS; } if(globalvar.rd <= globalvar.wr) len = min(len,(size_t)(globalvar.end - globalvar.wr)); else len = min(len,(size_t)(globalvar.rd - globalvar.wr-1)); if(copy_from_user(globalvar.wr,buf,len)) { up(&globalvar.sem); //V 操作 return -EFAULT; } globalvar.wr = globalvar.wr + len; if(globalvar.wr == globalvar.end) globalvar.wr = globalvar.buffer; //循环 up(&globalvar.sem);//V 操作 globalvar.flag = 1; //条件成立,可以唤醒读进程 wake_up_interruptible(&globalvar.outq); //唤醒读进程 return len; } static int globalvar_open(struct inode *inode,struct file *filp) { try_module_get(THIS_MODULE); //模块计数加一 printk("This chrdev is in openn"); return(0); } static int globalvar_release(struct inode *inode,struct file *filp) { module_put(THIS_MODULE); //模块计数减一 printk("This chrdev is in releasen"); return(0); } struct file_operations globalvar_fops = { .read = globalvar_read, .write = globalvar_write, .open = globalvar_open, .release = globalvar_release, }; int globalvar_init(void) { dev_t dev = MKDEV(major, 0); int result; if(major) { //静态申请设备编号 result = register_chrdev_region(dev, 1, "charmem"); } else { //动态分配设备号 result = alloc_chrdev_region(&dev, 0, 1, "charmem"); major = MAJOR(dev); } if(result < 0) return result; cdev_init(&globalvar.devm, &globalvar_fops); globalvar.devm.owner = THIS_MODULE; cdev_add(&globalvar.devm, dev, 1); sema_init(&globalvar.sem, 1); init_waitqueue_head(&globalvar.outq); globalvar.rd = globalvar.buffer; globalvar.wr = globalvar.buffer; globalvar.end = globalvar.buffer + MAXNUM; globalvar.flag = 0; my_class = class_create(THIS_MODULE, "chardev0"); device_create(my_class, NULL, dev, NULL, "chardev0"); return 0; } static void globalvar_exit(void) { device_destroy(my_class, MKDEV(major, 0)); class_destroy(my_class); cdev_del(&globalvar.devm); unregister_chrdev_region(MKDEV(major, 0), 1); } module_init(globalvar_init); module_exit(globalvar_exit); MODULE_LICENSE("GPL");
#include写者模块//read #include #include #include #include #include int main() { int fd,i; char msg[101]; fd= open("/dev/chardev0",O_RDWR,S_IRUSR|S_IWUSR); if(fd!=-1) { while(1) { for(i=0;i<101;i++) //初始化 msg[i]=' '; read(fd,msg,100); printf("%sn",msg); if(strcmp(msg,"quit()")==0) { close(fd); break; } } } else { printf("device open failure,%dn",fd); } return 0; }
#includeMakefile文件//writer #include #include #include #include #include int main() { int fd; char msg[100]; fd= open("/dev/chardev0",O_RDWR,S_IRUSR|S_IWUSR); if(fd!=-1) { while(1) { printf("Please input the globar:n"); scanf("%s",msg); write(fd,msg,strlen(msg)); if(strcmp(msg,"quit()")==0) { close(fd); break; } } } else { printf("device open failuren"); } return 0; }
CONFIG_MODULE_SIG=n
ifneq ($(KERNELRELEASE),)
obj-m :=dev.o
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif
多对多群聊
这里实现的是多写者多读者
这里需要设计一下,因为一对一是只要有写者写了,读者就会被唤醒,但是当有多个读者时,如何唤醒多个读者?如何确保每个读者只读一次?
这里修改了原本的唤醒信号量flag,又增加了一个等待队列,用来存放已经读了一次数据的读者。
Flag值为拥有的读进程个数,有几个读进程就有几个flag,因此读一次可以唤醒n个写进程
还需要另外一个互斥量,就是当多个读者一起读时,每个进程只能读一次,因此:
当读者读了一次时,并且还有其他读者没读(flag!=0),需要把读进程阻塞,当且仅当最后一个读进程读完时,读进程被唤醒。
#include#include #include #include #include #include #include #include #include //................. #include //................... #include #define MAXNUM 100 #define MAJOR_NUM 290 struct dev{ struct cdev devm; //zi fu she bei struct semaphore sem; //PV wait_queue_head_t outq,que; int flag; //huan xing char buffer[MAXNUM + 1]; char *rd, *wr, *end; }globalvar; //................ static struct class *my_class; //................ int major = MAJOR_NUM; int num = -1; int copy_num; static ssize_t globalvar_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { if(wait_event_interruptible(globalvar.outq, globalvar.flag!=0)) //不可读时 阻塞读进程,0 sleep 1wake up { return -ERESTARTSYS; } // bu bei zu se if(down_interruptible(&globalvar.sem)) //P 操作 { return -ERESTARTSYS; } //yao rang bie ren du globalvar.flag--; if(copy_to_user(buf,globalvar.rd,len)) { printk(KERN_alert"copy failedn"); up(&globalvar.sem); return -EFAULT; } copy_num--; up(&globalvar.sem); //V 操作 if(wait_event_interruptible(globalvar.que, copy_num == 0)) //不可读时 阻塞读进程,0 sleep 1wake up { return -ERESTARTSYS; } if(copy_num==0) wake_up_interruptible(&globalvar.que); return len; } static ssize_t globalvar_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) { if(down_interruptible(&globalvar.sem)) //P 操作 { return -ERESTARTSYS; } if(copy_from_user(globalvar.wr,buf,100)) { up(&globalvar.sem); //V 操作 return -EFAULT; } up(&globalvar.sem);//V 操作 globalvar.flag = num; //条件成立,可以唤醒读进程 copy_num = num; wake_up_interruptible(&globalvar.outq); //唤醒读进程 return len; } static int globalvar_open(struct inode *inode,struct file *filp) { num++; try_module_get(THIS_MODULE); //模块计数加一 printk("This chrdev is in openn"); return(0); } static int globalvar_release(struct inode *inode,struct file *filp) { num--; module_put(THIS_MODULE); //模块计数减一 printk("This chrdev is in releasen"); return(0); } struct file_operations globalvar_fops = { .read = globalvar_read, .write = globalvar_write, .open = globalvar_open, .release = globalvar_release, }; int globalvar_init(void) { //major and mijor to the place in table dev_t dev = MKDEV(major, 0); int err = 0; int result = 0; //register if(major) { //静态申请设备编号 result = register_chrdev_region(dev, 1, "charmem"); } else { //动态分配设备号 result = alloc_chrdev_region(&dev, 0, 1, "charmem"); major = MAJOR(dev); } //failure if(result < 0) return result; cdev_init(&globalvar.devm, &globalvar_fops); globalvar.devm.owner = THIS_MODULE; err = cdev_add(&globalvar.devm, dev, 1); if(err) printk(KERN_INFO"Error %d adding char_mem device",err); else{ //sema init sema_init(&globalvar.sem, 1); //waitquere init init_waitqueue_head(&globalvar.outq); init_waitqueue_head(&globalvar.que); globalvar.rd = globalvar.buffer; globalvar.wr = globalvar.buffer; globalvar.end = globalvar.buffer + MAXNUM; globalvar.flag = 0; } //............................. my_class = class_create(THIS_MODULE, "chardev0"); device_create(my_class, NULL, dev, NULL, "chardev0"); //.............................. return 0; } static void globalvar_exit(void) { //........................................... device_destroy(my_class, MKDEV(major, 0)); class_destroy(my_class); //............................................. cdev_del(&globalvar.devm); unregister_chrdev_region(MKDEV(major, 0), 1); } module_init(globalvar_init); module_exit(globalvar_exit); MODULE_LICENSE("GPL");
读写程序和Makefile文件相同



